feat(schema): replace manifestarticle article_id FK with sku, rename articlesupplier sku/stock fields

This commit is contained in:
seb
2026-09-15 09:24:43 +02:00
parent e56f725bd9
commit 00bbd2e764
18 changed files with 1720 additions and 1877 deletions

View File

@@ -297,8 +297,8 @@ Maps articles to suppliers (`entity`) with purchase pricing, stock, packaging un
| `article_id` | `INT` | FK → `article(id)` (`ON DELETE CASCADE`) | | `article_id` | `INT` | FK → `article(id)` (`ON DELETE CASCADE`) |
| `entity_id` | `INT` | FK → `entity(id)` (`ON DELETE CASCADE`) | | `entity_id` | `INT` | FK → `entity(id)` (`ON DELETE CASCADE`) |
| `price_id` | `INT` | FK → `price(id)` (`ON DELETE NO ACTION`), nullable | | `price_id` | `INT` | FK → `price(id)` (`ON DELETE NO ACTION`), nullable |
| `supplierSKU` | `NVARCHAR(100)` | Supplier's SKU code, nullable | | `sku` | `NVARCHAR(100)` | Supplier's SKU code, nullable |
| `supplierStock` | `FLOAT` | Stock available at supplier, nullable | | `stock` | `FLOAT` | Stock available at supplier, nullable |
| `pu` | `FLOAT` | Packaging unit (Verpackungseinheit), default `1` | | `pu` | `FLOAT` | Packaging unit (Verpackungseinheit), default `1` |
--- ---
@@ -327,9 +327,7 @@ type DeliverySummary = {
type DeliveryLine = { type DeliveryLine = {
id: number, id: number,
articleId: number | null,
sku: string | null, sku: string | null,
customsku: string | null,
customname: string | null, customname: string | null,
amount: number, amount: number,
net: number, net: number,
@@ -341,11 +339,11 @@ type DeliveryLine = {
type Delivery = DeliverySummary & { lines: DeliveryLine[] } type Delivery = DeliverySummary & { lines: DeliveryLine[] }
``` ```
`create` inserts header + lines in one transaction. The `number` is auto-allocated via `getnextnumberwithprefixandpadding` (`numbers` type `delivery`); supply `externalNumber` for an external (supplier) reference. `supplierId` null or a Lieferanten `entity` of the company (else `Supplier not found`). Each line requires either `sku` (resolved in the company category tree → `Article not found`; `customsku` and `customname` forced `null`) or custom line fields (`customsku` / `customname` with `articleId` set to `null`). If `article_id` is set, `customsku` and `customname` must be null (`CK_manifestarticle_article_or_custom`). `amount`, `net`, `tax` (rate → `tax.ensure`); `rebate` defaults `0`. Empty/invalid `date` → `Invalid delivery`; bad line payload → `Invalid lines`. `create` inserts header + lines in one transaction. The `number` is auto-allocated via `getnextnumberwithprefixandpadding` (`numbers` type `delivery`); supply `externalNumber` for an external (supplier) reference. `supplierId` null or a Lieferanten `entity` of the company (else `Supplier not found`). Each line requires either `sku` or `customname`. For delivery manifests, `sku` points to `articlesupplier.sku`; for quote and order manifests, `sku` points to `article.sku`. Lines are stored without FKs so manifest articles are preserved even if articles or suppliers are deleted. `amount`, `net`, `tax` (rate → `tax.ensure`); `rebate` defaults `0`. Empty/invalid `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`. `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: `No company selected`, `Company not found`, `Not authorized`, `Delivery not found`, `Supplier not found`, `Article not found`, `Invalid delivery`, `Invalid lines`. `delete` removes the manifest (`manifestarticle` cascades). Errors: `No company selected`, `Company not found`, `Not authorized`, `Delivery not found`, `Supplier not found`, `Invalid delivery`, `Invalid lines`.
--- ---
@@ -655,7 +653,7 @@ Auth via the article's `categoryarticle` category + `resolveCategoryAccess`. Err
`orderImages` sets `articlepic.sort` to `0..n-1` in the given order. `fullHashes` must list every image of the article exactly once. Errors: `Article not found`, `Invalid image order`, `Not authorized`. `orderImages` sets `articlepic.sort` to `0..n-1` in the given order. `fullHashes` must list every image of the article exactly once. Errors: `Article not found`, `Invalid image order`, `Not authorized`.
`delete` removes the article when it has no child articles (`fatherarticle_id` FK is `ON DELETE NO ACTION`). Cascades: `articlehistory`, `articleean`, `categoryarticle`, `price`, `articlesupplier`, `articletext`, `articlelistarticle`, `optionslistarticle`, `articlepic`; deletes linked `pic` rows and owned `articlelist` / `optionslist`. `manifestarticle.article_id` is set to `NULL` and `comment` gets `article <name> deleted` appended. Errors: `Article not found`, `Article has children`, `Not authorized`. `delete` removes the article when it has no child articles (`fatherarticle_id` FK is `ON DELETE NO ACTION`). Cascades: `articlehistory`, `articleean`, `categoryarticle`, `price`, `articlesupplier`, `articletext`, `articlelistarticle`, `optionslistarticle`, `articlepic`; deletes linked `pic` rows and owned `articlelist` / `optionslist`. Errors: `Article not found`, `Article has children`, `Not authorized`.
--- ---

View File

@@ -363,10 +363,15 @@ const CLUSTERS = [
label: 'Media', label: 'Media',
tables: ['pic', 'articlepic', 'categorypic', 'brandpic'], tables: ['pic', 'articlepic', 'categorypic', 'brandpic'],
}, },
{
id: 'manifests',
label: 'Documents',
tables: ['manifest', 'manifestarticle', 'ledger'],
},
{ {
id: 'commerce', id: 'commerce',
label: 'Pricing & Documents', label: 'Pricing',
tables: ['tax', 'price', 'manifest', 'manifestarticle', 'ledger'], tables: ['tax', 'price'],
}, },
{ id: 'units', label: 'Units', tables: ['unit'] }, { id: 'units', label: 'Units', tables: ['unit'] },
{ id: 'pos', label: 'POS', tables: ['posterminal', 'posterminalcategory'] }, { id: 'pos', label: 'POS', tables: ['posterminal', 'posterminalcategory'] },

272
package-lock.json generated
View File

@@ -9,15 +9,15 @@
"version": "0.1.0", "version": "0.1.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@clack/prompts": "^1.7.0", "@clack/prompts": "^1.8.1",
"@hpcc-js/wasm-graphviz": "^1.28.0", "@hpcc-js/wasm-graphviz": "^1.29.1",
"chalk": "^6.0.0", "chalk": "^6.0.0",
"dotenv": "^17.4.2", "dotenv": "^17.4.2",
"sharp": "^0.35.3", "sharp": "^0.35.4",
"thumbhash": "^0.1.1" "thumbhash": "^0.1.1"
}, },
"devDependencies": { "devDependencies": {
"mssql": "^12.7.0" "mssql": "^12.7.2"
}, },
"peerDependencies": { "peerDependencies": {
"mssql": "^12.6.0" "mssql": "^12.6.0"
@@ -282,9 +282,9 @@
} }
}, },
"node_modules/@clack/core": { "node_modules/@clack/core": {
"version": "1.4.3", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.3.tgz", "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.5.1.tgz",
"integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==", "integrity": "sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"fast-wrap-ansi": "^0.2.0", "fast-wrap-ansi": "^0.2.0",
@@ -295,12 +295,12 @@
} }
}, },
"node_modules/@clack/prompts": { "node_modules/@clack/prompts": {
"version": "1.7.0", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.7.0.tgz", "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.8.1.tgz",
"integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==", "integrity": "sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@clack/core": "1.4.3", "@clack/core": "1.5.1",
"fast-string-width": "^3.0.2", "fast-string-width": "^3.0.2",
"fast-wrap-ansi": "^0.2.0", "fast-wrap-ansi": "^0.2.0",
"sisteransi": "^1.0.5" "sisteransi": "^1.0.5"
@@ -320,9 +320,9 @@
} }
}, },
"node_modules/@hpcc-js/wasm-graphviz": { "node_modules/@hpcc-js/wasm-graphviz": {
"version": "1.28.0", "version": "1.29.1",
"resolved": "https://registry.npmjs.org/@hpcc-js/wasm-graphviz/-/wasm-graphviz-1.28.0.tgz", "resolved": "https://registry.npmjs.org/@hpcc-js/wasm-graphviz/-/wasm-graphviz-1.29.1.tgz",
"integrity": "sha512-KqvPy7ckxPc1xv8Kt7H3bo9cj8U4gfOXxQ8grLZvDZxyQQjnXsKxrweJLLJtEoWWtQqAk4biUB0g2qsjkTiMVA==", "integrity": "sha512-koAQL0wlryEMeBs4/cQC3GB5ziITv66gR9DU/SWYjjup+iQ+Nbjcqxeaef+sffN4F4cBYZ3P31B5z7+cbSABbw==",
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/@img/colour": { "node_modules/@img/colour": {
@@ -335,9 +335,9 @@
} }
}, },
"node_modules/@img/sharp-darwin-arm64": { "node_modules/@img/sharp-darwin-arm64": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.4.tgz",
"integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", "integrity": "sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -353,13 +353,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-darwin-arm64": "1.3.2" "@img/sharp-libvips-darwin-arm64": "1.3.3"
} }
}, },
"node_modules/@img/sharp-darwin-x64": { "node_modules/@img/sharp-darwin-x64": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.4.tgz",
"integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", "integrity": "sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -375,20 +375,20 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-darwin-x64": "1.3.2" "@img/sharp-libvips-darwin-x64": "1.3.3"
} }
}, },
"node_modules/@img/sharp-freebsd-wasm32": { "node_modules/@img/sharp-freebsd-wasm32": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.4.tgz",
"integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", "integrity": "sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"optional": true, "optional": true,
"os": [ "os": [
"freebsd" "freebsd"
], ],
"dependencies": { "dependencies": {
"@img/sharp-wasm32": "0.35.3" "@img/sharp-wasm32": "0.35.4"
}, },
"engines": { "engines": {
"node": ">=20.9.0" "node": ">=20.9.0"
@@ -398,9 +398,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-darwin-arm64": { "node_modules/@img/sharp-libvips-darwin-arm64": {
"version": "1.3.2", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.3.tgz",
"integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", "integrity": "sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -414,9 +414,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-darwin-x64": { "node_modules/@img/sharp-libvips-darwin-x64": {
"version": "1.3.2", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.3.tgz",
"integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", "integrity": "sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -430,9 +430,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linux-arm": { "node_modules/@img/sharp-libvips-linux-arm": {
"version": "1.3.2", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.3.tgz",
"integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", "integrity": "sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -449,9 +449,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linux-arm64": { "node_modules/@img/sharp-libvips-linux-arm64": {
"version": "1.3.2", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.3.tgz",
"integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", "integrity": "sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -468,9 +468,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linux-ppc64": { "node_modules/@img/sharp-libvips-linux-ppc64": {
"version": "1.3.2", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.3.tgz",
"integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", "integrity": "sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -487,9 +487,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linux-riscv64": { "node_modules/@img/sharp-libvips-linux-riscv64": {
"version": "1.3.2", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.3.tgz",
"integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", "integrity": "sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -506,9 +506,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linux-s390x": { "node_modules/@img/sharp-libvips-linux-s390x": {
"version": "1.3.2", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.3.tgz",
"integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", "integrity": "sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -525,9 +525,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linux-x64": { "node_modules/@img/sharp-libvips-linux-x64": {
"version": "1.3.2", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.3.tgz",
"integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==", "integrity": "sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -544,9 +544,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linuxmusl-arm64": { "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
"version": "1.3.2", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.3.tgz",
"integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==", "integrity": "sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -563,9 +563,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linuxmusl-x64": { "node_modules/@img/sharp-libvips-linuxmusl-x64": {
"version": "1.3.2", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.3.tgz",
"integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==", "integrity": "sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -582,9 +582,9 @@
} }
}, },
"node_modules/@img/sharp-linux-arm": { "node_modules/@img/sharp-linux-arm": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.4.tgz",
"integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==", "integrity": "sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -603,13 +603,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linux-arm": "1.3.2" "@img/sharp-libvips-linux-arm": "1.3.3"
} }
}, },
"node_modules/@img/sharp-linux-arm64": { "node_modules/@img/sharp-linux-arm64": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.4.tgz",
"integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==", "integrity": "sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -628,13 +628,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linux-arm64": "1.3.2" "@img/sharp-libvips-linux-arm64": "1.3.3"
} }
}, },
"node_modules/@img/sharp-linux-ppc64": { "node_modules/@img/sharp-linux-ppc64": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.4.tgz",
"integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==", "integrity": "sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -653,13 +653,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linux-ppc64": "1.3.2" "@img/sharp-libvips-linux-ppc64": "1.3.3"
} }
}, },
"node_modules/@img/sharp-linux-riscv64": { "node_modules/@img/sharp-linux-riscv64": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.4.tgz",
"integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==", "integrity": "sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -678,13 +678,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linux-riscv64": "1.3.2" "@img/sharp-libvips-linux-riscv64": "1.3.3"
} }
}, },
"node_modules/@img/sharp-linux-s390x": { "node_modules/@img/sharp-linux-s390x": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.4.tgz",
"integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==", "integrity": "sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -703,13 +703,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linux-s390x": "1.3.2" "@img/sharp-libvips-linux-s390x": "1.3.3"
} }
}, },
"node_modules/@img/sharp-linux-x64": { "node_modules/@img/sharp-linux-x64": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.4.tgz",
"integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==", "integrity": "sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -728,13 +728,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linux-x64": "1.3.2" "@img/sharp-libvips-linux-x64": "1.3.3"
} }
}, },
"node_modules/@img/sharp-linuxmusl-arm64": { "node_modules/@img/sharp-linuxmusl-arm64": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.4.tgz",
"integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==", "integrity": "sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -753,13 +753,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linuxmusl-arm64": "1.3.2" "@img/sharp-libvips-linuxmusl-arm64": "1.3.3"
} }
}, },
"node_modules/@img/sharp-linuxmusl-x64": { "node_modules/@img/sharp-linuxmusl-x64": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.4.tgz",
"integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==", "integrity": "sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -778,17 +778,17 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linuxmusl-x64": "1.3.2" "@img/sharp-libvips-linuxmusl-x64": "1.3.3"
} }
}, },
"node_modules/@img/sharp-wasm32": { "node_modules/@img/sharp-wasm32": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.4.tgz",
"integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", "integrity": "sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==",
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"@emnapi/runtime": "^1.11.1" "@emnapi/runtime": "^1.11.3"
}, },
"engines": { "engines": {
"node": ">=20.9.0" "node": ">=20.9.0"
@@ -798,16 +798,16 @@
} }
}, },
"node_modules/@img/sharp-webcontainers-wasm32": { "node_modules/@img/sharp-webcontainers-wasm32": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.4.tgz",
"integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==", "integrity": "sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==",
"cpu": [ "cpu": [
"wasm32" "wasm32"
], ],
"license": "Apache-2.0", "license": "Apache-2.0",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"@img/sharp-wasm32": "0.35.3" "@img/sharp-wasm32": "0.35.4"
}, },
"engines": { "engines": {
"node": ">=20.9.0" "node": ">=20.9.0"
@@ -817,9 +817,9 @@
} }
}, },
"node_modules/@img/sharp-win32-arm64": { "node_modules/@img/sharp-win32-arm64": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.4.tgz",
"integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==", "integrity": "sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -836,9 +836,9 @@
} }
}, },
"node_modules/@img/sharp-win32-ia32": { "node_modules/@img/sharp-win32-ia32": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.4.tgz",
"integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==", "integrity": "sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -855,9 +855,9 @@
} }
}, },
"node_modules/@img/sharp-win32-x64": { "node_modules/@img/sharp-win32-x64": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.4.tgz",
"integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==", "integrity": "sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1419,9 +1419,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/mssql": { "node_modules/mssql": {
"version": "12.7.0", "version": "12.7.2",
"resolved": "https://registry.npmjs.org/mssql/-/mssql-12.7.0.tgz", "resolved": "https://registry.npmjs.org/mssql/-/mssql-12.7.2.tgz",
"integrity": "sha512-J6SJKXi1jYbhHjjooLNtPnX7+s3cq5IJ701Wgy/UW1SXRpgFlJJsYi3IPve9RVgCUkq0Cqv2aaaSJ4IXtIF3mg==", "integrity": "sha512-zhpPw+WXBWLw7d7J6Y0aWgQy0EV8HKDGNSvmkAjP8bSM4H41X0fweAeKWI+bg9Ri+JHCbsf/QScjmACBFcEo8A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -1545,9 +1545,9 @@
} }
}, },
"node_modules/sharp": { "node_modules/sharp": {
"version": "0.35.3", "version": "0.35.4",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.4.tgz",
"integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", "integrity": "sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@img/colour": "^1.1.0", "@img/colour": "^1.1.0",
@@ -1561,31 +1561,31 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-darwin-arm64": "0.35.3", "@img/sharp-darwin-arm64": "0.35.4",
"@img/sharp-darwin-x64": "0.35.3", "@img/sharp-darwin-x64": "0.35.4",
"@img/sharp-freebsd-wasm32": "0.35.3", "@img/sharp-freebsd-wasm32": "0.35.4",
"@img/sharp-libvips-darwin-arm64": "1.3.2", "@img/sharp-libvips-darwin-arm64": "1.3.3",
"@img/sharp-libvips-darwin-x64": "1.3.2", "@img/sharp-libvips-darwin-x64": "1.3.3",
"@img/sharp-libvips-linux-arm": "1.3.2", "@img/sharp-libvips-linux-arm": "1.3.3",
"@img/sharp-libvips-linux-arm64": "1.3.2", "@img/sharp-libvips-linux-arm64": "1.3.3",
"@img/sharp-libvips-linux-ppc64": "1.3.2", "@img/sharp-libvips-linux-ppc64": "1.3.3",
"@img/sharp-libvips-linux-riscv64": "1.3.2", "@img/sharp-libvips-linux-riscv64": "1.3.3",
"@img/sharp-libvips-linux-s390x": "1.3.2", "@img/sharp-libvips-linux-s390x": "1.3.3",
"@img/sharp-libvips-linux-x64": "1.3.2", "@img/sharp-libvips-linux-x64": "1.3.3",
"@img/sharp-libvips-linuxmusl-arm64": "1.3.2", "@img/sharp-libvips-linuxmusl-arm64": "1.3.3",
"@img/sharp-libvips-linuxmusl-x64": "1.3.2", "@img/sharp-libvips-linuxmusl-x64": "1.3.3",
"@img/sharp-linux-arm": "0.35.3", "@img/sharp-linux-arm": "0.35.4",
"@img/sharp-linux-arm64": "0.35.3", "@img/sharp-linux-arm64": "0.35.4",
"@img/sharp-linux-ppc64": "0.35.3", "@img/sharp-linux-ppc64": "0.35.4",
"@img/sharp-linux-riscv64": "0.35.3", "@img/sharp-linux-riscv64": "0.35.4",
"@img/sharp-linux-s390x": "0.35.3", "@img/sharp-linux-s390x": "0.35.4",
"@img/sharp-linux-x64": "0.35.3", "@img/sharp-linux-x64": "0.35.4",
"@img/sharp-linuxmusl-arm64": "0.35.3", "@img/sharp-linuxmusl-arm64": "0.35.4",
"@img/sharp-linuxmusl-x64": "0.35.3", "@img/sharp-linuxmusl-x64": "0.35.4",
"@img/sharp-webcontainers-wasm32": "0.35.3", "@img/sharp-webcontainers-wasm32": "0.35.4",
"@img/sharp-win32-arm64": "0.35.3", "@img/sharp-win32-arm64": "0.35.4",
"@img/sharp-win32-ia32": "0.35.3", "@img/sharp-win32-ia32": "0.35.4",
"@img/sharp-win32-x64": "0.35.3" "@img/sharp-win32-x64": "0.35.4"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@types/node": { "@types/node": {

View File

@@ -18,17 +18,17 @@
"test:api": "node scripts/test-api.js" "test:api": "node scripts/test-api.js"
}, },
"dependencies": { "dependencies": {
"@clack/prompts": "^1.7.0", "@clack/prompts": "^1.8.1",
"@hpcc-js/wasm-graphviz": "^1.28.0", "@hpcc-js/wasm-graphviz": "^1.29.1",
"chalk": "^6.0.0", "chalk": "^6.0.0",
"dotenv": "^17.4.2", "dotenv": "^17.4.2",
"sharp": "^0.35.3", "sharp": "^0.35.4",
"thumbhash": "^0.1.1" "thumbhash": "^0.1.1"
}, },
"peerDependencies": { "peerDependencies": {
"mssql": "^12.6.0" "mssql": "^12.6.0"
}, },
"devDependencies": { "devDependencies": {
"mssql": "^12.7.0" "mssql": "^12.7.2"
} }
} }

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 196 KiB

View File

@@ -536,8 +536,8 @@ BEGIN
article_id INT NOT NULL, article_id INT NOT NULL,
entity_id INT NOT NULL, entity_id INT NOT NULL,
price_id INT NULL, price_id INT NULL,
supplierSKU NVARCHAR(100) NULL, sku NVARCHAR(100) NULL,
supplierStock FLOAT NULL, stock FLOAT NULL,
pu FLOAT NOT NULL CONSTRAINT DF_articlesupplier_pu DEFAULT 1, pu FLOAT NOT NULL CONSTRAINT DF_articlesupplier_pu DEFAULT 1,
CONSTRAINT FK_articlesupplier_article FOREIGN KEY (article_id) REFERENCES article(id) ON DELETE CASCADE, CONSTRAINT FK_articlesupplier_article FOREIGN KEY (article_id) REFERENCES article(id) ON DELETE CASCADE,
CONSTRAINT FK_articlesupplier_entity FOREIGN KEY (entity_id) REFERENCES entity(id) ON DELETE CASCADE, CONSTRAINT FK_articlesupplier_entity FOREIGN KEY (entity_id) REFERENCES entity(id) ON DELETE CASCADE,
@@ -572,8 +572,7 @@ BEGIN
CREATE TABLE manifestarticle ( CREATE TABLE manifestarticle (
id INT IDENTITY(1,1) PRIMARY KEY, id INT IDENTITY(1,1) PRIMARY KEY,
manifest_id INT NOT NULL, manifest_id INT NOT NULL,
article_id INT NULL, sku NVARCHAR(100) NULL,
customsku NVARCHAR(100) NULL,
customname NVARCHAR(255) NULL, customname NVARCHAR(255) NULL,
amount FLOAT NOT NULL, amount FLOAT NOT NULL,
net FLOAT NOT NULL, net FLOAT NOT NULL,
@@ -581,44 +580,12 @@ BEGIN
rebate FLOAT NOT NULL CONSTRAINT DF_manifestarticle_rebate DEFAULT 0, rebate FLOAT NOT NULL CONSTRAINT DF_manifestarticle_rebate DEFAULT 0,
tax_id INT NOT NULL, tax_id INT NOT NULL,
CONSTRAINT FK_manifestarticle_manifest FOREIGN KEY (manifest_id) REFERENCES manifest(id) ON DELETE CASCADE, CONSTRAINT FK_manifestarticle_manifest FOREIGN KEY (manifest_id) REFERENCES manifest(id) ON DELETE CASCADE,
CONSTRAINT FK_manifestarticle_article FOREIGN KEY (article_id) REFERENCES article(id) ON DELETE SET NULL, CONSTRAINT FK_manifestarticle_tax FOREIGN KEY (tax_id) REFERENCES tax(id) ON DELETE CASCADE
CONSTRAINT FK_manifestarticle_tax FOREIGN KEY (tax_id) REFERENCES tax(id) ON DELETE CASCADE,
CONSTRAINT CK_manifestarticle_article_or_custom CHECK (
(article_id IS NOT NULL AND customsku IS NULL AND customname IS NULL)
OR (article_id IS NULL)
)
); );
END END
IF NOT EXISTS (
SELECT 1 FROM sys.columns
WHERE object_id = OBJECT_ID(N'dbo.manifestarticle') AND name = N'customsku'
)
BEGIN
EXEC('ALTER TABLE dbo.manifestarticle ADD customsku NVARCHAR(100) NULL');
END
IF NOT EXISTS (
SELECT 1 FROM sys.columns
WHERE object_id = OBJECT_ID(N'dbo.manifestarticle') AND name = N'customname'
)
BEGIN
EXEC('ALTER TABLE dbo.manifestarticle ADD customname NVARCHAR(255) NULL');
END
IF NOT EXISTS (
SELECT 1 FROM sys.check_constraints
WHERE name = N'CK_manifestarticle_article_or_custom'
)
BEGIN
EXEC('ALTER TABLE dbo.manifestarticle ADD CONSTRAINT CK_manifestarticle_article_or_custom
CHECK (
(article_id IS NOT NULL AND customsku IS NULL AND customname IS NULL)
OR (article_id IS NULL)
)');
END
`; `;
export const INIT_LEDGER = ` export const INIT_LEDGER = `
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'ledger') IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'ledger')
BEGIN BEGIN

View File

@@ -10,22 +10,6 @@ FROM article
WHERE id = @articleId WHERE id = @articleId
`; `;
export const GET_NAME_FOR_DELETE = `
SELECT TOP 1 at.name
FROM articletext at
WHERE at.article_id = @articleId AND at.language_id = @languageId
`;
export const DETACH_MANIFEST_ARTICLES = `
UPDATE manifestarticle
SET article_id = NULL,
comment = CONCAT(
ISNULL(comment, ''),
CASE WHEN comment IS NULL OR comment = '' THEN '' ELSE ' ' END,
@suffix
)
WHERE article_id = @articleId
`;
export const DELETE_PICS_BY_ARTICLE = ` export const DELETE_PICS_BY_ARTICLE = `
DELETE p DELETE p

View File

@@ -31,9 +31,7 @@ WHERE m.id = @id
export const GET_DELIVERY_LINES = ` export const GET_DELIVERY_LINES = `
SELECT SELECT
ma.id, ma.id,
ma.article_id AS articleId, ma.sku,
a.sku,
ma.customsku,
ma.customname, ma.customname,
ma.amount, ma.amount,
ma.net, ma.net,
@@ -41,7 +39,6 @@ SELECT
t.rate AS tax, t.rate AS tax,
ma.comment ma.comment
FROM manifestarticle ma FROM manifestarticle ma
LEFT JOIN article a ON a.id = ma.article_id
INNER JOIN tax t ON t.id = ma.tax_id INNER JOIN tax t ON t.id = ma.tax_id
WHERE ma.manifest_id = @manifestId WHERE ma.manifest_id = @manifestId
ORDER BY ma.id ORDER BY ma.id
@@ -80,8 +77,7 @@ WHERE manifest_id = @manifestId
export const CREATE_LINE = ` export const CREATE_LINE = `
INSERT INTO manifestarticle ( INSERT INTO manifestarticle (
manifest_id, manifest_id,
article_id, sku,
customsku,
customname, customname,
amount, amount,
net, net,
@@ -92,8 +88,7 @@ INSERT INTO manifestarticle (
OUTPUT INSERTED.id OUTPUT INSERTED.id
VALUES ( VALUES (
@manifestId, @manifestId,
@articleId, @sku,
@customsku,
@customname, @customname,
@amount, @amount,
@net, @net,
@@ -102,27 +97,3 @@ VALUES (
@taxId @taxId
) )
`; `;
/** Resolve SKU to article id if reachable via the company category tree. */
export const RESOLVE_ARTICLE_ID_BY_SKU = `
;WITH category_tree AS (
SELECT id
FROM category
WHERE id = @rootCategoryId
UNION ALL
SELECT c.id
FROM category c
INNER JOIN category_tree ct ON c.parent_id = ct.id
)
SELECT TOP 1 a.id
FROM article a
WHERE a.sku = @sku
AND EXISTS (
SELECT 1
FROM categoryarticle ca
INNER JOIN category_tree ct ON ct.id = ca.category_id
WHERE ca.article_id = a.id
)
`;

View File

@@ -37,9 +37,7 @@ WHERE m.id = @id
export const GET_MANIFEST_LINES = ` export const GET_MANIFEST_LINES = `
SELECT SELECT
ma.id, ma.id,
ma.article_id AS articleId, ma.sku,
a.sku,
ma.customsku,
ma.customname, ma.customname,
ma.amount, ma.amount,
ma.net, ma.net,
@@ -47,7 +45,6 @@ SELECT
t.rate AS tax, t.rate AS tax,
ma.comment ma.comment
FROM manifestarticle ma FROM manifestarticle ma
LEFT JOIN article a ON a.id = ma.article_id
INNER JOIN tax t ON t.id = ma.tax_id INNER JOIN tax t ON t.id = ma.tax_id
WHERE ma.manifest_id = @manifestId WHERE ma.manifest_id = @manifestId
ORDER BY ma.id ORDER BY ma.id
@@ -86,8 +83,7 @@ WHERE manifest_id = @manifestId
export const CREATE_LINE = ` export const CREATE_LINE = `
INSERT INTO manifestarticle ( INSERT INTO manifestarticle (
manifest_id, manifest_id,
article_id, sku,
customsku,
customname, customname,
amount, amount,
net, net,
@@ -98,8 +94,7 @@ INSERT INTO manifestarticle (
OUTPUT INSERTED.id OUTPUT INSERTED.id
VALUES ( VALUES (
@manifestId, @manifestId,
@articleId, @sku,
@customsku,
@customname, @customname,
@amount, @amount,
@net, @net,
@@ -108,27 +103,3 @@ VALUES (
@taxId @taxId
) )
`; `;
/** Resolve SKU to article id if reachable via the company category tree. */
export const RESOLVE_ARTICLE_ID_BY_SKU = `
;WITH category_tree AS (
SELECT id
FROM category
WHERE id = @rootCategoryId
UNION ALL
SELECT c.id
FROM category c
INNER JOIN category_tree ct ON c.parent_id = ct.id
)
SELECT TOP 1 a.id
FROM article a
WHERE a.sku = @sku
AND EXISTS (
SELECT 1
FROM categoryarticle ca
INNER JOIN category_tree ct ON ct.id = ca.category_id
WHERE ca.article_id = a.id
)
`;

View File

@@ -3,10 +3,8 @@ import {
DELETE_BY_ID, DELETE_BY_ID,
DELETE_OPTIONSLIST, DELETE_OPTIONSLIST,
DELETE_PICS_BY_ARTICLE, DELETE_PICS_BY_ARTICLE,
DETACH_MANIFEST_ARTICLES,
GET_CHILD_COUNT, GET_CHILD_COUNT,
GET_LIST_IDS, GET_LIST_IDS,
GET_NAME_FOR_DELETE,
} from '../../sql/articleDelete.js'; } from '../../sql/articleDelete.js';
import resolveArticleBySku from './resolveArticleBySku.js'; import resolveArticleBySku from './resolveArticleBySku.js';
import request from '../request.js'; import request from '../request.js';
@@ -26,7 +24,7 @@ export default function del(pool) {
* await store.article.delete(42, 'SKU-1'); * await store.article.delete(42, 'SKU-1');
*/ */
return async (googleAuthId, sku) => { return async (googleAuthId, sku) => {
const { articleId, languageId } = await resolve(googleAuthId, sku); const { articleId } = await resolve(googleAuthId, sku);
const childCount = await pool const childCount = await pool
.request() .request()
@@ -37,15 +35,6 @@ export default function del(pool) {
throw new Error('Article has children'); throw new Error('Article has children');
} }
const nameResult = await pool
.request()
.input('articleId', articleId)
.input('languageId', languageId)
.query(GET_NAME_FOR_DELETE);
const name = nameResult.recordset[0]?.name ?? sku;
const suffix = `article ${name} deleted`;
const listIds = await pool const listIds = await pool
.request() .request()
.input('articleId', articleId) .input('articleId', articleId)
@@ -57,11 +46,6 @@ export default function del(pool) {
await tx.begin(); await tx.begin();
try { try {
await request(pool, tx)
.input('articleId', articleId)
.input('suffix', suffix)
.query(DETACH_MANIFEST_ARTICLES);
await request(pool, tx) await request(pool, tx)
.input('articleId', articleId) .input('articleId', articleId)
.query(DELETE_PICS_BY_ARTICLE); .query(DELETE_PICS_BY_ARTICLE);

View File

@@ -41,7 +41,7 @@ export default function create(pool) {
const lines = normalizeLines(body.lines ?? []); const lines = normalizeLines(body.lines ?? []);
const { companyId, rootCategoryId } = await access(googleAuthId); const { companyId } = await access(googleAuthId);
const tx = pool.transaction(); const tx = pool.transaction();
await tx.begin(); await tx.begin();
@@ -69,7 +69,6 @@ export default function create(pool) {
await insertLines(pool, tx, { await insertLines(pool, tx, {
manifestId, manifestId,
rootCategoryId,
lines, lines,
ensureTax, ensureTax,
}); });

View File

@@ -56,7 +56,7 @@ export default function update(pool) {
normalizedLines = normalizeLines(patch.lines); normalizedLines = normalizeLines(patch.lines);
} }
const { companyId, rootCategoryId } = await access(googleAuthId); const { companyId } = await access(googleAuthId);
const tx = pool.transaction(); const tx = pool.transaction();
await tx.begin(); await tx.begin();
@@ -125,7 +125,6 @@ export default function update(pool) {
await insertLines(pool, tx, { await insertLines(pool, tx, {
manifestId: id, manifestId: id,
rootCategoryId,
lines: normalizedLines, lines: normalizedLines,
ensureTax, ensureTax,
}); });

View File

@@ -1,11 +1,11 @@
import { CREATE_LINE, RESOLVE_ARTICLE_ID_BY_SKU } from '../sql/manifestDoc.js'; import { CREATE_LINE } from '../sql/manifestDoc.js';
import request from './request.js'; import request from './request.js';
/** /**
* Normalizes and validates an array of manifest line inputs. * Normalizes and validates an array of manifest line inputs.
* *
* @param {Array<object>} lines - The raw line inputs. * @param {Array<object>} lines - The raw line inputs.
* @returns {Array<{sku: string|null, customsku: string|null, customname: string|null, amount: number, net: number, rebate: number, tax: number, comment: string|null}>} The normalized lines. * @returns {Array<{sku: string|null, customname: string|null, amount: number, net: number, rebate: number, tax: number, comment: string|null}>} The normalized lines.
* @throws {Error} If the lines are invalid. * @throws {Error} If the lines are invalid.
*/ */
export function normalizeLines(lines) { export function normalizeLines(lines) {
@@ -15,16 +15,11 @@ export function normalizeLines(lines) {
return lines.map((entry) => { return lines.map((entry) => {
const sku = entry?.sku?.trim?.() ? entry.sku.trim() : null; const sku = entry?.sku?.trim?.() ? entry.sku.trim() : null;
let customsku = entry?.customsku?.trim?.() ? entry.customsku.trim() : null; const customname =
let customname =
entry?.customname?.trim?.() ? entry.customname.trim() : null; entry?.customname?.trim?.() ? entry.customname.trim() : null;
// If an article SKU is present, the custom fields must be null. // Must have either an SKU or a custom name.
if (sku) { if (!sku && !customname) {
customsku = null;
customname = null;
} else if (!customsku && !customname) {
// Must have either a catalog SKU or at least one custom field.
throw new Error('Invalid lines'); throw new Error('Invalid lines');
} }
@@ -47,7 +42,7 @@ export function normalizeLines(lines) {
throw new Error('Invalid lines'); throw new Error('Invalid lines');
} }
return { sku, customsku, customname, amount, net, rebate, tax, comment }; return { sku, customname, amount, net, rebate, tax, comment };
}); });
} }
@@ -79,9 +74,7 @@ export function parseDate(value) {
export function shapeLine(row) { export function shapeLine(row) {
return { return {
id: row.id, id: row.id,
articleId: row.articleId ?? null,
sku: row.sku ?? null, sku: row.sku ?? null,
customsku: row.customsku ?? null,
customname: row.customname ?? null, customname: row.customname ?? null,
amount: row.amount, amount: row.amount,
net: row.net, net: row.net,
@@ -91,28 +84,14 @@ export function shapeLine(row) {
}; };
} }
async function resolveArticleId(pool, tx, rootCategoryId, sku) {
const result = await request(pool, tx)
.input('rootCategoryId', rootCategoryId)
.input('sku', sku)
.query(RESOLVE_ARTICLE_ID_BY_SKU);
const articleId = result.recordset[0]?.id;
if (!articleId) {
throw new Error('Article not found');
}
return articleId;
}
/** /**
* Inserts manifest lines for a document, resolving each SKU to an article id * Inserts manifest lines for a document, storing each SKU directly
* and ensuring the tax rate. * and ensuring the tax rate.
* *
* @param {object} pool - The mssql connection pool. * @param {object} pool - The mssql connection pool.
* @param {object} tx - The transaction. * @param {object} tx - The transaction.
* @param {object} params - The insert parameters. * @param {object} params - The insert parameters.
* @param {number} params.manifestId - The manifest id. * @param {number} params.manifestId - The manifest id.
* @param {number} params.rootCategoryId - The company root category id.
* @param {Array<object>} params.lines - The normalized lines. * @param {Array<object>} params.lines - The normalized lines.
* @param {Function} params.ensureTax - The tax ensure function. * @param {Function} params.ensureTax - The tax ensure function.
* @returns {Promise<void>} * @returns {Promise<void>}
@@ -120,19 +99,15 @@ async function resolveArticleId(pool, tx, rootCategoryId, sku) {
export async function insertLines( export async function insertLines(
pool, pool,
tx, tx,
{ manifestId, rootCategoryId, lines, ensureTax }, { manifestId, lines, ensureTax },
) { ) {
for (const line of lines) { for (const line of lines) {
const articleId = line.sku
? await resolveArticleId(pool, tx, rootCategoryId, line.sku)
: null;
const taxId = await ensureTax(line.tax, tx); const taxId = await ensureTax(line.tax, tx);
await request(pool, tx) await request(pool, tx)
.input('manifestId', manifestId) .input('manifestId', manifestId)
.input('articleId', articleId) .input('sku', line.sku ?? null)
.input('customsku', line.sku ? null : line.customsku ?? null) .input('customname', line.customname ?? null)
.input('customname', line.sku ? null : line.customname ?? null)
.input('amount', line.amount) .input('amount', line.amount)
.input('net', line.net) .input('net', line.net)
.input('comment', line.comment) .input('comment', line.comment)
@@ -141,3 +116,4 @@ export async function insertLines(
.query(CREATE_LINE); .query(CREATE_LINE);
} }
} }

View File

@@ -37,7 +37,7 @@ export default function create(pool) {
: null; : null;
const lines = normalizeLines(body.lines ?? []); const lines = normalizeLines(body.lines ?? []);
const { companyId, rootCategoryId } = await access(googleAuthId); const { companyId } = await access(googleAuthId);
const tx = pool.transaction(); const tx = pool.transaction();
await tx.begin(); await tx.begin();
@@ -63,7 +63,6 @@ export default function create(pool) {
await insertLines(pool, tx, { await insertLines(pool, tx, {
manifestId, manifestId,
rootCategoryId,
lines, lines,
ensureTax, ensureTax,
}); });

View File

@@ -52,7 +52,7 @@ export default function update(pool) {
normalizedLines = normalizeLines(patch.lines); normalizedLines = normalizeLines(patch.lines);
} }
const { companyId, rootCategoryId } = await access(googleAuthId); const { companyId } = await access(googleAuthId);
const tx = pool.transaction(); const tx = pool.transaction();
await tx.begin(); await tx.begin();
@@ -121,7 +121,6 @@ export default function update(pool) {
await insertLines(pool, tx, { await insertLines(pool, tx, {
manifestId: id, manifestId: id,
rootCategoryId,
lines: normalizedLines, lines: normalizedLines,
ensureTax, ensureTax,
}); });

View File

@@ -37,7 +37,7 @@ export default function create(pool) {
: null; : null;
const lines = normalizeLines(body.lines ?? []); const lines = normalizeLines(body.lines ?? []);
const { companyId, rootCategoryId } = await access(googleAuthId); const { companyId } = await access(googleAuthId);
const tx = pool.transaction(); const tx = pool.transaction();
await tx.begin(); await tx.begin();
@@ -63,7 +63,6 @@ export default function create(pool) {
await insertLines(pool, tx, { await insertLines(pool, tx, {
manifestId, manifestId,
rootCategoryId,
lines, lines,
ensureTax, ensureTax,
}); });

View File

@@ -52,7 +52,7 @@ export default function update(pool) {
normalizedLines = normalizeLines(patch.lines); normalizedLines = normalizeLines(patch.lines);
} }
const { companyId, rootCategoryId } = await access(googleAuthId); const { companyId } = await access(googleAuthId);
const tx = pool.transaction(); const tx = pool.transaction();
await tx.begin(); await tx.begin();
@@ -121,7 +121,6 @@ export default function update(pool) {
await insertLines(pool, tx, { await insertLines(pool, tx, {
manifestId: id, manifestId: id,
rootCategoryId,
lines: normalizedLines, lines: normalizedLines,
ensureTax, ensureTax,
}); });