Compare commits
2 Commits
95ef6f2dd1
...
36dd81ee69
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36dd81ee69 | ||
|
|
e02bbd65c5 |
@@ -184,7 +184,7 @@ Returns the full detail of an article by its SKU, including unit, brand, categor
|
|||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
|
|
||||||
`Promise<{article: {id: number, sku: string, name: string, slug: string, unitamount: number|null, weight: number|null, track_stock: boolean, unit: {si: string|null, basesi: string|null, basesifactor: number|null, symbol: string|null, name: string|null}, brand: {id: number|null, name: string, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null}|null, categoryIds: number[], photos: Array<{sort: number, fullHash: string, fullW: number, fullH: number, fullSize: number, thumbW: number, thumbH: number, thumbHash: string}>, eans: string[], prices: Array<{minmultiplier: number, net: number, taxRate: number, customergroupId: number}>, suppliers: Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null}>, optionsCount: number, articleListCount: number, childCount: number, parentArticleId: number|null, parentSku: string|null}}>` — The full article detail.
|
`Promise<{article: {id: number, sku: string, name: string, slug: string, unitamount: number|null, weight: number|null, track_stock: boolean, unit: {si: string|null, basesi: string|null, basesifactor: number|null, symbol: string|null, name: string|null}, brand: {id: number|null, name: string, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null}|null, categoryIds: number[], photos: Array<{sort: number, fullHash: string, fullW: number, fullH: number, fullSize: number, thumbW: number, thumbH: number, thumbHash: string}>, eans: string[], prices: Array<{minmultiplier: number, net: number, taxRate: number, customergroupId: number}>, suppliers: Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null}>, optionsCount: number, articleListCount: number, childCount: number, parentArticleId: number|null, parentSku: string|null}}>` — The full article detail.
|
||||||
|
|
||||||
**Throws**
|
**Throws**
|
||||||
|
|
||||||
@@ -548,7 +548,7 @@ Replaces the price list of an article by its SKU.
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `googleAuthId` | `number` | The id of the Google auth user. |
|
| `googleAuthId` | `number` | The id of the Google auth user. |
|
||||||
| `sku` | `string` | The article SKU. |
|
| `sku` | `string` | The article SKU. |
|
||||||
| `prices` | `Array<{price: number, tax: number, minmultiplier?: number}>` | The price entries (minmultiplier defaults to 1). |
|
| `prices` | `Array<{net?: number, gross?: number, price?: number, taxRate?: number, tax?: number, minmultiplier?: number}>` | The price entries (net or gross, taxRate or tax percentage, minmultiplier defaults to 1). |
|
||||||
| `[tx]` | `object` | Optional transaction to run within. |
|
| `[tx]` | `object` | Optional transaction to run within. |
|
||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
@@ -562,7 +562,9 @@ Replaces the price list of an article by its SKU.
|
|||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const article = await store.article.setPricesBySku(42, 'SKU-1', [{ price: 1.5, tax: 19, minmultiplier: 1 }]);
|
const article = await store.article.setPricesBySku(42, 'SKU-1', [{ net: 10.0, taxRate: 19, minmultiplier: 1 }]);
|
||||||
|
// or with gross:
|
||||||
|
const article = await store.article.setPricesBySku(42, 'SKU-1', [{ gross: 11.9, taxRate: 19 }]);
|
||||||
// => { id, sku, name, ... }
|
// => { id, sku, name, ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ Assigns a supplier to an article, optionally creating a purchase price.
|
|||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
|
|
||||||
`Promise<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null}>` — The created assignment.
|
`Promise<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null}>` — The created assignment.
|
||||||
|
|
||||||
**Throws**
|
**Throws**
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ const created = await store.articlesupplier.create(42, 'SKU-1', {
|
|||||||
pu: 1,
|
pu: 1,
|
||||||
netPrice: 4.20,
|
netPrice: 4.20,
|
||||||
});
|
});
|
||||||
// => { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price }
|
// => { id, articleId, entityId, supplierName, sku, pu, stock, sort, price }
|
||||||
```
|
```
|
||||||
|
|
||||||
## `articlesupplier.delete`
|
## `articlesupplier.delete`
|
||||||
@@ -90,7 +90,7 @@ Lists the supplier assignments for an article by its SKU.
|
|||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
|
|
||||||
`Promise<Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null}>>` — The supplier assignments.
|
`Promise<Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null}>>` — The supplier assignments.
|
||||||
|
|
||||||
**Throws**
|
**Throws**
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ Lists the supplier assignments for an article by its SKU.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const suppliers = await store.articlesupplier.listByArticleSku(42, 'SKU-1');
|
const suppliers = await store.articlesupplier.listByArticleSku(42, 'SKU-1');
|
||||||
// => [{ id, articleId, entityId, supplierName, sku, pu, stock, priceId, price }]
|
// => [{ id, articleId, entityId, supplierName, sku, pu, stock, price }]
|
||||||
```
|
```
|
||||||
|
|
||||||
## `articlesupplier.listByEntityAndSkus`
|
## `articlesupplier.listByEntityAndSkus`
|
||||||
@@ -120,7 +120,7 @@ Lists article-supplier assignments for a given supplier (entityId) and SKU list,
|
|||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
|
|
||||||
`Promise<Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null, article: {id: number, sku: string, name: string|null, slug: string|null, photos: Array<{sort: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>, eans: string[]}}>>` — The supplier assignments with article details.
|
`Promise<Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null, article: {id: number, sku: string, name: string|null, slug: string|null, photos: Array<{sort: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>, eans: string[]}}>>` — The supplier assignments with article details.
|
||||||
|
|
||||||
**Throws**
|
**Throws**
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ Updates an existing supplier assignment and its associated purchase price.
|
|||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
|
|
||||||
`Promise<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null}>` — The updated assignment.
|
`Promise<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null}>` — The updated assignment.
|
||||||
|
|
||||||
**Throws**
|
**Throws**
|
||||||
|
|
||||||
@@ -203,5 +203,5 @@ const updated = await store.articlesupplier.update(42, 'SKU-1', 12, {
|
|||||||
pu: 6,
|
pu: 6,
|
||||||
netPrice: 22.50,
|
netPrice: 22.50,
|
||||||
});
|
});
|
||||||
// => { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price }
|
// => { id, articleId, entityId, supplierName, sku, pu, stock, sort, price }
|
||||||
```
|
```
|
||||||
|
|||||||
14
API.md
14
API.md
@@ -16,7 +16,7 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- **articlelistarticle**: `id PK, articlelist_id->articlelist, article_id->article, count:i=1, sort:i=0, UQ(articlelist_id, article_id), UQ(articlelist_id, sort)`
|
- **articlelistarticle**: `id PK, articlelist_id->articlelist, article_id->article, count:i=1, sort:i=0, UQ(articlelist_id, article_id), UQ(articlelist_id, sort)`
|
||||||
- **articlepic**: `id PK, article_id->article, pic_id->pic, sort:i=0, UQ(article_id, pic_id), UQ(article_id, sort)`
|
- **articlepic**: `id PK, article_id->article, pic_id->pic, sort:i=0, UQ(article_id, pic_id), UQ(article_id, sort)`
|
||||||
- **articleproperty**: `id PK, article_id->article, property_id->propertyname, value:txt, sort:i=0`
|
- **articleproperty**: `id PK, article_id->article, property_id->propertyname, value:txt, sort:i=0`
|
||||||
- **articlesupplier**: `id PK, article_id->article, entity_id->entity, price_id?->price, sku?:s(100), stock?:f, pu:f=1, sort:i=0, UQ(article_id, entity_id), UQ(article_id, sort)`
|
- **articlesupplier**: `id PK, article_id->article, entity_id->entity, net?:f, tax_id?->tax, sku?:s(100), stock?:f, pu:f=1, sort:i=0, UQ(article_id, entity_id), UQ(article_id, sort)`
|
||||||
- **articletext**: `id PK, article_id->article, language_id->language, name:s(255), slug:s(255), seo?:txt, desc?:txt, UQ(article_id, language_id)`
|
- **articletext**: `id PK, article_id->article, language_id->language, name:s(255), slug:s(255), seo?:txt, desc?:txt, UQ(article_id, language_id)`
|
||||||
- **attributename**: `id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)`
|
- **attributename**: `id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)`
|
||||||
- **attributevalue**: `id PK, attribute_id->attributename, value:s(255), sort:i=0, UQ(attribute_id, value)`
|
- **attributevalue**: `id PK, attribute_id->attributename, value:s(255), sort:i=0, UQ(attribute_id, value)`
|
||||||
@@ -92,7 +92,7 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- `createUnderParent(input: {googleAuthId: number, parentId: number, name: string, track_stock?: boolean|number}, tx?: object): Promise<{id: number, parentId: number, name: string, sku: string, track_stock: boolean}>`
|
- `createUnderParent(input: {googleAuthId: number, parentId: number, name: string, track_stock?: boolean|number}, tx?: object): Promise<{id: number, parentId: number, name: string, sku: string, track_stock: boolean}>`
|
||||||
- `delete(googleAuthId: number, sku: string, optionsOrTx?: object|*, maybeTx?: object): Promise<void>`
|
- `delete(googleAuthId: number, sku: string, optionsOrTx?: object|*, maybeTx?: object): Promise<void>`
|
||||||
- `deleteImage(googleAuthId: number, sku: string, fullHash: string, tx?: object): Promise<void>`
|
- `deleteImage(googleAuthId: number, sku: string, fullHash: string, tx?: object): Promise<void>`
|
||||||
- `getBySku(googleAuthId: number, sku: string, tx?: object): Promise<{article: {id: number, sku: string, name: string, slug: string, unitamount: number|null, weight: number|null, track_stock: boolean, unit: {si: string|null, basesi: string|null, basesifactor: number|null, symbol: string|null, name: string|null}, brand: {id: number|null, name: string, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null}|null, categoryIds: number[], photos: Array<{sort: number, fullHash: string, fullW: number, fullH: number, fullSize: number, thumbW: number, thumbH: number, thumbHash: string}>, eans: string[], prices: Array<{minmultiplier: number, net: number, taxRate: number, customergroupId: number}>, suppliers: Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null}>, optionsCount: number, articleListCount: number, childCount: number, parentArticleId: number|null, parentSku: string|null}}>`
|
- `getBySku(googleAuthId: number, sku: string, tx?: object): Promise<{article: {id: number, sku: string, name: string, slug: string, unitamount: number|null, weight: number|null, track_stock: boolean, unit: {si: string|null, basesi: string|null, basesifactor: number|null, symbol: string|null, name: string|null}, brand: {id: number|null, name: string, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null}|null, categoryIds: number[], photos: Array<{sort: number, fullHash: string, fullW: number, fullH: number, fullSize: number, thumbW: number, thumbH: number, thumbHash: string}>, eans: string[], prices: Array<{minmultiplier: number, net: number, taxRate: number, customergroupId: number}>, suppliers: Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null}>, optionsCount: number, articleListCount: number, childCount: number, parentArticleId: number|null, parentSku: string|null}}>`
|
||||||
- `getHistoryBySku(googleAuthId: number, sku: string, opts?: {limit?: number}, tx?: object): Promise<Array<{id: number, companyuserId: number|null, date: string, text: string}>>`
|
- `getHistoryBySku(googleAuthId: number, sku: string, opts?: {limit?: number}, tx?: object): Promise<Array<{id: number, companyuserId: number|null, date: string, text: string}>>`
|
||||||
- `importRows(input: {googleAuthId: number, rows: Array<object>}, tx?: object): Promise<{imported: Array<object>, skipped: Array<object>, errors: Array<object>}>`
|
- `importRows(input: {googleAuthId: number, rows: Array<object>}, tx?: object): Promise<{imported: Array<object>, skipped: Array<object>, errors: Array<object>}>`
|
||||||
- `listChildren(googleAuthId: number, parentSku: string, tx?: object): Promise<Array<{id: number, sku: string, parentsort: number, trackStock: boolean, unitamount: number, weight: number, name: string|null, slug: string|null, attributeValueId: number|null, attributeValue: string|null}>>`
|
- `listChildren(googleAuthId: number, parentSku: string, tx?: object): Promise<Array<{id: number, sku: string, parentsort: number, trackStock: boolean, unitamount: number, weight: number, name: string|null, slug: string|null, attributeValueId: number|null, attributeValue: string|null}>>`
|
||||||
@@ -105,7 +105,7 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- `setCategoryIdsBySku(googleAuthId: number, sku: string, categoryIds: Array<number>, tx?: object): Promise<object>`
|
- `setCategoryIdsBySku(googleAuthId: number, sku: string, categoryIds: Array<number>, tx?: object): Promise<object>`
|
||||||
- `setEansBySku(googleAuthId: number, sku: string, eans: Array<string>, tx?: object): Promise<object>`
|
- `setEansBySku(googleAuthId: number, sku: string, eans: Array<string>, tx?: object): Promise<object>`
|
||||||
- `setParentBySku(googleAuthId: number, sku: string, parentSku: string|null, tx?: object): Promise<object>`
|
- `setParentBySku(googleAuthId: number, sku: string, parentSku: string|null, tx?: object): Promise<object>`
|
||||||
- `setPricesBySku(googleAuthId: number, sku: string, prices: Array<{price: number, tax: number, minmultiplier?: number}>, tx?: object): Promise<object>`
|
- `setPricesBySku(googleAuthId: number, sku: string, prices: Array<{net?: number, gross?: number, price?: number, taxRate?: number, tax?: number, minmultiplier?: number}>, tx?: object): Promise<object>`
|
||||||
- `setTrackStockBySku(googleAuthId: number, sku: string, trackStock: boolean|number, tx?: object): Promise<object>`
|
- `setTrackStockBySku(googleAuthId: number, sku: string, trackStock: boolean|number, tx?: object): Promise<object>`
|
||||||
- `setWeightBySku(googleAuthId: number, sku: string, weight: number, tx?: object): Promise<object>`
|
- `setWeightBySku(googleAuthId: number, sku: string, weight: number, tx?: object): Promise<object>`
|
||||||
- `toggleParent(googleAuthId: number, sku: string, options: {isParent: boolean, attributeNameId?: number, parentAttributeNameId?: number}, tx?: object): Promise<object>`
|
- `toggleParent(googleAuthId: number, sku: string, options: {isParent: boolean, attributeNameId?: number, parentAttributeNameId?: number}, tx?: object): Promise<object>`
|
||||||
@@ -164,12 +164,12 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- `list(googleAuthId: number, tx?: object): Promise<Array<{id: number, name: string, createdAt: string, updatedAt: string}>>`
|
- `list(googleAuthId: number, tx?: object): Promise<Array<{id: number, name: string, createdAt: string, updatedAt: string}>>`
|
||||||
- `update(googleAuthId: number, id: number, input: {name: string}, tx?: object): Promise<{id: number, name: string, createdAt: string, updatedAt: string}>`
|
- `update(googleAuthId: number, id: number, input: {name: string}, tx?: object): Promise<{id: number, name: string, createdAt: string, updatedAt: string}>`
|
||||||
- [articlesupplier](API.articlesupplier.md)
|
- [articlesupplier](API.articlesupplier.md)
|
||||||
- `create(googleAuthId: number, sku: string, input: {entityId: number, sku?: string, pu?: number, stock?: number|null, sort?: number, netPrice?: number|null, taxId?: number, taxRate?: number}, tx?: object): Promise<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null}>`
|
- `create(googleAuthId: number, sku: string, input: {entityId: number, sku?: string, pu?: number, stock?: number|null, sort?: number, netPrice?: number|null, taxId?: number, taxRate?: number}, tx?: object): Promise<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null}>`
|
||||||
- `delete(googleAuthId: number, sku: string, id: number, tx?: object): Promise<void>`
|
- `delete(googleAuthId: number, sku: string, id: number, tx?: object): Promise<void>`
|
||||||
- `listByArticleSku(googleAuthId: number, sku: string, tx?: object): Promise<Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null}>>`
|
- `listByArticleSku(googleAuthId: number, sku: string, tx?: object): Promise<Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null}>>`
|
||||||
- `listByEntityAndSkus(googleAuthId: number, entityIdOrOptions: number|{entityId?: number, supplierId?: number, skus?: string[]|string}, maybeSkus?: string[]|string, tx?: object): Promise<Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null, article: {id: number, sku: string, name: string|null, slug: string|null, photos: Array<{sort: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>, eans: string[]}}>>`
|
- `listByEntityAndSkus(googleAuthId: number, entityIdOrOptions: number|{entityId?: number, supplierId?: number, skus?: string[]|string}, maybeSkus?: string[]|string, tx?: object): Promise<Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null, article: {id: number, sku: string, name: string|null, slug: string|null, photos: Array<{sort: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>, eans: string[]}}>>`
|
||||||
- `order(googleAuthId: number, sku: string, input: {ids: Array<number>}, tx?: object): Promise<{ids: Array<number>}>`
|
- `order(googleAuthId: number, sku: string, input: {ids: Array<number>}, tx?: object): Promise<{ids: Array<number>}>`
|
||||||
- `update(googleAuthId: number, sku: string, id: number, patch: {sku?: string|null, pu?: number, stock?: number|null, sort?: number, netPrice?: number|null, taxId?: number, taxRate?: number}, tx?: object): Promise<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null}>`
|
- `update(googleAuthId: number, sku: string, id: number, patch: {sku?: string|null, pu?: number, stock?: number|null, sort?: number, netPrice?: number|null, taxId?: number, taxRate?: number}, tx?: object): Promise<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null}>`
|
||||||
- [delivery](API.delivery.md)
|
- [delivery](API.delivery.md)
|
||||||
- `attachments(): void`
|
- `attachments(): void`
|
||||||
- [quote](API.quote.md)
|
- [quote](API.quote.md)
|
||||||
|
|||||||
@@ -296,7 +296,8 @@ Maps articles to suppliers (`entity`) with purchase pricing, stock, packaging un
|
|||||||
| `id` | `INT` | Primary Key (`IDENTITY(1,1)`) |
|
| `id` | `INT` | Primary Key (`IDENTITY(1,1)`) |
|
||||||
| `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 SET NULL`), nullable |
|
| `net` | `FLOAT` | Purchase net price, nullable |
|
||||||
|
| `tax_id` | `INT` | FK → `tax(id)` (`ON DELETE NO ACTION`), nullable |
|
||||||
| `sku` | `NVARCHAR(100)` | Supplier's SKU code, nullable |
|
| `sku` | `NVARCHAR(100)` | Supplier's SKU code, nullable |
|
||||||
| `stock` | `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,7 +327,7 @@ const SCHEMA_TABLES = [
|
|||||||
['articlelistarticle', 'id PK, articlelist_id->articlelist, article_id->article, count:i=1, sort:i=0, UQ(articlelist_id, article_id), UQ(articlelist_id, sort)'],
|
['articlelistarticle', 'id PK, articlelist_id->articlelist, article_id->article, count:i=1, sort:i=0, UQ(articlelist_id, article_id), UQ(articlelist_id, sort)'],
|
||||||
['articlepic', 'id PK, article_id->article, pic_id->pic, sort:i=0, UQ(article_id, pic_id), UQ(article_id, sort)'],
|
['articlepic', 'id PK, article_id->article, pic_id->pic, sort:i=0, UQ(article_id, pic_id), UQ(article_id, sort)'],
|
||||||
['articleproperty', 'id PK, article_id->article, property_id->propertyname, value:txt, sort:i=0'],
|
['articleproperty', 'id PK, article_id->article, property_id->propertyname, value:txt, sort:i=0'],
|
||||||
['articlesupplier', 'id PK, article_id->article, entity_id->entity, price_id?->price, sku?:s(100), stock?:f, pu:f=1, sort:i=0, UQ(article_id, entity_id), UQ(article_id, sort)'],
|
['articlesupplier', 'id PK, article_id->article, entity_id->entity, net?:f, tax_id?->tax, sku?:s(100), stock?:f, pu:f=1, sort:i=0, UQ(article_id, entity_id), UQ(article_id, sort)'],
|
||||||
['articletext', 'id PK, article_id->article, language_id->language, name:s(255), slug:s(255), seo?:txt, desc?:txt, UQ(article_id, language_id)'],
|
['articletext', 'id PK, article_id->article, language_id->language, name:s(255), slug:s(255), seo?:txt, desc?:txt, UQ(article_id, language_id)'],
|
||||||
['attributename', 'id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)'],
|
['attributename', 'id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)'],
|
||||||
['attributevalue', 'id PK, attribute_id->attributename, value:s(255), sort:i=0, UQ(attribute_id, value)'],
|
['attributevalue', 'id PK, attribute_id->attributename, value:s(255), sort:i=0, UQ(attribute_id, value)'],
|
||||||
|
|||||||
@@ -562,14 +562,12 @@ SELECT
|
|||||||
asup.pu,
|
asup.pu,
|
||||||
asup.stock,
|
asup.stock,
|
||||||
asup.sort,
|
asup.sort,
|
||||||
asup.price_id AS priceId,
|
asup.net AS [price.net],
|
||||||
p.net AS [price.net],
|
asup.tax_id AS [price.taxId],
|
||||||
p.tax_id AS [price.taxId],
|
|
||||||
t.rate AS [price.taxRate]
|
t.rate AS [price.taxRate]
|
||||||
FROM articlesupplier asup
|
FROM articlesupplier asup
|
||||||
INNER JOIN entity e ON e.id = asup.entity_id
|
INNER JOIN entity e ON e.id = asup.entity_id
|
||||||
LEFT JOIN price p ON p.id = asup.price_id
|
LEFT JOIN tax t ON t.id = asup.tax_id
|
||||||
LEFT JOIN tax t ON t.id = p.tax_id
|
|
||||||
WHERE asup.article_id = a.id
|
WHERE asup.article_id = a.id
|
||||||
ORDER BY asup.sort ASC, asup.id ASC
|
ORDER BY asup.sort ASC, asup.id ASC
|
||||||
FOR JSON PATH
|
FOR JSON PATH
|
||||||
|
|||||||
@@ -8,15 +8,13 @@ SELECT
|
|||||||
asup.pu,
|
asup.pu,
|
||||||
asup.stock,
|
asup.stock,
|
||||||
asup.sort,
|
asup.sort,
|
||||||
asup.price_id AS priceId,
|
asup.net AS priceNet,
|
||||||
p.net AS priceNet,
|
asup.tax_id AS priceTaxId,
|
||||||
p.tax_id AS priceTaxId,
|
|
||||||
t.rate AS priceTaxRate
|
t.rate AS priceTaxRate
|
||||||
FROM articlesupplier asup
|
FROM articlesupplier asup
|
||||||
INNER JOIN entity e ON e.id = asup.entity_id
|
INNER JOIN entity e ON e.id = asup.entity_id
|
||||||
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
|
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
|
||||||
LEFT JOIN price p ON p.id = asup.price_id
|
LEFT JOIN tax t ON t.id = asup.tax_id
|
||||||
LEFT JOIN tax t ON t.id = p.tax_id
|
|
||||||
WHERE asup.article_id = @articleId
|
WHERE asup.article_id = @articleId
|
||||||
AND cg.company_id = @companyId
|
AND cg.company_id = @companyId
|
||||||
ORDER BY asup.sort ASC, asup.id ASC;
|
ORDER BY asup.sort ASC, asup.id ASC;
|
||||||
@@ -32,15 +30,13 @@ SELECT
|
|||||||
asup.pu,
|
asup.pu,
|
||||||
asup.stock,
|
asup.stock,
|
||||||
asup.sort,
|
asup.sort,
|
||||||
asup.price_id AS priceId,
|
asup.net AS priceNet,
|
||||||
p.net AS priceNet,
|
asup.tax_id AS priceTaxId,
|
||||||
p.tax_id AS priceTaxId,
|
|
||||||
t.rate AS priceTaxRate
|
t.rate AS priceTaxRate
|
||||||
FROM articlesupplier asup
|
FROM articlesupplier asup
|
||||||
INNER JOIN entity e ON e.id = asup.entity_id
|
INNER JOIN entity e ON e.id = asup.entity_id
|
||||||
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
|
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
|
||||||
LEFT JOIN price p ON p.id = asup.price_id
|
LEFT JOIN tax t ON t.id = asup.tax_id
|
||||||
LEFT JOIN tax t ON t.id = p.tax_id
|
|
||||||
WHERE asup.id = @id
|
WHERE asup.id = @id
|
||||||
AND asup.article_id = @articleId
|
AND asup.article_id = @articleId
|
||||||
AND cg.company_id = @companyId;
|
AND cg.company_id = @companyId;
|
||||||
@@ -59,9 +55,9 @@ WHERE article_id = @articleId;
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const CREATE = `
|
export const CREATE = `
|
||||||
INSERT INTO articlesupplier (article_id, entity_id, price_id, sku, stock, pu, sort)
|
INSERT INTO articlesupplier (article_id, entity_id, net, tax_id, sku, stock, pu, sort)
|
||||||
OUTPUT INSERTED.id
|
OUTPUT INSERTED.id
|
||||||
VALUES (@articleId, @entityId, @priceId, @sku, @stock, @pu, @sort);
|
VALUES (@articleId, @entityId, @net, @taxId, @sku, @stock, @pu, @sort);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const UPDATE = `
|
export const UPDATE = `
|
||||||
@@ -70,7 +66,8 @@ SET
|
|||||||
sku = @sku,
|
sku = @sku,
|
||||||
stock = @stock,
|
stock = @stock,
|
||||||
pu = @pu,
|
pu = @pu,
|
||||||
price_id = @priceId,
|
net = @net,
|
||||||
|
tax_id = @taxId,
|
||||||
sort = @sort
|
sort = @sort
|
||||||
WHERE id = @id AND article_id = @articleId;
|
WHERE id = @id AND article_id = @articleId;
|
||||||
`;
|
`;
|
||||||
@@ -99,19 +96,6 @@ SET sort = @sort
|
|||||||
WHERE id = @id AND article_id = @articleId;
|
WHERE id = @id AND article_id = @articleId;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const UPDATE_PRICE = `
|
|
||||||
UPDATE price
|
|
||||||
SET
|
|
||||||
net = @net,
|
|
||||||
tax_id = @taxId
|
|
||||||
WHERE id = @id AND article_id = @articleId;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const DELETE_PRICE = `
|
|
||||||
DELETE FROM price
|
|
||||||
WHERE id = @id AND article_id = @articleId;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const GET_COMPANY_DEFAULT_TAX = `
|
export const GET_COMPANY_DEFAULT_TAX = `
|
||||||
SELECT taxrate
|
SELECT taxrate
|
||||||
FROM company
|
FROM company
|
||||||
@@ -128,9 +112,8 @@ SELECT
|
|||||||
asup.pu,
|
asup.pu,
|
||||||
asup.stock,
|
asup.stock,
|
||||||
asup.sort,
|
asup.sort,
|
||||||
asup.price_id AS priceId,
|
asup.net AS priceNet,
|
||||||
p.net AS priceNet,
|
asup.tax_id AS priceTaxId,
|
||||||
p.tax_id AS priceTaxId,
|
|
||||||
t.rate AS priceTaxRate,
|
t.rate AS priceTaxRate,
|
||||||
a.id AS a_id,
|
a.id AS a_id,
|
||||||
a.sku AS a_sku,
|
a.sku AS a_sku,
|
||||||
@@ -161,8 +144,7 @@ INNER JOIN entity e ON e.id = asup.entity_id
|
|||||||
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
|
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
|
||||||
INNER JOIN article a ON a.id = asup.article_id
|
INNER JOIN article a ON a.id = asup.article_id
|
||||||
LEFT JOIN articletext at ON at.article_id = a.id AND at.language_id = @languageId
|
LEFT JOIN articletext at ON at.article_id = a.id AND at.language_id = @languageId
|
||||||
LEFT JOIN price p ON p.id = asup.price_id
|
LEFT JOIN tax t ON t.id = asup.tax_id
|
||||||
LEFT JOIN tax t ON t.id = p.tax_id
|
|
||||||
WHERE asup.entity_id = @entityId
|
WHERE asup.entity_id = @entityId
|
||||||
AND cg.company_id = @companyId
|
AND cg.company_id = @companyId
|
||||||
AND (
|
AND (
|
||||||
|
|||||||
@@ -590,14 +590,15 @@ BEGIN
|
|||||||
id INT IDENTITY(1,1) PRIMARY KEY,
|
id INT IDENTITY(1,1) PRIMARY KEY,
|
||||||
article_id INT NOT NULL,
|
article_id INT NOT NULL,
|
||||||
entity_id INT NOT NULL,
|
entity_id INT NOT NULL,
|
||||||
price_id INT NULL,
|
net FLOAT NULL,
|
||||||
|
tax_id INT NULL,
|
||||||
sku NVARCHAR(100) NULL,
|
sku NVARCHAR(100) NULL,
|
||||||
stock 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,
|
||||||
sort INT NOT NULL CONSTRAINT DF_articlesupplier_sort DEFAULT 0,
|
sort INT NOT NULL CONSTRAINT DF_articlesupplier_sort DEFAULT 0,
|
||||||
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,
|
||||||
CONSTRAINT FK_articlesupplier_price FOREIGN KEY (price_id) REFERENCES price(id) ON DELETE NO ACTION,
|
CONSTRAINT FK_articlesupplier_tax FOREIGN KEY (tax_id) REFERENCES tax(id) ON DELETE NO ACTION,
|
||||||
CONSTRAINT UQ_articlesupplier_article_entity UNIQUE (article_id, entity_id),
|
CONSTRAINT UQ_articlesupplier_article_entity UNIQUE (article_id, entity_id),
|
||||||
CONSTRAINT UQ_articlesupplier_article_sort UNIQUE (article_id, sort)
|
CONSTRAINT UQ_articlesupplier_article_sort UNIQUE (article_id, sort)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -203,17 +203,16 @@ SELECT auth.*,
|
|||||||
'suppliersJson', json((SELECT COALESCE(json_group_array(json_object(
|
'suppliersJson', json((SELECT COALESCE(json_group_array(json_object(
|
||||||
'id', id, 'articleId', article_id, 'entityId', entity_id,
|
'id', id, 'articleId', article_id, 'entityId', entity_id,
|
||||||
'supplierName', supplier_name, 'sku', sku, 'pu', pu,
|
'supplierName', supplier_name, 'sku', sku, 'pu', pu,
|
||||||
'stock', stock, 'sort', sort, 'priceId', price_id,
|
'stock', stock, 'sort', sort,
|
||||||
'price', CASE WHEN price_id IS NULL THEN NULL ELSE json_object(
|
'price', CASE WHEN net IS NULL THEN NULL ELSE json_object(
|
||||||
'net', net, 'taxId', tax_id, 'taxRate', tax_rate
|
'net', net, 'taxId', tax_id, 'taxRate', tax_rate
|
||||||
) END
|
) END
|
||||||
)), '[]') FROM (
|
)), '[]') FROM (
|
||||||
SELECT s.id, s.article_id, s.entity_id, e.name AS supplier_name,
|
SELECT s.id, s.article_id, s.entity_id, e.name AS supplier_name,
|
||||||
s.sku, s.pu, s.stock, s.sort, s.price_id,
|
s.sku, s.pu, s.stock, s.sort,
|
||||||
pr.net, pr.tax_id, t.rate AS tax_rate
|
s.net, s.tax_id, t.rate AS tax_rate
|
||||||
FROM articlesupplier s INNER JOIN entity e ON e.id = s.entity_id
|
FROM articlesupplier s INNER JOIN entity e ON e.id = s.entity_id
|
||||||
LEFT JOIN price pr ON pr.id = s.price_id
|
LEFT JOIN tax t ON t.id = s.tax_id
|
||||||
LEFT JOIN tax t ON t.id = pr.tax_id
|
|
||||||
WHERE s.article_id = a.id ORDER BY s.sort, s.id
|
WHERE s.article_id = a.id ORDER BY s.sort, s.id
|
||||||
))),
|
))),
|
||||||
'warehousesJson', json((SELECT COALESCE(json_group_array(json_object(
|
'warehousesJson', json((SELECT COALESCE(json_group_array(json_object(
|
||||||
|
|||||||
@@ -3,17 +3,17 @@ import { translateQueries } from './translate.js';
|
|||||||
|
|
||||||
const queries = translateQueries(source, 'articlesupplier');
|
const queries = translateQueries(source, 'articlesupplier');
|
||||||
export const {
|
export const {
|
||||||
CHECK_EXISTS, CREATE, DELETE_BY_ID_AND_ARTICLE_ID, DELETE_PRICE,
|
CHECK_EXISTS, CREATE, DELETE_BY_ID_AND_ARTICLE_ID,
|
||||||
GET_BY_ID_AND_ARTICLE_ID, GET_COMPANY_DEFAULT_TAX, GET_NEXT_SORT,
|
GET_BY_ID_AND_ARTICLE_ID, GET_COMPANY_DEFAULT_TAX, GET_NEXT_SORT,
|
||||||
LIST_BY_ARTICLE_ID, LIST_IDS_BY_ARTICLE,
|
LIST_BY_ARTICLE_ID, LIST_IDS_BY_ARTICLE,
|
||||||
SET_TEMP_SORTS, UPDATE, UPDATE_PRICE, UPDATE_SORT,
|
SET_TEMP_SORTS, UPDATE, UPDATE_SORT,
|
||||||
} = queries;
|
} = queries;
|
||||||
|
|
||||||
export const LIST_BY_ENTITY_AND_SKUS = `
|
export const LIST_BY_ENTITY_AND_SKUS = `
|
||||||
SELECT
|
SELECT
|
||||||
asup.id, asup.article_id AS articleId, asup.entity_id AS entityId,
|
asup.id, asup.article_id AS articleId, asup.entity_id AS entityId,
|
||||||
e.name AS supplierName, asup.sku, asup.pu, asup.stock, asup.sort,
|
e.name AS supplierName, asup.sku, asup.pu, asup.stock, asup.sort,
|
||||||
asup.price_id AS priceId, p.net AS priceNet, p.tax_id AS priceTaxId,
|
asup.net AS priceNet, asup.tax_id AS priceTaxId,
|
||||||
t.rate AS priceTaxRate, a.id AS a_id, a.sku AS a_sku,
|
t.rate AS priceTaxRate, a.id AS a_id, a.sku AS a_sku,
|
||||||
at.name AS a_name, at.slug AS a_slug,
|
at.name AS a_name, at.slug AS a_slug,
|
||||||
(SELECT COALESCE(json_group_array(json_object(
|
(SELECT COALESCE(json_group_array(json_object(
|
||||||
@@ -31,8 +31,7 @@ INNER JOIN entity e ON e.id = asup.entity_id
|
|||||||
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
|
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
|
||||||
INNER JOIN article a ON a.id = asup.article_id
|
INNER JOIN article a ON a.id = asup.article_id
|
||||||
LEFT JOIN articletext at ON at.article_id = a.id AND at.language_id = @languageId
|
LEFT JOIN articletext at ON at.article_id = a.id AND at.language_id = @languageId
|
||||||
LEFT JOIN price p ON p.id = asup.price_id
|
LEFT JOIN tax t ON t.id = asup.tax_id
|
||||||
LEFT JOIN tax t ON t.id = p.tax_id
|
|
||||||
WHERE asup.entity_id = @entityId
|
WHERE asup.entity_id = @entityId
|
||||||
AND cg.company_id = @companyId
|
AND cg.company_id = @companyId
|
||||||
AND (
|
AND (
|
||||||
|
|||||||
@@ -385,7 +385,8 @@ CREATE TABLE IF NOT EXISTS articlesupplier (
|
|||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
article_id INTEGER NOT NULL,
|
article_id INTEGER NOT NULL,
|
||||||
entity_id INTEGER NOT NULL,
|
entity_id INTEGER NOT NULL,
|
||||||
price_id INTEGER,
|
net REAL,
|
||||||
|
tax_id INTEGER,
|
||||||
sku TEXT,
|
sku TEXT,
|
||||||
stock REAL,
|
stock REAL,
|
||||||
pu REAL NOT NULL DEFAULT 1,
|
pu REAL NOT NULL DEFAULT 1,
|
||||||
@@ -394,7 +395,7 @@ CREATE TABLE IF NOT EXISTS articlesupplier (
|
|||||||
UNIQUE (article_id, sort),
|
UNIQUE (article_id, sort),
|
||||||
FOREIGN KEY (article_id) REFERENCES article(id) ON DELETE CASCADE,
|
FOREIGN KEY (article_id) REFERENCES article(id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (entity_id) REFERENCES entity(id) ON DELETE CASCADE,
|
FOREIGN KEY (entity_id) REFERENCES entity(id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (price_id) REFERENCES price(id) ON DELETE NO ACTION
|
FOREIGN KEY (tax_id) REFERENCES tax(id) ON DELETE NO ACTION
|
||||||
);
|
);
|
||||||
CREATE INDEX IF NOT EXISTS IX_articlesupplier_article_entity
|
CREATE INDEX IF NOT EXISTS IX_articlesupplier_article_entity
|
||||||
ON articlesupplier(article_id, entity_id);
|
ON articlesupplier(article_id, entity_id);
|
||||||
|
|||||||
@@ -42,42 +42,62 @@ export default function addImage(provider) {
|
|||||||
|
|
||||||
const sortResult = await runner.query(getSortSql, { articleId });
|
const sortResult = await runner.query(getSortSql, { articleId });
|
||||||
const sort = sortResult.rows[0].sort;
|
const sort = sortResult.rows[0].sort;
|
||||||
const fullHash = newFullHash();
|
const fullHash = newFullHash(processed.full.buffer);
|
||||||
|
|
||||||
if (isSqlite) {
|
let picId;
|
||||||
if (runner.writePicFull) {
|
const existingPic = await runner.query(
|
||||||
await runner.writePicFull(fullHash, processed.full.buffer);
|
'SELECT id FROM pic WHERE hash = @fullHash',
|
||||||
await runner.writePicThumb(fullHash, processed.thumb.buffer);
|
{ fullHash },
|
||||||
} else if (provider?.writePicFull) {
|
);
|
||||||
await provider.writePicFull(fullHash, processed.full.buffer);
|
|
||||||
await provider.writePicThumb(fullHash, processed.thumb.buffer);
|
if (existingPic.rows[0]) {
|
||||||
|
picId = existingPic.rows[0].id;
|
||||||
|
} else {
|
||||||
|
if (isSqlite) {
|
||||||
|
if (runner.writePicFull) {
|
||||||
|
await runner.writePicFull(fullHash, processed.full.buffer);
|
||||||
|
await runner.writePicThumb(fullHash, processed.thumb.buffer);
|
||||||
|
} else if (provider?.writePicFull) {
|
||||||
|
await provider.writePicFull(fullHash, processed.full.buffer);
|
||||||
|
await provider.writePicThumb(fullHash, processed.thumb.buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const picResult = await runner.query(createPicSql, {
|
||||||
|
w: processed.full.w,
|
||||||
|
h: processed.full.h,
|
||||||
|
size: processed.full.size,
|
||||||
|
hash: fullHash,
|
||||||
|
thumbw: processed.thumb.w,
|
||||||
|
thumbh: processed.thumb.h,
|
||||||
|
thumbhash: processed.thumb.hash,
|
||||||
|
source: '',
|
||||||
|
fullbinary: processed.full.buffer,
|
||||||
|
thumbbinary: processed.thumb.buffer,
|
||||||
|
});
|
||||||
|
|
||||||
|
picId = picResult.rows[0]?.id ?? picResult.insertId;
|
||||||
}
|
}
|
||||||
|
|
||||||
const picResult = await runner.query(createPicSql, {
|
const existingArticlePic = await runner.query(
|
||||||
w: processed.full.w,
|
'SELECT id, sort FROM articlepic WHERE article_id = @articleId AND pic_id = @picId',
|
||||||
h: processed.full.h,
|
{ articleId, picId },
|
||||||
size: processed.full.size,
|
);
|
||||||
hash: fullHash,
|
|
||||||
thumbw: processed.thumb.w,
|
|
||||||
thumbh: processed.thumb.h,
|
|
||||||
thumbhash: processed.thumb.hash,
|
|
||||||
source: '',
|
|
||||||
fullbinary: processed.full.buffer,
|
|
||||||
thumbbinary: processed.thumb.buffer,
|
|
||||||
});
|
|
||||||
|
|
||||||
const picId = picResult.rows[0]?.id ?? picResult.insertId;
|
let effectiveSort = sort;
|
||||||
|
if (existingArticlePic.rows[0]) {
|
||||||
await runner.query(addArticlePicSql, {
|
effectiveSort = existingArticlePic.rows[0].sort;
|
||||||
articleId,
|
} else {
|
||||||
picId,
|
await runner.query(addArticlePicSql, {
|
||||||
sort,
|
articleId,
|
||||||
});
|
picId,
|
||||||
|
sort,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
picId,
|
picId,
|
||||||
sort,
|
sort: effectiveSort,
|
||||||
full: {
|
full: {
|
||||||
w: processed.full.w,
|
w: processed.full.w,
|
||||||
h: processed.full.h,
|
h: processed.full.h,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default function getBySku(provider) {
|
|||||||
* @param {number} googleAuthId - The id of the Google auth user.
|
* @param {number} googleAuthId - The id of the Google auth user.
|
||||||
* @param {string} sku - The article SKU.
|
* @param {string} sku - The article SKU.
|
||||||
* @param {object} [tx] - Optional transaction.
|
* @param {object} [tx] - Optional transaction.
|
||||||
* @returns {Promise<{article: {id: number, sku: string, name: string, slug: string, unitamount: number|null, weight: number|null, track_stock: boolean, unit: {si: string|null, basesi: string|null, basesifactor: number|null, symbol: string|null, name: string|null}, brand: {id: number|null, name: string, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null}|null, categoryIds: number[], photos: Array<{sort: number, fullHash: string, fullW: number, fullH: number, fullSize: number, thumbW: number, thumbH: number, thumbHash: string}>, eans: string[], prices: Array<{minmultiplier: number, net: number, taxRate: number, customergroupId: number}>, suppliers: Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null}>, optionsCount: number, articleListCount: number, childCount: number, parentArticleId: number|null, parentSku: string|null}}>} The full article detail.
|
* @returns {Promise<{article: {id: number, sku: string, name: string, slug: string, unitamount: number|null, weight: number|null, track_stock: boolean, unit: {si: string|null, basesi: string|null, basesifactor: number|null, symbol: string|null, name: string|null}, brand: {id: number|null, name: string, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null}|null, categoryIds: number[], photos: Array<{sort: number, fullHash: string, fullW: number, fullH: number, fullSize: number, thumbW: number, thumbH: number, thumbHash: string}>, eans: string[], prices: Array<{minmultiplier: number, net: number, taxRate: number, customergroupId: number}>, suppliers: Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null}>, optionsCount: number, articleListCount: number, childCount: number, parentArticleId: number|null, parentSku: string|null}}>} The full article detail.
|
||||||
* @throws {Error} If the article is not found or the user is not authorized.
|
* @throws {Error} If the article is not found or the user is not authorized.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
@@ -87,8 +87,7 @@ export default function getBySku(provider) {
|
|||||||
pu: s.pu,
|
pu: s.pu,
|
||||||
stock: s.stock ?? null,
|
stock: s.stock ?? null,
|
||||||
sort: s.sort,
|
sort: s.sort,
|
||||||
priceId: s.priceId ?? null,
|
price: s.price?.net != null ? s.price : null,
|
||||||
price: s.priceId != null && s.price?.net != null ? s.price : null,
|
|
||||||
})),
|
})),
|
||||||
warehouses: parseJsonArray(a.warehousesJson).map((w) => ({
|
warehouses: parseJsonArray(a.warehousesJson).map((w) => ({
|
||||||
id: w.id,
|
id: w.id,
|
||||||
|
|||||||
@@ -22,28 +22,37 @@ function normalizePrices(prices) {
|
|||||||
const normalized = [];
|
const normalized = [];
|
||||||
|
|
||||||
for (const entry of prices) {
|
for (const entry of prices) {
|
||||||
const price = entry?.price;
|
const rawTax = entry?.taxRate ?? entry?.tax;
|
||||||
const tax = entry?.tax;
|
|
||||||
const minmultiplier =
|
const minmultiplier =
|
||||||
entry?.minmultiplier === undefined || entry?.minmultiplier === null
|
entry?.minmultiplier === undefined || entry?.minmultiplier === null
|
||||||
? 1
|
? 1
|
||||||
: entry.minmultiplier;
|
: entry.minmultiplier;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
typeof price !== 'number' || !Number.isFinite(price) || price < 0 ||
|
typeof rawTax !== 'number' || !Number.isFinite(rawTax) || rawTax < 0 ||
|
||||||
typeof tax !== 'number' || !Number.isFinite(tax) || tax < 0 ||
|
|
||||||
typeof minmultiplier !== 'number' || !Number.isFinite(minmultiplier) || minmultiplier <= 0
|
typeof minmultiplier !== 'number' || !Number.isFinite(minmultiplier) || minmultiplier <= 0
|
||||||
) {
|
) {
|
||||||
throw new Error('Invalid prices');
|
throw new Error('Invalid prices');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let netPrice;
|
||||||
|
if (typeof entry?.net === 'number' && Number.isFinite(entry.net) && entry.net >= 0) {
|
||||||
|
netPrice = entry.net;
|
||||||
|
} else if (typeof entry?.price === 'number' && Number.isFinite(entry.price) && entry.price >= 0) {
|
||||||
|
netPrice = entry.price;
|
||||||
|
} else if (typeof entry?.gross === 'number' && Number.isFinite(entry.gross) && entry.gross >= 0) {
|
||||||
|
netPrice = +Number(entry.gross / (1 + rawTax / 100)).toFixed(4);
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid prices');
|
||||||
|
}
|
||||||
|
|
||||||
const key = String(minmultiplier);
|
const key = String(minmultiplier);
|
||||||
if (seen.has(key)) {
|
if (seen.has(key)) {
|
||||||
throw new Error('Invalid prices');
|
throw new Error('Invalid prices');
|
||||||
}
|
}
|
||||||
seen.add(key);
|
seen.add(key);
|
||||||
|
|
||||||
normalized.push({ price, tax, minmultiplier });
|
normalized.push({ price: netPrice, tax: rawTax, minmultiplier });
|
||||||
}
|
}
|
||||||
|
|
||||||
return normalized;
|
return normalized;
|
||||||
@@ -64,13 +73,15 @@ export default function setPricesBySku(provider) {
|
|||||||
*
|
*
|
||||||
* @param {number} googleAuthId - The id of the Google auth user.
|
* @param {number} googleAuthId - The id of the Google auth user.
|
||||||
* @param {string} sku - The article SKU.
|
* @param {string} sku - The article SKU.
|
||||||
* @param {Array<{price: number, tax: number, minmultiplier?: number}>} prices - The price entries (minmultiplier defaults to 1).
|
* @param {Array<{net?: number, gross?: number, price?: number, taxRate?: number, tax?: number, minmultiplier?: number}>} prices - The price entries (net or gross, taxRate or tax percentage, minmultiplier defaults to 1).
|
||||||
* @param {object} [tx] - Optional transaction to run within.
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
* @returns {Promise<object>} The updated article.
|
* @returns {Promise<object>} The updated article.
|
||||||
* @throws {Error} If the prices are invalid or the article is not found.
|
* @throws {Error} If the prices are invalid or the article is not found.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const article = await store.article.setPricesBySku(42, 'SKU-1', [{ price: 1.5, tax: 19, minmultiplier: 1 }]);
|
* const article = await store.article.setPricesBySku(42, 'SKU-1', [{ net: 10.0, taxRate: 19, minmultiplier: 1 }]);
|
||||||
|
* // or with gross:
|
||||||
|
* const article = await store.article.setPricesBySku(42, 'SKU-1', [{ gross: 11.9, taxRate: 19 }]);
|
||||||
* // => { id, sku, name, ... }
|
* // => { id, sku, name, ... }
|
||||||
*/
|
*/
|
||||||
return async (googleAuthId, sku, prices, tx) => {
|
return async (googleAuthId, sku, prices, tx) => {
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
import * as mssqlQueries from '../../providers/mssql/queries/articlesupplier.js';
|
import * as mssqlQueries from '../../providers/mssql/queries/articlesupplier.js';
|
||||||
import * as sqliteQueries from '../../providers/sqlite3/queries/articlesupplier.js';
|
import * as sqliteQueries from '../../providers/sqlite3/queries/articlesupplier.js';
|
||||||
import { CREATE as MSSQL_CREATE_PRICE } from '../../providers/mssql/queries/price.js';
|
|
||||||
import { CREATE as SQLITE_CREATE_PRICE } from '../../providers/sqlite3/queries/price.js';
|
|
||||||
import { INSERT as MSSQL_INSERT_HISTORY } from '../../providers/mssql/queries/articlehistory.js';
|
import { INSERT as MSSQL_INSERT_HISTORY } from '../../providers/mssql/queries/articlehistory.js';
|
||||||
import { INSERT as SQLITE_INSERT_HISTORY } from '../../providers/sqlite3/queries/articlehistory.js';
|
import { INSERT as SQLITE_INSERT_HISTORY } from '../../providers/sqlite3/queries/articlehistory.js';
|
||||||
import resolveArticleBySku from '../article/resolveArticleBySku.js';
|
import resolveArticleBySku from '../article/resolveArticleBySku.js';
|
||||||
import ensureLieferantenGroup from '../supplier/ensureLieferantenGroup.js';
|
|
||||||
import taxEnsure from '../tax/ensure.js';
|
import taxEnsure from '../tax/ensure.js';
|
||||||
import {
|
import {
|
||||||
assertSupplier,
|
assertSupplier,
|
||||||
@@ -21,7 +18,6 @@ export default function create(provider) {
|
|||||||
const isSqlite = provider?.dialect === 'sqlite3';
|
const isSqlite = provider?.dialect === 'sqlite3';
|
||||||
|
|
||||||
const queries = isSqlite ? sqliteQueries : mssqlQueries;
|
const queries = isSqlite ? sqliteQueries : mssqlQueries;
|
||||||
const createPriceSql = isSqlite ? SQLITE_CREATE_PRICE : MSSQL_CREATE_PRICE;
|
|
||||||
const insertHistorySql = isSqlite ? SQLITE_INSERT_HISTORY : MSSQL_INSERT_HISTORY;
|
const insertHistorySql = isSqlite ? SQLITE_INSERT_HISTORY : MSSQL_INSERT_HISTORY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,7 +35,7 @@ export default function create(provider) {
|
|||||||
* @param {number} [input.taxId] - The tax id for the purchase price.
|
* @param {number} [input.taxId] - The tax id for the purchase price.
|
||||||
* @param {number} [input.taxRate] - The tax rate in percent (used if taxId is not provided).
|
* @param {number} [input.taxRate] - The tax rate in percent (used if taxId is not provided).
|
||||||
* @param {object} [tx] - Optional transaction to run within.
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
* @returns {Promise<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null}>} The created assignment.
|
* @returns {Promise<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null}>} The created assignment.
|
||||||
* @throws {Error} If input is invalid, article or supplier is not found, or supplier is already assigned.
|
* @throws {Error} If input is invalid, article or supplier is not found, or supplier is already assigned.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
@@ -49,7 +45,7 @@ export default function create(provider) {
|
|||||||
* pu: 1,
|
* pu: 1,
|
||||||
* netPrice: 4.20,
|
* netPrice: 4.20,
|
||||||
* });
|
* });
|
||||||
* // => { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price }
|
* // => { id, articleId, entityId, supplierName, sku, pu, stock, sort, price }
|
||||||
*/
|
*/
|
||||||
return async (googleAuthId, sku, input = {}, tx) => {
|
return async (googleAuthId, sku, input = {}, tx) => {
|
||||||
const entityId = input.entityId;
|
const entityId = input.entityId;
|
||||||
@@ -115,10 +111,9 @@ export default function create(provider) {
|
|||||||
sort = sortRes.rows[0].sort;
|
sort = sortRes.rows[0].sort;
|
||||||
}
|
}
|
||||||
|
|
||||||
let priceId = null;
|
let taxId = null;
|
||||||
|
|
||||||
if (netPrice !== null) {
|
if (netPrice !== null) {
|
||||||
let taxId = input.taxId;
|
taxId = input.taxId;
|
||||||
if (taxId == null || !Number.isFinite(taxId)) {
|
if (taxId == null || !Number.isFinite(taxId)) {
|
||||||
if (input.taxRate != null && Number.isFinite(input.taxRate)) {
|
if (input.taxRate != null && Number.isFinite(input.taxRate)) {
|
||||||
taxId = await ensureTax(input.taxRate, runner);
|
taxId = await ensureTax(input.taxRate, runner);
|
||||||
@@ -130,27 +125,13 @@ export default function create(provider) {
|
|||||||
taxId = defaultTaxId != null ? defaultTaxId : await ensureTax(0, runner);
|
taxId = defaultTaxId != null ? defaultTaxId : await ensureTax(0, runner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const customerGroupId = await ensureLieferantenGroup(
|
|
||||||
runner,
|
|
||||||
companyId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const priceRes = await runner.query(createPriceSql, {
|
|
||||||
taxId,
|
|
||||||
articleId,
|
|
||||||
minmultiplier: 1,
|
|
||||||
customerGroupId,
|
|
||||||
net: netPrice,
|
|
||||||
});
|
|
||||||
|
|
||||||
priceId = priceRes.rows[0]?.id ?? priceRes.insertId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const createdRes = await runner.query(queries.CREATE, {
|
const createdRes = await runner.query(queries.CREATE, {
|
||||||
articleId,
|
articleId,
|
||||||
entityId,
|
entityId,
|
||||||
priceId,
|
net: netPrice,
|
||||||
|
taxId,
|
||||||
sku: supplierSku,
|
sku: supplierSku,
|
||||||
stock,
|
stock,
|
||||||
pu,
|
pu,
|
||||||
|
|||||||
@@ -52,13 +52,6 @@ export default function del(provider) {
|
|||||||
articleId,
|
articleId,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (existing.priceId != null) {
|
|
||||||
await runner.query(queries.DELETE_PRICE, {
|
|
||||||
id: existing.priceId,
|
|
||||||
articleId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const supplierName =
|
const supplierName =
|
||||||
existing.supplierName ?? (existing.entityId ? `Lieferant #${existing.entityId}` : 'Lieferant');
|
existing.supplierName ?? (existing.entityId ? `Lieferant #${existing.entityId}` : 'Lieferant');
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,8 @@ export function shapeArticleSupplier(row) {
|
|||||||
pu: row.pu,
|
pu: row.pu,
|
||||||
stock: row.stock ?? null,
|
stock: row.stock ?? null,
|
||||||
sort: row.sort,
|
sort: row.sort,
|
||||||
priceId: row.priceId ?? null,
|
|
||||||
price:
|
price:
|
||||||
row.priceId != null && row.priceNet != null
|
row.priceNet != null
|
||||||
? {
|
? {
|
||||||
net: row.priceNet,
|
net: row.priceNet,
|
||||||
taxId: row.priceTaxId,
|
taxId: row.priceTaxId,
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ export default function listByArticleSku(provider) {
|
|||||||
* @param {number} googleAuthId - The id of the Google auth user.
|
* @param {number} googleAuthId - The id of the Google auth user.
|
||||||
* @param {string} sku - The article SKU.
|
* @param {string} sku - The article SKU.
|
||||||
* @param {object} [tx] - Optional transaction.
|
* @param {object} [tx] - Optional transaction.
|
||||||
* @returns {Promise<Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null}>>} The supplier assignments.
|
* @returns {Promise<Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null}>>} The supplier assignments.
|
||||||
* @throws {Error} If the article is not found or the user is not authorized.
|
* @throws {Error} If the article is not found or the user is not authorized.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const suppliers = await store.articlesupplier.listByArticleSku(42, 'SKU-1');
|
* const suppliers = await store.articlesupplier.listByArticleSku(42, 'SKU-1');
|
||||||
* // => [{ id, articleId, entityId, supplierName, sku, pu, stock, priceId, price }]
|
* // => [{ id, articleId, entityId, supplierName, sku, pu, stock, price }]
|
||||||
*/
|
*/
|
||||||
return async (googleAuthId, sku, tx) => {
|
return async (googleAuthId, sku, tx) => {
|
||||||
const runner = makeRunner(provider, tx);
|
const runner = makeRunner(provider, tx);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export default function listByEntityAndSkus(provider) {
|
|||||||
* @param {number|{entityId?: number, supplierId?: number, skus?: string[]|string}} entityIdOrOptions - The supplier entity id or an options object.
|
* @param {number|{entityId?: number, supplierId?: number, skus?: string[]|string}} entityIdOrOptions - The supplier entity id or an options object.
|
||||||
* @param {string[]|string} [maybeSkus] - The list of SKUs to filter by (or single SKU string).
|
* @param {string[]|string} [maybeSkus] - The list of SKUs to filter by (or single SKU string).
|
||||||
* @param {object} [tx] - Optional transaction.
|
* @param {object} [tx] - Optional transaction.
|
||||||
* @returns {Promise<Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null, article: {id: number, sku: string, name: string|null, slug: string|null, photos: Array<{sort: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>, eans: string[]}}>>} The supplier assignments with article details.
|
* @returns {Promise<Array<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null, article: {id: number, sku: string, name: string|null, slug: string|null, photos: Array<{sort: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>, eans: string[]}}>>} The supplier assignments with article details.
|
||||||
* @throws {Error} If user is not authorized, entityId is missing, or supplier does not exist.
|
* @throws {Error} If user is not authorized, entityId is missing, or supplier does not exist.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
@@ -93,9 +93,8 @@ export default function listByEntityAndSkus(provider) {
|
|||||||
pu: row.pu,
|
pu: row.pu,
|
||||||
stock: row.stock ?? null,
|
stock: row.stock ?? null,
|
||||||
sort: row.sort,
|
sort: row.sort,
|
||||||
priceId: row.priceId ?? null,
|
|
||||||
price:
|
price:
|
||||||
row.priceId != null && row.priceNet != null
|
row.priceNet != null
|
||||||
? {
|
? {
|
||||||
net: row.priceNet,
|
net: row.priceNet,
|
||||||
taxId: row.priceTaxId,
|
taxId: row.priceTaxId,
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
import * as mssqlQueries from '../../providers/mssql/queries/articlesupplier.js';
|
import * as mssqlQueries from '../../providers/mssql/queries/articlesupplier.js';
|
||||||
import * as sqliteQueries from '../../providers/sqlite3/queries/articlesupplier.js';
|
import * as sqliteQueries from '../../providers/sqlite3/queries/articlesupplier.js';
|
||||||
import { CREATE as MSSQL_CREATE_PRICE } from '../../providers/mssql/queries/price.js';
|
|
||||||
import { CREATE as SQLITE_CREATE_PRICE } from '../../providers/sqlite3/queries/price.js';
|
|
||||||
import { INSERT as MSSQL_INSERT_HISTORY } from '../../providers/mssql/queries/articlehistory.js';
|
import { INSERT as MSSQL_INSERT_HISTORY } from '../../providers/mssql/queries/articlehistory.js';
|
||||||
import { INSERT as SQLITE_INSERT_HISTORY } from '../../providers/sqlite3/queries/articlehistory.js';
|
import { INSERT as SQLITE_INSERT_HISTORY } from '../../providers/sqlite3/queries/articlehistory.js';
|
||||||
import resolveArticleBySku from '../article/resolveArticleBySku.js';
|
import resolveArticleBySku from '../article/resolveArticleBySku.js';
|
||||||
import ensureLieferantenGroup from '../supplier/ensureLieferantenGroup.js';
|
|
||||||
import taxEnsure from '../tax/ensure.js';
|
import taxEnsure from '../tax/ensure.js';
|
||||||
import {
|
import {
|
||||||
optionalString,
|
optionalString,
|
||||||
@@ -20,7 +17,6 @@ export default function update(provider) {
|
|||||||
const isSqlite = provider?.dialect === 'sqlite3';
|
const isSqlite = provider?.dialect === 'sqlite3';
|
||||||
|
|
||||||
const queries = isSqlite ? sqliteQueries : mssqlQueries;
|
const queries = isSqlite ? sqliteQueries : mssqlQueries;
|
||||||
const createPriceSql = isSqlite ? SQLITE_CREATE_PRICE : MSSQL_CREATE_PRICE;
|
|
||||||
const insertHistorySql = isSqlite ? SQLITE_INSERT_HISTORY : MSSQL_INSERT_HISTORY;
|
const insertHistorySql = isSqlite ? SQLITE_INSERT_HISTORY : MSSQL_INSERT_HISTORY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,7 +34,7 @@ export default function update(provider) {
|
|||||||
* @param {number} [patch.taxId] - The tax id for the purchase price.
|
* @param {number} [patch.taxId] - The tax id for the purchase price.
|
||||||
* @param {number} [patch.taxRate] - The tax rate in percent.
|
* @param {number} [patch.taxRate] - The tax rate in percent.
|
||||||
* @param {object} [tx] - Optional transaction to run within.
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
* @returns {Promise<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null}>} The updated assignment.
|
* @returns {Promise<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, sort: number, price: {net: number, taxId: number, taxRate?: number}|null}>} The updated assignment.
|
||||||
* @throws {Error} If input is invalid or supplier assignment is not found.
|
* @throws {Error} If input is invalid or supplier assignment is not found.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
@@ -47,7 +43,7 @@ export default function update(provider) {
|
|||||||
* pu: 6,
|
* pu: 6,
|
||||||
* netPrice: 22.50,
|
* netPrice: 22.50,
|
||||||
* });
|
* });
|
||||||
* // => { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price }
|
* // => { id, articleId, entityId, supplierName, sku, pu, stock, sort, price }
|
||||||
*/
|
*/
|
||||||
return async (googleAuthId, sku, id, patch = {}, tx) => {
|
return async (googleAuthId, sku, id, patch = {}, tx) => {
|
||||||
if (id == null || !Number.isFinite(id)) {
|
if (id == null || !Number.isFinite(id)) {
|
||||||
@@ -96,49 +92,16 @@ export default function update(provider) {
|
|||||||
throw new Error('Supplier assignment not found');
|
throw new Error('Supplier assignment not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
let priceId = existing.priceId;
|
let nextNet = existing.priceNet;
|
||||||
|
let nextTaxId = existing.priceTaxId;
|
||||||
|
|
||||||
if (patch.netPrice !== undefined) {
|
if (patch.netPrice !== undefined) {
|
||||||
if (patch.netPrice === null) {
|
if (patch.netPrice === null) {
|
||||||
if (priceId != null) {
|
nextNet = null;
|
||||||
const oldPriceId = priceId;
|
nextTaxId = null;
|
||||||
priceId = null;
|
|
||||||
|
|
||||||
await runner.query(queries.UPDATE, {
|
|
||||||
id,
|
|
||||||
articleId,
|
|
||||||
sku: existing.sku,
|
|
||||||
stock: existing.stock,
|
|
||||||
pu: existing.pu,
|
|
||||||
sort: existing.sort,
|
|
||||||
priceId: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
await runner.query(queries.DELETE_PRICE, {
|
|
||||||
id: oldPriceId,
|
|
||||||
articleId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// netPrice is a valid number
|
nextNet = patch.netPrice;
|
||||||
if (priceId != null) {
|
if (patch.taxId !== undefined || patch.taxRate !== undefined) {
|
||||||
let taxId = patch.taxId;
|
|
||||||
if (taxId == null || !Number.isFinite(taxId)) {
|
|
||||||
if (patch.taxRate != null && Number.isFinite(patch.taxRate)) {
|
|
||||||
taxId = await ensureTax(patch.taxRate, runner);
|
|
||||||
} else {
|
|
||||||
taxId = existing.priceTaxId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await runner.query(queries.UPDATE_PRICE, {
|
|
||||||
id: priceId,
|
|
||||||
articleId,
|
|
||||||
net: patch.netPrice,
|
|
||||||
taxId,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// create new price row
|
|
||||||
let taxId = patch.taxId;
|
let taxId = patch.taxId;
|
||||||
if (taxId == null || !Number.isFinite(taxId)) {
|
if (taxId == null || !Number.isFinite(taxId)) {
|
||||||
if (patch.taxRate != null && Number.isFinite(patch.taxRate)) {
|
if (patch.taxRate != null && Number.isFinite(patch.taxRate)) {
|
||||||
@@ -151,24 +114,16 @@ export default function update(provider) {
|
|||||||
taxId = defaultTaxId != null ? defaultTaxId : await ensureTax(0, runner);
|
taxId = defaultTaxId != null ? defaultTaxId : await ensureTax(0, runner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
nextTaxId = taxId;
|
||||||
const customerGroupId = await ensureLieferantenGroup(
|
} else if (nextTaxId == null) {
|
||||||
|
const defaultTaxId = await resolveCompanyDefaultTax(
|
||||||
runner,
|
runner,
|
||||||
companyId,
|
companyId,
|
||||||
);
|
);
|
||||||
|
nextTaxId = defaultTaxId != null ? defaultTaxId : await ensureTax(0, runner);
|
||||||
const priceRes = await runner.query(createPriceSql, {
|
|
||||||
taxId,
|
|
||||||
articleId,
|
|
||||||
minmultiplier: 1,
|
|
||||||
customerGroupId,
|
|
||||||
net: patch.netPrice,
|
|
||||||
});
|
|
||||||
|
|
||||||
priceId = priceRes.rows[0]?.id ?? priceRes.insertId;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (priceId != null && (patch.taxId !== undefined || patch.taxRate !== undefined)) {
|
} else if (nextNet != null && (patch.taxId !== undefined || patch.taxRate !== undefined)) {
|
||||||
let taxId = patch.taxId;
|
let taxId = patch.taxId;
|
||||||
if (taxId == null || !Number.isFinite(taxId)) {
|
if (taxId == null || !Number.isFinite(taxId)) {
|
||||||
if (patch.taxRate != null && Number.isFinite(patch.taxRate)) {
|
if (patch.taxRate != null && Number.isFinite(patch.taxRate)) {
|
||||||
@@ -177,13 +132,7 @@ export default function update(provider) {
|
|||||||
taxId = existing.priceTaxId;
|
taxId = existing.priceTaxId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
nextTaxId = taxId;
|
||||||
await runner.query(queries.UPDATE_PRICE, {
|
|
||||||
id: priceId,
|
|
||||||
articleId,
|
|
||||||
net: existing.priceNet,
|
|
||||||
taxId,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextSku =
|
const nextSku =
|
||||||
@@ -204,7 +153,8 @@ export default function update(provider) {
|
|||||||
stock: nextStock,
|
stock: nextStock,
|
||||||
pu: nextPu,
|
pu: nextPu,
|
||||||
sort: nextSort,
|
sort: nextSort,
|
||||||
priceId,
|
net: nextNet,
|
||||||
|
taxId: nextTaxId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const supplierName =
|
const supplierName =
|
||||||
@@ -239,7 +189,7 @@ export default function update(provider) {
|
|||||||
|
|
||||||
if (patch.netPrice !== undefined) {
|
if (patch.netPrice !== undefined) {
|
||||||
if (patch.netPrice === null) {
|
if (patch.netPrice === null) {
|
||||||
if (existing.priceId != null && existing.priceNet != null) {
|
if (existing.priceNet != null) {
|
||||||
historyLines.push(
|
historyLines.push(
|
||||||
`Lieferant "${supplierName}": Einkaufspreis geändert von "${existing.priceNet}" auf ""`,
|
`Lieferant "${supplierName}": Einkaufspreis geändert von "${existing.priceNet}" auf ""`,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -40,33 +40,43 @@ export default function addImage(provider) {
|
|||||||
await runner.query(deleteBrandPicSql, { brandId });
|
await runner.query(deleteBrandPicSql, { brandId });
|
||||||
|
|
||||||
const sort = 0;
|
const sort = 0;
|
||||||
const fullHash = newFullHash();
|
const fullHash = newFullHash(processed.full.buffer);
|
||||||
|
|
||||||
if (isSqlite) {
|
let picId;
|
||||||
if (runner.writePicFull) {
|
const existingPic = await runner.query(
|
||||||
await runner.writePicFull(fullHash, processed.full.buffer);
|
'SELECT id FROM pic WHERE hash = @fullHash',
|
||||||
await runner.writePicThumb(fullHash, processed.thumb.buffer);
|
{ fullHash },
|
||||||
} else if (provider?.writePicFull) {
|
);
|
||||||
await provider.writePicFull(fullHash, processed.full.buffer);
|
|
||||||
await provider.writePicThumb(fullHash, processed.thumb.buffer);
|
if (existingPic.rows[0]) {
|
||||||
|
picId = existingPic.rows[0].id;
|
||||||
|
} else {
|
||||||
|
if (isSqlite) {
|
||||||
|
if (runner.writePicFull) {
|
||||||
|
await runner.writePicFull(fullHash, processed.full.buffer);
|
||||||
|
await runner.writePicThumb(fullHash, processed.thumb.buffer);
|
||||||
|
} else if (provider?.writePicFull) {
|
||||||
|
await provider.writePicFull(fullHash, processed.full.buffer);
|
||||||
|
await provider.writePicThumb(fullHash, processed.thumb.buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const picResult = await runner.query(createPicSql, {
|
||||||
|
w: processed.full.w,
|
||||||
|
h: processed.full.h,
|
||||||
|
size: processed.full.size,
|
||||||
|
hash: fullHash,
|
||||||
|
thumbw: processed.thumb.w,
|
||||||
|
thumbh: processed.thumb.h,
|
||||||
|
thumbhash: processed.thumb.hash,
|
||||||
|
source: '',
|
||||||
|
fullbinary: processed.full.buffer,
|
||||||
|
thumbbinary: processed.thumb.buffer,
|
||||||
|
});
|
||||||
|
|
||||||
|
picId = picResult.rows[0]?.id ?? picResult.insertId;
|
||||||
}
|
}
|
||||||
|
|
||||||
const picResult = await runner.query(createPicSql, {
|
|
||||||
w: processed.full.w,
|
|
||||||
h: processed.full.h,
|
|
||||||
size: processed.full.size,
|
|
||||||
hash: fullHash,
|
|
||||||
thumbw: processed.thumb.w,
|
|
||||||
thumbh: processed.thumb.h,
|
|
||||||
thumbhash: processed.thumb.hash,
|
|
||||||
source: '',
|
|
||||||
fullbinary: processed.full.buffer,
|
|
||||||
thumbbinary: processed.thumb.buffer,
|
|
||||||
});
|
|
||||||
|
|
||||||
const picId = picResult.rows[0]?.id ?? picResult.insertId;
|
|
||||||
|
|
||||||
const brandPicResult = await runner.query(addBrandPicSql, {
|
const brandPicResult = await runner.query(addBrandPicSql, {
|
||||||
brandId,
|
brandId,
|
||||||
picId,
|
picId,
|
||||||
|
|||||||
@@ -42,38 +42,55 @@ export default function addImage(provider) {
|
|||||||
|
|
||||||
const sortResult = await runner.query(getSortSql, { categoryId });
|
const sortResult = await runner.query(getSortSql, { categoryId });
|
||||||
const sort = sortResult.rows[0].sort;
|
const sort = sortResult.rows[0].sort;
|
||||||
const fullHash = newFullHash();
|
const fullHash = newFullHash(processed.full.buffer);
|
||||||
|
|
||||||
if (isSqlite) {
|
let picId;
|
||||||
if (runner.writePicFull) {
|
const existingPic = await runner.query(
|
||||||
await runner.writePicFull(fullHash, processed.full.buffer);
|
'SELECT id FROM pic WHERE hash = @fullHash',
|
||||||
await runner.writePicThumb(fullHash, processed.thumb.buffer);
|
{ fullHash },
|
||||||
} else if (provider?.writePicFull) {
|
);
|
||||||
await provider.writePicFull(fullHash, processed.full.buffer);
|
|
||||||
await provider.writePicThumb(fullHash, processed.thumb.buffer);
|
if (existingPic.rows[0]) {
|
||||||
|
picId = existingPic.rows[0].id;
|
||||||
|
} else {
|
||||||
|
if (isSqlite) {
|
||||||
|
if (runner.writePicFull) {
|
||||||
|
await runner.writePicFull(fullHash, processed.full.buffer);
|
||||||
|
await runner.writePicThumb(fullHash, processed.thumb.buffer);
|
||||||
|
} else if (provider?.writePicFull) {
|
||||||
|
await provider.writePicFull(fullHash, processed.full.buffer);
|
||||||
|
await provider.writePicThumb(fullHash, processed.thumb.buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const picResult = await runner.query(createPicSql, {
|
||||||
|
w: processed.full.w,
|
||||||
|
h: processed.full.h,
|
||||||
|
size: processed.full.size,
|
||||||
|
hash: fullHash,
|
||||||
|
thumbw: processed.thumb.w,
|
||||||
|
thumbh: processed.thumb.h,
|
||||||
|
thumbhash: processed.thumb.hash,
|
||||||
|
source: '',
|
||||||
|
fullbinary: processed.full.buffer,
|
||||||
|
thumbbinary: processed.thumb.buffer,
|
||||||
|
});
|
||||||
|
|
||||||
|
picId = picResult.rows[0]?.id ?? picResult.insertId;
|
||||||
}
|
}
|
||||||
|
|
||||||
const picResult = await runner.query(createPicSql, {
|
const existingCategoryPic = await runner.query(
|
||||||
w: processed.full.w,
|
'SELECT id, sort FROM categorypic WHERE category_id = @categoryId AND pic_id = @picId',
|
||||||
h: processed.full.h,
|
{ categoryId, picId },
|
||||||
size: processed.full.size,
|
);
|
||||||
hash: fullHash,
|
|
||||||
thumbw: processed.thumb.w,
|
|
||||||
thumbh: processed.thumb.h,
|
|
||||||
thumbhash: processed.thumb.hash,
|
|
||||||
source: '',
|
|
||||||
fullbinary: processed.full.buffer,
|
|
||||||
thumbbinary: processed.thumb.buffer,
|
|
||||||
});
|
|
||||||
|
|
||||||
const picId = picResult.rows[0]?.id ?? picResult.insertId;
|
if (!existingCategoryPic.rows[0]) {
|
||||||
|
await runner.query(addCategoryPicSql, {
|
||||||
await runner.query(addCategoryPicSql, {
|
categoryId,
|
||||||
categoryId,
|
picId,
|
||||||
picId,
|
sort,
|
||||||
sort,
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: categoryId,
|
id: categoryId,
|
||||||
|
|||||||
@@ -1,5 +1,24 @@
|
|||||||
import { randomBytes } from 'node:crypto';
|
import { createHash, randomBytes } from 'node:crypto';
|
||||||
|
|
||||||
export default function newFullHash() {
|
const CHARSET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
return randomBytes(32).toString('hex');
|
|
||||||
|
export function toBase62(buffer) {
|
||||||
|
let num = BigInt('0x' + buffer.toString('hex'));
|
||||||
|
if (num === 0n) return CHARSET[0].repeat(8);
|
||||||
|
let res = '';
|
||||||
|
while (num > 0n) {
|
||||||
|
res = CHARSET[Number(num % 62n)] + res;
|
||||||
|
num /= 62n;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function newFullHash(buffer) {
|
||||||
|
if (buffer) {
|
||||||
|
const digest = createHash('sha256').update(buffer).digest();
|
||||||
|
return toBase62(digest).slice(0, 8);
|
||||||
|
}
|
||||||
|
const bytes = randomBytes(16);
|
||||||
|
return toBase62(bytes).slice(0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user