file meta

This commit is contained in:
seb
2026-09-18 05:20:03 +02:00
parent bbd285109d
commit 8c19388901
6 changed files with 334 additions and 12 deletions

View File

@@ -4477,6 +4477,13 @@
"items": { "items": {
"$ref": "#/components/schemas/DeliveryLineInput" "$ref": "#/components/schemas/DeliveryLineInput"
} }
},
"files": {
"type": "array",
"description": "Attached documents (pdf or txt) stored with the delivery\nand returned in `files` on every delivery response.\n",
"items": {
"$ref": "#/components/schemas/DeliveryFileInput"
}
} }
}, },
"example": { "example": {
@@ -4492,6 +4499,13 @@
"net": 99.5, "net": 99.5,
"taxrate": 19 "taxrate": 19
} }
],
"files": [
{
"mimetype": "application/pdf",
"name": "delivery-note.pdf",
"content": "<base64 encoded content>"
}
] ]
} }
} }
@@ -4515,7 +4529,7 @@
} }
}, },
"400": { "400": {
"description": "Invalid delivery, invalid lines, or no company selected", "description": "Invalid delivery, invalid lines or files, or no company selected",
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
@@ -4545,7 +4559,7 @@
} }
}, },
"404": { "404": {
"description": "Company, supplier, or article not found", "description": "Company or supplier not found",
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
@@ -4685,6 +4699,13 @@
"items": { "items": {
"$ref": "#/components/schemas/DeliveryLineInput" "$ref": "#/components/schemas/DeliveryLineInput"
} }
},
"files": {
"type": "array",
"description": "Appends attachments (pdf or txt) to the delivery.\nOmit to leave existing files unchanged.\n",
"items": {
"$ref": "#/components/schemas/DeliveryFileInput"
}
} }
}, },
"example": { "example": {
@@ -4742,7 +4763,7 @@
} }
}, },
"404": { "404": {
"description": "Delivery, supplier, article, or company not found", "description": "Delivery, supplier, or company not found",
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
@@ -10003,7 +10024,8 @@
{ {
"type": "object", "type": "object",
"required": [ "required": [
"lines" "lines",
"files"
], ],
"properties": { "properties": {
"lines": { "lines": {
@@ -10011,11 +10033,143 @@
"items": { "items": {
"$ref": "#/components/schemas/DeliveryLine" "$ref": "#/components/schemas/DeliveryLine"
} }
},
"files": {
"type": "array",
"description": "Attached documents (pdf/txt) for the delivery",
"items": {
"$ref": "#/components/schemas/DeliveryFile"
}
} }
} }
} }
] ]
}, },
"DeliveryFile": {
"type": "object",
"description": "Attachment metadata (binary content is served via the attachment content endpoints)",
"required": [
"id",
"manifestId",
"fileId",
"sort",
"hash",
"mimetype",
"name",
"size"
],
"properties": {
"id": {
"type": "integer",
"description": "manifestattachment id"
},
"manifestId": {
"type": "integer"
},
"fileId": {
"type": "integer"
},
"sort": {
"type": "integer"
},
"hash": {
"type": "string",
"description": "SHA-256 of the file content"
},
"mimetype": {
"type": "string",
"description": "application/pdf or text/plain"
},
"name": {
"type": "string"
},
"size": {
"type": "integer"
},
"created": {
"type": "string",
"format": "date-time"
},
"modified": {
"type": "string",
"format": "date-time"
},
"thumbavif": {
"type": "string",
"format": "byte",
"nullable": true
},
"thumbx": {
"type": "integer",
"nullable": true
},
"thumby": {
"type": "integer",
"nullable": true
},
"meta": {
"type": "object",
"nullable": true,
"description": "String key/value metadata from the file row",
"additionalProperties": {
"type": "string"
}
}
}
},
"DeliveryFileInput": {
"type": "object",
"required": [
"mimetype",
"name",
"content"
],
"description": "Attachment input. Only application/pdf and text/plain are accepted.",
"properties": {
"mimetype": {
"type": "string",
"enum": [
"application/pdf",
"text/plain"
]
},
"name": {
"type": "string"
},
"content": {
"type": "string",
"format": "byte",
"description": "File content (base64-encoded in JSON)"
},
"sort": {
"type": "integer",
"description": "Optional sort order (defaults to appending after existing files)"
},
"size": {
"type": "integer",
"description": "Optional size in bytes (defaults to content length)"
},
"hash": {
"type": "string",
"description": "Optional SHA-256 (auto-computed if omitted)"
},
"created": {
"type": "string",
"format": "date-time"
},
"modified": {
"type": "string",
"format": "date-time"
},
"meta": {
"type": "object",
"description": "Optional string key/value metadata stored with the file",
"additionalProperties": {
"type": "string"
}
}
}
},
"ManifestLine": { "ManifestLine": {
"type": "object", "type": "object",
"required": [ "required": [

View File

@@ -27,6 +27,13 @@ The manifest `number` is allocated automatically via
"net": 99.5, "net": 99.5,
"taxrate": 19 "taxrate": 19
} }
],
"files": [
{
"mimetype": "application/pdf",
"name": "delivery-note.pdf",
"content": "<base64 encoded content>"
}
] ]
} }
``` ```
@@ -56,6 +63,24 @@ Created delivery
"taxrate": 1, "taxrate": 1,
"comment": "…" "comment": "…"
} }
],
"files": [
{
"id": 1,
"manifestId": 1,
"fileId": 1,
"sort": 1,
"hash": "…",
"mimetype": "…",
"name": "…",
"size": 1,
"created": "2026-08-10T00:00:00.000Z",
"modified": "2026-08-10T00:00:00.000Z",
"thumbavif": "…",
"thumbx": 1,
"thumby": 1,
"meta": {}
}
] ]
} }
} }
@@ -65,10 +90,10 @@ Created delivery
| Status | Description | | Status | Description |
|--------|-------------| |--------|-------------|
| 400 | Invalid delivery, invalid lines, or no company selected — `{"error":"…"}` | | 400 | Invalid delivery, invalid lines or files, or no company selected — `{"error":"…"}` |
| 401 | Unauthorized — `{"error":"…"}` | | 401 | Unauthorized — `{"error":"…"}` |
| 403 | Not authorized — `{"error":"…"}` | | 403 | Not authorized — `{"error":"…"}` |
| 404 | Company, supplier, or article not found — `{"error":"…"}` | | 404 | Company or supplier not found — `{"error":"…"}` |
--- ---

View File

@@ -37,6 +37,24 @@ Delivery
"taxrate": 1, "taxrate": 1,
"comment": "…" "comment": "…"
} }
],
"files": [
{
"id": 1,
"manifestId": 1,
"fileId": 1,
"sort": 1,
"hash": "…",
"mimetype": "…",
"name": "…",
"size": 1,
"created": "2026-08-10T00:00:00.000Z",
"modified": "2026-08-10T00:00:00.000Z",
"thumbavif": "…",
"thumbx": 1,
"thumby": 1,
"meta": {}
}
] ]
} }
} }

View File

@@ -50,6 +50,24 @@ Updated delivery
"taxrate": 1, "taxrate": 1,
"comment": "…" "comment": "…"
} }
],
"files": [
{
"id": 1,
"manifestId": 1,
"fileId": 1,
"sort": 1,
"hash": "…",
"mimetype": "…",
"name": "…",
"size": 1,
"created": "2026-08-10T00:00:00.000Z",
"modified": "2026-08-10T00:00:00.000Z",
"thumbavif": "…",
"thumbx": 1,
"thumby": 1,
"meta": {}
}
] ]
} }
} }
@@ -62,7 +80,7 @@ Updated delivery
| 400 | Invalid delivery, invalid lines, invalid id, or no company selected — `{"error":"…"}` | | 400 | Invalid delivery, invalid lines, invalid id, or no company selected — `{"error":"…"}` |
| 401 | Unauthorized — `{"error":"…"}` | | 401 | Unauthorized — `{"error":"…"}` |
| 403 | Not authorized — `{"error":"…"}` | | 403 | Not authorized — `{"error":"…"}` |
| 404 | Delivery, supplier, article, or company not found — `{"error":"…"}` | | 404 | Delivery, supplier, or company not found — `{"error":"…"}` |
--- ---

View File

@@ -422,12 +422,97 @@
* allOf: * allOf:
* - $ref: '#/components/schemas/DeliverySummary' * - $ref: '#/components/schemas/DeliverySummary'
* - type: object * - type: object
* required: [lines] * required: [lines, files]
* properties: * properties:
* lines: * lines:
* type: array * type: array
* items: * items:
* $ref: '#/components/schemas/DeliveryLine' * $ref: '#/components/schemas/DeliveryLine'
* files:
* type: array
* description: Attached documents (pdf/txt) for the delivery
* items:
* $ref: '#/components/schemas/DeliveryFile'
* DeliveryFile:
* type: object
* description: Attachment metadata (binary content is served via the attachment content endpoints)
* required: [id, manifestId, fileId, sort, hash, mimetype, name, size]
* properties:
* id:
* type: integer
* description: manifestattachment id
* manifestId:
* type: integer
* fileId:
* type: integer
* sort:
* type: integer
* hash:
* type: string
* description: SHA-256 of the file content
* mimetype:
* type: string
* description: application/pdf or text/plain
* name:
* type: string
* size:
* type: integer
* created:
* type: string
* format: date-time
* modified:
* type: string
* format: date-time
* thumbavif:
* type: string
* format: byte
* nullable: true
* thumbx:
* type: integer
* nullable: true
* thumby:
* type: integer
* nullable: true
* meta:
* type: object
* nullable: true
* description: String key/value metadata from the file row
* additionalProperties:
* type: string
* DeliveryFileInput:
* type: object
* required: [mimetype, name, content]
* description: Attachment input. Only application/pdf and text/plain are accepted.
* properties:
* mimetype:
* type: string
* enum: [application/pdf, text/plain]
* name:
* type: string
* content:
* type: string
* format: byte
* description: File content (base64-encoded in JSON)
* sort:
* type: integer
* description: Optional sort order (defaults to appending after existing files)
* size:
* type: integer
* description: Optional size in bytes (defaults to content length)
* hash:
* type: string
* description: Optional SHA-256 (auto-computed if omitted)
* created:
* type: string
* format: date-time
* modified:
* type: string
* format: date-time
* meta:
* type: object
* description: Optional string key/value metadata stored with the file
* additionalProperties:
* type: string
* ManifestLine: * ManifestLine:
* type: object * type: object
* required: [id, sku, name, pu, amount, net, rebate, taxrate, comment] * required: [id, sku, name, pu, amount, net, rebate, taxrate, comment]

View File

@@ -107,6 +107,13 @@ export function register(app, basePath = '') {
* type: array * type: array
* items: * items:
* $ref: '#/components/schemas/DeliveryLineInput' * $ref: '#/components/schemas/DeliveryLineInput'
* files:
* type: array
* description: |
* Attached documents (pdf or txt) stored with the delivery
* and returned in `files` on every delivery response.
* items:
* $ref: '#/components/schemas/DeliveryFileInput'
* example: * example:
* externalNumber: DHL-123 * externalNumber: DHL-123
* date: '2026-08-10' * date: '2026-08-10'
@@ -118,6 +125,10 @@ export function register(app, basePath = '') {
* amount: 10 * amount: 10
* net: 99.5 * net: 99.5
* taxrate: 19 * taxrate: 19
* files:
* - mimetype: application/pdf
* name: delivery-note.pdf
* content: '<base64 encoded content>'
* responses: * responses:
* 201: * 201:
* description: Created delivery * description: Created delivery
@@ -129,7 +140,7 @@ export function register(app, basePath = '') {
* delivery: * delivery:
* $ref: '#/components/schemas/Delivery' * $ref: '#/components/schemas/Delivery'
* 400: * 400:
* description: Invalid delivery, invalid lines, or no company selected * description: Invalid delivery, invalid lines or files, or no company selected
* content: * content:
* application/json: * application/json:
* schema: * schema:
@@ -147,7 +158,7 @@ export function register(app, basePath = '') {
* schema: * schema:
* $ref: '#/components/schemas/Error' * $ref: '#/components/schemas/Error'
* 404: * 404:
* description: Company, supplier, or article not found * description: Company or supplier not found
* content: * content:
* application/json: * application/json:
* schema: * schema:
@@ -175,7 +186,7 @@ export function register(app, basePath = '') {
return res.status(400).json({ error: selected.error }); return res.status(400).json({ error: selected.error });
} }
const { externalNumber, date, supplierId, lines } = req.body ?? {}; const { externalNumber, date, supplierId, lines, files } = req.body ?? {};
try { try {
const delivery = await db.create(req.user.id, { const delivery = await db.create(req.user.id, {
@@ -183,6 +194,7 @@ export function register(app, basePath = '') {
date, date,
supplierId, supplierId,
lines, lines,
files,
}); });
res.status(201).json({ delivery }); res.status(201).json({ delivery });
} catch (error) { } catch (error) {
@@ -280,6 +292,13 @@ export function register(app, basePath = '') {
* type: array * type: array
* items: * items:
* $ref: '#/components/schemas/DeliveryLineInput' * $ref: '#/components/schemas/DeliveryLineInput'
* files:
* type: array
* description: |
* Appends attachments (pdf or txt) to the delivery.
* Omit to leave existing files unchanged.
* items:
* $ref: '#/components/schemas/DeliveryFileInput'
* example: * example:
* externalNumber: DHL-124 * externalNumber: DHL-124
* lines: [] * lines: []
@@ -312,7 +331,7 @@ export function register(app, basePath = '') {
* schema: * schema:
* $ref: '#/components/schemas/Error' * $ref: '#/components/schemas/Error'
* 404: * 404:
* description: Delivery, supplier, article, or company not found * description: Delivery, supplier, or company not found
* content: * content:
* application/json: * application/json:
* schema: * schema:
@@ -405,6 +424,9 @@ export function register(app, basePath = '') {
if (Object.prototype.hasOwnProperty.call(body, 'lines')) { if (Object.prototype.hasOwnProperty.call(body, 'lines')) {
patch.lines = body.lines; patch.lines = body.lines;
} }
if (Object.prototype.hasOwnProperty.call(body, 'files')) {
patch.files = body.files;
}
try { try {
const delivery = await db.update(req.user.id, id, patch); const delivery = await db.update(req.user.id, id, patch);