Angebote und Aufträge
Zuletzt geändert: 18.07.2026 17:11

Ressourcen: quotes und sales-orders #

Angebote (Angebot) und Aufträge (Auftrag) mit Positionen. Alles Wertbildende läuft über die EULANDA-SQL-API: Kopf-Anlage über cn_AnCre bzw. cn_CreAf (vergibt die Belegnummer aus dem Nummernkreis), Positionen über cn_CreAnp bzw. cn_CreAfp (macht Preisfindung, Steuer und Summen), Wandlung über cn_TraAnAf_Typ. Summen, Steuern und Status sind read-only. Buchen und Storno bleiben bewusst dem ERP-Anwender vorbehalten (eigene Scopes documents:book/documents:cancel folgen später).

Endpunkte #

Für beide Belegarten identisch (/api/v1/quotes/... bzw. /api/v1/sales-orders/...):

MethodePfadScopeZweck
GET/documents:readListe (Paging, q, changedSince, fields, customerMatch)
GET/by-number/{number}documents:readBeleg über die Belegnummer (KopfNummer)
GET/{id}documents:readBeleg über die Id
GET/{id}/itemsdocuments:readPositionen (read-only)
POST/documents:writeBeleg anlegen, optional mit Positionen
POST/{id}/itemsdocuments:writeEinzelne Position anlegen
PATCH/{id}documents:writeUnkritische Kopf-Felder ändern

Nur Angebote: POST /quotes/{id}/actions/convert-to-order wandelt in einen Auftrag (Antwort: orderId, orderNumber).

?customerMatch= filtert die Liste über den Matchcode der Adresse - bei Aktiv-Service ist das Bauvorhaben als Adresse angelegt, der Match ist die Bauvorhaben-Nummer. DMS-Dateien der Belege: siehe DMS-Dateien.

Lieferscheine und Rechnungen (read-only) #

Dieselben vier Lese-Routen gibt es unter /api/v1/delivery-notes/... und /api/v1/invoices/... (Scope documents:read) - bewusst ohne Schreibwege: Lieferscheine und Rechnungen entstehen über die EULANDA-Wandlungs-Jobs, Buchen und Storno bleiben beim ERP-Anwender.

Besondere Felder: Lieferscheine liefern trackingNumber, shippingDate, deliveredAt, goodsValue und je Position orderItemId (Rückverweis auf die Auftragsposition) - Positionen bewusst ohne Preise. Rechnungen liefern isCredit (Gutschrift), dunningLevel, paidAmount, balance (offener Saldo) und dueDate; je Position deliveryNoteItemId als Rückverweis.

Invoke-RestMethod 'http://localhost:8100/api/v1/invoices?balance=0&limit=5' -Headers $h
Invoke-RestMethod 'http://localhost:8100/api/v1/delivery-notes/by-number/2021500123' -Headers $h
Invoke-RestMethod 'http://localhost:8100/api/v1/invoices/57/items' -Headers $h
curl.exe -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/invoices?limit=5&fields=id,number,name,grossTotal,balance"
curl.exe -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/delivery-notes/by-number/2021500123"
curl.exe -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/invoices/57/items"

Anlegen #

Body für POST: customerId oder customerMatch (Pflicht, die Adresse muss existieren), optional deliveryAddressId, buyerOrderNo, object, items sowie weitere schreibbare Kopf-Felder (preText, postText, info, Termine). Jede Position braucht articleId oder articleNumber (der Artikel muss existieren) und quantity. Fehlende Stammdaten ergeben 422 REFERENCE_NOT_FOUND - die API legt nie stillschweigend Stammdaten an.

Eine übergebene buyerOrderNo wird auf Dubletten geprüft (409 DOC_DUPLICATE; skipDuplicateCheck: true erzwingt die Anlage).

Idempotenz (wichtig für Abrechnungsläufe) #

Jeder POST akzeptiert den Header Idempotency-Key. Derselbe Key mit demselben Body liefert die gespeicherte Antwort erneut (X-Idempotency-Replay: true) statt einen zweiten Beleg zu erzeugen; derselbe Key mit anderem Body ergibt 409 IDEMPOTENCY_MISMATCH. Empfehlung für Sync-Clients wie EulandaXtrack: fachlichen Schlüssel als Key verwenden (z.B. xtrack-abrechnung-2026-07-baustelle-4711).

Beispiele #

Angebot mit Positionen anlegen:

$h = @{ Authorization = "Bearer $key"; 'Idempotency-Key' = 'quote-2026-07-18-demo' }
$body = @{
    customerMatch = 'EULANDA'
    object        = 'API-Demo Bauvorhaben'
    items         = @(
        @{ articleNumber = '1100'; quantity = 2 }
        @{ articleId = 2; quantity = 1 }
    )
} | ConvertTo-Json -Depth 4
Invoke-RestMethod 'http://localhost:8100/api/v1/quotes' -Method Post -Headers $h -ContentType 'application/json' -Body $body
curl.exe -X POST -H "Authorization: Bearer %KEY%" -H "Idempotency-Key: quote-2026-07-18-demo" -H "Content-Type: application/json" -d "{ \"customerMatch\": \"EULANDA\", \"object\": \"API-Demo Bauvorhaben\", \"items\": [ { \"articleNumber\": \"1100\", \"quantity\": 2 } ] }" "http://localhost:8100/api/v1/quotes"

Angebot lesen und in einen Auftrag wandeln:

Invoke-RestMethod 'http://localhost:8100/api/v1/quotes/by-number/100123' -Headers $h
Invoke-RestMethod 'http://localhost:8100/api/v1/quotes/57/items' -Headers $h
Invoke-RestMethod 'http://localhost:8100/api/v1/quotes/57/actions/convert-to-order' -Method Post -Headers $h
curl.exe -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/quotes/by-number/100123"
curl.exe -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/quotes/57/items"
curl.exe -X POST -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/quotes/57/actions/convert-to-order"

Aufträge eines Bauvorhabens und Position nachtragen:

Invoke-RestMethod 'http://localhost:8100/api/v1/sales-orders?customerMatch=2412V0117' -Headers $h
$item = @{ articleNumber = '1100'; quantity = 8 } | ConvertTo-Json
Invoke-RestMethod 'http://localhost:8100/api/v1/sales-orders/172/items' -Method Post `
    -Headers ($h + @{ 'Idempotency-Key' = 'xtrack-2026-07-baustelle-0117' }) `
    -ContentType 'application/json' -Body $item
curl.exe -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/sales-orders?customerMatch=2412V0117"
curl.exe -X POST -H "Authorization: Bearer %KEY%" -H "Idempotency-Key: xtrack-2026-07-baustelle-0117" -H "Content-Type: application/json" -d "{ \"articleNumber\": \"1100\", \"quantity\": 8 }" "http://localhost:8100/api/v1/sales-orders/172/items"

Fehlercodes dieser Ressourcen #

HTTPCodeBedeutung
404NOT_FOUNDKein Beleg zum Schlüssel
409DOC_DUPLICATEBestellnummer existiert bereits
409IDEMPOTENCY_MISMATCHIdempotency-Key mit anderem Body wiederverwendet
422REFERENCE_NOT_FOUNDKunde bzw. Artikel existiert nicht
422VALIDATION_ITEM_INVALIDPosition ohne Artikel oder ohne gültige Menge

Belegfluss bis zur Rechnung #

Teillieferung: POST /sales-orders/{id}/delivery-notes mit Body { "items": [ { "itemId": 1780, "quantity": 1.5 } ] } liefert Teilmengen je Position (ohne Body: Volllieferung). Rechnung: POST /delivery-notes/{id}/invoices (einzeln) bzw. POST /invoices/from-delivery-notes mit { "deliveryNoteIds": [...] } als Sammelrechnung mehrerer Lieferscheine desselben Kunden.

Drei Direktgutschrift-Fälle (Scope documents:cancel): POST /invoices/{id}/actions/credit mit mode = newOrder (Gutschrifts-Auftrag Typ 12, keine SN), reopenDeliveryNotes (Lieferscheine wieder berechenbar) oder reopenOrder (negative Lieferscheine, Auftrag ins Weitererfassen - danach korrigieren und neu berechnen). Der Zahlungsausgleich zwischen Rechnung und Gutschrift läuft automatisch. Dazu POST /invoices/{id}/actions/cancel (klassisches Storno: löscht die Rechnung, Lieferscheine wieder offen) und POST /sales-orders/{id}/actions/reopen.

PDF-Ausgabe #

GET /{quotes|sales-orders|delivery-notes|invoices}/{id}/pdf rendert den Beleg headless über ReportXtools als application/pdf-Download; ?form= wählt das Formular, ohne Angabe gilt das Standard-Formular des Bereichs (IsDefault in der Formular-Registry). GET /{entity}/reports listet die Formulare mit isDefault. Voraussetzung: Udl in der Serverkonfiguration (sonst 501 PDF_RENDERER_UNAVAILABLE).