diff --git a/API.article.md b/API.article.md index c360cb7..c86ab17 100644 --- a/API.article.md +++ b/API.article.md @@ -184,7 +184,7 @@ Returns the full detail of an article by its SKU, including unit, brand, categor **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** diff --git a/API.articlesupplier.md b/API.articlesupplier.md index 0a28f51..1e01cc6 100644 --- a/API.articlesupplier.md +++ b/API.articlesupplier.md @@ -27,7 +27,7 @@ Assigns a supplier to an article, optionally creating a purchase price. **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** @@ -42,7 +42,7 @@ const created = await store.articlesupplier.create(42, 'SKU-1', { pu: 1, netPrice: 4.20, }); -// => { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price } +// => { id, articleId, entityId, supplierName, sku, pu, stock, sort, price } ``` ## `articlesupplier.delete` @@ -90,7 +90,7 @@ Lists the supplier assignments for an article by its SKU. **Returns** -`Promise>` — The supplier assignments. +`Promise>` — The supplier assignments. **Throws** @@ -100,7 +100,7 @@ Lists the supplier assignments for an article by its SKU. ```js 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` @@ -120,7 +120,7 @@ Lists article-supplier assignments for a given supplier (entityId) and SKU list, **Returns** -`Promise, eans: string[]}}>>` — The supplier assignments with article details. +`Promise, eans: string[]}}>>` — The supplier assignments with article details. **Throws** @@ -189,7 +189,7 @@ Updates an existing supplier assignment and its associated purchase price. **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** @@ -203,5 +203,5 @@ const updated = await store.articlesupplier.update(42, 'SKU-1', 12, { pu: 6, netPrice: 22.50, }); -// => { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price } +// => { id, articleId, entityId, supplierName, sku, pu, stock, sort, price } ``` diff --git a/API.md b/API.md index 90650e5..28ff6f5 100644 --- a/API.md +++ b/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)` - **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` -- **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)` - **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)` @@ -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}>` - `delete(googleAuthId: number, sku: string, optionsOrTx?: object|*, maybeTx?: object): Promise` - `deleteImage(googleAuthId: number, sku: string, fullHash: string, tx?: object): Promise` - - `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>` - `importRows(input: {googleAuthId: number, rows: Array}, tx?: object): Promise<{imported: Array, skipped: Array, errors: Array}>` - `listChildren(googleAuthId: number, parentSku: string, tx?: object): Promise>` @@ -164,12 +164,12 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met - `list(googleAuthId: number, tx?: object): Promise>` - `update(googleAuthId: number, id: number, input: {name: string}, tx?: object): Promise<{id: number, name: string, createdAt: string, updatedAt: string}>` - [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` - - `listByArticleSku(googleAuthId: number, sku: string, tx?: object): Promise>` - - `listByEntityAndSkus(googleAuthId: number, entityIdOrOptions: number|{entityId?: number, supplierId?: number, skus?: string[]|string}, maybeSkus?: string[]|string, tx?: object): Promise, eans: string[]}}>>` + - `listByArticleSku(googleAuthId: number, sku: string, tx?: object): Promise>` + - `listByEntityAndSkus(googleAuthId: number, entityIdOrOptions: number|{entityId?: number, supplierId?: number, skus?: string[]|string}, maybeSkus?: string[]|string, tx?: object): Promise, eans: string[]}}>>` - `order(googleAuthId: number, sku: string, input: {ids: Array}, tx?: object): Promise<{ids: Array}>` - - `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) - `attachments(): void` - [quote](API.quote.md) diff --git a/README.md b/README.md index 2158b09..273fda6 100644 --- a/README.md +++ b/README.md @@ -296,7 +296,8 @@ Maps articles to suppliers (`entity`) with purchase pricing, stock, packaging un | `id` | `INT` | Primary Key (`IDENTITY(1,1)`) | | `article_id` | `INT` | FK → `article(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 | | `stock` | `FLOAT` | Stock available at supplier, nullable | | `pu` | `FLOAT` | Packaging unit (Verpackungseinheit), default `1` | diff --git a/generate-api-doc.js b/generate-api-doc.js index 9367493..51afd59 100644 --- a/generate-api-doc.js +++ b/generate-api-doc.js @@ -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)'], ['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'], - ['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)'], ['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)'], diff --git a/src/providers/mssql/queries/article.js b/src/providers/mssql/queries/article.js index b50ef18..17b4e55 100644 --- a/src/providers/mssql/queries/article.js +++ b/src/providers/mssql/queries/article.js @@ -562,14 +562,12 @@ SELECT asup.pu, asup.stock, asup.sort, - asup.price_id AS priceId, - p.net AS [price.net], - p.tax_id AS [price.taxId], + asup.net AS [price.net], + asup.tax_id AS [price.taxId], t.rate AS [price.taxRate] FROM articlesupplier asup 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 = p.tax_id + LEFT JOIN tax t ON t.id = asup.tax_id WHERE asup.article_id = a.id ORDER BY asup.sort ASC, asup.id ASC FOR JSON PATH diff --git a/src/providers/mssql/queries/articlesupplier.js b/src/providers/mssql/queries/articlesupplier.js index ee7c304..2a833ca 100644 --- a/src/providers/mssql/queries/articlesupplier.js +++ b/src/providers/mssql/queries/articlesupplier.js @@ -8,15 +8,13 @@ SELECT 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 FROM articlesupplier asup INNER JOIN entity e ON e.id = asup.entity_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 = p.tax_id +LEFT JOIN tax t ON t.id = asup.tax_id WHERE asup.article_id = @articleId AND cg.company_id = @companyId ORDER BY asup.sort ASC, asup.id ASC; @@ -32,15 +30,13 @@ SELECT 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 FROM articlesupplier asup INNER JOIN entity e ON e.id = asup.entity_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 = p.tax_id +LEFT JOIN tax t ON t.id = asup.tax_id WHERE asup.id = @id AND asup.article_id = @articleId AND cg.company_id = @companyId; @@ -59,9 +55,9 @@ WHERE article_id = @articleId; `; 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 -VALUES (@articleId, @entityId, @priceId, @sku, @stock, @pu, @sort); +VALUES (@articleId, @entityId, @net, @taxId, @sku, @stock, @pu, @sort); `; export const UPDATE = ` @@ -70,7 +66,8 @@ SET sku = @sku, stock = @stock, pu = @pu, - price_id = @priceId, + net = @net, + tax_id = @taxId, sort = @sort WHERE id = @id AND article_id = @articleId; `; @@ -99,19 +96,6 @@ SET sort = @sort 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 = ` SELECT taxrate FROM company @@ -128,9 +112,8 @@ SELECT 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, @@ -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 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 price p ON p.id = asup.price_id -LEFT JOIN tax t ON t.id = p.tax_id +LEFT JOIN tax t ON t.id = asup.tax_id WHERE asup.entity_id = @entityId AND cg.company_id = @companyId AND ( diff --git a/src/providers/mssql/schema.js b/src/providers/mssql/schema.js index feed3cc..ae7e1ae 100644 --- a/src/providers/mssql/schema.js +++ b/src/providers/mssql/schema.js @@ -590,14 +590,15 @@ BEGIN id INT IDENTITY(1,1) PRIMARY KEY, article_id INT NOT NULL, entity_id INT NOT NULL, - price_id INT NULL, + net FLOAT NULL, + tax_id INT NULL, sku NVARCHAR(100) NULL, stock FLOAT NULL, pu FLOAT NOT NULL CONSTRAINT DF_articlesupplier_pu DEFAULT 1, 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_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_sort UNIQUE (article_id, sort) ); diff --git a/src/providers/sqlite3/queries/article.js b/src/providers/sqlite3/queries/article.js index 6f0ecfc..f05c2f3 100644 --- a/src/providers/sqlite3/queries/article.js +++ b/src/providers/sqlite3/queries/article.js @@ -203,17 +203,16 @@ SELECT auth.*, 'suppliersJson', json((SELECT COALESCE(json_group_array(json_object( 'id', id, 'articleId', article_id, 'entityId', entity_id, 'supplierName', supplier_name, 'sku', sku, 'pu', pu, - 'stock', stock, 'sort', sort, 'priceId', price_id, - 'price', CASE WHEN price_id IS NULL THEN NULL ELSE json_object( + 'stock', stock, 'sort', sort, + 'price', CASE WHEN net IS NULL THEN NULL ELSE json_object( 'net', net, 'taxId', tax_id, 'taxRate', tax_rate ) END )), '[]') FROM ( 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, - pr.net, pr.tax_id, t.rate AS tax_rate + s.sku, s.pu, s.stock, s.sort, + s.net, s.tax_id, t.rate AS tax_rate 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 = pr.tax_id + LEFT JOIN tax t ON t.id = s.tax_id WHERE s.article_id = a.id ORDER BY s.sort, s.id ))), 'warehousesJson', json((SELECT COALESCE(json_group_array(json_object( diff --git a/src/providers/sqlite3/queries/articlesupplier.js b/src/providers/sqlite3/queries/articlesupplier.js index 40e6891..9b6f163 100644 --- a/src/providers/sqlite3/queries/articlesupplier.js +++ b/src/providers/sqlite3/queries/articlesupplier.js @@ -3,17 +3,17 @@ import { translateQueries } from './translate.js'; const queries = translateQueries(source, 'articlesupplier'); 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, LIST_BY_ARTICLE_ID, LIST_IDS_BY_ARTICLE, - SET_TEMP_SORTS, UPDATE, UPDATE_PRICE, UPDATE_SORT, + SET_TEMP_SORTS, UPDATE, UPDATE_SORT, } = queries; export const LIST_BY_ENTITY_AND_SKUS = ` SELECT asup.id, asup.article_id AS articleId, asup.entity_id AS entityId, 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, at.name AS a_name, at.slug AS a_slug, (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 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 price p ON p.id = asup.price_id -LEFT JOIN tax t ON t.id = p.tax_id +LEFT JOIN tax t ON t.id = asup.tax_id WHERE asup.entity_id = @entityId AND cg.company_id = @companyId AND ( diff --git a/src/providers/sqlite3/schema.js b/src/providers/sqlite3/schema.js index 10251e1..5cfb7c8 100644 --- a/src/providers/sqlite3/schema.js +++ b/src/providers/sqlite3/schema.js @@ -385,7 +385,8 @@ CREATE TABLE IF NOT EXISTS articlesupplier ( id INTEGER PRIMARY KEY, article_id INTEGER NOT NULL, entity_id INTEGER NOT NULL, - price_id INTEGER, + net REAL, + tax_id INTEGER, sku TEXT, stock REAL, pu REAL NOT NULL DEFAULT 1, @@ -394,7 +395,7 @@ CREATE TABLE IF NOT EXISTS articlesupplier ( UNIQUE (article_id, sort), FOREIGN KEY (article_id) REFERENCES article(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 ON articlesupplier(article_id, entity_id); diff --git a/src/store/article/getBySku.js b/src/store/article/getBySku.js index 6df5bd8..9511624 100644 --- a/src/store/article/getBySku.js +++ b/src/store/article/getBySku.js @@ -18,7 +18,7 @@ export default function getBySku(provider) { * @param {number} googleAuthId - The id of the Google auth user. * @param {string} sku - The article SKU. * @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. * * @example @@ -87,8 +87,7 @@ export default function getBySku(provider) { pu: s.pu, stock: s.stock ?? null, sort: s.sort, - priceId: s.priceId ?? null, - price: s.priceId != null && s.price?.net != null ? s.price : null, + price: s.price?.net != null ? s.price : null, })), warehouses: parseJsonArray(a.warehousesJson).map((w) => ({ id: w.id, diff --git a/src/store/articlesupplier/create.js b/src/store/articlesupplier/create.js index dfd0e2d..968dd82 100644 --- a/src/store/articlesupplier/create.js +++ b/src/store/articlesupplier/create.js @@ -1,11 +1,8 @@ import * as mssqlQueries from '../../providers/mssql/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 SQLITE_INSERT_HISTORY } from '../../providers/sqlite3/queries/articlehistory.js'; import resolveArticleBySku from '../article/resolveArticleBySku.js'; -import ensureLieferantenGroup from '../supplier/ensureLieferantenGroup.js'; import taxEnsure from '../tax/ensure.js'; import { assertSupplier, @@ -21,7 +18,6 @@ export default function create(provider) { const isSqlite = provider?.dialect === 'sqlite3'; const queries = isSqlite ? sqliteQueries : mssqlQueries; - const createPriceSql = isSqlite ? SQLITE_CREATE_PRICE : MSSQL_CREATE_PRICE; 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.taxRate] - The tax rate in percent (used if taxId is not provided). * @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. * * @example @@ -49,7 +45,7 @@ export default function create(provider) { * pu: 1, * 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) => { const entityId = input.entityId; @@ -115,10 +111,9 @@ export default function create(provider) { sort = sortRes.rows[0].sort; } - let priceId = null; - + let taxId = null; if (netPrice !== null) { - let taxId = input.taxId; + taxId = input.taxId; if (taxId == null || !Number.isFinite(taxId)) { if (input.taxRate != null && Number.isFinite(input.taxRate)) { taxId = await ensureTax(input.taxRate, runner); @@ -130,27 +125,13 @@ export default function create(provider) { 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, { articleId, entityId, - priceId, + net: netPrice, + taxId, sku: supplierSku, stock, pu, diff --git a/src/store/articlesupplier/delete.js b/src/store/articlesupplier/delete.js index 2429106..c161c86 100644 --- a/src/store/articlesupplier/delete.js +++ b/src/store/articlesupplier/delete.js @@ -52,13 +52,6 @@ export default function del(provider) { articleId, }); - if (existing.priceId != null) { - await runner.query(queries.DELETE_PRICE, { - id: existing.priceId, - articleId, - }); - } - const supplierName = existing.supplierName ?? (existing.entityId ? `Lieferant #${existing.entityId}` : 'Lieferant'); diff --git a/src/store/articlesupplier/helpers.js b/src/store/articlesupplier/helpers.js index 58c022a..efb2d0a 100644 --- a/src/store/articlesupplier/helpers.js +++ b/src/store/articlesupplier/helpers.js @@ -26,9 +26,8 @@ export function shapeArticleSupplier(row) { pu: row.pu, stock: row.stock ?? null, sort: row.sort, - priceId: row.priceId ?? null, price: - row.priceId != null && row.priceNet != null + row.priceNet != null ? { net: row.priceNet, taxId: row.priceTaxId, diff --git a/src/store/articlesupplier/listByArticleSku.js b/src/store/articlesupplier/listByArticleSku.js index 3065ec8..2d55827 100644 --- a/src/store/articlesupplier/listByArticleSku.js +++ b/src/store/articlesupplier/listByArticleSku.js @@ -14,12 +14,12 @@ export default function listByArticleSku(provider) { * @param {number} googleAuthId - The id of the Google auth user. * @param {string} sku - The article SKU. * @param {object} [tx] - Optional transaction. - * @returns {Promise>} The supplier assignments. + * @returns {Promise>} The supplier assignments. * @throws {Error} If the article is not found or the user is not authorized. * * @example * 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) => { const runner = makeRunner(provider, tx); diff --git a/src/store/articlesupplier/listByEntityAndSkus.js b/src/store/articlesupplier/listByEntityAndSkus.js index b716914..dcc245a 100644 --- a/src/store/articlesupplier/listByEntityAndSkus.js +++ b/src/store/articlesupplier/listByEntityAndSkus.js @@ -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 {string[]|string} [maybeSkus] - The list of SKUs to filter by (or single SKU string). * @param {object} [tx] - Optional transaction. - * @returns {Promise, eans: string[]}}>>} The supplier assignments with article details. + * @returns {Promise, eans: string[]}}>>} The supplier assignments with article details. * @throws {Error} If user is not authorized, entityId is missing, or supplier does not exist. * * @example @@ -93,9 +93,8 @@ export default function listByEntityAndSkus(provider) { pu: row.pu, stock: row.stock ?? null, sort: row.sort, - priceId: row.priceId ?? null, price: - row.priceId != null && row.priceNet != null + row.priceNet != null ? { net: row.priceNet, taxId: row.priceTaxId, diff --git a/src/store/articlesupplier/update.js b/src/store/articlesupplier/update.js index 7775b88..f610ee2 100644 --- a/src/store/articlesupplier/update.js +++ b/src/store/articlesupplier/update.js @@ -1,11 +1,8 @@ import * as mssqlQueries from '../../providers/mssql/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 SQLITE_INSERT_HISTORY } from '../../providers/sqlite3/queries/articlehistory.js'; import resolveArticleBySku from '../article/resolveArticleBySku.js'; -import ensureLieferantenGroup from '../supplier/ensureLieferantenGroup.js'; import taxEnsure from '../tax/ensure.js'; import { optionalString, @@ -20,7 +17,6 @@ export default function update(provider) { const isSqlite = provider?.dialect === 'sqlite3'; const queries = isSqlite ? sqliteQueries : mssqlQueries; - const createPriceSql = isSqlite ? SQLITE_CREATE_PRICE : MSSQL_CREATE_PRICE; 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.taxRate] - The tax rate in percent. * @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. * * @example @@ -47,7 +43,7 @@ export default function update(provider) { * pu: 6, * 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) => { if (id == null || !Number.isFinite(id)) { @@ -96,49 +92,16 @@ export default function update(provider) { 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 === null) { - if (priceId != null) { - const oldPriceId = priceId; - 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, - }); - } + nextNet = null; + nextTaxId = null; } else { - // netPrice is a valid number - if (priceId != null) { - 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 + nextNet = patch.netPrice; + 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)) { @@ -151,24 +114,16 @@ export default function update(provider) { taxId = defaultTaxId != null ? defaultTaxId : await ensureTax(0, runner); } } - - const customerGroupId = await ensureLieferantenGroup( + nextTaxId = taxId; + } else if (nextTaxId == null) { + const defaultTaxId = await resolveCompanyDefaultTax( runner, companyId, ); - - const priceRes = await runner.query(createPriceSql, { - taxId, - articleId, - minmultiplier: 1, - customerGroupId, - net: patch.netPrice, - }); - - priceId = priceRes.rows[0]?.id ?? priceRes.insertId; + nextTaxId = defaultTaxId != null ? defaultTaxId : await ensureTax(0, runner); } } - } else if (priceId != null && (patch.taxId !== undefined || patch.taxRate !== undefined)) { + } else if (nextNet != null && (patch.taxId !== undefined || patch.taxRate !== undefined)) { let taxId = patch.taxId; if (taxId == null || !Number.isFinite(taxId)) { if (patch.taxRate != null && Number.isFinite(patch.taxRate)) { @@ -177,13 +132,7 @@ export default function update(provider) { taxId = existing.priceTaxId; } } - - await runner.query(queries.UPDATE_PRICE, { - id: priceId, - articleId, - net: existing.priceNet, - taxId, - }); + nextTaxId = taxId; } const nextSku = @@ -204,7 +153,8 @@ export default function update(provider) { stock: nextStock, pu: nextPu, sort: nextSort, - priceId, + net: nextNet, + taxId: nextTaxId, }); const supplierName = @@ -239,7 +189,7 @@ export default function update(provider) { if (patch.netPrice !== undefined) { if (patch.netPrice === null) { - if (existing.priceId != null && existing.priceNet != null) { + if (existing.priceNet != null) { historyLines.push( `Lieferant "${supplierName}": Einkaufspreis geändert von "${existing.priceNet}" auf ""`, );