12 KiB
Quote Text and PDF Generation - Implementation Summary
Overview
Complete implementation of quote text generation (static and AI-powered) and PDF export functionality for the FinalReview component.
Existing Code Found
1. PDF Generation Service
File: backend/src/services/pdfGenerationService.js
Features:
- Complete PDF template with professional layout (2 pages)
- Logo integration from filesystem (3 logos loaded as base64):
- Mikael Holck company logo
- Byg Garanti certification logo
- Elite Håndværker badge
- Uses Puppeteer for PDF generation
- Automatic work description generation based on materials and geometry
- Company information footer on both pages
- Professional formatting with A4 size, proper margins
Key Methods:
loadLogos()- Loads 3 company logos from/home/alex/git/tilbudgivern/frontend/firmadata/firmabilledergenerateWorkDescription(data)- Generates task description based on materials and roof typegeneratePdfHtml(data)- Creates complete HTML template with stylinggenerateQuotePdf(data)- Converts HTML to PDF buffer using Puppeteer
Logo Files Required:
MIKHOL_logo.png- Company logobyggarenti_logo.png- Byg Garanti certificationelitehaandvaerker_logo.png- Elite craftsman badge
2. Project Quote Generation Service
File: backend/src/services/projectQuoteGenerationService.js
Features:
- Static template-based quote generation (no AI tokens)
- Professional quote with Danish language
- Service descriptions for different project types (roof, floor, windows, terrace, etc.)
- Company values and guarantees included
- Automatic service description selection based on project type
Key Methods:
generateStaticQuote(projectId, calculationId, options)- Generate quote without AIgenerateProfessionalQuote(projectId, calculationId, options)- Generate with AIgetRelevantServiceDescription(projectDescription, roofType)- Smart service matchingbuildCompleteStaticQuote(companyInfo, serviceDescriptions, quoteData)- Template builder
Service Types Covered:
- Tagrenovering (roof renovation)
- Gulvudskiftning (floor replacement)
- Vinduer og døre (windows and doors)
- Terrasser (decks)
- Tilbygninger (extensions)
- Tagvinduer (skylights)
3. OpenAI Service
File: backend/src/services/openaiService.js
Features:
- AI-powered quote generation with custom instructions
- Historical data integration for accurate pricing
- Smart prompt engineering for carpenter/construction work
- Token usage tracking and cost calculation
- Support for regional pricing (Denmark)
Key Method:
generateQuote(quoteRequest)- Generate AI quote with context
Parameters:
description- Project descriptionarea- Project area in m²projectType- Type of construction workadditionalInfo- Custom instructions from userregion- Regional pricing context
New Endpoints Implemented
1. POST /api/quotes/generate-static
Purpose: Generate static quote text without using AI (no tokens/cost)
Request Body:
{
"projectId": 19
}
Response:
{
"success": true,
"quoteText": "TILBUD FRA...",
"method": "static_template",
"tokensUsed": 0,
"cost": 0
}
Features:
- Loads project, geometry, materials, and tasks from database
- Calculates all totals (labor, materials, subtotal, VAT, total)
- Generates professional Danish quote with company information
- Includes material list, labor breakdown, pricing, guarantees
- Company contact information and 30-day validity
2. POST /api/quotes/generate-ai
Purpose: Generate AI-powered quote text with custom instructions
Request Body:
{
"projectId": 19,
"customInstructions": "Fokuser på miljøvenlige materialer og bæredygtighed"
}
Response:
{
"success": true,
"quoteText": "AI-generated quote...",
"method": "ai_generated",
"tokensUsed": 1500,
"cost": 0.03
}
Features:
- Uses OpenAI GPT model for natural language generation
- Includes all project details in AI prompt
- Supports custom instructions from user
- Tracks token usage and costs
- Professional, warm, and detailed output in Danish
- Highlights quality, service, and company values
3. POST /api/pdf/generate
Purpose: Generate and download PDF with logos and professional layout
Request Body:
{
"projectId": 19,
"quoteText": "Optional pre-generated quote text"
}
Response:
- Binary PDF file (application/pdf)
- Filename:
tilbud_ProjectName_timestamp.pdf
Features:
- 2-page professional PDF layout
- Page 1: Quote with pricing and details
- Page 2: Company description and certifications
- 3 embedded logos (base64 encoded)
- Proper Danish formatting (currency, dates)
- Company footer on both pages
- A4 format with 20mm margins
Frontend Integration
FinalReview Component
File: frontend/src/components/FinalReview.js
UI Elements Added:
-
Quote Type Selector:
- Radio buttons: "Standard tilbudstekst" (static) or "AI-genereret" (AI)
-
AI Instructions Field:
- Textarea for custom instructions
- Only visible when AI option selected
- Placeholder: "F.eks. 'Fokuser på miljøvenlige materialer'..."
-
Generate Quote Button:
- Calls appropriate endpoint based on selection
- Shows loading state during generation
- Displays generated text in textarea editor
-
Quote Text Editor:
- Large textarea for viewing/editing quote
- 400px height, 12 rows
- User can edit before generating PDF
-
PDF Generation Button:
- Downloads PDF with current project data
- Shows loading state
- Error handling with user-friendly messages
API Integration:
// Static quote
const response = await fetch(`${apiBaseUrl}/api/quotes/generate-static`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ projectId: project.id })
});
// AI quote
const response = await fetch(`${apiBaseUrl}/api/quotes/generate-ai`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
projectId: project.id,
customInstructions: aiInstructions
})
});
// PDF download
const response = await fetch(`${apiBaseUrl}/api/pdf/generate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ projectId: project.id })
});
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `tilbud_${project.project_name}_${Date.now()}.pdf`;
a.click();
CSS Styling
File: frontend/src/components/FinalReview.css
Sections Added:
.quote-text-section- Main container.quote-generation-controls- Control panel layout.quote-type-selector- Radio button styling.quote-type-option- Individual option styling.ai-instructions- Textarea styling.generate-quote-btn- Generate button (blue).quote-editor- Text editor styling.generate-pdf-btn- PDF button (green)- Hover states and loading states
Company Information
Default Company Data:
{
name: "Tømrer- og Snedkermester Mikael Holck ApS",
phone: "42 46 81 10",
cvr: "38178059",
address: "Hornumvej 7",
city: "4600 Køge",
bank: "Nordea",
email: "[email protected]",
account: "2558 6284200630",
website: "www.mikaelholck.dk"
}
Company Values:
- Kvalitet i verdensklasse
- Til tiden, hver gang
- Ryddelig aflevering
- Åben kommunikation
Guarantees:
- Byg Garanti medlem
- 5 års garanti på arbejde
- 10 års garanti på materialer
- Elite Håndværker certificeret
Testing
Test Project Data (Project ID 19)
- Customer: Test Kunde
- Project: Test Tag Projekt (ID: 19)
- Geometry: wall_height=3.5m, stern_to_ridge_height=1.5m, total_area=117.19m²
- Materials: 6 Bygma materials (63,638 kr)
- Tasks: 8 tasks with 128 hours (222,720 kr labor)
- Total: ~358,000 kr (incl. VAT)
Testing Checklist
- Static quote generation works
- AI quote generation with custom instructions
- PDF generation with logos
- Quote text editing in textarea
- PDF download with correct filename
- Error handling for missing data
- Loading states during generation
- Test with actual OpenAI API key (requires setup)
- Verify logo files exist at correct path
- Test on different project types
- Mobile responsive testing
Deployment Status
Backend
- ✅ New endpoints added to
unified-server.js - ✅ Server restarted with PM2 (14 restarts)
- ✅ No errors in logs
- ✅ Services initialized correctly
Frontend
- ✅ FinalReview component updated with UI
- ✅ CSS styling complete
- ✅ API calls implemented
- ✅ Built successfully (main.1c3e93b5.js)
- ✅ Deployed to production
Services Status (PM2)
┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name │ mode │ ↺ │ status │ cpu │ memory │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 1 │ analytics-api │ fork │ 0 │ online │ 0% │ 66.0mb │
│ 2 │ carpenter-tasks-a… │ fork │ 0 │ online │ 0% │ 63.7mb │
│ 0 │ tilbudgivern-unif… │ fork │ 14 │ online │ 0% │ 21.0mb │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘
Configuration Requirements
Environment Variables
# OpenAI API (for AI quote generation)
OPENAI_API_KEY=sk-...
# Database
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=...
DB_NAME=tilbudgivern
# Logo Path (in pdfGenerationService.js)
LOGO_PATH=/home/alex/git/tilbudgivern/frontend/firmadata/firmabilleder
Required Files
/home/alex/git/tilbudgivern/frontend/firmadata/firmabilleder/
├── MIKHOL_logo.png (company logo)
├── byggarenti_logo.png (Byg Garanti certification)
└── elitehaandvaerker_logo.png (Elite craftsman badge)
Dependencies
puppeteer- PDF generation from HTMLopenai- AI quote generation- Node.js 18.20.8+
- MySQL database
Future Enhancements
Short Term
- Add quote text preview before PDF generation
- Save generated quotes to database for history
- Email delivery of PDF quotes
- Template customization interface
Long Term
- Multiple company profile support
- Custom logo upload interface
- Quote comparison feature
- Customer feedback integration
- Version control for quotes
- Digital signature support
Documentation Links
- PDF Generation Service - Complete PDF generation logic
- Project Quote Service - Static template logic
- OpenAI Service - AI quote generation
- FinalReview Component - UI implementation
- API Endpoints - Lines 1349-1778 (new endpoints)
Support
For issues or questions:
- Check PM2 logs:
pm2 logs tilbudgivern-unified - Verify logo files exist:
ls -la /home/alex/git/tilbudgivern/frontend/firmadata/firmabilleder/ - Test OpenAI API: Check OPENAI_API_KEY environment variable
- Database queries: Check MySQL connection and table structure
Last Updated: 2025-10-25 06:05 Status: ✅ Production Ready Version: 1.0.0