This commit is contained in:
seb
2026-10-16 16:24:58 +02:00
parent f506dd35be
commit 3b875c9f9a
14 changed files with 28 additions and 1228 deletions

View File

@@ -1,382 +0,0 @@
VFS Drafts: Collaborative Quote and Order Editing
# Overview
The virtual directory `drafts/` in VFS allows the LLM agent and the frontend user to collaborate in real time on in-progress commercial documents.
Drafts are stateful forms maintained in the frontend application and synchronized with the backend.
There are two virtual draft files:
1. `drafts/quote` : Sales Quote / Angebot (Customer sales proposal)
2. `drafts/order` : Sales Order / Auftrag & Bestellung (Customer order confirmation)
---
# Draft JSON Schemas
## 1. Common Manifest Envelope Schema
Every draft file contains a root object with a `manifest` property conforming to this JSON Schema:
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "DraftManifestEnvelope",
"type": "object",
"required": ["manifest"],
"properties": {
"manifest": {
"type": "object",
"required": ["kind", "mode", "lines"],
"properties": {
"kind": {
"type": "string",
"enum": ["quote", "order"],
"description": "Document type"
},
"mode": {
"type": "string",
"enum": ["create", "edit"],
"description": "Whether creating a new document or editing an existing saved one"
},
"id": {
"type": ["integer", "null"],
"description": "Database document ID (null for new drafts, integer when editing)"
},
"date": {
"type": ["string", "null"],
"format": "date",
"description": "ISO date string (YYYY-MM-DD) or null"
},
"partyId": {
"type": ["integer", "null"],
"description": "Customer entity.id for quotes and orders"
},
"number": {
"type": ["string", "null"],
"description": "Document identifier. Null for automatic numbering upon commit"
},
"externalNumber": {
"type": ["string", "null"],
"description": "External reference (e.g. customer PO number, supplier delivery slip number)"
},
"comment": {
"type": ["string", "null"],
"description": "Document-level remarks or notes"
},
"lines": {
"type": "array",
"description": "Ordered line items of the document"
}
}
}
}
}
```
---
## 2. Sales Quote Draft (`drafts/quote`)
Used for preparing customer sales proposals (Angebote).
### Complete Quote JSON Schema
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "QuoteDraft",
"type": "object",
"required": ["manifest"],
"properties": {
"manifest": {
"type": "object",
"required": ["kind", "mode", "lines"],
"properties": {
"kind": { "type": "string", "const": "quote" },
"mode": { "type": "string", "enum": ["create", "edit"] },
"id": { "type": ["integer", "null"] },
"date": {
"type": ["string", "null"],
"format": "date",
"description": "Offer validity expiration date (Gültig bis, YYYY-MM-DD)"
},
"partyId": {
"type": ["integer", "null"],
"description": "Customer entity ID (entity.id)"
},
"number": {
"type": ["string", "null"],
"description": "Quote number (null for auto-generation)"
},
"externalNumber": {
"type": ["string", "null"],
"description": "Customer project or RFQ reference"
},
"comment": {
"type": ["string", "null"],
"description": "Optional quotation remark"
},
"lines": {
"type": "array",
"items": {
"type": "object",
"required": ["name", "amount", "net", "taxrate"],
"properties": {
"pos": {
"type": "integer",
"minimum": 1,
"description": "Position line number (1, 2, 3...)"
},
"sku": {
"type": ["string", "null"],
"description": "Catalogue article SKU, or null for custom service/text position"
},
"name": {
"type": "string",
"description": "Title or designation of the position"
},
"amount": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Quoted quantity"
},
"pu": {
"type": "number",
"minimum": 1,
"default": 1,
"description": "Packing unit / price unit (Preiseinheit, default 1)"
},
"net": {
"type": "number",
"minimum": 0,
"description": "Net unit price in EUR"
},
"gross": {
"type": ["number", "null"],
"description": "Gross unit price in EUR (net * (1 + taxrate/100))"
},
"taxrate": {
"type": "number",
"minimum": 0,
"description": "VAT rate percentage (e.g. 19 or 7)"
},
"rebate": {
"type": "number",
"minimum": 0,
"maximum": 100,
"default": 0,
"description": "Line discount percentage (0 to 100)"
},
"unit": {
"type": ["string", "null"],
"description": "Unit of measurement (e.g. 'Stück', 'm', 'kg', 'Pauschal')"
},
"comment": {
"type": ["string", "null"],
"description": "Optional line-specific comment or specification"
}
}
}
}
}
}
}
}
```
### Complete Quote Example
```json
{
"manifest": {
"kind": "quote",
"mode": "create",
"id": null,
"date": "2026-11-30",
"partyId": 104,
"number": null,
"externalNumber": "ANFRAGE-2026-441",
"comment": "Angebot freibleibend, Lieferung frei Haus ab 250 EUR.",
"lines": [
{
"pos": 1,
"sku": "42001257",
"name": "1 Pot 8L System inkl. 47L Wasserfass",
"amount": 2,
"pu": 1,
"net": 58.74,
"gross": 69.90,
"taxrate": 19,
"rebate": 0,
"unit": "Stück",
"comment": null
},
{
"pos": 2,
"sku": null,
"name": "Aufbau und Fachberatung vor Ort",
"amount": 1.5,
"pu": 1,
"net": 80.00,
"gross": 95.20,
"taxrate": 19,
"rebate": 10,
"unit": "Std",
"comment": "Inklusive Anfahrt Zone 1"
}
]
}
}
```
---
## 3. Sales Order Draft (`drafts/order`)
Used for customer order confirmations and sales orders (Aufträge & Bestellungen).
### Complete Order JSON Schema
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderDraft",
"type": "object",
"required": ["manifest"],
"properties": {
"manifest": {
"type": "object",
"required": ["kind", "mode", "lines"],
"properties": {
"kind": { "type": "string", "const": "order" },
"mode": { "type": "string", "enum": ["create", "edit"] },
"id": { "type": ["integer", "null"] },
"date": {
"type": ["string", "null"],
"format": "date",
"description": "Expected delivery date (Liefertermin, YYYY-MM-DD)"
},
"partyId": {
"type": ["integer", "null"],
"description": "Customer entity ID (entity.id)"
},
"number": {
"type": ["string", "null"],
"description": "Order number (null for auto-generation)"
},
"externalNumber": {
"type": ["string", "null"],
"description": "Customer purchase order / PO number (Kundenbestellnummer)"
},
"comment": {
"type": ["string", "null"],
"description": "Optional order remark or delivery instruction"
},
"lines": {
"type": "array",
"items": {
"type": "object",
"required": ["name", "amount", "net", "taxrate"],
"properties": {
"pos": {
"type": "integer",
"minimum": 1,
"description": "Position line number (1, 2, 3...)"
},
"sku": {
"type": ["string", "null"],
"description": "Article SKU"
},
"name": {
"type": "string",
"description": "Line item description"
},
"amount": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Ordered quantity"
},
"pu": {
"type": "number",
"minimum": 1,
"default": 1,
"description": "Packaging unit / price unit (default 1)"
},
"net": {
"type": "number",
"minimum": 0,
"description": "Net unit price in EUR"
},
"gross": {
"type": ["number", "null"],
"description": "Gross unit price in EUR"
},
"taxrate": {
"type": "number",
"minimum": 0,
"description": "VAT percentage (19 or 7)"
},
"rebate": {
"type": "number",
"minimum": 0,
"maximum": 100,
"default": 0,
"description": "Line discount percentage"
},
"unit": {
"type": ["string", "null"],
"description": "Unit of measurement"
},
"comment": {
"type": ["string", "null"],
"description": "Line comment or customer note"
}
}
}
}
}
}
}
}
```
### Complete Order Example
```json
{
"manifest": {
"kind": "order",
"mode": "create",
"id": null,
"date": "2026-10-28",
"partyId": 104,
"number": null,
"externalNumber": "PO-2026-8841",
"comment": "Bitte Lieferung avisieren unter +49 171 1234567.",
"lines": [
{
"pos": 1,
"sku": "42001257",
"name": "1 Pot 8L System inkl. 47L Wasserfass",
"amount": 5,
"pu": 1,
"net": 58.74,
"gross": 69.90,
"taxrate": 19,
"rebate": 5,
"unit": "Stück",
"comment": null
},
{
"pos": 2,
"sku": "42000009",
"name": "Autopot Easy2Grow Erweiterungsset 2Pot",
"amount": 2,
"pu": 1,
"net": 39.50,
"gross": 47.01,
"taxrate": 19,
"rebate": 0,
"unit": "Stück",
"comment": "Farbe: Schwarz"
}
]
}
}
```

View File

@@ -1,43 +1,11 @@
Process Incoming Product and Invoices: Extraction & Delivery Drafts
Process Incoming Product and Invoices: Document Extraction & Manifests
# Overview
This skill guides the automated and interactive processing of inbound supplier documents (invoices / *Rechnungen* and delivery notes / *Lieferscheine*).
It covers:
1. **Document Data Extraction**: Extracting structured metadata, packaging units (VPE), units of measurement, line items, and notes from document text/images via the `output_manifest` tool.
2. **Goods Inbound Delivery Draft (`drafts/delivery`)**: Storing and maintaining the inbound receipt in the virtual file system (`drafts/delivery`) for real-time collaboration with the user in the UI.
---
# 1. Document Extraction Rules & Prompt Logic
When reading or processing an invoice or delivery note, follow these core rules:
## General Extraction Rules
- **Document Type (`manifestType`)**: `"rechnung"` or `"lieferschein"`. For `"lieferschein"`, prices (`eknetto`) and taxes (`mwst`) must be `null`.
- **Exclude Non-Product Lines**: Exclude freight, shipping, postage, pallet charges, packaging disposal fees, and handling surcharges. Only include physical inventory products.
- **Line Items**: Extract `position`, `count`, `vpe` (default: 1), `unit`, `articleName`, `liefArtNr`, `mwst` (7, 19, or null), and `eknetto` per piece in euro cents (or null).
- **Supplier Matching**: Match the supplier against known company suppliers to identify `lieferant_id` and `lieferantName`. For unknown suppliers, extract `lieferantName` as string and set `lieferant_id` to `null`.
- **Notes Strictly in German**: Record all notes, ambiguities, packaging assumptions, or excluded line details in German. These notes assist a human reviewer in double-checking results.
- **Delta / Batching Updates**: The `output_manifest` tool consists of three optional components: `basedata`, `notes`, and `items`. Only include a component when it carries genuinely new or changed data; omit unchanged components.
- Include `basedata` ONLY when at least one field is currently null/empty or value actually changes.
- Include `items` ONLY when new product line items are being added.
- Include `notes` ONLY when there is a genuinely new noteworthy detail.
## VPE (Verpackungseinheit) Logic
VPE represents the number of individually sellable units inside a bulk item. If not explicitly split for individual sale, default to 1.
- `"20 Boxen á 10 Stück"` -> `vpe = 20`.
- `"10 Gläser á 100 Filter"` -> `vpe = 10` (the 10 glasses are sold individually).
- `"100 Stück"` -> `vpe = 1` (sold as one bulk pack).
- Typical sellable VPEs are containers like *Beutel*, *Gläser*, *Boxen*, *Hefte*, not loose sub-components.
- In `"Y Hefte á X Blatt"` the VPE is NOT X, but `Y`.
- A "Display" represents a VPE: `"20er Display"` means `vpe = 20`.
- `eknetto` is the price of one full VPE.
## Unit (ME) Rules
- The unit (ME) must ALWAYS refer to the individual sellable item (e.g. `Stk.`, `Beutel`, `Flasche`, `Box`, `Set`). It must **NEVER** be `"VE"` or `"VPE"`.
- A packaging size like `"VE100"` means the bulk pack contains 100 individual items: set `vpe = 100` and `unit = "Stk."` (or the relevant individual unit).
- Example: `"Einhängesiebe Stahl, VE100"` -> `vpe = 100`, `unit = "Stk."`, `count = 1` (one bulk pack of 100 sieves).
- **Document Data Extraction**: Extracting structured metadata, packaging units (VPE), units of measurement, line items, and notes from document text or images.
- **Delta & Batching Updates**: Formatting and returning extracted product and document metadata via the `output_manifest` tool.
---
@@ -125,181 +93,4 @@ The extraction engine outputs structured findings via the `output_manifest` tool
}
```
---
# 3. Goods Inbound Delivery Draft (`drafts/delivery`)
Inbound deliveries are staged and edited as drafts in the virtual file system under `drafts/delivery`.
This allows the agent and frontend user to review, correct, and finalize stock receipts and purchase costs before committing them into the inventory ledger.
## Field Mapping from Extracted Manifest to Delivery Draft
- **`date`**: Document date (`YYYY-MM-DD`).
- **`partyId`**: Supplier ID (`lieferant_id` / `entity.id`).
- **`externalNumber`**: Supplier delivery slip number or invoice number (`manifestNr`).
- **`comment`**: Human-readable notes, inspection remarks, storage location, or extraction caveats.
- **`lines`**:
- `pos`: 1-based position line number.
- `sku`: Internal article SKU or matched supplier SKU (`liefArtNr`).
- `name`: Delivered product name (`articleName`).
- `amount`: Quantity delivered (`count`).
- `pu`: Packaging unit size (`vpe`, default `1`).
- `net`: Purchase cost net per unit in EUR (`eknetto / 100`, or `0` for delivery notes without prices).
- `gross`: Purchase cost gross per unit in EUR (`net * (1 + taxrate/100)`).
- `taxrate`: Input tax rate percentage (`19`, `7`, or `0`).
- `rebate`: Supplier discount percentage (default `0`).
- `unit`: Individual sellable unit (e.g. `Stück`, `Beutel`, `Flasche`).
- `comment`: Specific batch, lot, or packaging comment.
---
## Delivery Draft JSON Schema
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "DeliveryDraft",
"type": "object",
"required": ["manifest"],
"properties": {
"manifest": {
"type": "object",
"required": ["kind", "mode", "lines"],
"properties": {
"kind": { "type": "string", "const": "delivery" },
"mode": { "type": "string", "enum": ["create", "edit"] },
"id": { "type": ["integer", "null"] },
"date": {
"type": ["string", "null"],
"format": "date",
"description": "Delivery arrival / receipt date (Lieferdatum, YYYY-MM-DD)"
},
"partyId": {
"type": ["integer", "null"],
"description": "Supplier ID (supplier.id / entity_id)"
},
"number": {
"type": ["string", "null"],
"description": "Delivery manifest number (allocated by system sequence upon creation)"
},
"externalNumber": {
"type": ["string", "null"],
"description": "Supplier delivery slip number (Lieferschein-Nr. des Lieferanten)"
},
"comment": {
"type": ["string", "null"],
"description": "Warehouse receipt remarks or gate notes"
},
"lines": {
"type": "array",
"items": {
"type": "object",
"required": ["name", "amount", "net", "taxrate"],
"properties": {
"pos": {
"type": "integer",
"minimum": 1,
"description": "Position line number (1, 2, 3...)"
},
"sku": {
"type": ["string", "null"],
"description": "Article SKU (internal SKU or matched supplier SKU)"
},
"name": {
"type": "string",
"description": "Delivered article name"
},
"amount": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Delivered quantity received into warehouse"
},
"pu": {
"type": "number",
"minimum": 1,
"default": 1,
"description": "Packaging unit / VPE (default 1)"
},
"net": {
"type": "number",
"minimum": 0,
"description": "Purchase cost net per unit in EUR (EK netto)"
},
"gross": {
"type": ["number", "null"],
"description": "Purchase cost gross per unit in EUR (EK brutto)"
},
"taxrate": {
"type": "number",
"minimum": 0,
"description": "Input tax percentage (e.g. 19 or 7)"
},
"rebate": {
"type": "number",
"minimum": 0,
"maximum": 100,
"default": 0,
"description": "Supplier discount percentage"
},
"unit": {
"type": ["string", "null"],
"description": "Unit of measurement"
},
"comment": {
"type": ["string", "null"],
"description": "Batch number, lot, condition, or storage bin note"
}
}
}
}
}
}
}
}
```
---
## Delivery Draft Complete Example
```json
{
"manifest": {
"kind": "delivery",
"mode": "create",
"id": null,
"date": "2026-10-14",
"partyId": 12,
"number": null,
"externalNumber": "LS-SUP-99412",
"comment": "Ware unbeschädigt auf Palette 3 angeliefert.",
"lines": [
{
"pos": 1,
"sku": "42001257",
"name": "1 Pot 8L System inkl. 47L Wasserfass",
"amount": 20,
"pu": 1,
"net": 38.50,
"gross": 45.82,
"taxrate": 19,
"rebate": 0,
"unit": "Stück",
"comment": "Palette A-04"
},
{
"pos": 2,
"sku": "42000009",
"name": "Autopot Easy2Grow Erweiterungsset 2Pot",
"amount": 50,
"pu": 1,
"net": 24.00,
"gross": 28.56,
"taxrate": 19,
"rebate": 3,
"unit": "Stück",
"comment": "Karton 1 bis 5"
}
]
}
}
```