Files
tilbudgivern/docs/features/ORDRESTYRING_GRAPHQL_INTEGRATION.md
T

499 lines
12 KiB
Markdown

# 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": "[email protected]"
},
"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 (
<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
```bash
# .env
ORDRESTYRING_GRAPHQL_URL=https://graphql.ordrestyring.dk/graphql
ORDRESTYRING_API_KEY=<ORDRESTYRING_API_TOKEN>
```
### 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/`