u
This commit is contained in:
@@ -228,6 +228,16 @@ SET updated_at = SYSUTCDATETIME()
|
||||
WHERE id = @articleId
|
||||
`;
|
||||
|
||||
export const TOUCH_OPTION_PARENT_ARTICLES_UPDATED_AT = `
|
||||
UPDATE article
|
||||
SET updated_at = SYSUTCDATETIME()
|
||||
WHERE optionslist_id IN (
|
||||
SELECT ola.optionslist_id
|
||||
FROM optionslistarticle ola
|
||||
WHERE ola.article_id = @articleId
|
||||
)
|
||||
`;
|
||||
|
||||
export const CREATE = `
|
||||
INSERT INTO article (company_id, sku, unit_id, unitamount, weight, track_stock)
|
||||
OUTPUT INSERTED.id
|
||||
|
||||
@@ -483,6 +483,25 @@ WHERE pr.minmultiplier = 1
|
||||
GROUP BY pr.article_id, pr.customergroup_id
|
||||
`;
|
||||
|
||||
export const LIST_POS_MANDATED_OPTIONS = `
|
||||
SELECT
|
||||
a.id AS articleId,
|
||||
ola.count,
|
||||
COALESCE(opt_at.name, opt_a.sku) AS depositName,
|
||||
opt_pr.net AS depositNetPrice,
|
||||
COALESCE(opt_ptax.rate, opt_ctax.rate, 0) AS depositTaxRate
|
||||
FROM article a
|
||||
INNER JOIN optionslistarticle ola ON ola.optionslist_id = a.optionslist_id AND ola.mandated = 1
|
||||
INNER JOIN article opt_a ON opt_a.id = ola.article_id
|
||||
INNER JOIN company co ON co.id = a.company_id
|
||||
INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = a.company_id
|
||||
LEFT JOIN articletext opt_at ON opt_at.article_id = opt_a.id AND opt_at.language_id = co.default_language_id
|
||||
LEFT JOIN price opt_pr ON opt_pr.article_id = opt_a.id AND opt_pr.customergroup_id = co.poscustomergroup_id AND opt_pr.minmultiplier = 1
|
||||
LEFT JOIN tax opt_ptax ON opt_ptax.id = opt_pr.tax_id
|
||||
LEFT JOIN tax opt_ctax ON opt_ctax.id = co.taxrate
|
||||
ORDER BY ola.sort ASC, ola.id ASC
|
||||
`;
|
||||
|
||||
export const RECORD_OBITUARY = `
|
||||
INSERT INTO posterminalobituary (posterminal_id, entity_type, entity_id)
|
||||
SELECT pt.id, @entityType, @entityId
|
||||
|
||||
@@ -11,7 +11,8 @@ export const {
|
||||
INSERT_POSTERMINAL_OBITUARY,
|
||||
LIST_CHILDREN_BY_PARENT_ID, LIST_PAIRED_POSTERMINAL_IDS_BY_ARTICLE,
|
||||
SET_PARENT_SORT,
|
||||
SET_IS_PARENT, TOGGLE_PARENT, TOUCH_UPDATED_AT, UNLINK_CHILD, UPDATE_BRAND, UPDATE_PARENT_BY_SKU, UPDATE_TRACK_STOCK, UPDATE_UNIT,
|
||||
SET_IS_PARENT, TOGGLE_PARENT, TOUCH_UPDATED_AT, TOUCH_OPTION_PARENT_ARTICLES_UPDATED_AT,
|
||||
UNLINK_CHILD, UPDATE_BRAND, UPDATE_PARENT_BY_SKU, UPDATE_TRACK_STOCK, UPDATE_UNIT,
|
||||
UPDATE_UNITAMOUNT, UPDATE_UNIT_AND_AMOUNT, UPDATE_WEIGHT,
|
||||
} = queries;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ export const {
|
||||
FIND_BY_TOKEN, COUNT_PRODUCTS, COUNT_CATEGORIES, COUNT_CUSTOMERS,
|
||||
COUNT_CUSTOMER_GROUPS, COUNT_COMPOSITE_PRODUCTS, MAX_ORDER_ID,
|
||||
LIST_POS_PRODUCT_CATEGORIES, LIST_POS_CUSTOMER_GROUP_IDS, LIST_POS_PRODUCT_PRICES,
|
||||
LIST_POS_MANDATED_OPTIONS,
|
||||
TOUCH_LASTSEEN, RECORD_OBITUARY, COUNT_DELETED_ENTITIES,
|
||||
} = queries;
|
||||
|
||||
|
||||
@@ -49,6 +49,9 @@ export default function del(provider) {
|
||||
|
||||
await runner.query(queries.DELETE_PICS_BY_ARTICLE, { articleId: id });
|
||||
|
||||
// Touch any parent articles that used this article as an option before deleting it
|
||||
await runner.query(articleQueries.TOUCH_OPTION_PARENT_ARTICLES_UPDATED_AT, { articleId: id });
|
||||
|
||||
const deleted = await runner.query(queries.DELETE_BY_ID, { articleId: id });
|
||||
if (!deleted.rowsAffected) {
|
||||
throw new Error('Article not found');
|
||||
|
||||
@@ -6,8 +6,14 @@ import {
|
||||
CREATE as SQLITE_CREATE_PRICE,
|
||||
DELETE_BY_ARTICLE_AND_CUSTOMERGROUP as SQLITE_DELETE_PRICE,
|
||||
} from '../../providers/sqlite3/queries/price.js';
|
||||
import { TOUCH_UPDATED_AT as MSSQL_TOUCH } from '../../providers/mssql/queries/article.js';
|
||||
import { TOUCH_UPDATED_AT as SQLITE_TOUCH } from '../../providers/sqlite3/queries/article.js';
|
||||
import {
|
||||
TOUCH_UPDATED_AT as MSSQL_TOUCH,
|
||||
TOUCH_OPTION_PARENT_ARTICLES_UPDATED_AT as MSSQL_TOUCH_OPTION_PARENTS,
|
||||
} from '../../providers/mssql/queries/article.js';
|
||||
import {
|
||||
TOUCH_UPDATED_AT as SQLITE_TOUCH,
|
||||
TOUCH_OPTION_PARENT_ARTICLES_UPDATED_AT as SQLITE_TOUCH_OPTION_PARENTS,
|
||||
} from '../../providers/sqlite3/queries/article.js';
|
||||
import taxEnsure from '../tax/ensure.js';
|
||||
import queryBySku from './queryBySku.js';
|
||||
import resolveArticleBySku from './resolveArticleBySku.js';
|
||||
@@ -68,6 +74,7 @@ export default function setPricesBySku(provider) {
|
||||
const createPriceSql = isSqlite ? SQLITE_CREATE_PRICE : MSSQL_CREATE_PRICE;
|
||||
const deletePriceSql = isSqlite ? SQLITE_DELETE_PRICE : MSSQL_DELETE_PRICE;
|
||||
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
|
||||
const touchOptionParentsSql = isSqlite ? SQLITE_TOUCH_OPTION_PARENTS : MSSQL_TOUCH_OPTION_PARENTS;
|
||||
|
||||
/**
|
||||
* Replaces the price list of an article by its SKU.
|
||||
@@ -147,6 +154,9 @@ export default function setPricesBySku(provider) {
|
||||
// Touch article updated_at so POS and other consumers pick up the price change
|
||||
await runner.query(touchArticleSql, { articleId });
|
||||
|
||||
// Touch any parent articles using this article as an option so their deposit price updates
|
||||
await runner.query(touchOptionParentsSql, { articleId });
|
||||
|
||||
const article = await load(articleId, languageId, runner);
|
||||
if (!article) {
|
||||
throw new Error('Article not found');
|
||||
|
||||
@@ -235,6 +235,9 @@ export default function updateBySku(provider) {
|
||||
// Touch article updated_at so all consumers pick up changes
|
||||
await runner.query(articleQueries.TOUCH_UPDATED_AT, { articleId });
|
||||
|
||||
// Touch any parent articles that use this article as an option so their deposit name/details update on POS
|
||||
await runner.query(articleQueries.TOUCH_OPTION_PARENT_ARTICLES_UPDATED_AT, { articleId });
|
||||
|
||||
const article = await load(articleId, languageId, runner);
|
||||
if (!article) {
|
||||
throw new Error('Article not found');
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import * as mssqlQueries from '../../providers/mssql/queries/optionslist.js';
|
||||
import * as sqliteQueries from '../../providers/sqlite3/queries/optionslist.js';
|
||||
import { TOUCH_UPDATED_AT as MSSQL_TOUCH } from '../../providers/mssql/queries/article.js';
|
||||
import { TOUCH_UPDATED_AT as SQLITE_TOUCH } from '../../providers/sqlite3/queries/article.js';
|
||||
import resolveArticleBySku from '../article/resolveArticleBySku.js';
|
||||
import getOptionsByArticleSku from './getOptionsByArticleSku.js';
|
||||
import {
|
||||
@@ -46,6 +48,7 @@ export default function setOptionsByArticleSku(provider) {
|
||||
const getOptions = getOptionsByArticleSku(provider);
|
||||
const isSqlite = provider?.dialect === 'sqlite3';
|
||||
const queries = isSqlite ? sqliteQueries : mssqlQueries;
|
||||
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
|
||||
|
||||
/**
|
||||
* Sets or clears the options list for an article.
|
||||
@@ -108,6 +111,7 @@ export default function setOptionsByArticleSku(provider) {
|
||||
type: 'optionslist_cleared',
|
||||
});
|
||||
}
|
||||
await runner.query(touchArticleSql, { articleId });
|
||||
}
|
||||
return [];
|
||||
}
|
||||
@@ -236,6 +240,9 @@ export default function setOptionsByArticleSku(provider) {
|
||||
options: result,
|
||||
});
|
||||
|
||||
// Touch article updated_at so POS and other consumers pick up options/deposit changes
|
||||
await runner.query(touchArticleSql, { articleId });
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,12 +3,14 @@ import {
|
||||
LIST_POS_PRODUCT_CATEGORIES as MSSQL_CATEGORIES,
|
||||
LIST_POS_CUSTOMER_GROUP_IDS as MSSQL_CG_IDS,
|
||||
LIST_POS_PRODUCT_PRICES as MSSQL_PRICES,
|
||||
LIST_POS_MANDATED_OPTIONS as MSSQL_MANDATED_OPTIONS,
|
||||
} from '../../providers/mssql/queries/posterminal.js';
|
||||
import {
|
||||
LIST_POS_PRODUCTS as SQLITE_PRODUCTS,
|
||||
LIST_POS_PRODUCT_CATEGORIES as SQLITE_CATEGORIES,
|
||||
LIST_POS_CUSTOMER_GROUP_IDS as SQLITE_CG_IDS,
|
||||
LIST_POS_PRODUCT_PRICES as SQLITE_PRICES,
|
||||
LIST_POS_MANDATED_OPTIONS as SQLITE_MANDATED_OPTIONS,
|
||||
} from '../../providers/sqlite3/queries/posterminal.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
@@ -36,6 +38,7 @@ export default function getProductList(provider) {
|
||||
const categoriesSql = isSqlite ? SQLITE_CATEGORIES : MSSQL_CATEGORIES;
|
||||
const cgIdsSql = isSqlite ? SQLITE_CG_IDS : MSSQL_CG_IDS;
|
||||
const pricesSql = isSqlite ? SQLITE_PRICES : MSSQL_PRICES;
|
||||
const mandatedOptionsSql = isSqlite ? SQLITE_MANDATED_OPTIONS : MSSQL_MANDATED_OPTIONS;
|
||||
|
||||
/**
|
||||
* Lists products for a POS terminal modified after the cursor.
|
||||
@@ -52,7 +55,7 @@ export default function getProductList(provider) {
|
||||
const runner = makeRunner(provider, tx);
|
||||
const pid = Number(posterminalId);
|
||||
|
||||
const [prodRes, catRes, cgRes, priceRes] = await Promise.all([
|
||||
const [prodRes, catRes, cgRes, priceRes, optRes] = await Promise.all([
|
||||
runner.query(productsSql, {
|
||||
posterminalId: pid,
|
||||
cursor: normalizeCursor(cursor),
|
||||
@@ -61,6 +64,7 @@ export default function getProductList(provider) {
|
||||
runner.query(categoriesSql, { posterminalId: pid }),
|
||||
runner.query(cgIdsSql, { posterminalId: pid }),
|
||||
runner.query(pricesSql, { posterminalId: pid }),
|
||||
runner.query(mandatedOptionsSql, { posterminalId: pid }),
|
||||
]);
|
||||
|
||||
const categoriesByArticle = new Map();
|
||||
@@ -79,6 +83,24 @@ export default function getProductList(provider) {
|
||||
overridesByArticle.get(row.articleId).set(row.customerGroupId, row.netPrice);
|
||||
}
|
||||
|
||||
const mandatedOptionsByArticle = new Map();
|
||||
for (const row of optRes.rows) {
|
||||
const gross =
|
||||
Number(row.count || 1) *
|
||||
Number(row.depositNetPrice || 0) *
|
||||
(1 + Number(row.depositTaxRate || 0) / 100);
|
||||
if (!mandatedOptionsByArticle.has(row.articleId)) {
|
||||
mandatedOptionsByArticle.set(row.articleId, {
|
||||
names: [row.depositName],
|
||||
totalPrice: gross,
|
||||
});
|
||||
} else {
|
||||
const existing = mandatedOptionsByArticle.get(row.articleId);
|
||||
existing.names.push(row.depositName);
|
||||
existing.totalPrice += gross;
|
||||
}
|
||||
}
|
||||
|
||||
const customerGroupIds = cgRes.rows.map((row) => row.id);
|
||||
|
||||
return prodRes.rows.map((product) => {
|
||||
@@ -100,6 +122,10 @@ export default function getProductList(provider) {
|
||||
});
|
||||
|
||||
const categoryIds = categoriesByArticle.get(product.id) ?? [];
|
||||
const mandatedOpt = mandatedOptionsByArticle.get(product.id);
|
||||
const hasDeposit = Boolean(mandatedOpt);
|
||||
const depositName = mandatedOpt ? mandatedOpt.names.join(' + ') : '';
|
||||
const depositPrice = mandatedOpt ? mandatedOpt.totalPrice.toFixed(2) : '0.0';
|
||||
|
||||
return {
|
||||
_id: String(product.id),
|
||||
@@ -123,6 +149,9 @@ export default function getProductList(provider) {
|
||||
attributes: [],
|
||||
use_stock: product.trackStock ? '1' : '0',
|
||||
quantity: String(product.fBestand ?? 0),
|
||||
deposit: hasDeposit ? '1' : '0',
|
||||
d_price: depositPrice,
|
||||
deposit_name: depositName,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user