Files
tilbudgivern/docs/features/ORDRESTYRING_GRAPHQL_INTEGRATION.md
2026-08-13 14:29:15 +02:00

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 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:

{
  "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 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:

{
  "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:

  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
  4. getOfferFromOrdrestyring(offerId)

    • Henter tilbud via GraphQL query
    • Returnerer komplet offer med linjer og status
  5. 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:

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:

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

  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:

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/