# Ordrestyring GraphQL Integration ## Oversigt Denne integration sender komplette tilbud til Ordrestyring via GraphQL API med detaljeret beskrivelse i professionelt format. ## Features ✅ **Detaljeret tilbudsbeskrivelse** med alle sektioner: - ARBEJDE DER UDFØRES (geometri, arbejdstimer, opgavebeskrivelse) - MATERIALER (komplet liste med priser) - PRISSPECIFIKATION (arbejde, materialer, moms, totaler) - VORES LØFTE TIL DIG (firma kvalitetsløfter) - GARANTIER OG SERVICE (garantier og support) - Standard tekster og disclaimers ✅ **Interne beregninger i bemærkninger** (ikke synlige for kunde): - Overhead og fortjeneste gemmes i `notes` feltet - Kun synligt internt i Ordrestyring systemet - Fuld transparens internt uden at afsløre fortjeneste til kunde ✅ **Automatisk status**: Sætter "Tilbudsgiver Oprettet Tilbud" når tilbud oprettes ✅ **Dansk prisformatering** med tusindtalsseparator (195.906,94 kr) ✅ **GraphQL API integration** via https://graphql.ordrestyring.dk/graphql ✅ **Automatisk synkronisering** mellem lokal database og Ordrestyring ✅ **Status tracking** af tilbud i begge systemer ## API Endpoints ### 1. Preview Tilbudsbeskrivelse **Endpoint:** `POST /api/ordrestyring/preview-description` Preview tilbudsbeskrivelse uden at sende til Ordrestyring. **Request:** ```json { "projectId": 1, "calculationId": 1 } ``` **Response:** ```json { "success": true, "description": "Tilbud på udskiftning af tag...\n\nARBEJDE DER UDFØRES:\n...", "internalNotes": "INTERNE BEREGNINGER (kun synlig internt):\n\nSubtotal: 116.093,00 kr\nOverhead (15%): 17.413,95 kr\nFortjeneste (20%): 23.218,60 kr\n...", "priceExVat": 156725.55, "priceInclVat": 195906.94, "materials": [...] } ``` ### 2. Send Tilbud til Ordrestyring **Endpoint:** `POST /api/ordrestyring/send-quote-graphql` Send tilbud til Ordrestyring med komplet beskrivelse via GraphQL API. **Request:** ```json { "projectId": 1, "calculationId": 1, "customerId": 5358 } ``` **Response:** ```json { "success": true, "message": "Tilbud sendt til Ordrestyring via GraphQL", "offer": { "id": 12345, "number": "TIL-2024-00123", "createdAt": "2024-01-15T10:30:00Z", "customer": { "id": 5358, "name": "Anders Jensen" }, "totals": { "salesPrice": 156725.55, "salesPriceWithVat": 195906.94 }, "status": { "id": 999926, "text": "Tilbudsgiver Oprettet Tilbud" } }, "description": "..." } ``` **Funktionalitet:** - Sender komplet tilbudsbeskrivelse til kunde (uden overhead/fortjeneste) - Gemmer interne beregninger i `notes` feltet (kun synligt internt i Ordrestyring) - Sætter automatisk status til "Tilbudsgiver Oprettet Tilbud" - Opdaterer lokal database med Ordrestyring reference ### 3. Hent Tilbud fra Ordrestyring **Endpoint:** `GET /api/ordrestyring/offer/:offerId` Hent detaljer om tilbud fra Ordrestyring. **Response:** ```json { "success": true, "offer": { "id": 12345, "number": "TIL-2024-00123", "description": "...", "customer": { "id": 5358, "name": "Anders Jensen", "email": "anders@example.com" }, "lines": [ { "id": 1, "description": "Eternit B7 tagplader", "quantity": 223, "unit": "stk", "unitPrice": 245.00, "total": 54635.00 } ], "totals": {...}, "status": {...} } } ``` ### 4. Opdater Tilbud Status **Endpoint:** `POST /api/ordrestyring/offer/:offerId/status` Opdater status på tilbud i Ordrestyring. **Request:** ```json { "statusId": 2 } ``` Status IDs: - 1: Draft - 2: Sent - 3: Accepted - 4: Rejected **Response:** ```json { "success": true, "message": "Tilbud status opdateret", "offer": { "id": 12345, "number": "TIL-2024-00123", "status": { "id": 2, "text": "Sent" } } } ``` ## Database Schema Nye kolonner i `generated_quotes` tabel: ```sql ALTER TABLE generated_quotes ADD COLUMN ordrestyring_offer_id INT NULL COMMENT 'Offer ID fra Ordrestyring GraphQL API', ADD COLUMN ordrestyring_offer_number VARCHAR(50) NULL COMMENT 'Offer nummer fra Ordrestyring', ADD COLUMN ordrestyring_sent_at DATETIME NULL COMMENT 'Tidspunkt for afsendelse til Ordrestyring', ADD COLUMN ordrestyring_status VARCHAR(50) NULL COMMENT 'Status fra Ordrestyring'; ``` ## Service Arkitektur ### OrdrestyringQuoteService **Location:** `backend/src/services/ordrestyringQuoteService.js` **Metoder:** 1. **generateDetailedQuoteDescription(projectId, calculationId)** - Henter projekt, geometri, arbejdstimer, materialer, beregninger - Formaterer komplet beskrivelse med alle sektioner (ARBEJDE, MATERIALER, PRISER, LØFTER, GARANTIER) - Genererer interne noter med overhead og fortjeneste (gemmes i `notes`) - Beregner priser med overhead og fortjeneste inkluderet - Returnerer beskrivelse, internalNotes og pris data 2. **getOfferStatusId(statusText)** - Henter alle tilgængelige statusser fra Ordrestyring - Finder status ID baseret på tekst (case-insensitive) - Fallback til "Nyt tilbud" hvis status ikke findes - Bruges til at sætte "Tilbudsgiver Oprettet Tilbud" status 3. **sendQuoteToOrdrestyring(projectId, calculationId, customerId)** - Genererer beskrivelse via generateDetailedQuoteDescription() - Henter status ID for "Tilbudsgiver Oprettet Tilbud" - Sender GraphQL createOffer mutation med: * `description`: Komplet tilbudsbeskrivelse (til kunde) * `notes`: Interne beregninger med overhead/fortjeneste (kun internt) * `statusId`: "Tilbudsgiver Oprettet Tilbud" * `lines`: Materialer som offer linjer - Gemmer Ordrestyring reference i lokal database - Returnerer offer data fra Ordrestyring 3. **getOfferFromOrdrestyring(offerId)** - Henter tilbud via GraphQL query - Returnerer komplet offer med linjer og status 4. **updateOfferStatus(offerId, statusId)** - Opdaterer status via GraphQL mutation - Logger status ændring ## Interne Beregninger Overhead og fortjeneste beregnes men vises **KUN** i interne noter: ### Kunde Beskrivelse (description) ``` PRISSPECIFIKATION: Arbejdsløn: 49.590,00 kr Materialer: 66.503,00 kr ───────────────────────────── Subtotal: 116.093,00 kr Moms (25%): 39.181,39 kr ───────────────────────────── SAMLET PRIS EKS. MOMS: 156.725,55 kr INKL. MOMS (25%): 195.906,94 kr ``` ### Interne Noter (notes - kun synligt internt) ``` INTERNE BEREGNINGER (kun synlig internt): Subtotal (arbejde + materialer): 116.093,00 kr Overhead (15%): 17.413,95 kr Fortjeneste (20%): 23.218,60 kr ───────────────────────────── Pris ex. moms: 156.725,55 kr Moms (25%): 39.181,39 kr Pris inkl. moms: 195.906,94 kr Projektinfo: - Projekt ID: 1 - Beregning ID: 1 - Oprettet: 2024-01-15T10:30:00Z - Timepris: 580,00 kr/time - Timer total: 85.5 timer ``` Dette sikrer: - ✅ Kunden ser kun arbejde, materialer og totaler - ✅ Interne medarbejdere kan se fuld kalkulation i Ordrestyring - ✅ Transparens internt uden at afsløre fortjeneste eksternt ## Tilbudsstatus Når tilbud sendes til Ordrestyring sættes automatisk status: **"Tilbudsgiver Oprettet Tilbud"** Servicen finder automatisk det korrekte status ID ved at: 1. Hente alle tilgængelige statusser fra Ordrestyring API 2. Søge efter "Tilbudsgiver Oprettet Tilbud" (case-insensitive) 3. Bruge det fundne status ID i createOffer mutation 4. Fallback til "Nyt tilbud" hvis status ikke findes Status kan senere opdateres via `updateOfferStatus()` metoden. ## Beskrivelsesformat Genereret beskrivelse følger dette format: ``` Tilbud på [projekt beskrivelse]. ARBEJDE DER UDFØRES: [Tag type / arbejdstype] Opmåling og forberedelse • Samlet areal: X m² • Taghældning: X° • Taghøjde: X m Arbejdsudførelse • Arbejdstimer: X timer med X tømrere • Timepris: X kr/time • Alt affald bortkøres • Området ryddes og efterlades rent MATERIALER: • Material 1: X stk - XX.XXX,XX kr • Material 2: X stk - XX.XXX,XX kr ... Vi indhenter tilbud fra flere leverandører... PRISSPECIFIKATION: Arbejdsløn: XX.XXX,XX kr Materialer: XX.XXX,XX kr ───────────────────────────── Subtotal: XX.XXX,XX kr Moms (25%): XX.XXX,XX kr ───────────────────────────── SAMLET PRIS EKS. MOMS: XXX.XXX,XX kr INKL. MOMS (25%): XXX.XXX,XX kr *Hvis der bruges kortere tid... VORES LØFTE TIL DIG: • Præcision og ordentlighed i alt hvad vi laver • Tradition og transformation går hånd i hånd • Meningsfuldt, ordentligt og bæredygtigt håndværk • Vi kommer til tiden og står inde for vores arbejde Vi leverer altid det aftalte... GARANTIER OG SERVICE: • Gratis tagtjek tilbydes • Professionel rådgivning i valg af løsninger • Korrekt dokumentation og tryghed • Kvalitet der holder i mange år TILBUDDET ER GYLDIGT I 30 DAGE Der tages forbehold for rød og svamp... Med venlig hilsen Tømrer- og Snedkermester Mikael Holck ApS ... ``` ## Test Script **Location:** `test_ordrestyring_integration.py` Kør test: ```bash python3 test_ordrestyring_integration.py ``` Test scriptet: 1. Genererer preview af beskrivelse 2. Spørger om tilladelse til at sende 3. Sender tilbud til Ordrestyring 4. Henter tilbuddet tilbage for verifikation ## Frontend Integration ### FinalReview Component Tilføj "Send til Ordrestyring" knap: ```javascript const sendToOrdrestyring = async () => { try { setLoading(true); const response = await fetch('/api/ordrestyring/send-quote-graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ projectId: project.id, calculationId: calculation.id, customerId: project.ordrestyring_customer_id // Fra kunde record }) }); const data = await response.json(); if (data.success) { setOfferNumber(data.offer.number); showSuccess(`Tilbud sendt til Ordrestyring: ${data.offer.number}`); } else { showError(data.error); } } catch (error) { showError('Fejl ved afsendelse til Ordrestyring'); } finally { setLoading(false); } }; return (
{/* Eksisterende UI */} {offerNumber && (
✅ Sendt til Ordrestyring: {offerNumber}
)}
); ``` ## Configuration ### Environment Variables ```bash # .env ORDRESTYRING_GRAPHQL_URL=https://graphql.ordrestyring.dk/graphql ORDRESTYRING_API_KEY=cRD7xfeoiGh1OhzV ``` ### Dependencies Tilføjet i `backend/package.json`: ```json { "dependencies": { "graphql": "^16.8.1", "graphql-request": "^6.1.0" } } ``` ## Workflow 1. **Kunde opretter projekt** → Projekt gemt i customer_projects 2. **AI/Manual beregning** → Beregning gemt i project_calculations 3. **Final Review** → Bruger ser komplet tilbud 4. **Send til Ordrestyring** → Click button - generateDetailedQuoteDescription() genererer beskrivelse - sendQuoteToOrdrestyring() sender via GraphQL - Offer ID og nummer gemt i database 5. **Status tracking** → Synkroniser status mellem systemer 6. **Kunde godkender** → updateOfferStatus(offerId, 3) ## Error Handling Service håndterer fejl gracefully: - **Database fejl**: Logger og returnerer specifik fejl - **GraphQL fejl**: Parser fejl fra Ordrestyring API - **Network fejl**: Timeout efter 10 sekunder - **Validation fejl**: Checker required fields før API kald Alle fejl logges via Winston logger: ```javascript logger.error('Error sending quote to Ordrestyring:', error); ``` ## Security - ✅ API key gemt i environment variable - ✅ Authorization header med Bearer token - ✅ Input validation på alle endpoints - ✅ SQL injection protection via parameterized queries - ✅ HTTPS til Ordrestyring API ## Fremtidige Forbedringer 1. **Webhook integration**: Modtag status opdateringer fra Ordrestyring 2. **Batch sending**: Send flere tilbud på én gang 3. **Automatic sync**: Periodisk synkronisering af status 4. **Customer mapping**: Automatisk match mellem lokale kunder og Ordrestyring kunder 5. **Template system**: Tilpassede beskrivelser per kunde type ## Support Ved fejl eller spørgsmål, se: - GraphQL dokumentation: `apitest/API_INTEGRATION_GUIDE.md` - Service implementation: `backend/src/services/ordrestyringQuoteService.js` - Test examples: `apitest/examples/`