12 KiB
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
notesfeltet - 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:
{
"projectId": 1,
"calculationId": 1
}
Response:
{
"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:
{
"projectId": 1,
"calculationId": 1,
"customerId": 5358
}
Response:
{
"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
notesfeltet (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:
{
"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:
{
"statusId": 2
}
Status IDs:
- 1: Draft
- 2: Sent
- 3: Accepted
- 4: Rejected
Response:
{
"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:
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:
-
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
-
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
-
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
-
getOfferFromOrdrestyring(offerId)
- Henter tilbud via GraphQL query
- Returnerer komplet offer med linjer og status
-
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:
- Hente alle tilgængelige statusser fra Ordrestyring API
- Søge efter "Tilbudsgiver Oprettet Tilbud" (case-insensitive)
- Bruge det fundne status ID i createOffer mutation
- 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:
python3 test_ordrestyring_integration.py
Test scriptet:
- Genererer preview af beskrivelse
- Spørger om tilladelse til at sende
- Sender tilbud til Ordrestyring
- Henter tilbuddet tilbage for verifikation
Frontend Integration
FinalReview Component
Tilføj "Send til Ordrestyring" knap:
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 (
<div>
{/* Eksisterende UI */}
<button
onClick={sendToOrdrestyring}
disabled={loading || !project.ordrestyring_customer_id}
className="btn-primary"
>
📤 Send til Ordrestyring
</button>
{offerNumber && (
<div className="success-message">
✅ Sendt til Ordrestyring: {offerNumber}
</div>
)}
</div>
);
Configuration
Environment Variables
# .env
ORDRESTYRING_GRAPHQL_URL=https://graphql.ordrestyring.dk/graphql
ORDRESTYRING_API_KEY=<ORDRESTYRING_API_TOKEN>
Dependencies
Tilføjet i backend/package.json:
{
"dependencies": {
"graphql": "^16.8.1",
"graphql-request": "^6.1.0"
}
}
Workflow
- Kunde opretter projekt → Projekt gemt i customer_projects
- AI/Manual beregning → Beregning gemt i project_calculations
- Final Review → Bruger ser komplet tilbud
- Send til Ordrestyring → Click button
- generateDetailedQuoteDescription() genererer beskrivelse
- sendQuoteToOrdrestyring() sender via GraphQL
- Offer ID og nummer gemt i database
- Status tracking → Synkroniser status mellem systemer
- 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:
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
- Webhook integration: Modtag status opdateringer fra Ordrestyring
- Batch sending: Send flere tilbud på én gang
- Automatic sync: Periodisk synkronisering af status
- Customer mapping: Automatisk match mellem lokale kunder og Ordrestyring kunder
- 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/