This commit is contained in:
seb
2026-10-07 16:46:41 +02:00
parent 95ef6f2dd1
commit e02bbd65c5
18 changed files with 78 additions and 176 deletions

View File

@@ -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**

View File

@@ -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 }
``` ```

12
API.md
View File

@@ -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}>>`
@@ -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)

View File

@@ -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` |

View File

@@ -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)'],

View File

@@ -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

View File

@@ -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 (

View File

@@ -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)
); );

View File

@@ -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(

View File

@@ -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 (

View File

@@ -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);

View File

@@ -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,

View File

@@ -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,

View File

@@ -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');

View File

@@ -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,

View File

@@ -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);

View File

@@ -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,

View File

@@ -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 ""`,
); );