diff --git a/README.md b/README.md
index c3daa7f..e1c4799 100644
--- a/README.md
+++ b/README.md
@@ -202,6 +202,50 @@ Suppliers are `entity` rows in the company `customergroup` named `Lieferanten` (
---
+## `delivery`
+
+Company-scoped goods receipts on `manifest` / `manifestarticle` with fixed `type = 'delivery'`. Auth via `resolveCompanyAccess`. `manifest.company_id` scopes the list (`ON DELETE NO ACTION` — avoid SQL Server multiple cascade paths with `entity_id`).
+
+| Method | Signature | Returns |
+| --- | --- | --- |
+| `list` | `(googleAuthId, companyId)` | `DeliverySummary[]` |
+| `getById` | `(googleAuthId, companyId, id)` | `Delivery` |
+| `create` | `(googleAuthId, companyId, { number, date, supplierId?, lines })` | `Delivery` |
+| `update` | `(googleAuthId, companyId, id, { number?, date?, supplierId?, lines? })` | `Delivery` |
+| `delete` | `(googleAuthId, companyId, id)` | `void` |
+
+```ts
+type DeliverySummary = {
+ id: number,
+ number: string,
+ type: 'delivery',
+ supplierId: number | null, // manifest.entity_id
+ date: Date,
+}
+
+type DeliveryLine = {
+ id: number,
+ articleId: number | null,
+ sku: string | null,
+ amount: number,
+ net: number,
+ transactedAmount: number,
+ rebate: number,
+ tax: number, // tax.rate
+ comment: string | null,
+}
+
+type Delivery = DeliverySummary & { lines: DeliveryLine[] }
+```
+
+`create` inserts header + lines in one transaction. `supplierId` null or a Lieferanten `entity` of the company (else `Supplier not found`). Each line requires `sku` (resolved in the company category tree → `Article not found`), `amount`, `net`, `tax` (rate → `tax.ensure`); `rebate` defaults `0`; `transactedAmount` defaults to `amount`. Empty/invalid `number` or `date` → `Invalid delivery`; bad line payload → `Invalid lines`.
+
+`update` patches header fields that are present. If `lines` is present, replace-all lines; if omitted, leave lines unchanged. Returns full `Delivery`.
+
+`delete` removes the manifest (`manifestarticle` cascades). Errors: `Company not found`, `Not authorized`, `Delivery not found`, `Supplier not found`, `Article not found`, `Invalid delivery`, `Invalid lines`.
+
+---
+
## `posterminal`
Company-scoped POS terminals. Auth via `resolveCompanyAccess`.
@@ -479,6 +523,11 @@ res.set('Content-Type', thumb.contentType).send(thumb.buffer);
| `POST /api/supplier` | `supplier.create(googleAuthId, companyId, { name })` |
| `PATCH /api/supplier/:id` | `supplier.update(googleAuthId, companyId, id, { name })` |
| `DELETE /api/supplier/:id` | `supplier.delete(googleAuthId, companyId, id)` |
+| `GET /api/delivery` | `delivery.list(googleAuthId, companyId)` |
+| `GET /api/delivery/:id` | `delivery.getById(googleAuthId, companyId, id)` |
+| `POST /api/delivery` | `delivery.create(googleAuthId, companyId, { number, date, supplierId?, lines })` |
+| `PATCH /api/delivery/:id` | `delivery.update(googleAuthId, companyId, id, { number?, date?, supplierId?, lines? })` |
+| `DELETE /api/delivery/:id` | `delivery.delete(googleAuthId, companyId, id)` |
| `GET /api/posterminal` | `posterminal.list(googleAuthId, companyId)` |
| `PUT /api/posterminal` | `posterminal.upsert(googleAuthId, companyId, { id?, name, token?, pairingpin })` |
| `DELETE /api/posterminal/:id` | `posterminal.delete(googleAuthId, companyId, id)` |
diff --git a/schema-graph.dot b/schema-graph.dot
index 4221cc3..5797eb8 100644
--- a/schema-graph.dot
+++ b/schema-graph.dot
@@ -9,58 +9,58 @@ digraph schema {
label="Identity & Company"; labeljust="l"; fontsize=15;
style="rounded,filled"; fillcolor="#ffffff60"; color="#a0aec0";
fontcolor="#1a365d"; margin=14;
- entity [label=<
>];
- meta [label=<>];
- numbers [label=<>];
customergroup [label=<>];
+ numbers [label=<>];
+ company [label=< |
|
| default_language_id? | INT FK |
|
|
| poscustomergroup_id | INT FK |
|
|
|
|
|
>];
+ entity [label=<>];
syncpos [label=<>];
- company [label=< |
|
|
|
|
| poscustomergroup_id | INT FK |
|
|
| default_language_id? | INT FK |
|
|
>];
+ meta [label=<>];
entityhistory [label=<>];
- companysetting [label=<>];
companyuser [label=<>];
+ companysetting [label=<>];
google_auth [label=< |
|
|
|
|
| picturebinary? | VARBINARY(MAX) |
|
|
|
>];
}
subgraph cluster_i18n {
label="Localization"; labeljust="l"; fontsize=15;
style="rounded,filled"; fillcolor="#ffffff60"; color="#a0aec0";
fontcolor="#1a365d"; margin=14;
- unittext [label=<>];
+ unittext [label=<>];
language [label=<>];
- articletext [label=<>];
- categorytext [label=<>];
+ categorytext [label=<>];
+ articletext [label=<>];
}
subgraph cluster_catalog {
label="Catalog"; labeljust="l"; fontsize=15;
style="rounded,filled"; fillcolor="#ffffff60"; color="#a0aec0";
fontcolor="#1a365d"; margin=14;
- category [label=<>];
- categoryarticle [label=<>];
articlelistarticle [label=<>];
articlelist [label=<>];
article [label=<>];
- articlehistory [label=<>];
- optionslist [label=<>];
articleean [label=<>];
- brand [label=<>];
+ optionslist [label=<>];
optionslistarticle [label=<>];
+ articlehistory [label=<>];
+ brand [label=<>];
+ category [label=<>];
+ categoryarticle [label=<>];
}
subgraph cluster_media {
label="Media"; labeljust="l"; fontsize=15;
style="rounded,filled"; fillcolor="#ffffff60"; color="#a0aec0";
fontcolor="#1a365d"; margin=14;
- categorypic [label=<>];
+ brandpic [label=<>];
articlepic [label=<>];
pic [label=< |
|
|
|
|
|
|
|
|
|
|
| thumbbinary | VARBINARY(MAX) |
|
>];
- brandpic [label=<>];
+ categorypic [label=<>];
}
subgraph cluster_commerce {
label="Pricing & Documents"; labeljust="l"; fontsize=15;
style="rounded,filled"; fillcolor="#ffffff60"; color="#a0aec0";
fontcolor="#1a365d"; margin=14;
- price [label=<| price |
|
|
|
|
| minmultiplier | DECIMAL(18,4) |
|
|
>];
- manifest [label=<>];
- manifestarticle [label=<>];
tax [label=<>];
+ manifest [label=<>];
+ manifestarticle [label=<>];
+ price [label=<| price |
|
|
|
|
| minmultiplier | DECIMAL(18,4) |
|
|
>];
}
subgraph cluster_units {
label="Units"; labeljust="l"; fontsize=15;
@@ -68,64 +68,65 @@ digraph schema {
fontcolor="#1a365d"; margin=14;
unit [label=<>];
}
- posterminalcategory [label=<>];
+ posterminalcategory [label=<>];
posterminal [label=<>];
__legend [label=<| Legend |
| PK | primary key |
| FK | foreign key |
| ? | nullable column |
| — | FOREIGN KEY constraint |
| - - | naming convention only, no constraint |
>];
- google_auth:selected_company:sw -> company:in5:n [color="#c53030", fontcolor="#c53030", tooltip="FK_google_auth_selected_company"];
+ google_auth:selected_company:w -> company:in8:n [color="#c53030", fontcolor="#c53030", tooltip="FK_google_auth_selected_company"];
category:parent_id:e -> category:id:e [color="#2f855a", fontcolor="#2f855a", tooltip="FK_category_parent"];
- company:root_category_id:e -> category:in0:n [color="#2b6cb0", fontcolor="#2b6cb0", tooltip="FK_company_root_category"];
- company:default_language_id:e -> language:in0:n [color="#b7791f", fontcolor="#b7791f", tooltip="FK_company_default_language"];
- company:taxrate:w -> tax:in4:n [color="#6b46c1", fontcolor="#6b46c1", tooltip="FK_company_taxrate"];
- company:reducedtaxrate:w -> tax:in2:n [color="#c05621", fontcolor="#c05621", tooltip="FK_company_reducedtaxrate"];
- company:taxfreerate:w -> tax:in3:n [color="#319795", fontcolor="#319795", tooltip="FK_company_taxfreerate"];
- customergroup:company_id:ne -> company:in1:n [color="#97266d", fontcolor="#97266d", tooltip="FK_customergroup_company"];
- company:poscustomergroup_id:sw -> customergroup:in2:n [color="#4c51bf", fontcolor="#4c51bf", tooltip="FK_company_poscustomergroup"];
- entity:customergroup_id:se -> customergroup:in1:n [color="#276749", fontcolor="#276749", tooltip="FK_entity_customergroup"];
- entityhistory:entity_id:sw -> entity:in1:n [color="#9c4221", fontcolor="#9c4221", tooltip="FK_entityhistory_entity"];
- entityhistory:companyuser_id:se -> companyuser:in0:n [color="#0987a0", fontcolor="#0987a0", tooltip="FK_entityhistory_companyuser"];
- unit:company_id:w -> company:in7:n [color="#553c9a", fontcolor="#553c9a", tooltip="FK_unit_company"];
- unittext:unit_id:w -> unit:in1:n [color="#742a2a", fontcolor="#742a2a", tooltip="FK_unittext_unit"];
- unittext:language_id:se -> language:in1:n [color="#22543d", fontcolor="#22543d", tooltip="FK_unittext_language"];
- brand:company_id:w -> company:in8:n [color="#1a365d", fontcolor="#1a365d", tooltip="FK_brand_company"];
- article:unit_id:w -> unit:in0:n [color="#702459", fontcolor="#702459", tooltip="FK_article_unit"];
- article:brand_id:se -> brand:in0:n [color="#744210", fontcolor="#744210", tooltip="FK_article_brand"];
+ company:root_category_id:w -> category:in5:n [color="#2b6cb0", fontcolor="#2b6cb0", tooltip="FK_company_root_category"];
+ company:default_language_id:w -> language:in3:n [color="#b7791f", fontcolor="#b7791f", tooltip="FK_company_default_language"];
+ company:taxrate:e -> tax:in2:n [color="#6b46c1", fontcolor="#6b46c1", tooltip="FK_company_taxrate"];
+ company:reducedtaxrate:e -> tax:in0:n [color="#c05621", fontcolor="#c05621", tooltip="FK_company_reducedtaxrate"];
+ company:taxfreerate:e -> tax:in1:n [color="#319795", fontcolor="#319795", tooltip="FK_company_taxfreerate"];
+ customergroup:company_id:se -> company:in3:n [color="#97266d", fontcolor="#97266d", tooltip="FK_customergroup_company"];
+ company:poscustomergroup_id:nw -> customergroup:in0:n [color="#4c51bf", fontcolor="#4c51bf", tooltip="FK_company_poscustomergroup"];
+ entity:customergroup_id:sw -> customergroup:in1:n [color="#276749", fontcolor="#276749", tooltip="FK_entity_customergroup"];
+ entityhistory:entity_id:sw -> entity:in0:n [color="#9c4221", fontcolor="#9c4221", tooltip="FK_entityhistory_entity"];
+ entityhistory:companyuser_id:se -> companyuser:in1:n [color="#0987a0", fontcolor="#0987a0", tooltip="FK_entityhistory_companyuser"];
+ unit:company_id:e -> company:in0:n [color="#553c9a", fontcolor="#553c9a", tooltip="FK_unit_company"];
+ unittext:unit_id:se -> unit:in0:n [color="#742a2a", fontcolor="#742a2a", tooltip="FK_unittext_unit"];
+ unittext:language_id:se -> language:in0:n [color="#22543d", fontcolor="#22543d", tooltip="FK_unittext_language"];
+ brand:company_id:e -> company:in1:n [color="#1a365d", fontcolor="#1a365d", tooltip="FK_brand_company"];
+ article:unit_id:sw -> unit:in1:n [color="#702459", fontcolor="#702459", tooltip="FK_article_unit"];
+ article:brand_id:e -> brand:in0:n [color="#744210", fontcolor="#744210", tooltip="FK_article_brand"];
article:articlelist_id:sw -> articlelist:in1:n [color="#285e61", fontcolor="#285e61", tooltip="FK_article_articlelist"];
article:optionslist_id:se -> optionslist:in0:n [color="#d53f8c", fontcolor="#d53f8c", tooltip="FK_article_optionslist"];
article:fatherarticle_id:e -> article:id:e [color="#dd6b20", fontcolor="#dd6b20", tooltip="FK_article_fatherarticle"];
- articlehistory:article_id:sw -> article:in5:n [color="#38a169", fontcolor="#38a169", tooltip="FK_articlehistory_article"];
- articlehistory:companyuser_id:w -> companyuser:in1:n [color="#3182ce", fontcolor="#3182ce", tooltip="FK_articlehistory_companyuser"];
- articleean:article_id:sw -> article:in6:n [color="#805ad5", fontcolor="#805ad5", tooltip="FK_articleean_article"];
- articlepic:article_id:w -> article:in8:n [color="#c53030", fontcolor="#c53030", tooltip="FK_articlepic_article"];
+ articlehistory:article_id:w -> article:in5:n [color="#38a169", fontcolor="#38a169", tooltip="FK_articlehistory_article"];
+ articlehistory:companyuser_id:e -> companyuser:in0:n [color="#3182ce", fontcolor="#3182ce", tooltip="FK_articlehistory_companyuser"];
+ articleean:article_id:sw -> article:in3:n [color="#805ad5", fontcolor="#805ad5", tooltip="FK_articleean_article"];
+ articlepic:article_id:w -> article:in7:n [color="#c53030", fontcolor="#c53030", tooltip="FK_articlepic_article"];
articlepic:pic_id:se -> pic:in1:n [color="#2f855a", fontcolor="#2f855a", tooltip="FK_articlepic_pic"];
brandpic:brand_id:w -> brand:in1:n [color="#2b6cb0", fontcolor="#2b6cb0", tooltip="FK_brandpic_brand"];
- brandpic:pic_id:sw -> pic:in2:n [color="#b7791f", fontcolor="#b7791f", tooltip="FK_brandpic_pic"];
+ brandpic:pic_id:se -> pic:in0:n [color="#b7791f", fontcolor="#b7791f", tooltip="FK_brandpic_pic"];
articlelistarticle:articlelist_id:se -> articlelist:in0:n [color="#6b46c1", fontcolor="#6b46c1", tooltip="FK_articlelistarticle_articlelist"];
- articlelistarticle:article_id:se -> article:in3:n [color="#c05621", fontcolor="#c05621", tooltip="FK_articlelistarticle_article"];
+ articlelistarticle:article_id:se -> article:in1:n [color="#c05621", fontcolor="#c05621", tooltip="FK_articlelistarticle_article"];
optionslistarticle:optionslist_id:sw -> optionslist:in1:n [color="#319795", fontcolor="#319795", tooltip="FK_optionslistarticle_optionslist"];
- optionslistarticle:article_id:w -> article:in7:n [color="#97266d", fontcolor="#97266d", tooltip="FK_optionslistarticle_article"];
- categoryarticle:category_id:sw -> category:in3:n [color="#4c51bf", fontcolor="#4c51bf", tooltip="FK_categoryarticle_category"];
- categoryarticle:article_id:se -> article:in2:n [color="#276749", fontcolor="#276749", tooltip="FK_categoryarticle_article"];
+ optionslistarticle:article_id:sw -> article:in4:n [color="#97266d", fontcolor="#97266d", tooltip="FK_optionslistarticle_article"];
+ categoryarticle:category_id:sw -> category:in2:n [color="#4c51bf", fontcolor="#4c51bf", tooltip="FK_categoryarticle_category"];
+ categoryarticle:article_id:w -> article:in6:n [color="#276749", fontcolor="#276749", tooltip="FK_categoryarticle_article"];
categorypic:category_id:sw -> category:in4:n [color="#9c4221", fontcolor="#9c4221", tooltip="FK_categorypic_category"];
- categorypic:pic_id:se -> pic:in0:n [color="#0987a0", fontcolor="#0987a0", tooltip="FK_categorypic_pic"];
- categorytext:category_id:w -> category:in5:n [color="#553c9a", fontcolor="#553c9a", tooltip="FK_categorytext_category"];
- categorytext:language_id:sw -> language:in3:n [color="#742a2a", fontcolor="#742a2a", tooltip="FK_categorytext_language"];
- articletext:article_id:w -> article:in9:n [color="#22543d", fontcolor="#22543d", tooltip="FK_articletext_article"];
+ categorypic:pic_id:sw -> pic:in2:n [color="#0987a0", fontcolor="#0987a0", tooltip="FK_categorypic_pic"];
+ categorytext:category_id:e -> category:in0:n [color="#553c9a", fontcolor="#553c9a", tooltip="FK_categorytext_category"];
+ categorytext:language_id:sw -> language:in1:n [color="#742a2a", fontcolor="#742a2a", tooltip="FK_categorytext_language"];
+ articletext:article_id:e -> article:in0:n [color="#22543d", fontcolor="#22543d", tooltip="FK_articletext_article"];
articletext:language_id:sw -> language:in2:n [color="#1a365d", fontcolor="#1a365d", tooltip="FK_articletext_language"];
- price:tax_id:se -> tax:in0:n [color="#702459", fontcolor="#702459", tooltip="FK_price_tax"];
- price:article_id:e -> article:in0:n [color="#744210", fontcolor="#744210", tooltip="FK_price_article"];
- price:customergroup_id:se -> customergroup:in0:n [color="#285e61", fontcolor="#285e61", tooltip="FK_price_customergroup"];
- manifest:entity_id:se -> entity:in0:n [color="#d53f8c", fontcolor="#d53f8c", tooltip="FK_manifest_entity"];
- manifestarticle:manifest_id:sw -> manifest:in0:n [color="#dd6b20", fontcolor="#dd6b20", tooltip="FK_manifestarticle_manifest"];
- manifestarticle:article_id:e -> article:in1:n [color="#38a169", fontcolor="#38a169", tooltip="FK_manifestarticle_article"];
- manifestarticle:tax_id:se -> tax:in1:n [color="#3182ce", fontcolor="#3182ce", tooltip="FK_manifestarticle_tax"];
- numbers:company_id:se -> company:in0:n [color="#805ad5", fontcolor="#805ad5", tooltip="FK_numbers_company"];
- companyuser:google_auth_id:se -> google_auth:in0:n [color="#c53030", fontcolor="#c53030", tooltip="FK_companyuser_google_auth"];
- companyuser:company_id:sw -> company:in4:n [color="#2f855a", fontcolor="#2f855a", tooltip="FK_companyuser_company"];
- syncpos:company_id:se -> company:in2:n [color="#2b6cb0", fontcolor="#2b6cb0", tooltip="FK_syncpos_company"];
- companysetting:company_id:sw -> company:in3:n [color="#b7791f", fontcolor="#b7791f", tooltip="FK_companysetting_company"];
- posterminal:company_id:w -> company:in6:n [color="#6b46c1", fontcolor="#6b46c1", tooltip="FK_posterminal_company"];
- posterminalcategory:posterminal_id:se -> posterminal:in0:n [color="#c05621", fontcolor="#c05621", tooltip="FK_posterminalcategory_posterminal"];
- posterminalcategory:category_id:se -> category:in1:n [color="#319795", fontcolor="#319795", tooltip="FK_posterminalcategory_category"];
+ price:tax_id:sw -> tax:in4:n [color="#702459", fontcolor="#702459", tooltip="FK_price_tax"];
+ price:article_id:w -> article:in9:n [color="#744210", fontcolor="#744210", tooltip="FK_price_article"];
+ price:customergroup_id:w -> customergroup:in2:n [color="#285e61", fontcolor="#285e61", tooltip="FK_price_customergroup"];
+ manifest:company_id:sw -> company:in9:n [color="#d53f8c", fontcolor="#d53f8c", tooltip="FK_manifest_company"];
+ manifest:entity_id:w -> entity:in1:n [color="#dd6b20", fontcolor="#dd6b20", tooltip="FK_manifest_entity"];
+ manifestarticle:manifest_id:sw -> manifest:in0:n [color="#38a169", fontcolor="#38a169", tooltip="FK_manifestarticle_manifest"];
+ manifestarticle:article_id:w -> article:in8:n [color="#3182ce", fontcolor="#3182ce", tooltip="FK_manifestarticle_article"];
+ manifestarticle:tax_id:sw -> tax:in3:n [color="#805ad5", fontcolor="#805ad5", tooltip="FK_manifestarticle_tax"];
+ numbers:company_id:se -> company:in4:n [color="#c53030", fontcolor="#c53030", tooltip="FK_numbers_company"];
+ companyuser:google_auth_id:se -> google_auth:in0:n [color="#2f855a", fontcolor="#2f855a", tooltip="FK_companyuser_google_auth"];
+ companyuser:company_id:sw -> company:in6:n [color="#2b6cb0", fontcolor="#2b6cb0", tooltip="FK_companyuser_company"];
+ syncpos:company_id:sw -> company:in5:n [color="#b7791f", fontcolor="#b7791f", tooltip="FK_syncpos_company"];
+ companysetting:company_id:sw -> company:in7:n [color="#6b46c1", fontcolor="#6b46c1", tooltip="FK_companysetting_company"];
+ posterminal:company_id:e -> company:in2:n [color="#c05621", fontcolor="#c05621", tooltip="FK_posterminal_company"];
+ posterminalcategory:posterminal_id:se -> posterminal:in0:n [color="#319795", fontcolor="#319795", tooltip="FK_posterminalcategory_posterminal"];
+ posterminalcategory:category_id:sw -> category:in3:n [color="#97266d", fontcolor="#97266d", tooltip="FK_posterminalcategory_category"];
}
\ No newline at end of file
diff --git a/schema-graph.svg b/schema-graph.svg
index d1fa67f..2360bcd 100644
--- a/schema-graph.svg
+++ b/schema-graph.svg
@@ -4,939 +4,891 @@
-