feat(delivery): add supplier article lookup, article creation, and unified parsing

- Unified PDF/TXT parsing to single POST /api/delivery/parse endpoint
- Added supplier article lookup with SKU/EAN matching in delivery lines
- Added "Artikel anlegen" button to create articles from missing SKUs
- Fixed delivery line taxrate field (was sending 'tax', now 'taxrate')
- Extended TXT file support for rescan functionality
- Updated ApiClient with getArticles method for supplier article lookup
- Added supplier article state management to deliveryEditorAutomat

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
seb
2026-09-18 04:39:07 +02:00
parent 27f6dfdebf
commit d5ade4923d
8 changed files with 670 additions and 91 deletions

View File

@@ -80,6 +80,18 @@ export class ApiClient {
update: (id, body) => this.#json('PATCH', `/api/supplier/${enc(id)}`, { body }),
/** DELETE /api/supplier/{id} → 204 */
delete: (id) => this.#empty('DELETE', `/api/supplier/${enc(id)}`),
/** GET /api/supplier/{id}/articles?skus=... → { articles: SupplierArticle[] } */
getArticles: (id, skus) => {
let query = '';
if (skus != null) {
const list = Array.isArray(skus) ? skus : [skus];
const filtered = list.map((s) => String(s).trim()).filter(Boolean);
if (filtered.length > 0) {
query = `?skus=${encodeURIComponent(filtered.join(','))}`;
}
}
return this.#json('GET', `/api/supplier/${enc(id)}/articles${query}`);
},
};
this.delivery = {
@@ -94,14 +106,15 @@ export class ApiClient {
/** DELETE /api/delivery/{id} → 204 */
delete: (id) => this.#empty('DELETE', `/api/delivery/${enc(id)}`),
/**
* POST /api/delivery/parsePDF — multipart/form-data, field "pdf"
* POST /api/delivery/parse — multipart/form-data, field "file"
* Accepts PDF or text files (max 50 MB), detection via mimetype/filename
* Returns an async generator that yields SSE event objects:
* { event: 'status'|'llm_call'|'tool_call'|'usage'|'progress'|'result'|'error', data: object }
*/
parsePdfSse: async function* (file) {
parseSse: async function* (file) {
const formData = new FormData();
formData.append('pdf', file, file.name);
const res = await fetch('/api/delivery/parsePDF', {
formData.append('file', file, file.name);
const res = await fetch('/api/delivery/parse', {
method: 'POST',
credentials: 'include',
body: formData,