u
This commit is contained in:
@@ -1,14 +1,13 @@
|
||||
VFS Drafts: Collaborative Quote, Order, and Delivery Editing
|
||||
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 three virtual draft files:
|
||||
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)
|
||||
3. `drafts/delivery` : Goods Inbound / Wareneingang & Lieferschein (Supplier delivery receipt)
|
||||
|
||||
---
|
||||
|
||||
@@ -31,7 +30,7 @@ Every draft file contains a root object with a `manifest` property conforming to
|
||||
"properties": {
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"enum": ["quote", "order", "delivery"],
|
||||
"enum": ["quote", "order"],
|
||||
"description": "Document type"
|
||||
},
|
||||
"mode": {
|
||||
@@ -50,7 +49,7 @@ Every draft file contains a root object with a `manifest` property conforming to
|
||||
},
|
||||
"partyId": {
|
||||
"type": ["integer", "null"],
|
||||
"description": "Customer entity.id for quotes/orders; supplier.id for deliveries"
|
||||
"description": "Customer entity.id for quotes and orders"
|
||||
},
|
||||
"number": {
|
||||
"type": ["string", "null"],
|
||||
@@ -381,157 +380,3 @@ Used for customer order confirmations and sales orders (Aufträge & Bestellungen
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Goods Inbound Delivery Draft (`drafts/delivery`)
|
||||
|
||||
Used for inbound delivery receipts from suppliers (Wareneingang & Lieferscheine).
|
||||
|
||||
### Complete Delivery 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Complete Delivery 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
305
src/defaultSkills/process-incoming-product-and-invoices.SKILL
Normal file
305
src/defaultSkills/process-incoming-product-and-invoices.SKILL
Normal file
@@ -0,0 +1,305 @@
|
||||
Process Incoming Product and Invoices: Extraction & Delivery Drafts
|
||||
|
||||
# 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).
|
||||
|
||||
---
|
||||
|
||||
# 2. Extraction Tool Specification (`output_manifest`)
|
||||
|
||||
The extraction engine outputs structured findings via the `output_manifest` tool call.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "output_manifest",
|
||||
"description": "Stores extracted invoice/delivery-note data: header metadata (basedata), notes, and product line items. Each component is strictly optional — only include the ones that carry new data.",
|
||||
"strict": false,
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [],
|
||||
"properties": {
|
||||
"basedata": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"date": { "type": ["string", "null"], "description": "Document date (ISO 8601, YYYY-MM-DD)" },
|
||||
"lieferant_id": { "type": ["number", "null"], "description": "Lieferant ID if matched, else null" },
|
||||
"lieferantName": { "type": "string", "description": "Supplier name" },
|
||||
"manifestNr": { "type": ["string", "null"], "description": "Lieferscheinnummer or Rechnungsnummer" },
|
||||
"manifestType": {
|
||||
"anyOf": [
|
||||
{ "type": "string", "enum": ["rechnung", "lieferschein"] },
|
||||
{ "type": "null" }
|
||||
],
|
||||
"description": "Document type"
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "type": "null" }
|
||||
],
|
||||
"description": "Header/metadata. Only include fields that are currently missing or changed."
|
||||
},
|
||||
"notes": {
|
||||
"anyOf": [
|
||||
{ "type": "array", "items": { "type": "string" } },
|
||||
{ "type": "null" }
|
||||
],
|
||||
"description": "New noteworthy details (in German), for a human to double-check the result."
|
||||
},
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"numberOfItemsToAdd": { "type": "number", "description": "Number of NEW line items being added in this call." },
|
||||
"items": {
|
||||
"type": "array",
|
||||
"description": "Invoice/delivery product line items",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["position", "count", "vpe", "unit", "articleName", "liefArtNr", "mwst", "eknetto"],
|
||||
"properties": {
|
||||
"position": { "type": "number", "description": "Position number" },
|
||||
"count": { "type": "number", "description": "Quantity (Menge)" },
|
||||
"vpe": { "type": "number", "description": "Packaging unit size (VPE). Default: 1." },
|
||||
"unit": { "type": "string", "description": "Unit of the individual sellable item. NEVER 'VE' or 'VPE'." },
|
||||
"articleName": { "type": "string", "description": "Article name" },
|
||||
"liefArtNr": { "type": "string", "description": "Supplier article number" },
|
||||
"mwst": {
|
||||
"anyOf": [{ "type": "string", "enum": ["7", "19"] }, { "type": "null" }],
|
||||
"description": "VAT rate percentage; null if delivery note or missing"
|
||||
},
|
||||
"eknetto": { "type": ["number", "null"], "description": "Net purchase price per VPE in euro cents; null if missing" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "type": "null" }
|
||||
],
|
||||
"description": "New product line items."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user