6.4 KiB
Comparison Offers Feature Documentation
Overview
The comparison offers feature requires users to provide at least 3 comparison offers for each cost position in their application. This ensures transparency and cost-effectiveness in funding requests. Users can alternatively provide a justification if comparison offers are not applicable for specific cost positions.
Features
- 3 Offers Requirement: Each cost position must have at least 3 comparison offers
- Justification Alternative: Users can mark that no offers are required and provide a detailed justification
- Attachment Support: Each offer can be linked to an uploaded attachment (e.g., quotes, invoices)
- Visual Indicators: Cost positions without sufficient offers are highlighted with warning icons
- Status Tracking: Real-time status display showing offer count and completion status
Database Schema
comparison_offers Table
Stores comparison offers for cost positions:
id(INT, PRIMARY KEY) - Unique identifierapplication_id(INT) - References the applicationcost_position_index(INT) - Index of the cost position in the costs arraysupplier_name(VARCHAR 255) - Name of the supplier/vendoramount(INT) - Offer amount in centsdescription(TEXT) - Optional description of the offerurl(VARCHAR 500) - Optional URL to offer document or webpageattachment_id(INT) - Optional reference to an attachmentcreated_at(DATETIME) - Creation timestampupdated_at(DATETIME) - Last update timestamp
cost_position_justifications Table
Stores justifications for positions without offers:
id(INT, PRIMARY KEY) - Unique identifierapplication_id(INT) - References the applicationcost_position_index(INT) - Index of the cost positionno_offers_required(INT) - Boolean flag (0/1)justification(TEXT) - Required explanation when no_offers_required is 1created_at(DATETIME) - Creation timestampupdated_at(DATETIME) - Last update timestamp
API Endpoints
Create Comparison Offer
POST /api/applications/{pa_id}/costs/{cost_position_index}/offers
- Request body:
{ "supplier_name": "Supplier GmbH", "amount": 1500.50, "description": "Optional description", "url": "https://beispiel.de/angebot.pdf", "attachment_id": 123 } - Returns: ComparisonOfferResponse with offer details
Get Cost Position Offers
GET /api/applications/{pa_id}/costs/{cost_position_index}/offers
- Returns: CostPositionOffersResponse with all offers and justification info
Delete Comparison Offer
DELETE /api/applications/{pa_id}/costs/{cost_position_index}/offers/{offer_id}
- Removes a specific offer
Update Cost Position Justification
PUT /api/applications/{pa_id}/costs/{cost_position_index}/justification
- Request body:
{ "no_offers_required": true, "justification": "Detailed explanation why no offers are needed..." }
Frontend Components
ComparisonOffersDialog
Main dialog for managing offers for a cost position:
- Add/remove comparison offers
- Add URL links to online offers
- Link attachments to offers (either URL or attachment required)
- Mark position as not requiring offers
- Provide justification when needed
CostPositionsList
Enhanced cost positions list with offer status:
- Visual indicators for offer status
- Warning icons for incomplete positions
- Quick access to manage offers
- Real-time status updates
User Interface
Status Indicators
- ✅ Green checkmark: Position has 3+ offers
- ℹ️ Blue info icon: Position marked as not requiring offers (with justification)
- ⚠️ Yellow warning: Position needs more offers or justification
- 🔄 Loading spinner: Status being loaded
Validation Rules
- Each cost position must have either:
- At least 3 comparison offers, OR
- Be marked as "no offers required" with a justification (min. 10 characters)
- Cost positions without sufficient offers are highlighted in the list
- Offers must include:
- Supplier name (required, must be unique per cost position)
- Amount (required, must be greater than 0)
- Either URL or attachment (at least one required)
- Description (optional)
- Duplicate suppliers: Each supplier can only have one offer per cost position
- URL format: Must be a valid HTTP/HTTPS URL (protocol is auto-added if missing)
- Amount format: Accepts both comma and period as decimal separator
Migration
To add the comparison offers tables to your database:
mysql -u your_user -p your_database < src/migrations/add_comparison_offers_tables.sql
mysql -u your_user -p your_database < src/migrations/add_url_to_comparison_offers.sql
Usage Example
In Cost Positions List
<CostPositionsList
costs={formData.costs}
paId={applicationId}
paKey={applicationKey}
isAdmin={false}
readOnly={false}
attachments={availableAttachments}
/>
Managing Offers
- Click "Angebote" button next to any cost position
- In the dialog:
- Add up to 5 comparison offers
- Link existing attachments to offers
- OR check "no offers required" and provide justification
- Save changes
Best Practices
- Encourage Early Collection: Remind users to collect offers before starting the application
- Clear Instructions: Provide examples of valid justifications for positions without offers
- Attachment Organization: Name attachment files clearly to easily link them to offers
- Regular Validation: Check offer status before submission
Error Handling
- Duplicate Suppliers: Shows user-friendly error message when trying to add the same supplier twice
- Invalid URLs: Automatically prepends https:// if missing, validates format
- Invalid Amounts: Real-time validation with support for German number format (comma as decimal)
- Missing Data: Clear error messages when required fields are missing
Future Enhancements
- Bulk Import: Import multiple offers from CSV/Excel
- Templates: Save common suppliers for quick reuse
- Price Comparison: Automatic highlighting of best offer
- History Tracking: Track changes to offers over time
- Export Function: Export all offers as PDF/Excel report
- Smart Validation: Detect duplicate suppliers or suspicious patterns
- URL Validation: Automatic checking of URL availability and validity
- Screenshot Capture: Automatic capture of web-based offers for archival