This commit is contained in:
seb
2026-10-27 06:48:35 +00:00
parent bab5c151d0
commit ccb81cdb26
84 changed files with 5072 additions and 3625 deletions

View File

@@ -143,6 +143,7 @@ import posterminalGetCompositeProductCount from './store/posterminal/getComposit
import posterminalGetDeletedEntityCount from './store/posterminal/getDeletedEntityCount.js';
import posterminalGetDeletedEntityList from './store/posterminal/getDeletedEntityList.js';
import posterminalRecordObituary from './store/posterminal/recordObituary.js';
import posterminalRecordSyncQueue from './store/posterminal/recordSyncQueue.js';
import posterminalGetMaxOrderIdCount from './store/posterminal/getMaxOrderIdCount.js';
import posterminalGetCategoryList from './store/posterminal/getCategoryList.js';
import posterminalGetProductList from './store/posterminal/getProductList.js';
@@ -528,6 +529,7 @@ export default class LibDashStore {
getDeletedEntityCount: posterminalGetDeletedEntityCount(provider),
getDeletedEntityList: posterminalGetDeletedEntityList(provider),
recordObituary: posterminalRecordObituary(provider),
recordSyncQueue: posterminalRecordSyncQueue(provider),
getMaxOrderIdCount: posterminalGetMaxOrderIdCount(provider),
getCategoryList: posterminalGetCategoryList(provider),
getProductList: posterminalGetProductList(provider),

View File

@@ -24,6 +24,8 @@ export const TABLES = [
'modelconversation',
'companyuser',
'companysetting',
'posterminalsyncqueue',
'posterminalobituary',
'posterminalcategory',
'posterminal',
'printer',

View File

@@ -249,6 +249,38 @@ WHERE articlelist_id IN (
)
`;
export const ENQUEUE_SYNC_BY_ARTICLE = `
INSERT INTO posterminalsyncqueue (posterminal_id, entity_type, entity_id)
SELECT pt.id, 'article', a.id
FROM article a
INNER JOIN posterminal pt ON pt.company_id = a.company_id
WHERE a.id = @articleId
`;
export const ENQUEUE_OPTION_PARENT_ARTICLES_SYNC = `
INSERT INTO posterminalsyncqueue (posterminal_id, entity_type, entity_id)
SELECT pt.id, 'article', a.id
FROM article a
INNER JOIN posterminal pt ON pt.company_id = a.company_id
WHERE a.optionslist_id IN (
SELECT ola.optionslist_id
FROM optionslistarticle ola
WHERE ola.article_id = @articleId
)
`;
export const ENQUEUE_STUECKLISTE_ARTICLES_SYNC = `
INSERT INTO posterminalsyncqueue (posterminal_id, entity_type, entity_id)
SELECT pt.id, 'article', a.id
FROM article a
INNER JOIN posterminal pt ON pt.company_id = a.company_id
WHERE a.articlelist_id IN (
SELECT ala.articlelist_id
FROM articlelistarticle ala
WHERE ala.article_id = @articleId
)
`;
export const CREATE = `
INSERT INTO article (company_id, sku, unit_id, unitamount, weight, track_stock)

View File

@@ -240,3 +240,40 @@ WHERE id IN (
)
`;
export const ENQUEUE_SUBTREE_CATEGORIES_SYNC = `
;WITH cats AS (
SELECT id FROM category WHERE id = @id
UNION ALL
SELECT c.id FROM category c INNER JOIN cats ON c.parent_id = cats.id
)
INSERT INTO posterminalsyncqueue (posterminal_id, entity_type, entity_id)
SELECT pt.id, 'category', cats.id
FROM cats
INNER JOIN posterminal pt ON pt.company_id = @companyId
`;
export const ENQUEUE_SUBTREE_ARTICLES_SYNC = `
;WITH cats AS (
SELECT id FROM category WHERE id = @id
UNION ALL
SELECT c.id FROM category c INNER JOIN cats ON c.parent_id = cats.id
),
arts AS (
SELECT ca.article_id AS id FROM categoryarticle ca WHERE ca.category_id IN (SELECT id FROM cats)
UNION
SELECT child.id FROM article child
WHERE child.parentarticle_id IN (
SELECT ca.article_id FROM categoryarticle ca WHERE ca.category_id IN (SELECT id FROM cats)
)
UNION
SELECT parent.parentarticle_id AS id FROM article parent
WHERE parent.id IN (
SELECT ca.article_id FROM categoryarticle ca WHERE ca.category_id IN (SELECT id FROM cats)
) AND parent.parentarticle_id IS NOT NULL
)
INSERT INTO posterminalsyncqueue (posterminal_id, entity_type, entity_id)
SELECT pt.id, 'article', arts.id
FROM arts
INNER JOIN posterminal pt ON pt.company_id = @companyId
`;

View File

@@ -136,6 +136,12 @@ WHERE id = @id
AND customergroup_id = @customergroupId
`;
export const TOUCH_UPDATED_AT = `
UPDATE entity
SET updated_at = SYSUTCDATETIME()
WHERE id = @id
`;
export const DELETE_BY_COMPANY_AND_ID = `
DELETE e
FROM entity e

View File

@@ -172,66 +172,100 @@ WHERE token = @token
`;
export const COUNT_PRODUCTS = `
SELECT COUNT(DISTINCT a.id) AS count
FROM article a
INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = a.company_id
WHERE EXISTS (
SELECT 1
FROM categoryarticle ca
INNER JOIN posterminalcategory pc ON pc.category_id = ca.category_id
WHERE ca.article_id = a.id
AND pc.posterminal_id = @posterminalId
)
AND (DATEDIFF_BIG(second, '1970-01-01', a.updated_at) * 1000000 + (a.id % 1000000)) > @cursor
SELECT COUNT(*) AS count
FROM (
SELECT MAX(q.id) AS syncId, a.id
FROM posterminalsyncqueue q
INNER JOIN article a ON a.id = q.entity_id
INNER JOIN posterminal pt ON pt.id = q.posterminal_id AND pt.company_id = a.company_id
WHERE q.posterminal_id = @posterminalId
AND q.entity_type = 'article'
AND EXISTS (
SELECT 1
FROM categoryarticle ca
INNER JOIN posterminalcategory pc ON pc.category_id = ca.category_id
WHERE ca.article_id = a.id
AND pc.posterminal_id = @posterminalId
)
GROUP BY a.id
HAVING MAX(q.id) > @cursor
) t
`;
export const COUNT_CATEGORIES = `
SELECT COUNT(*) AS count
FROM category c
INNER JOIN posterminalcategory pc ON pc.category_id = c.id
INNER JOIN posterminal pt ON pt.id = pc.posterminal_id
INNER JOIN company co ON co.id = pt.company_id
WHERE pc.posterminal_id = @posterminalId
AND (co.root_category_id IS NULL OR c.id <> co.root_category_id)
AND DATEDIFF_BIG(second, '1970-01-01', c.updated_at) > @cursor
FROM (
SELECT MAX(q.id) AS syncId, c.id
FROM posterminalsyncqueue q
INNER JOIN category c ON c.id = q.entity_id
INNER JOIN posterminalcategory pc ON pc.category_id = c.id AND pc.posterminal_id = q.posterminal_id
INNER JOIN posterminal pt ON pt.id = pc.posterminal_id
INNER JOIN company co ON co.id = pt.company_id
WHERE q.posterminal_id = @posterminalId
AND q.entity_type = 'category'
AND (co.root_category_id IS NULL OR c.id <> co.root_category_id)
GROUP BY c.id
HAVING MAX(q.id) > @cursor
) t
`;
export const COUNT_CUSTOMERS = `
SELECT COUNT(*) AS count
FROM entity e
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = cg.company_id
WHERE cg.name <> 'Lieferanten'
AND DATEDIFF_BIG(second, '1970-01-01', e.updated_at) > @cursor
FROM (
SELECT MAX(q.id) AS syncId, e.id
FROM posterminalsyncqueue q
INNER JOIN entity e ON e.id = q.entity_id
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
INNER JOIN posterminal pt ON pt.id = q.posterminal_id AND pt.company_id = cg.company_id
WHERE q.posterminal_id = @posterminalId
AND q.entity_type = 'customer'
AND cg.name <> 'Lieferanten'
GROUP BY e.id
HAVING MAX(q.id) > @cursor
) t
`;
export const COUNT_CUSTOMER_GROUPS = `
SELECT COUNT(*) AS count
FROM customergroup cg
INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = cg.company_id
WHERE cg.name <> 'Lieferanten'
AND DATEDIFF_BIG(second, '1970-01-01', cg.updated_at) > @cursor
FROM (
SELECT MAX(q.id) AS syncId, cg.id
FROM posterminalsyncqueue q
INNER JOIN customergroup cg ON cg.id = q.entity_id
INNER JOIN posterminal pt ON pt.id = q.posterminal_id AND pt.company_id = cg.company_id
WHERE q.posterminal_id = @posterminalId
AND q.entity_type = 'customergroup'
AND cg.name <> 'Lieferanten'
GROUP BY cg.id
HAVING MAX(q.id) > @cursor
) t
`;
export const COUNT_COMPOSITE_PRODUCTS = `
SELECT COUNT(DISTINCT a.id) AS count
FROM article a
INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = a.company_id
WHERE a.articlelist_id IS NOT NULL
AND EXISTS (
SELECT 1
FROM articlelistarticle ala
WHERE ala.articlelist_id = a.articlelist_id
)
AND EXISTS (
SELECT 1
FROM categoryarticle ca
INNER JOIN posterminalcategory pc ON pc.category_id = ca.category_id
WHERE ca.article_id = a.id
AND pc.posterminal_id = @posterminalId
)
AND (DATEDIFF_BIG(second, '1970-01-01', a.updated_at) * 1000000 + (a.id % 1000000)) > @cursor
SELECT COUNT(*) AS count
FROM (
SELECT MAX(q.id) AS syncId, a.id
FROM posterminalsyncqueue q
INNER JOIN article a ON a.id = q.entity_id
INNER JOIN posterminal pt ON pt.id = q.posterminal_id AND pt.company_id = a.company_id
WHERE q.posterminal_id = @posterminalId
AND q.entity_type = 'article'
AND a.articlelist_id IS NOT NULL
AND EXISTS (
SELECT 1
FROM articlelistarticle ala
WHERE ala.articlelist_id = a.articlelist_id
)
AND EXISTS (
SELECT 1
FROM categoryarticle ca
INNER JOIN posterminalcategory pc ON pc.category_id = ca.category_id
WHERE ca.article_id = a.id
AND pc.posterminal_id = @posterminalId
)
GROUP BY a.id
HAVING MAX(q.id) > @cursor
) t
`;
export const MAX_ORDER_ID = `
@@ -255,16 +289,21 @@ SELECT TOP (@limit)
WHERE cp.category_id = c.id
ORDER BY cp.sort ASC, cp.id ASC
) AS imgHash,
DATEDIFF_BIG(second, '1970-01-01', c.updated_at) AS lastChanged
FROM category c
INNER JOIN posterminalcategory pc ON pc.category_id = c.id
sq.syncId AS lastChanged
FROM (
SELECT entity_id, MAX(id) AS syncId
FROM posterminalsyncqueue
WHERE posterminal_id = @posterminalId AND entity_type = 'category'
GROUP BY entity_id
HAVING MAX(id) > @cursor
) sq
INNER JOIN category c ON c.id = sq.entity_id
INNER JOIN posterminalcategory pc ON pc.category_id = c.id AND pc.posterminal_id = @posterminalId
INNER JOIN posterminal pt ON pt.id = pc.posterminal_id
INNER JOIN company co ON co.id = pt.company_id
LEFT JOIN categorytext ct ON ct.category_id = c.id AND ct.language_id = co.default_language_id
WHERE pc.posterminal_id = @posterminalId
AND (co.root_category_id IS NULL OR c.id <> co.root_category_id)
AND DATEDIFF_BIG(second, '1970-01-01', c.updated_at) > @cursor
ORDER BY DATEDIFF_BIG(second, '1970-01-01', c.updated_at) ASC, c.id ASC
WHERE (co.root_category_id IS NULL OR c.id <> co.root_category_id)
ORDER BY sq.syncId ASC
`;
export const LIST_POS_PRODUCTS = `
@@ -275,7 +314,7 @@ SELECT TOP (@limit)
COALESCE(pr.net, 0) AS netPrice,
COALESCE(ptax.rate, ctax.rate, 0) AS taxRate,
a.created_at AS createdAt,
(DATEDIFF_BIG(second, '1970-01-01', a.updated_at) * 1000000 + (a.id % 1000000)) AS lastChanged,
sq.syncId AS lastChanged,
COALESCE(
(
SELECT TOP 1 p.hash
@@ -374,7 +413,14 @@ SELECT TOP (@limit)
co.id AS companyId,
co.root_category_id AS rootCategoryId,
co.poscustomergroup_id AS posCustomerGroupId
FROM article a
FROM (
SELECT entity_id, MAX(id) AS syncId
FROM posterminalsyncqueue
WHERE posterminal_id = @posterminalId AND entity_type = 'article'
GROUP BY entity_id
HAVING MAX(id) > @cursor
) sq
INNER JOIN article a ON a.id = sq.entity_id
INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = a.company_id
INNER JOIN company co ON co.id = a.company_id
LEFT JOIN articletext at ON at.article_id = a.id AND at.language_id = co.default_language_id
@@ -388,8 +434,7 @@ WHERE EXISTS (
WHERE ca.article_id = a.id
AND pc.posterminal_id = @posterminalId
)
AND (DATEDIFF_BIG(second, '1970-01-01', a.updated_at) * 1000000 + (a.id % 1000000)) > @cursor
ORDER BY (DATEDIFF_BIG(second, '1970-01-01', a.updated_at) * 1000000 + (a.id % 1000000)) ASC
ORDER BY sq.syncId ASC
`;
export const LIST_POS_PRODUCT_CATEGORIES = `
@@ -411,13 +456,19 @@ SELECT TOP (@limit)
cg.name,
CASE WHEN cg.id = co.poscustomergroup_id THEN '1' ELSE '0' END AS standard,
'0.000000' AS discountPercent,
DATEDIFF_BIG(second, '1970-01-01', cg.updated_at) AS lastChanged
FROM customergroup cg
sq.syncId AS lastChanged
FROM (
SELECT entity_id, MAX(id) AS syncId
FROM posterminalsyncqueue
WHERE posterminal_id = @posterminalId AND entity_type = 'customergroup'
GROUP BY entity_id
HAVING MAX(id) > @cursor
) sq
INNER JOIN customergroup cg ON cg.id = sq.entity_id
INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = cg.company_id
INNER JOIN company co ON co.id = pt.company_id
WHERE cg.name <> 'Lieferanten'
AND DATEDIFF_BIG(second, '1970-01-01', cg.updated_at) > @cursor
ORDER BY DATEDIFF_BIG(second, '1970-01-01', cg.updated_at) ASC, cg.id ASC
ORDER BY sq.syncId ASC
`;
export const LIST_POS_CUSTOMERS = `
@@ -469,13 +520,19 @@ SELECT TOP (@limit)
WHERE ec.entity_id = e.id AND ec.contacttype IN ('email', 'mail')
ORDER BY ec.sort ASC, ec.id ASC
) AS email,
DATEDIFF_BIG(second, '1970-01-01', e.updated_at) AS lastChanged
FROM entity e
sq.syncId AS lastChanged
FROM (
SELECT entity_id, MAX(id) AS syncId
FROM posterminalsyncqueue
WHERE posterminal_id = @posterminalId AND entity_type = 'customer'
GROUP BY entity_id
HAVING MAX(id) > @cursor
) sq
INNER JOIN entity e ON e.id = sq.entity_id
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = cg.company_id
WHERE cg.name <> 'Lieferanten'
AND DATEDIFF_BIG(second, '1970-01-01', e.updated_at) > @cursor
ORDER BY DATEDIFF_BIG(second, '1970-01-01', e.updated_at) ASC, e.id ASC
ORDER BY sq.syncId ASC
`;
@@ -541,6 +598,34 @@ FROM posterminal pt
WHERE pt.company_id = @companyId AND pt.token IS NOT NULL
`;
export const RECORD_SYNC_QUEUE = `
INSERT INTO posterminalsyncqueue (posterminal_id, entity_type, entity_id)
SELECT pt.id, @entityType, @entityId
FROM posterminal pt
WHERE pt.company_id = @companyId
`;
export const SEED_SYNC_QUEUE_FOR_TERMINAL = `
INSERT INTO posterminalsyncqueue (posterminal_id, entity_type, entity_id)
SELECT @posterminalId, 'customergroup', cg.id
FROM customergroup cg
WHERE cg.company_id = @companyId
UNION ALL
SELECT @posterminalId, 'customer', e.id
FROM entity e
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
WHERE cg.company_id = @companyId
UNION ALL
SELECT @posterminalId, 'category', c.id
FROM category c
INNER JOIN posterminalcategory pc ON pc.category_id = c.id
WHERE pc.posterminal_id = @posterminalId
UNION ALL
SELECT @posterminalId, 'article', a.id
FROM article a
WHERE a.company_id = @companyId
`;
export const COUNT_DELETED_ENTITIES = `
SELECT COUNT(*) AS count
FROM posterminalobituary

View File

@@ -417,6 +417,23 @@ BEGIN
END
`;
export const INIT_POSTERMINALSYNCQUEUE = `
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'posterminalsyncqueue')
BEGIN
CREATE TABLE posterminalsyncqueue (
id INT IDENTITY(1,1) PRIMARY KEY,
posterminal_id INT NOT NULL,
entity_type NVARCHAR(50) NOT NULL,
entity_id INT NOT NULL,
CONSTRAINT CK_posterminalsyncqueue_entity_type CHECK (entity_type IN ('article', 'category', 'customer', 'customergroup')),
CONSTRAINT FK_posterminalsyncqueue_posterminal FOREIGN KEY (posterminal_id) REFERENCES posterminal(id) ON DELETE CASCADE
);
CREATE INDEX IX_posterminalsyncqueue_posterminal_id
ON posterminalsyncqueue (posterminal_id, id);
END
`;
export const INIT_ARTICLEEAN = `
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'articleean')
@@ -1642,6 +1659,7 @@ export const SCHEMA_SCRIPTS = [
INIT_POSTERMINAL,
INIT_POSTERMINALCATEGORY,
INIT_POSTERMINALOBITUARY,
INIT_POSTERMINALSYNCQUEUE,
INIT_PRINTER,
INIT_LABELTEMPLATE,
INIT_FILE,

View File

@@ -13,6 +13,7 @@ export const {
SET_PARENT_SORT,
SET_IS_PARENT, TOGGLE_PARENT, TOUCH_UPDATED_AT, TOUCH_OPTION_PARENT_ARTICLES_UPDATED_AT,
TOUCH_STUECKLISTE_ARTICLES_UPDATED_AT,
ENQUEUE_SYNC_BY_ARTICLE, ENQUEUE_OPTION_PARENT_ARTICLES_SYNC, ENQUEUE_STUECKLISTE_ARTICLES_SYNC,
UNLINK_CHILD, UPDATE_BRAND, UPDATE_PARENT_BY_SKU, UPDATE_TRACK_STOCK, UPDATE_UNIT,
UPDATE_UNITAMOUNT, UPDATE_UNIT_AND_AMOUNT, UPDATE_WEIGHT,
} = queries;

View File

@@ -163,4 +163,41 @@ WHERE id IN (
SELECT ca.article_id FROM categoryarticle ca WHERE ca.category_id IN (SELECT id FROM cats)
) AND parent.parentarticle_id IS NOT NULL
)
`;
export const ENQUEUE_SUBTREE_CATEGORIES_SYNC = `
WITH RECURSIVE cats AS (
SELECT id FROM category WHERE id = @id
UNION ALL
SELECT c.id FROM category c INNER JOIN cats ON c.parent_id = cats.id
)
INSERT INTO posterminalsyncqueue (posterminal_id, entity_type, entity_id)
SELECT pt.id, 'category', cats.id
FROM cats
INNER JOIN posterminal pt ON pt.company_id = @companyId
`;
export const ENQUEUE_SUBTREE_ARTICLES_SYNC = `
WITH RECURSIVE cats AS (
SELECT id FROM category WHERE id = @id
UNION ALL
SELECT c.id FROM category c INNER JOIN cats ON c.parent_id = cats.id
),
arts AS (
SELECT ca.article_id AS id FROM categoryarticle ca WHERE ca.category_id IN (SELECT id FROM cats)
UNION
SELECT child.id FROM article child
WHERE child.parentarticle_id IN (
SELECT ca.article_id FROM categoryarticle ca WHERE ca.category_id IN (SELECT id FROM cats)
)
UNION
SELECT parent.parentarticle_id AS id FROM article parent
WHERE parent.id IN (
SELECT ca.article_id FROM categoryarticle ca WHERE ca.category_id IN (SELECT id FROM cats)
) AND parent.parentarticle_id IS NOT NULL
)
INSERT INTO posterminalsyncqueue (posterminal_id, entity_type, entity_id)
SELECT pt.id, 'article', arts.id
FROM arts
INNER JOIN posterminal pt ON pt.company_id = @companyId
`;

View File

@@ -7,8 +7,8 @@ export const {
GET_BY_COMPANY_AND_ID, GET_CUSTOMER_BY_ID, GET_GROUP_ID_FOR_SUPPLIER,
GET_SUPPLIER_BY_ID, LIST_BY_COMPANY, LIST_BY_COMPANY_AND_GROUP,
LIST_CUSTOMERS_BY_COMPANY, LIST_SUPPLIERS_BY_COMPANY,
NUMBER_TAKEN_IN_COMPANY, POS_GROUP_NAME, SUPPLIER_GROUP_NAME, UPDATE,
UPDATE_NAME,
NUMBER_TAKEN_IN_COMPANY, POS_GROUP_NAME, SUPPLIER_GROUP_NAME,
TOUCH_UPDATED_AT, UPDATE, UPDATE_NAME,
} = queries;
export const DELETE_BY_COMPANY_AND_ID = `

View File

@@ -10,7 +10,8 @@ export const {
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, LIST_POS_PARENT_OPTIONS,
TOUCH_LASTSEEN, RECORD_OBITUARY, COUNT_DELETED_ENTITIES,
TOUCH_LASTSEEN, RECORD_OBITUARY, RECORD_SYNC_QUEUE, SEED_SYNC_QUEUE_FOR_TERMINAL,
COUNT_DELETED_ENTITIES,
} = queries;
export const SET_ON = `
@@ -50,13 +51,19 @@ SELECT
cg.name,
CASE WHEN cg.id = co.poscustomergroup_id THEN '1' ELSE '0' END AS standard,
'0.000000' AS discountPercent,
CAST(strftime('%s', cg.updated_at) AS INTEGER) AS lastChanged
FROM customergroup cg
sq.syncId AS lastChanged
FROM (
SELECT entity_id, MAX(id) AS syncId
FROM posterminalsyncqueue
WHERE posterminal_id = @posterminalId AND entity_type = 'customergroup'
GROUP BY entity_id
HAVING MAX(id) > @cursor
) sq
INNER JOIN customergroup cg ON cg.id = sq.entity_id
INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = cg.company_id
INNER JOIN company co ON co.id = pt.company_id
WHERE cg.name <> 'Lieferanten'
AND CAST(strftime('%s', cg.updated_at) AS INTEGER) > @cursor
ORDER BY lastChanged ASC, cg.id ASC
ORDER BY sq.syncId ASC
LIMIT @limit
`;
@@ -116,13 +123,19 @@ SELECT
ORDER BY ec.sort ASC, ec.id ASC
LIMIT 1
) AS email,
CAST(strftime('%s', e.updated_at) AS INTEGER) AS lastChanged
FROM entity e
sq.syncId AS lastChanged
FROM (
SELECT entity_id, MAX(id) AS syncId
FROM posterminalsyncqueue
WHERE posterminal_id = @posterminalId AND entity_type = 'customer'
GROUP BY entity_id
HAVING MAX(id) > @cursor
) sq
INNER JOIN entity e ON e.id = sq.entity_id
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = cg.company_id
WHERE cg.name <> 'Lieferanten'
AND CAST(strftime('%s', e.updated_at) AS INTEGER) > @cursor
ORDER BY lastChanged ASC, e.id ASC
ORDER BY sq.syncId ASC
LIMIT @limit
`;
@@ -141,16 +154,21 @@ SELECT
ORDER BY cp.sort ASC, cp.id ASC
LIMIT 1
) AS imgHash,
CAST(strftime('%s', c.updated_at) AS INTEGER) AS lastChanged
FROM category c
INNER JOIN posterminalcategory pc ON pc.category_id = c.id
sq.syncId AS lastChanged
FROM (
SELECT entity_id, MAX(id) AS syncId
FROM posterminalsyncqueue
WHERE posterminal_id = @posterminalId AND entity_type = 'category'
GROUP BY entity_id
HAVING MAX(id) > @cursor
) sq
INNER JOIN category c ON c.id = sq.entity_id
INNER JOIN posterminalcategory pc ON pc.category_id = c.id AND pc.posterminal_id = @posterminalId
INNER JOIN posterminal pt ON pt.id = pc.posterminal_id
INNER JOIN company co ON co.id = pt.company_id
LEFT JOIN categorytext ct ON ct.category_id = c.id AND ct.language_id = co.default_language_id
WHERE pc.posterminal_id = @posterminalId
AND (co.root_category_id IS NULL OR c.id <> co.root_category_id)
AND CAST(strftime('%s', c.updated_at) AS INTEGER) > @cursor
ORDER BY lastChanged ASC, c.id ASC
WHERE (co.root_category_id IS NULL OR c.id <> co.root_category_id)
ORDER BY sq.syncId ASC
LIMIT @limit
`;
@@ -162,7 +180,7 @@ SELECT
COALESCE(pr.net, 0) AS netPrice,
COALESCE(ptax.rate, ctax.rate, 0) AS taxRate,
a.created_at AS createdAt,
(CAST(strftime('%s', a.updated_at) AS INTEGER) * 1000000 + (a.id % 1000000)) AS lastChanged,
sq.syncId AS lastChanged,
COALESCE(
(
SELECT p.hash
@@ -265,7 +283,14 @@ SELECT
co.id AS companyId,
co.root_category_id AS rootCategoryId,
co.poscustomergroup_id AS posCustomerGroupId
FROM article a
FROM (
SELECT entity_id, MAX(id) AS syncId
FROM posterminalsyncqueue
WHERE posterminal_id = @posterminalId AND entity_type = 'article'
GROUP BY entity_id
HAVING MAX(id) > @cursor
) sq
INNER JOIN article a ON a.id = sq.entity_id
INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = a.company_id
INNER JOIN company co ON co.id = a.company_id
LEFT JOIN articletext at ON at.article_id = a.id AND at.language_id = co.default_language_id
@@ -279,8 +304,7 @@ WHERE EXISTS (
WHERE ca.article_id = a.id
AND pc.posterminal_id = @posterminalId
)
AND (CAST(strftime('%s', a.updated_at) AS INTEGER) * 1000000 + (a.id % 1000000)) > @cursor
ORDER BY (CAST(strftime('%s', a.updated_at) AS INTEGER) * 1000000 + (a.id % 1000000)) ASC
ORDER BY sq.syncId ASC
LIMIT @limit
`;

View File

@@ -660,6 +660,18 @@ CREATE INDEX IF NOT EXISTS IX_posterminalobituary_posterminal_id
ON posterminalobituary (posterminal_id, id);
`;
export const INIT_POSTERMINALSYNCQUEUE = `
CREATE TABLE IF NOT EXISTS posterminalsyncqueue (
id INTEGER PRIMARY KEY AUTOINCREMENT,
posterminal_id INTEGER NOT NULL,
entity_type TEXT NOT NULL CHECK (entity_type IN ('article', 'category', 'customer', 'customergroup')),
entity_id INTEGER NOT NULL,
FOREIGN KEY (posterminal_id) REFERENCES posterminal(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS IX_posterminalsyncqueue_posterminal_id
ON posterminalsyncqueue (posterminal_id, id);
`;
export const INIT_PRINTER = `
CREATE TABLE IF NOT EXISTS printer (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -1206,6 +1218,7 @@ export const SCHEMA_SCRIPTS = [
INIT_POSTERMINAL,
INIT_POSTERMINALCATEGORY,
INIT_POSTERMINALOBITUARY,
INIT_POSTERMINALSYNCQUEUE,
INIT_PRINTER,
INIT_LABELTEMPLATE,
INIT_FILE,

View File

@@ -273,6 +273,8 @@ export default function addChild(provider) {
// Touch parent article updated_at so POS and other consumers refresh parent options
await runner.query(queries.TOUCH_UPDATED_AT, { articleId: parentId });
await runner.query(queries.ENQUEUE_SYNC_BY_ARTICLE, { articleId: childId });
await runner.query(queries.ENQUEUE_SYNC_BY_ARTICLE, { articleId: parentId });
return load(googleAuthId, childSku, runner);
};

View File

@@ -8,8 +8,14 @@ import {
} from '../../providers/sqlite3/queries/articlepic.js';
import { CREATE as MSSQL_CREATE_PIC } from '../../providers/mssql/queries/pic.js';
import { CREATE as SQLITE_CREATE_PIC } from '../../providers/sqlite3/queries/pic.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,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import processAvifImage from '../../util/processAvifImage.js';
import newFullHash from '../../util/newFullHash.js';
import resolveArticleBySku from './resolveArticleBySku.js';
@@ -24,6 +30,7 @@ export default function addImage(provider) {
const createPicSql = isSqlite ? SQLITE_CREATE_PIC : MSSQL_CREATE_PIC;
const addArticlePicSql = isSqlite ? SQLITE_ADD_ARTICLEPIC : MSSQL_ADD_ARTICLEPIC;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Adds an image to an article by its SKU, processing full, thumb, and 32px-edge small-thumb AVIF variants.
@@ -107,6 +114,7 @@ export default function addImage(provider) {
}
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
return {
picId,

View File

@@ -173,6 +173,8 @@ export default function attachChild(provider) {
});
}
}
await runner.query(queries.TOUCH_UPDATED_AT, { articleId: prevParentId });
await runner.query(queries.ENQUEUE_SYNC_BY_ARTICLE, { articleId: prevParentId });
}
// Assign parentsort if not already child of this parent
@@ -305,6 +307,11 @@ export default function attachChild(provider) {
});
}
await runner.query(queries.TOUCH_UPDATED_AT, { articleId: child.id });
await runner.query(queries.ENQUEUE_SYNC_BY_ARTICLE, { articleId: child.id });
await runner.query(queries.TOUCH_UPDATED_AT, { articleId: parentId });
await runner.query(queries.ENQUEUE_SYNC_BY_ARTICLE, { articleId: parentId });
const updated = await load(googleAuthId, childSku, runner);
const children = await list(googleAuthId, parentSku, runner);

View File

@@ -1,10 +1,12 @@
import {
CREATE as MSSQL_CREATE_ARTICLE,
CHECK_HAS_WAREHOUSE as MSSQL_CHECK_HAS_WAREHOUSE,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
CREATE as SQLITE_CREATE_ARTICLE,
CHECK_HAS_WAREHOUSE as SQLITE_CHECK_HAS_WAREHOUSE,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import { ADD as MSSQL_ADD_CATEGORYARTICLE } from '../../providers/mssql/queries/categoryarticle.js';
import { ADD as SQLITE_ADD_CATEGORYARTICLE } from '../../providers/sqlite3/queries/categoryarticle.js';
@@ -30,6 +32,7 @@ export default function createUnderParent(provider) {
const checkHasWarehouseSql = isSqlite ? SQLITE_CHECK_HAS_WAREHOUSE : MSSQL_CHECK_HAS_WAREHOUSE;
const addCategoryArticleSql = isSqlite ? SQLITE_ADD_CATEGORYARTICLE : MSSQL_ADD_CATEGORYARTICLE;
const createArticleTextSql = isSqlite ? SQLITE_CREATE_ARTICLETEXT : MSSQL_CREATE_ARTICLETEXT;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Creates a new article under a given parent category, allocating a SKU and
@@ -118,6 +121,8 @@ export default function createUnderParent(provider) {
await initArticleWarehouseSummary(runner, { companyId, articleId: id });
}
await runner.query(enqueueSyncSql, { articleId: id });
return {
id,
parentId,

View File

@@ -51,6 +51,7 @@ export default function del(provider) {
// 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 });
await runner.query(articleQueries.ENQUEUE_OPTION_PARENT_ARTICLES_SYNC, { articleId: id });
const deleted = await runner.query(queries.DELETE_BY_ID, { articleId: id });
if (!deleted.rowsAffected) {

View File

@@ -2,16 +2,24 @@ import sharp from 'sharp';
import { encodeRGBA } from 'skelehash-wasm';
import { DELETE_BY_ARTICLE_AND_HASH as MSSQL_QUERY } from '../../providers/mssql/queries/pic.js';
import { DELETE_BY_ARTICLE_AND_HASH as SQLITE_QUERY } from '../../providers/sqlite3/queries/pic.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,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import resolveArticleBySku from './resolveArticleBySku.js';
import { recordImageDeleteHistory } from '../articlehistory/record.js';
import makeRunner from '../runner.js';
export default function deleteImage(provider) {
const resolve = resolveArticleBySku(provider);
const sql = provider?.dialect === 'sqlite3' ? SQLITE_QUERY : MSSQL_QUERY;
const touchArticleSql = provider?.dialect === 'sqlite3' ? SQLITE_TOUCH : MSSQL_TOUCH;
const isSqlite = provider?.dialect === 'sqlite3';
const sql = isSqlite ? SQLITE_QUERY : MSSQL_QUERY;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Deletes an image from an article by its SKU and full image hash.
@@ -86,6 +94,7 @@ export default function deleteImage(provider) {
});
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
};
if (tx) {

View File

@@ -1,7 +1,13 @@
import * as mssqlPic from '../../providers/mssql/queries/articlepic.js';
import * as sqlitePic from '../../providers/sqlite3/queries/articlepic.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,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import resolveArticleBySku from './resolveArticleBySku.js';
import { recordImageOrderHistory } from '../articlehistory/record.js';
import makeRunner from '../runner.js';
@@ -11,6 +17,7 @@ export default function orderImages(provider) {
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqlitePic : mssqlPic;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Reorders the images of an article by its SKU.
@@ -73,6 +80,7 @@ export default function orderImages(provider) {
fullHashes,
});
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
}
return { fullHashes };

View File

@@ -88,6 +88,7 @@ export default function removeChild(provider) {
// Touch parent article updated_at so POS and other consumers refresh parent options
await runner.query(queries.TOUCH_UPDATED_AT, { articleId: parentId });
await runner.query(queries.ENQUEUE_SYNC_BY_ARTICLE, { articleId: parentId });
return {
success: true,
@@ -134,8 +135,11 @@ export default function removeChild(provider) {
parentSku,
});
// Touch parent article updated_at so POS and other consumers refresh parent options
// Touch child and parent article updated_at so POS and other consumers refresh parent options
await runner.query(queries.TOUCH_UPDATED_AT, { articleId: childId });
await runner.query(queries.ENQUEUE_SYNC_BY_ARTICLE, { articleId: childId });
await runner.query(queries.TOUCH_UPDATED_AT, { articleId: parentId });
await runner.query(queries.ENQUEUE_SYNC_BY_ARTICLE, { articleId: parentId });
return {
success: true,

View File

@@ -1,10 +1,12 @@
import {
GET_BRAND_BY_COMPANY_AND_ID as MSSQL_GET_BRAND,
UPDATE_BRAND as MSSQL_UPDATE_BRAND,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
GET_BRAND_BY_COMPANY_AND_ID as SQLITE_GET_BRAND,
UPDATE_BRAND as SQLITE_UPDATE_BRAND,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import queryBySku from './queryBySku.js';
import resolveArticleBySku from './resolveArticleBySku.js';
@@ -18,6 +20,7 @@ export default function setBrandIdBySku(provider) {
const getBrandSql = isSqlite ? SQLITE_GET_BRAND : MSSQL_GET_BRAND;
const updateBrandSql = isSqlite ? SQLITE_UPDATE_BRAND : MSSQL_UPDATE_BRAND;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Sets (or clears) the brand of an article by its SKU.
@@ -79,6 +82,8 @@ export default function setBrandIdBySku(provider) {
throw new Error('Article not found');
}
await runner.query(enqueueSyncSql, { articleId });
// null = no brand; treat as distinct sentinel so first assignment is logged
await recordBrandChangeHistory(runner, {
articleId,

View File

@@ -5,6 +5,7 @@ import {
INSERT_POSTERMINAL_OBITUARY as MSSQL_INSERT_OBITUARY,
LIST_PAIRED_POSTERMINAL_IDS_BY_ARTICLE as MSSQL_LIST_TERMINALS,
TOUCH_UPDATED_AT as MSSQL_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
ADD_CATEGORY as SQLITE_ADD_CATEGORY,
@@ -13,6 +14,7 @@ import {
INSERT_POSTERMINAL_OBITUARY as SQLITE_INSERT_OBITUARY,
LIST_PAIRED_POSTERMINAL_IDS_BY_ARTICLE as SQLITE_LIST_TERMINALS,
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import resolveCategoryAccess from '../category/resolveCategoryAccess.js';
import queryBySku from './queryBySku.js';
@@ -32,6 +34,7 @@ export default function setCategoryIdsBySku(provider) {
const listTerminalsSql = isSqlite ? SQLITE_LIST_TERMINALS : MSSQL_LIST_TERMINALS;
const insertObituarySql = isSqlite ? SQLITE_INSERT_OBITUARY : MSSQL_INSERT_OBITUARY;
const clearObituarySql = isSqlite ? SQLITE_CLEAR_OBITUARY : MSSQL_CLEAR_OBITUARY;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Replaces the category membership of an article by its SKU.
@@ -150,6 +153,7 @@ export default function setCategoryIdsBySku(provider) {
// Touch article updated_at so POS and other consumers pick up category assignment changes
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
const article = await load(articleId, languageId, runner);
if (!article) {

View File

@@ -3,12 +3,14 @@ import {
DELETE_EANS_BY_ARTICLE as MSSQL_DELETE_EANS,
EAN_EXISTS_FOR_OTHER_ARTICLE as MSSQL_CHECK_CONFLICT,
TOUCH_UPDATED_AT as MSSQL_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
ADD_EAN as SQLITE_ADD_EAN,
DELETE_EANS_BY_ARTICLE as SQLITE_DELETE_EANS,
EAN_EXISTS_FOR_OTHER_ARTICLE as SQLITE_CHECK_CONFLICT,
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import { isUniqueConstraintError } from '../../providers/provider.js';
import queryBySku from './queryBySku.js';
@@ -25,6 +27,7 @@ export default function setEansBySku(provider) {
const deleteEansSql = isSqlite ? SQLITE_DELETE_EANS : MSSQL_DELETE_EANS;
const checkConflictSql = isSqlite ? SQLITE_CHECK_CONFLICT : MSSQL_CHECK_CONFLICT;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Replaces the EAN list of an article by its SKU.
@@ -103,6 +106,7 @@ export default function setEansBySku(provider) {
// Touch article updated_at so POS and other consumers pick up the barcode change
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
const article = await load(articleId, languageId, runner);
if (!article) {

View File

@@ -56,6 +56,9 @@ export default function setParentBySku(provider) {
parentArticleId: null,
});
await runner.query(queries.TOUCH_UPDATED_AT, { articleId });
await runner.query(queries.ENQUEUE_SYNC_BY_ARTICLE, { articleId });
if (prevParentId) {
const prevParentTextRes = await runner.query(
'SELECT sku FROM article WHERE id = @prevParentId',
@@ -74,6 +77,9 @@ export default function setParentBySku(provider) {
companyuserId,
text: `Variante "${childName}" (${sku}) getrennt`,
});
await runner.query(queries.TOUCH_UPDATED_AT, { articleId: prevParentId });
await runner.query(queries.ENQUEUE_SYNC_BY_ARTICLE, { articleId: prevParentId });
}
const unlinked = await load(articleId, languageId, runner);
@@ -141,6 +147,11 @@ export default function setParentBySku(provider) {
parentSku,
});
await runner.query(queries.TOUCH_UPDATED_AT, { articleId });
await runner.query(queries.ENQUEUE_SYNC_BY_ARTICLE, { articleId });
await runner.query(queries.TOUCH_UPDATED_AT, { articleId: parentId });
await runner.query(queries.ENQUEUE_SYNC_BY_ARTICLE, { articleId: parentId });
const article = await load(articleId, languageId, runner);
if (!article) {
throw new Error('Article not found');

View File

@@ -9,10 +9,14 @@ import {
import {
TOUCH_UPDATED_AT as MSSQL_TOUCH,
TOUCH_OPTION_PARENT_ARTICLES_UPDATED_AT as MSSQL_TOUCH_OPTION_PARENTS,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
ENQUEUE_OPTION_PARENT_ARTICLES_SYNC as MSSQL_ENQUEUE_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,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
ENQUEUE_OPTION_PARENT_ARTICLES_SYNC as SQLITE_ENQUEUE_OPTION_PARENTS,
} from '../../providers/sqlite3/queries/article.js';
import taxEnsure from '../tax/ensure.js';
import queryBySku from './queryBySku.js';
@@ -75,6 +79,8 @@ export default function setPricesBySku(provider) {
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;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
const enqueueOptionParentsSql = isSqlite ? SQLITE_ENQUEUE_OPTION_PARENTS : MSSQL_ENQUEUE_OPTION_PARENTS;
/**
* Replaces the price list of an article by its SKU.
@@ -153,9 +159,11 @@ export default function setPricesBySku(provider) {
// Touch article updated_at so POS and other consumers pick up the price change
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
// Touch any parent articles using this article as an option so their deposit price updates
await runner.query(touchOptionParentsSql, { articleId });
await runner.query(enqueueOptionParentsSql, { articleId });
const article = await load(articleId, languageId, runner);
if (!article) {

View File

@@ -2,11 +2,13 @@ import {
UPDATE_TRACK_STOCK as MSSQL_UPDATE_TRACK_STOCK,
CHECK_HAS_WAREHOUSE as MSSQL_CHECK_HAS_WAREHOUSE,
CHECK_ARTICLE_WAREHOUSE_STOCKS as MSSQL_CHECK_ARTICLE_WAREHOUSE_STOCKS,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
UPDATE_TRACK_STOCK as SQLITE_UPDATE_TRACK_STOCK,
CHECK_HAS_WAREHOUSE as SQLITE_CHECK_HAS_WAREHOUSE,
CHECK_ARTICLE_WAREHOUSE_STOCKS as SQLITE_CHECK_ARTICLE_WAREHOUSE_STOCKS,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import queryBySku from './queryBySku.js';
import resolveArticleBySku from './resolveArticleBySku.js';
@@ -26,6 +28,7 @@ export default function setTrackStockBySku(provider) {
const sql = isSqlite ? SQLITE_UPDATE_TRACK_STOCK : MSSQL_UPDATE_TRACK_STOCK;
const checkHasWarehouseSql = isSqlite ? SQLITE_CHECK_HAS_WAREHOUSE : MSSQL_CHECK_HAS_WAREHOUSE;
const checkStocksSql = isSqlite ? SQLITE_CHECK_ARTICLE_WAREHOUSE_STOCKS : MSSQL_CHECK_ARTICLE_WAREHOUSE_STOCKS;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Sets the track_stock flag of an article by its SKU.
@@ -96,6 +99,8 @@ export default function setTrackStockBySku(provider) {
throw new Error('Article not found');
}
await runner.query(enqueueSyncSql, { articleId });
// Write history if track_stock changed
if (oldTrack !== newTrack) {
if (!newTrack) {

View File

@@ -1,5 +1,11 @@
import { UPDATE_WEIGHT as MSSQL_UPDATE_WEIGHT } from '../../providers/mssql/queries/article.js';
import { UPDATE_WEIGHT as SQLITE_UPDATE_WEIGHT } from '../../providers/sqlite3/queries/article.js';
import {
UPDATE_WEIGHT as MSSQL_UPDATE_WEIGHT,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
UPDATE_WEIGHT as SQLITE_UPDATE_WEIGHT,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import queryBySku from './queryBySku.js';
import resolveArticleBySku from './resolveArticleBySku.js';
import { recordWeightChangeHistory } from '../articlehistory/record.js';
@@ -8,7 +14,9 @@ import makeRunner from '../runner.js';
export default function setWeightBySku(provider) {
const resolve = resolveArticleBySku(provider);
const load = queryBySku(provider);
const sql = provider?.dialect === 'sqlite3' ? SQLITE_UPDATE_WEIGHT : MSSQL_UPDATE_WEIGHT;
const isSqlite = provider?.dialect === 'sqlite3';
const sql = isSqlite ? SQLITE_UPDATE_WEIGHT : MSSQL_UPDATE_WEIGHT;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Sets the weight of an article by its SKU.
@@ -48,6 +56,8 @@ export default function setWeightBySku(provider) {
throw new Error('Article not found');
}
await runner.query(enqueueSyncSql, { articleId });
// Write history if weight changed
await recordWeightChangeHistory(runner, {
articleId,

View File

@@ -171,6 +171,8 @@ export default function toggleParent(provider) {
});
}
await runner.query(queries.ENQUEUE_SYNC_BY_ARTICLE, { articleId });
return load(googleAuthId, sku, runner);
};

View File

@@ -234,9 +234,11 @@ export default function updateBySku(provider) {
// Touch article updated_at so all consumers pick up changes
await runner.query(articleQueries.TOUCH_UPDATED_AT, { articleId });
await runner.query(articleQueries.ENQUEUE_SYNC_BY_ARTICLE, { 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 });
await runner.query(articleQueries.ENQUEUE_OPTION_PARENT_ARTICLES_SYNC, { articleId });
const article = await load(articleId, languageId, runner);
if (!article) {

View File

@@ -8,6 +8,14 @@ import {
INSERT_ROW as SQLITE_INSERT,
GET_VALUE_DETAIL as SQLITE_GET_DETAIL,
} from '../../providers/sqlite3/queries/articleattributevalue.js';
import {
TOUCH_UPDATED_AT as MSSQL_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import resolveArticleBySku from '../article/resolveArticleBySku.js';
import { recordAttributeChangeHistory } from '../articlehistory/record.js';
import makeRunner from '../runner.js';
@@ -18,6 +26,8 @@ export default function setByArticleSku(provider) {
const deleteSql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
const insertSql = isSqlite ? SQLITE_INSERT : MSSQL_INSERT;
const getDetailSql = isSqlite ? SQLITE_GET_DETAIL : MSSQL_GET_DETAIL;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Replaces all attribute values for an article by its SKU.
@@ -187,6 +197,13 @@ export default function setByArticleSku(provider) {
newAttrs: validated,
});
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
if (article?.parentarticle_id != null) {
await runner.query(touchArticleSql, { articleId: article.parentarticle_id });
await runner.query(enqueueSyncSql, { articleId: article.parentarticle_id });
}
return inserted;
};

View File

@@ -1,5 +1,13 @@
import * as mssqlQueries from '../../providers/mssql/queries/articlelist.js';
import * as sqliteQueries from '../../providers/sqlite3/queries/articlelist.js';
import {
TOUCH_UPDATED_AT as MSSQL_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import resolveArticleBySku from '../article/resolveArticleBySku.js';
import getItemsByArticleSku from './getItemsByArticleSku.js';
import {
@@ -46,6 +54,8 @@ export default function setItemsByArticleSku(provider) {
const getItems = getItemsByArticleSku(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteQueries : mssqlQueries;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Sets or clears the Stückliste (bundle items) for an article.
@@ -108,6 +118,8 @@ export default function setItemsByArticleSku(provider) {
type: 'articlelist_cleared',
});
}
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
}
return [];
}
@@ -229,6 +241,9 @@ export default function setItemsByArticleSku(provider) {
items: result,
});
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
return result;
};

View File

@@ -4,6 +4,14 @@ import {
import {
DELETE_BY_ARTICLE_AND_PROPERTY_ID as SQLITE_DELETE,
} from '../../providers/sqlite3/queries/articleproperty.js';
import {
TOUCH_UPDATED_AT as MSSQL_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import resolveArticleBySku from '../article/resolveArticleBySku.js';
import { recordPropertyDeleteHistory } from '../articlehistory/record.js';
import makeRunner from '../runner.js';
@@ -12,6 +20,8 @@ export default function deleteArticleProperty(provider) {
const resolve = resolveArticleBySku(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const deleteSql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Deletes a property from an article by SKU and propertyId.
@@ -45,6 +55,8 @@ export default function deleteArticleProperty(provider) {
name: prop.name,
value: prop.value,
});
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
}
};
}

View File

@@ -12,6 +12,14 @@ import {
import {
GET_BY_COMPANY_AND_ID as SQLITE_GET_PROP,
} from '../../providers/sqlite3/queries/propertyname.js';
import {
TOUCH_UPDATED_AT as MSSQL_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import resolveArticleBySku from '../article/resolveArticleBySku.js';
import { recordPropertyChangeHistory } from '../articlehistory/record.js';
import makeRunner from '../runner.js';
@@ -22,6 +30,8 @@ export default function setByArticleSku(provider) {
const deleteSql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
const insertSql = isSqlite ? SQLITE_INSERT : MSSQL_INSERT;
const getPropSql = isSqlite ? SQLITE_GET_PROP : MSSQL_GET_PROP;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Replaces all properties for an article by its SKU.
@@ -124,6 +134,9 @@ export default function setByArticleSku(provider) {
newProps: validated,
});
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
return inserted;
};

View File

@@ -1,5 +1,13 @@
import * as mssqlQueries from '../../providers/mssql/queries/articlesupplier.js';
import * as sqliteQueries from '../../providers/sqlite3/queries/articlesupplier.js';
import {
TOUCH_UPDATED_AT as MSSQL_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import resolveArticleBySku from '../article/resolveArticleBySku.js';
import taxEnsure from '../tax/ensure.js';
import {
@@ -17,6 +25,8 @@ export default function create(provider) {
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteQueries : mssqlQueries;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Assigns a supplier to an article, optionally creating a purchase price.
@@ -161,6 +171,9 @@ export default function create(provider) {
pu: actualPu,
});
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
return shapeArticleSupplier(supplierRow);
};

View File

@@ -1,5 +1,13 @@
import * as mssqlQueries from '../../providers/mssql/queries/articlesupplier.js';
import * as sqliteQueries from '../../providers/sqlite3/queries/articlesupplier.js';
import {
TOUCH_UPDATED_AT as MSSQL_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import resolveArticleBySku from '../article/resolveArticleBySku.js';
import { recordSupplierDeleteHistory } from '../articlehistory/record.js';
import makeRunner from '../runner.js';
@@ -8,6 +16,8 @@ export default function del(provider) {
const resolve = resolveArticleBySku(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteQueries : mssqlQueries;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Deletes a supplier assignment and cleans up its associated purchase price.
@@ -59,6 +69,9 @@ export default function del(provider) {
supplierName,
supplierSku: existing.sku,
});
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
};
if (tx) {

View File

@@ -1,5 +1,13 @@
import * as mssqlQueries from '../../providers/mssql/queries/articlesupplier.js';
import * as sqliteQueries from '../../providers/sqlite3/queries/articlesupplier.js';
import {
TOUCH_UPDATED_AT as MSSQL_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import resolveArticleBySku from '../article/resolveArticleBySku.js';
import makeRunner from '../runner.js';
@@ -7,6 +15,8 @@ export default function order(provider) {
const resolve = resolveArticleBySku(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteQueries : mssqlQueries;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Reorders the supplier assignments of an article by its SKU.
@@ -65,6 +75,9 @@ export default function order(provider) {
}
}
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
return { ids };
};

View File

@@ -1,5 +1,13 @@
import * as mssqlQueries from '../../providers/mssql/queries/articlesupplier.js';
import * as sqliteQueries from '../../providers/sqlite3/queries/articlesupplier.js';
import {
TOUCH_UPDATED_AT as MSSQL_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import resolveArticleBySku from '../article/resolveArticleBySku.js';
import taxEnsure from '../tax/ensure.js';
import {
@@ -16,6 +24,8 @@ export default function update(provider) {
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteQueries : mssqlQueries;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Updates an existing supplier assignment and its associated purchase price.
@@ -218,6 +228,9 @@ export default function update(provider) {
supplierName,
});
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
const loadRes = await runner.query(queries.GET_BY_ID_AND_ARTICLE_ID, {
id,
articleId,

View File

@@ -1,10 +1,14 @@
import {
TOUCH_UPDATED_AT as MSSQL_TOUCH,
TOUCH_STUECKLISTE_ARTICLES_UPDATED_AT as MSSQL_TOUCH_STUECKLISTE,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
ENQUEUE_STUECKLISTE_ARTICLES_SYNC as MSSQL_ENQUEUE_STUECKLISTE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
TOUCH_STUECKLISTE_ARTICLES_UPDATED_AT as SQLITE_TOUCH_STUECKLISTE,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
ENQUEUE_STUECKLISTE_ARTICLES_SYNC as SQLITE_ENQUEUE_STUECKLISTE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
/**
@@ -154,8 +158,12 @@ export async function syncArticleWarehouseSummaryForLedger(runner, { companyId,
const touchSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const touchStuecklisteSql = isSqlite ? SQLITE_TOUCH_STUECKLISTE : MSSQL_TOUCH_STUECKLISTE;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
const enqueueStuecklisteSyncSql = isSqlite ? SQLITE_ENQUEUE_STUECKLISTE_SYNC : MSSQL_ENQUEUE_STUECKLISTE_SYNC;
await runner.query(touchSql, { articleId });
await runner.query(touchStuecklisteSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
await runner.query(enqueueStuecklisteSyncSql, { articleId });
}
}

View File

@@ -62,6 +62,51 @@ export default function update(provider) {
throw err;
}
if (value !== existing.rows[0].value || sort !== existing.rows[0].sort) {
const touchSql = isSqlite
? `UPDATE article SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
WHERE company_id = @companyId
AND (
id IN (SELECT article_id FROM articleattributevalue WHERE attributevalue_id = @valId)
OR id IN (
SELECT a.parentarticle_id
FROM article a
INNER JOIN articleattributevalue aav ON aav.article_id = a.id
WHERE aav.attributevalue_id = @valId AND a.parentarticle_id IS NOT NULL
)
)`
: `UPDATE article SET updated_at = SYSUTCDATETIME()
WHERE company_id = @companyId
AND (
id IN (SELECT article_id FROM articleattributevalue WHERE attributevalue_id = @valId)
OR id IN (
SELECT a.parentarticle_id
FROM article a
INNER JOIN articleattributevalue aav ON aav.article_id = a.id
WHERE aav.attributevalue_id = @valId AND a.parentarticle_id IS NOT NULL
)
)`;
await runner.query(touchSql, { valId, companyId });
const enqueueSql = `
INSERT INTO posterminalsyncqueue (posterminal_id, entity_type, entity_id)
SELECT pt.id, 'article', a.id
FROM article a
INNER JOIN posterminal pt ON pt.company_id = a.company_id
WHERE a.company_id = @companyId
AND (
a.id IN (SELECT article_id FROM articleattributevalue WHERE attributevalue_id = @valId)
OR a.id IN (
SELECT child.parentarticle_id
FROM article child
INNER JOIN articleattributevalue aav ON aav.article_id = child.id
WHERE aav.attributevalue_id = @valId AND child.parentarticle_id IS NOT NULL
)
)
`;
await runner.query(enqueueSql, { valId, companyId });
}
return {
id: valId,
attributeId: existing.rows[0].attributeId,

View File

@@ -78,6 +78,15 @@ export default function update(provider) {
: 'UPDATE article SET updated_at = SYSUTCDATETIME() WHERE brand_id = @brandId AND company_id = @companyId';
const touched = await runner.query(touchSql, { brandId: numericId, companyId });
touchedArticleCount = touched.rowsAffected ?? 0;
const enqueueSql = `
INSERT INTO posterminalsyncqueue (posterminal_id, entity_type, entity_id)
SELECT pt.id, 'article', a.id
FROM article a
INNER JOIN posterminal pt ON pt.company_id = a.company_id
WHERE a.brand_id = @brandId AND a.company_id = @companyId
`;
await runner.query(enqueueSql, { brandId: numericId, companyId });
}
return {

View File

@@ -11,10 +11,12 @@ import { CREATE as SQLITE_CREATE_PIC } from '../../providers/sqlite3/queries/pic
import processAvifImage from '../../util/processAvifImage.js';
import newFullHash from '../../util/newFullHash.js';
import resolveCategoryAccess from './resolveCategoryAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
export default function addImage(provider) {
const access = resolveCategoryAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const getSortSql = isSqlite ? SQLITE_GET_NEXT_SORT : MSSQL_GET_NEXT_SORT;
@@ -42,7 +44,7 @@ export default function addImage(provider) {
const fullHash = newFullHash(processed.full.buffer);
const runAdd = async (runner) => {
await access(googleAuthId, categoryId, runner);
const { companyId } = await access(googleAuthId, categoryId, runner);
const sortResult = await runner.query(getSortSql, { categoryId });
const sort = sortResult.rows[0].sort;
@@ -95,6 +97,7 @@ export default function addImage(provider) {
}
await runner.query(touchSql, { categoryId });
await recordSync({ companyId, entityType: 'category', entityId: categoryId }, runner);
return {
id: categoryId,

View File

@@ -9,11 +9,13 @@ import {
import { CREATE as MSSQL_CREATE_CATEGORYTEXT } from '../../providers/mssql/queries/categorytext.js';
import { CREATE as SQLITE_CREATE_CATEGORYTEXT } from '../../providers/sqlite3/queries/categorytext.js';
import resolveCategoryAccess from './resolveCategoryAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import slugify from '../slugify.js';
import makeRunner from '../runner.js';
export default function createUnderParent(provider) {
const access = resolveCategoryAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const getSortSql = isSqlite
@@ -40,7 +42,7 @@ export default function createUnderParent(provider) {
*/
return async ({ googleAuthId, parentId, name }, tx) => {
const runCreate = async (runner) => {
const { languageId } = await access(googleAuthId, parentId, runner);
const { languageId, companyId } = await access(googleAuthId, parentId, runner);
const sortResult = await runner.query(getSortSql, { parentId });
const sort = sortResult.rows[0].sort;
@@ -60,6 +62,8 @@ export default function createUnderParent(provider) {
slug,
});
await recordSync({ companyId, entityType: 'category', entityId: id }, runner);
return {
id,
parentId,

View File

@@ -1,10 +1,12 @@
import { DELETE_BY_CATEGORY as MSSQL_DELETE } from '../../providers/mssql/queries/categorypic.js';
import { DELETE_BY_CATEGORY as SQLITE_DELETE } from '../../providers/sqlite3/queries/categorypic.js';
import resolveCategoryAccess from './resolveCategoryAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
export default function deleteImage(provider) {
const access = resolveCategoryAccess(provider);
const recordSync = recordSyncQueue(provider);
const sql = provider?.dialect === 'sqlite3' ? SQLITE_DELETE : MSSQL_DELETE;
const isSqlite = provider?.dialect === 'sqlite3';
const touchSql = isSqlite
@@ -26,7 +28,7 @@ export default function deleteImage(provider) {
*/
return async (googleAuthId, categoryId, tx) => {
const runner = makeRunner(provider, tx);
await access(googleAuthId, categoryId, runner);
const { companyId } = await access(googleAuthId, categoryId, runner);
const result = await runner.query(sql, { categoryId });
@@ -35,6 +37,7 @@ export default function deleteImage(provider) {
}
await runner.query(touchSql, { categoryId });
await recordSync({ companyId, entityType: 'category', entityId: categoryId }, runner);
return {
id: categoryId,

View File

@@ -11,6 +11,7 @@ import {
import { CREATE as MSSQL_CREATE_CATEGORYTEXT } from '../../providers/mssql/queries/categorytext.js';
import { CREATE as SQLITE_CREATE_CATEGORYTEXT } from '../../providers/sqlite3/queries/categorytext.js';
import resolveCategoryAccess from './resolveCategoryAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import slugify from '../slugify.js';
import makeRunner from '../runner.js';
@@ -25,6 +26,7 @@ export function splitPath(path) {
export default function ensureByPath(provider) {
const access = resolveCategoryAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const getSortSql = isSqlite
@@ -61,7 +63,7 @@ export default function ensureByPath(provider) {
let currentId = parentId;
const createCategory = async (runner, parentId, name, languageId) => {
const createCategory = async (runner, parentId, name, languageId, companyId) => {
const sortResult = await runner.query(getSortSql, { parentId });
const sort = sortResult.rows[0].sort;
const slug = slugify(name);
@@ -79,11 +81,13 @@ export default function ensureByPath(provider) {
slug,
});
await recordSync({ companyId, entityType: 'category', entityId: id }, runner);
return id;
};
for (const name of names) {
const { languageId } = await access(googleAuthId, currentId, tx);
const { languageId, companyId } = await access(googleAuthId, currentId, tx);
const existing = await makeRunner(provider, tx).query(getByNameSql, {
parentId: currentId,
@@ -98,17 +102,17 @@ export default function ensureByPath(provider) {
if (tx) {
// Run within the caller's transaction (e.g. article import row).
currentId = await createCategory(makeRunner(provider, tx), currentId, name, languageId);
currentId = await createCategory(makeRunner(provider, tx), currentId, name, languageId, companyId);
continue;
}
// Standalone use: own transaction per created category.
if (typeof provider?.transaction === 'function') {
currentId = await provider.transaction((runner) =>
createCategory(runner, currentId, name, languageId),
createCategory(runner, currentId, name, languageId, companyId),
);
} else {
currentId = await createCategory(makeRunner(provider), currentId, name, languageId);
currentId = await createCategory(makeRunner(provider), currentId, name, languageId, companyId);
}
}

View File

@@ -4,6 +4,8 @@ import {
MOVE as MSSQL_MOVE,
TOUCH_SUBTREE_CATEGORIES as MSSQL_TOUCH_SUBTREE_CATEGORIES,
TOUCH_SUBTREE_ARTICLES as MSSQL_TOUCH_SUBTREE_ARTICLES,
ENQUEUE_SUBTREE_CATEGORIES_SYNC as MSSQL_ENQUEUE_SUBTREE_CATEGORIES,
ENQUEUE_SUBTREE_ARTICLES_SYNC as MSSQL_ENQUEUE_SUBTREE_ARTICLES,
} from '../../providers/mssql/queries/category.js';
import {
GET_NEXT_SIBLING_SORT as SQLITE_GET_NEXT_SIBLING_SORT,
@@ -11,6 +13,8 @@ import {
MOVE as SQLITE_MOVE,
TOUCH_SUBTREE_CATEGORIES as SQLITE_TOUCH_SUBTREE_CATEGORIES,
TOUCH_SUBTREE_ARTICLES as SQLITE_TOUCH_SUBTREE_ARTICLES,
ENQUEUE_SUBTREE_CATEGORIES_SYNC as SQLITE_ENQUEUE_SUBTREE_CATEGORIES,
ENQUEUE_SUBTREE_ARTICLES_SYNC as SQLITE_ENQUEUE_SUBTREE_ARTICLES,
} from '../../providers/sqlite3/queries/category.js';
import resolveCategoryAccess from './resolveCategoryAccess.js';
import makeRunner from '../runner.js';
@@ -30,6 +34,12 @@ export default function move(provider) {
const touchArticlesSql = isSqlite
? SQLITE_TOUCH_SUBTREE_ARTICLES
: MSSQL_TOUCH_SUBTREE_ARTICLES;
const enqueueCategoriesSql = isSqlite
? SQLITE_ENQUEUE_SUBTREE_CATEGORIES
: MSSQL_ENQUEUE_SUBTREE_CATEGORIES;
const enqueueArticlesSql = isSqlite
? SQLITE_ENQUEUE_SUBTREE_ARTICLES
: MSSQL_ENQUEUE_SUBTREE_ARTICLES;
/**
* Moves a category to a new parent, preventing cycles and cross-company moves.
@@ -82,6 +92,8 @@ export default function move(provider) {
await runner.query(touchCategoriesSql, { id });
await runner.query(touchArticlesSql, { id });
await runner.query(enqueueCategoriesSql, { id, companyId: source.companyId });
await runner.query(enqueueArticlesSql, { id, companyId: source.companyId });
return { id, parentId, sort };
};

View File

@@ -7,10 +7,12 @@ import {
UPDATE_SORT as SQLITE_UPDATE_SORT,
} from '../../providers/sqlite3/queries/category.js';
import resolveCategoryAccess from './resolveCategoryAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
export default function order(provider) {
const access = resolveCategoryAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const listChildIdsSql = isSqlite
? SQLITE_LIST_CHILD_IDS
@@ -39,7 +41,7 @@ export default function order(provider) {
const runOrder = async (runner) => {
// Auth + ensures parentId is a real category of the user's company.
await access(googleAuthId, parentId, runner);
const { companyId } = await access(googleAuthId, parentId, runner);
const children = await runner.query(listChildIdsSql, { parentId });
@@ -63,6 +65,7 @@ export default function order(provider) {
parentId,
sort,
});
await recordSync({ companyId, entityType: 'category', entityId: categoryIds[sort] }, runner);
}
return { categoryIds };

View File

@@ -1,11 +1,13 @@
import { UPDATE_BY_CATEGORY_AND_LANGUAGE as MSSQL_UPDATE } from '../../providers/mssql/queries/categorytext.js';
import { UPDATE_BY_CATEGORY_AND_LANGUAGE as SQLITE_UPDATE } from '../../providers/sqlite3/queries/categorytext.js';
import resolveCategoryAccess from './resolveCategoryAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import slugify from '../slugify.js';
import makeRunner from '../runner.js';
export default function rename(provider) {
const access = resolveCategoryAccess(provider);
const recordSync = recordSyncQueue(provider);
const sql = provider?.dialect === 'sqlite3' ? SQLITE_UPDATE : MSSQL_UPDATE;
const isSqlite = provider?.dialect === 'sqlite3';
const touchSql = isSqlite
@@ -33,7 +35,7 @@ export default function rename(provider) {
}
const cleaned = name.trim();
const { languageId } = await access(googleAuthId, id, tx);
const { languageId, companyId } = await access(googleAuthId, id, tx);
const slug = slugify(cleaned);
@@ -50,6 +52,7 @@ export default function rename(provider) {
}
await runner.query(touchSql, { categoryId: id });
await recordSync({ companyId, entityType: 'category', entityId: id }, runner);
return { id, name: cleaned, slug };
};

View File

@@ -9,10 +9,12 @@ import {
GET_VALUE_DETAIL as SQLITE_GET_DETAIL,
} from '../../providers/sqlite3/queries/categoryattributevalue.js';
import resolveCategoryAccess from '../category/resolveCategoryAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
export default function setByCategoryId(provider) {
const resolve = resolveCategoryAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const deleteSql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
const insertSql = isSqlite ? SQLITE_INSERT : MSSQL_INSERT;
@@ -140,6 +142,7 @@ export default function setByCategoryId(provider) {
? "UPDATE category SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = @categoryId"
: 'UPDATE category SET updated_at = SYSUTCDATETIME() WHERE id = @categoryId';
await runner.query(touchSql, { categoryId });
await recordSync({ companyId, entityType: 'category', entityId: categoryId }, runner);
return inserted;
};

View File

@@ -5,10 +5,12 @@ import {
DELETE_BY_CATEGORY_AND_PROPERTY_ID as SQLITE_DELETE,
} from '../../providers/sqlite3/queries/categoryproperty.js';
import resolveCategoryAccess from '../category/resolveCategoryAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
export default function deleteCategoryProperty(provider) {
const resolve = resolveCategoryAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const deleteSql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
@@ -23,7 +25,7 @@ export default function deleteCategoryProperty(provider) {
*/
return async (googleAuthId, categoryId, propertyId, tx) => {
const runner = makeRunner(provider, tx);
await resolve(googleAuthId, categoryId, runner);
const { companyId } = await resolve(googleAuthId, categoryId, runner);
await runner.query(deleteSql, { categoryId, propertyId });
@@ -32,5 +34,6 @@ export default function deleteCategoryProperty(provider) {
? "UPDATE category SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = @categoryId"
: 'UPDATE category SET updated_at = SYSUTCDATETIME() WHERE id = @categoryId';
await runner.query(touchSql, { categoryId });
await recordSync({ companyId, entityType: 'category', entityId: categoryId }, runner);
};
}

View File

@@ -13,10 +13,12 @@ import {
GET_BY_COMPANY_AND_ID as SQLITE_GET_PROP,
} from '../../providers/sqlite3/queries/propertyname.js';
import resolveCategoryAccess from '../category/resolveCategoryAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
export default function setByCategoryId(provider) {
const resolve = resolveCategoryAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const deleteSql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
const insertSql = isSqlite ? SQLITE_INSERT : MSSQL_INSERT;
@@ -102,6 +104,7 @@ export default function setByCategoryId(provider) {
? "UPDATE category SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = @categoryId"
: 'UPDATE category SET updated_at = SYSUTCDATETIME() WHERE id = @categoryId';
await runner.query(touchSql, { categoryId });
await recordSync({ companyId, entityType: 'category', entityId: categoryId }, runner);
return inserted;
};

View File

@@ -8,6 +8,7 @@ import {
} from '../../providers/sqlite3/queries/customergroup.js';
import { POS_GROUP_NAME, SUPPLIER_GROUP_NAME } from '../../providers/mssql/queries/entity.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
const RESERVED_NAMES = new Set([POS_GROUP_NAME, SUPPLIER_GROUP_NAME]);
@@ -18,6 +19,7 @@ function shape(row) {
export default function create(provider) {
const access = resolveSelectedCompanyAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const getSortSql = isSqlite ? SQLITE_GET_NEXT_SORT : MSSQL_GET_NEXT_SORT;
const createSql = isSqlite ? SQLITE_CREATE : MSSQL_CREATE;
@@ -58,6 +60,7 @@ export default function create(provider) {
});
const row = result.rows[0] ?? { id: result.insertId, name: cleaned, sort };
await recordSync({ companyId, entityType: 'customergroup', entityId: row.id }, runner);
return shape(row);
};
}

View File

@@ -7,10 +7,12 @@ import {
UPDATE_SORT as SQLITE_UPDATE_SORT,
} from '../../providers/sqlite3/queries/customergroup.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
export default function order(provider) {
const access = resolveSelectedCompanyAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const listIdsSql = isSqlite
? SQLITE_LIST_IDS_BY_COMPANY
@@ -65,6 +67,7 @@ export default function order(provider) {
companyId,
sort,
});
await recordSync({ companyId, entityType: 'customergroup', entityId: customergroupIds[sort] }, runner);
}
return { customergroupIds };

View File

@@ -8,6 +8,7 @@ import {
} from '../../providers/sqlite3/queries/customergroup.js';
import { POS_GROUP_NAME, SUPPLIER_GROUP_NAME } from '../../providers/mssql/queries/entity.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
const LOCKED_NAMES = new Set([POS_GROUP_NAME, SUPPLIER_GROUP_NAME]);
@@ -18,6 +19,7 @@ function shape(row) {
export default function update(provider) {
const access = resolveSelectedCompanyAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const getSql = isSqlite
? SQLITE_GET_BY_COMPANY_AND_ID
@@ -70,6 +72,7 @@ export default function update(provider) {
});
const row = result.rows[0] ?? { id, name: cleaned, sort: current.sort };
await recordSync({ companyId, entityType: 'customergroup', entityId: id }, runner);
return shape(row);
};
}

View File

@@ -5,6 +5,7 @@ import { INSERT as SQLITE_INSERT_HISTORY } from '../../providers/sqlite3/queries
import { isUniqueConstraintError } from '../../providers/provider.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import resolveCustomerGroupAccess from '../customergroup/resolveCustomerGroupAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import nextNumber from '../numbers/nextNumber.js';
import shape from './shape.js';
import makeRunner from '../runner.js';
@@ -12,6 +13,7 @@ import makeRunner from '../runner.js';
export default function create(provider) {
const access = resolveSelectedCompanyAccess(provider);
const groupAccess = resolveCustomerGroupAccess(provider);
const recordSync = recordSyncQueue(provider);
const allocateNumber = nextNumber(provider);
const isSqlite = provider?.dialect === 'sqlite3';
@@ -82,6 +84,8 @@ export default function create(provider) {
text: 'Erstellt',
});
await recordSync({ companyId, entityType: 'customer', entityId: row.id }, runner);
return shape(row);
} catch (err) {
if (isUniqueConstraintError(err)) {

View File

@@ -10,11 +10,13 @@ import { INSERT as MSSQL_INSERT_HISTORY } from '../../providers/mssql/queries/en
import { INSERT as SQLITE_INSERT_HISTORY } from '../../providers/sqlite3/queries/entityhistory.js';
import { isUniqueConstraintError } from '../../providers/provider.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import shape from './shape.js';
import makeRunner from '../runner.js';
export default function update(provider) {
const access = resolveSelectedCompanyAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const getSql = isSqlite
? SQLITE_GET_BY_COMPANY_AND_ID
@@ -134,6 +136,8 @@ export default function update(provider) {
text: historyLines.join('\n'),
});
await recordSync({ companyId, entityType: 'customer', entityId: id }, runner);
return shape(row);
} catch (err) {
if (isUniqueConstraintError(err)) {

View File

@@ -6,8 +6,11 @@ import {
CREATE as SQLITE_CREATE,
GET_NEXT_SORT as SQLITE_GET_NEXT_SORT,
} from '../../providers/sqlite3/queries/entityaddress.js';
import { TOUCH_UPDATED_AT as MSSQL_TOUCH_ENTITY } from '../../providers/mssql/queries/entity.js';
import { TOUCH_UPDATED_AT as SQLITE_TOUCH_ENTITY } from '../../providers/sqlite3/queries/entity.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
function shape(row) {
@@ -35,9 +38,11 @@ function optionalString(value) {
export default function create(provider) {
const access = resolveSelectedCompanyAccess(provider);
const entityAccess = resolveEntityAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const getSortSql = isSqlite ? SQLITE_GET_NEXT_SORT : MSSQL_GET_NEXT_SORT;
const createSql = isSqlite ? SQLITE_CREATE : MSSQL_CREATE;
const touchEntitySql = isSqlite ? SQLITE_TOUCH_ENTITY : MSSQL_TOUCH_ENTITY;
/**
* Creates a new address for an entity.
@@ -109,6 +114,9 @@ export default function create(provider) {
sort,
};
await runner.query(touchEntitySql, { id: entityId });
await recordSync({ companyId, entityType: 'customer', entityId }, runner);
return shape(row);
};
}

View File

@@ -1,13 +1,19 @@
import { DELETE_BY_ENTITY_AND_ID as MSSQL_DELETE } from '../../providers/mssql/queries/entityaddress.js';
import { DELETE_BY_ENTITY_AND_ID as SQLITE_DELETE } from '../../providers/sqlite3/queries/entityaddress.js';
import { TOUCH_UPDATED_AT as MSSQL_TOUCH_ENTITY } from '../../providers/mssql/queries/entity.js';
import { TOUCH_UPDATED_AT as SQLITE_TOUCH_ENTITY } from '../../providers/sqlite3/queries/entity.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
export default function del(provider) {
const access = resolveSelectedCompanyAccess(provider);
const entityAccess = resolveEntityAccess(provider);
const sql = provider?.dialect === 'sqlite3' ? SQLITE_DELETE : MSSQL_DELETE;
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const sql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
const touchEntitySql = isSqlite ? SQLITE_TOUCH_ENTITY : MSSQL_TOUCH_ENTITY;
/**
* Deletes an address of an entity.
@@ -39,5 +45,8 @@ export default function del(provider) {
if (!result.rowsAffected) {
throw new Error('Address not found');
}
await runner.query(touchEntitySql, { id: entityId });
await recordSync({ companyId, entityType: 'customer', entityId }, runner);
};
}

View File

@@ -6,8 +6,11 @@ import {
GET_BY_ENTITY_AND_ID as SQLITE_GET_BY_ENTITY_AND_ID,
UPDATE as SQLITE_UPDATE,
} from '../../providers/sqlite3/queries/entityaddress.js';
import { TOUCH_UPDATED_AT as MSSQL_TOUCH_ENTITY } from '../../providers/mssql/queries/entity.js';
import { TOUCH_UPDATED_AT as SQLITE_TOUCH_ENTITY } from '../../providers/sqlite3/queries/entity.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
function shape(row) {
@@ -35,11 +38,13 @@ function optionalString(value) {
export default function update(provider) {
const access = resolveSelectedCompanyAccess(provider);
const entityAccess = resolveEntityAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const getSql = isSqlite
? SQLITE_GET_BY_ENTITY_AND_ID
: MSSQL_GET_BY_ENTITY_AND_ID;
const updateSql = isSqlite ? SQLITE_UPDATE : MSSQL_UPDATE;
const touchEntitySql = isSqlite ? SQLITE_TOUCH_ENTITY : MSSQL_TOUCH_ENTITY;
/**
* Updates an address of an entity.
@@ -152,6 +157,9 @@ export default function update(provider) {
sort,
};
await runner.query(touchEntitySql, { id: entityId });
await recordSync({ companyId, entityType: 'customer', entityId }, runner);
return shape(row);
};
}

View File

@@ -6,8 +6,11 @@ import {
CREATE as SQLITE_CREATE,
GET_NEXT_SORT as SQLITE_GET_NEXT_SORT,
} from '../../providers/sqlite3/queries/entitycontact.js';
import { TOUCH_UPDATED_AT as MSSQL_TOUCH_ENTITY } from '../../providers/mssql/queries/entity.js';
import { TOUCH_UPDATED_AT as SQLITE_TOUCH_ENTITY } from '../../providers/sqlite3/queries/entity.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
function shape(row) {
@@ -23,9 +26,11 @@ function shape(row) {
export default function create(provider) {
const access = resolveSelectedCompanyAccess(provider);
const entityAccess = resolveEntityAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const getSortSql = isSqlite ? SQLITE_GET_NEXT_SORT : MSSQL_GET_NEXT_SORT;
const createSql = isSqlite ? SQLITE_CREATE : MSSQL_CREATE;
const touchEntitySql = isSqlite ? SQLITE_TOUCH_ENTITY : MSSQL_TOUCH_ENTITY;
/**
* Creates a new contact for an entity.
@@ -80,6 +85,9 @@ export default function create(provider) {
sort,
};
await runner.query(touchEntitySql, { id: entityId });
await recordSync({ companyId, entityType: 'customer', entityId }, runner);
return shape(row);
};
}

View File

@@ -1,13 +1,19 @@
import { DELETE_BY_ENTITY_AND_ID as MSSQL_DELETE } from '../../providers/mssql/queries/entitycontact.js';
import { DELETE_BY_ENTITY_AND_ID as SQLITE_DELETE } from '../../providers/sqlite3/queries/entitycontact.js';
import { TOUCH_UPDATED_AT as MSSQL_TOUCH_ENTITY } from '../../providers/mssql/queries/entity.js';
import { TOUCH_UPDATED_AT as SQLITE_TOUCH_ENTITY } from '../../providers/sqlite3/queries/entity.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
export default function del(provider) {
const access = resolveSelectedCompanyAccess(provider);
const entityAccess = resolveEntityAccess(provider);
const sql = provider?.dialect === 'sqlite3' ? SQLITE_DELETE : MSSQL_DELETE;
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const sql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
const touchEntitySql = isSqlite ? SQLITE_TOUCH_ENTITY : MSSQL_TOUCH_ENTITY;
/**
* Deletes a contact of an entity.
@@ -39,5 +45,8 @@ export default function del(provider) {
if (!result.rowsAffected) {
throw new Error('Contact not found');
}
await runner.query(touchEntitySql, { id: entityId });
await recordSync({ companyId, entityType: 'customer', entityId }, runner);
};
}

View File

@@ -6,8 +6,11 @@ import {
GET_BY_ENTITY_AND_ID as SQLITE_GET_BY_ENTITY_AND_ID,
UPDATE as SQLITE_UPDATE,
} from '../../providers/sqlite3/queries/entitycontact.js';
import { TOUCH_UPDATED_AT as MSSQL_TOUCH_ENTITY } from '../../providers/mssql/queries/entity.js';
import { TOUCH_UPDATED_AT as SQLITE_TOUCH_ENTITY } from '../../providers/sqlite3/queries/entity.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
import recordSyncQueue from '../posterminal/recordSyncQueue.js';
import makeRunner from '../runner.js';
function shape(row) {
@@ -23,11 +26,13 @@ function shape(row) {
export default function update(provider) {
const access = resolveSelectedCompanyAccess(provider);
const entityAccess = resolveEntityAccess(provider);
const recordSync = recordSyncQueue(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const getSql = isSqlite
? SQLITE_GET_BY_ENTITY_AND_ID
: MSSQL_GET_BY_ENTITY_AND_ID;
const updateSql = isSqlite ? SQLITE_UPDATE : MSSQL_UPDATE;
const touchEntitySql = isSqlite ? SQLITE_TOUCH_ENTITY : MSSQL_TOUCH_ENTITY;
/**
* Updates a contact of an entity.
@@ -100,6 +105,9 @@ export default function update(provider) {
sort,
};
await runner.query(touchEntitySql, { id: entityId });
await recordSync({ companyId, entityType: 'customer', entityId }, runner);
return shape(row);
};
}

View File

@@ -14,10 +14,14 @@ import makeRunner from '../runner.js';
import {
TOUCH_UPDATED_AT as MSSQL_TOUCH,
TOUCH_STUECKLISTE_ARTICLES_UPDATED_AT as MSSQL_TOUCH_STUECKLISTE,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
ENQUEUE_STUECKLISTE_ARTICLES_SYNC as MSSQL_ENQUEUE_STUECKLISTE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
TOUCH_STUECKLISTE_ARTICLES_UPDATED_AT as SQLITE_TOUCH_STUECKLISTE,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
ENQUEUE_STUECKLISTE_ARTICLES_SYNC as SQLITE_ENQUEUE_STUECKLISTE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
export const INIT_HASH = 'TODO_TSE_BASED_INITHASH';
@@ -218,6 +222,12 @@ export default function add(provider) {
const touchStuecklisteSql = isSqlite ? SQLITE_TOUCH_STUECKLISTE : MSSQL_TOUCH_STUECKLISTE;
await runner.query(touchSql, { articleId: match.id });
await runner.query(touchStuecklisteSql, { articleId: match.id });
if (!isTracked) {
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
const enqueueStuecklisteSyncSql = isSqlite ? SQLITE_ENQUEUE_STUECKLISTE_SYNC : MSSQL_ENQUEUE_STUECKLISTE_SYNC;
await runner.query(enqueueSyncSql, { articleId: match.id });
await runner.query(enqueueStuecklisteSyncSql, { articleId: match.id });
}
await recordAcceptanceHistory(runner, {
articleId: match.id,
companyuserId,
@@ -312,6 +322,12 @@ export default function add(provider) {
const touchStuecklisteSql = isSqlite ? SQLITE_TOUCH_STUECKLISTE : MSSQL_TOUCH_STUECKLISTE;
await runner.query(touchSql, { articleId: match.id });
await runner.query(touchStuecklisteSql, { articleId: match.id });
if (!isTracked) {
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
const enqueueStuecklisteSyncSql = isSqlite ? SQLITE_ENQUEUE_STUECKLISTE_SYNC : MSSQL_ENQUEUE_STUECKLISTE_SYNC;
await runner.query(enqueueSyncSql, { articleId: match.id });
await runner.query(enqueueStuecklisteSyncSql, { articleId: match.id });
}
await recordShipmentHistory(runner, {
articleId: match.id,
companyuserId,

View File

@@ -1,7 +1,13 @@
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 {
TOUCH_UPDATED_AT as MSSQL_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as MSSQL_ENQUEUE_SYNC,
} from '../../providers/mssql/queries/article.js';
import {
TOUCH_UPDATED_AT as SQLITE_TOUCH,
ENQUEUE_SYNC_BY_ARTICLE as SQLITE_ENQUEUE_SYNC,
} from '../../providers/sqlite3/queries/article.js';
import resolveArticleBySku from '../article/resolveArticleBySku.js';
import getOptionsByArticleSku from './getOptionsByArticleSku.js';
import {
@@ -49,6 +55,7 @@ export default function setOptionsByArticleSku(provider) {
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteQueries : mssqlQueries;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
const enqueueSyncSql = isSqlite ? SQLITE_ENQUEUE_SYNC : MSSQL_ENQUEUE_SYNC;
/**
* Sets or clears the options list for an article.
@@ -112,6 +119,7 @@ export default function setOptionsByArticleSku(provider) {
});
}
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
}
return [];
}
@@ -242,6 +250,7 @@ export default function setOptionsByArticleSku(provider) {
// Touch article updated_at so POS and other consumers pick up options/deposit changes
await runner.query(touchArticleSql, { articleId });
await runner.query(enqueueSyncSql, { articleId });
return result;
};

View File

@@ -4,19 +4,18 @@ import makeRunner from '../runner.js';
function normalizeCursor(cursor) {
const n = Number(cursor) || 0;
if (n <= 0) return 0;
return n >= 1e11 ? Math.floor(n / 1000) : Math.floor(n);
return n > 0 ? Math.floor(n) : 0;
}
export default function getCategoryCount(provider) {
const sql = provider?.dialect === 'sqlite3' ? SQLITE_SQL : MSSQL_SQL;
/**
* Counts categories assigned to the POS terminal updated after the given unix timestamp cursor.
* Counts categories assigned to the POS terminal queued after the given sync queue cursor ID.
*
* @param {object} input
* @param {number} input.posterminalId - The POS terminal id.
* @param {number} [input.cursor=0] - Unix timestamp cursor of last update.
* @param {number} [input.cursor=0] - Sequential ID cursor of last synced posterminalsyncqueue entry.
* @param {object} [tx] - Optional transaction to run within.
* @returns {Promise<number>} The count of changed records.
*/

View File

@@ -4,19 +4,18 @@ import makeRunner from '../runner.js';
function normalizeCursor(cursor) {
const n = Number(cursor) || 0;
if (n <= 0) return 0;
return n >= 1e11 ? Math.floor(n / 1000) : Math.floor(n);
return n > 0 ? Math.floor(n) : 0;
}
export default function getCategoryList(provider) {
const sql = provider?.dialect === 'sqlite3' ? SQLITE_SQL : MSSQL_SQL;
/**
* Lists categories for a POS terminal modified after the cursor.
* Lists categories for a POS terminal queued after the sync queue cursor ID.
*
* @param {object} input
* @param {number} input.posterminalId - The POS terminal id.
* @param {number} [input.cursor=0] - Unix timestamp cursor.
* @param {number} [input.cursor=0] - Sequential ID cursor of last synced posterminalsyncqueue entry.
* @param {number} [input.limit=20] - Max items to return.
* @param {object} [tx] - Optional transaction.
* @returns {Promise<Array<object>>}

View File

@@ -4,21 +4,18 @@ import makeRunner from '../runner.js';
function normalizeCursor(cursor) {
const n = Number(cursor) || 0;
if (n <= 0) return 0;
if (n < 1e11) return Math.floor(n * 1000000);
if (n < 1e14) return Math.floor((n / 1000) * 1000000);
return Math.floor(n);
return n > 0 ? Math.floor(n) : 0;
}
export default function getCompositeProductCount(provider) {
const sql = provider?.dialect === 'sqlite3' ? SQLITE_SQL : MSSQL_SQL;
/**
* Counts composite products (Stücklisten) assigned to the POS terminal updated after the given unix timestamp cursor.
* Counts composite products (Stücklisten) assigned to the POS terminal queued after the given sync queue cursor ID.
*
* @param {object} input
* @param {number} input.posterminalId - The POS terminal id.
* @param {number} [input.cursor=0] - Unix timestamp cursor of last update.
* @param {number} [input.cursor=0] - Sequential ID cursor of last synced posterminalsyncqueue entry.
* @param {object} [tx] - Optional transaction to run within.
* @returns {Promise<number>} The count of changed records.
*/

View File

@@ -4,19 +4,18 @@ import makeRunner from '../runner.js';
function normalizeCursor(cursor) {
const n = Number(cursor) || 0;
if (n <= 0) return 0;
return n >= 1e11 ? Math.floor(n / 1000) : Math.floor(n);
return n > 0 ? Math.floor(n) : 0;
}
export default function getCustomerCount(provider) {
const sql = provider?.dialect === 'sqlite3' ? SQLITE_SQL : MSSQL_SQL;
/**
* Counts customers of the POS terminal company updated after the given unix timestamp cursor.
* Counts customers of the POS terminal company queued after the given sync queue cursor ID.
*
* @param {object} input
* @param {number} input.posterminalId - The POS terminal id.
* @param {number} [input.cursor=0] - Unix timestamp cursor of last update.
* @param {number} [input.cursor=0] - Sequential ID cursor of last synced posterminalsyncqueue entry.
* @param {object} [tx] - Optional transaction to run within.
* @returns {Promise<number>} The count of changed records.
*/

View File

@@ -4,19 +4,18 @@ import makeRunner from '../runner.js';
function normalizeCursor(cursor) {
const n = Number(cursor) || 0;
if (n <= 0) return 0;
return n >= 1e11 ? Math.floor(n / 1000) : Math.floor(n);
return n > 0 ? Math.floor(n) : 0;
}
export default function getCustomerGroupCount(provider) {
const sql = provider?.dialect === 'sqlite3' ? SQLITE_SQL : MSSQL_SQL;
/**
* Counts customer groups of the POS terminal company updated after the given unix timestamp cursor.
* Counts customer groups of the POS terminal company queued after the given sync queue cursor ID.
*
* @param {object} input
* @param {number} input.posterminalId - The POS terminal id.
* @param {number} [input.cursor=0] - Unix timestamp cursor of last update.
* @param {number} [input.cursor=0] - Sequential ID cursor of last synced posterminalsyncqueue entry.
* @param {object} [tx] - Optional transaction to run within.
* @returns {Promise<number>} The count of changed records.
*/

View File

@@ -4,19 +4,18 @@ import makeRunner from '../runner.js';
function normalizeCursor(cursor) {
const n = Number(cursor) || 0;
if (n <= 0) return 0;
return n >= 1e11 ? Math.floor(n / 1000) : Math.floor(n);
return n > 0 ? Math.floor(n) : 0;
}
export default function getCustomerGroupList(provider) {
const sql = provider?.dialect === 'sqlite3' ? SQLITE_SQL : MSSQL_SQL;
/**
* Lists customer groups for a POS terminal modified after the cursor, excluding 'Lieferanten'.
* Lists customer groups for a POS terminal queued after the sync queue cursor ID, excluding 'Lieferanten'.
*
* @param {object} input
* @param {number} input.posterminalId - The POS terminal id.
* @param {number} [input.cursor=0] - Unix timestamp cursor.
* @param {number} [input.cursor=0] - Sequential ID cursor of last synced posterminalsyncqueue entry.
* @param {number} [input.limit=50] - Max items to return.
* @param {object} [tx] - Optional transaction.
* @returns {Promise<Array<{customerGroupId: string, name: string, standard: string, discountPercent: string, lastChanged: string}>>}

View File

@@ -4,19 +4,18 @@ import makeRunner from '../runner.js';
function normalizeCursor(cursor) {
const n = Number(cursor) || 0;
if (n <= 0) return 0;
return n >= 1e11 ? Math.floor(n / 1000) : Math.floor(n);
return n > 0 ? Math.floor(n) : 0;
}
export default function getCustomerList(provider) {
const sql = provider?.dialect === 'sqlite3' ? SQLITE_SQL : MSSQL_SQL;
/**
* Lists customers for a POS terminal modified after the cursor, excluding 'Lieferanten'.
* Lists customers for a POS terminal queued after the sync queue cursor ID, excluding 'Lieferanten'.
*
* @param {object} input
* @param {number} input.posterminalId - The POS terminal id.
* @param {number} [input.cursor=0] - Unix timestamp cursor.
* @param {number} [input.cursor=0] - Sequential ID cursor of last synced posterminalsyncqueue entry.
* @param {number} [input.limit=20] - Max items to return.
* @param {object} [tx] - Optional transaction.
* @returns {Promise<Array<object>>}

View File

@@ -4,21 +4,18 @@ import makeRunner from '../runner.js';
function normalizeCursor(cursor) {
const n = Number(cursor) || 0;
if (n <= 0) return 0;
if (n < 1e11) return Math.floor(n * 1000000);
if (n < 1e14) return Math.floor((n / 1000) * 1000000);
return Math.floor(n);
return n > 0 ? Math.floor(n) : 0;
}
export default function getProductCount(provider) {
const sql = provider?.dialect === 'sqlite3' ? SQLITE_SQL : MSSQL_SQL;
/**
* Counts products assigned to the POS terminal updated after the given unix timestamp cursor.
* Counts products assigned to the POS terminal queued after the given sync queue cursor ID.
*
* @param {object} input
* @param {number} input.posterminalId - The POS terminal id.
* @param {number} [input.cursor=0] - Unix timestamp cursor of last update.
* @param {number} [input.cursor=0] - Sequential ID cursor of last synced posterminalsyncqueue entry.
* @param {object} [tx] - Optional transaction to run within.
* @returns {Promise<number>} The count of changed records.
*/

View File

@@ -18,10 +18,7 @@ import makeRunner from '../runner.js';
function normalizeCursor(cursor) {
const n = Number(cursor) || 0;
if (n <= 0) return 0;
if (n < 1e11) return Math.floor(n * 1000000);
if (n < 1e14) return Math.floor((n / 1000) * 1000000);
return Math.floor(n);
return n > 0 ? Math.floor(n) : 0;
}
function formatDateTime(value) {
@@ -46,11 +43,11 @@ export default function getProductList(provider) {
const parentOptionsSql = isSqlite ? SQLITE_PARENT_OPTIONS : MSSQL_PARENT_OPTIONS;
/**
* Lists products for a POS terminal modified after the cursor.
* Lists products for a POS terminal queued after the sync queue cursor ID.
*
* @param {object} input
* @param {number} input.posterminalId - The POS terminal id.
* @param {number} [input.cursor=0] - Unix timestamp cursor.
* @param {number} [input.cursor=0] - Sequential ID cursor of last synced posterminalsyncqueue entry.
* @param {number} [input.limit=20] - Max items to return.
* @param {object} [tx] - Optional transaction.
* @returns {Promise<Array<object>>}

View File

@@ -0,0 +1,28 @@
import { RECORD_SYNC_QUEUE as MSSQL_SQL } from '../../providers/mssql/queries/posterminal.js';
import { RECORD_SYNC_QUEUE as SQLITE_SQL } from '../../providers/sqlite3/queries/posterminal.js';
import makeRunner from '../runner.js';
export default function recordSyncQueue(provider) {
const sql = provider?.dialect === 'sqlite3' ? SQLITE_SQL : MSSQL_SQL;
/**
* Enqueues a sync notification for all POS terminals of a company.
*
* @param {object} input
* @param {number} input.companyId - The company id.
* @param {string} input.entityType - 'category' | 'article' | 'customer' | 'customergroup'
* @param {number} input.entityId - The entity's id.
* @param {object} [tx] - Optional transaction/runner.
* @returns {Promise<void>}
*/
return async ({ companyId, entityType, entityId }, tx) => {
if (!companyId || !entityType || !entityId) return;
const runner = makeRunner(provider, tx);
await runner.query(sql, {
companyId: Number(companyId),
entityType: String(entityType).toLowerCase().trim(),
entityId: Number(entityId),
});
};
}

View File

@@ -8,6 +8,14 @@ import {
SET_OFF as SQLITE_SET_OFF,
LIST_CATEGORY_IDS as SQLITE_LIST_CATEGORY_IDS,
} from '../../providers/sqlite3/queries/posterminal.js';
import {
ENQUEUE_SUBTREE_CATEGORIES_SYNC as MSSQL_ENQUEUE_SUBTREE_CATEGORIES,
ENQUEUE_SUBTREE_ARTICLES_SYNC as MSSQL_ENQUEUE_SUBTREE_ARTICLES,
} from '../../providers/mssql/queries/category.js';
import {
ENQUEUE_SUBTREE_CATEGORIES_SYNC as SQLITE_ENQUEUE_SUBTREE_CATEGORIES,
ENQUEUE_SUBTREE_ARTICLES_SYNC as SQLITE_ENQUEUE_SUBTREE_ARTICLES,
} from '../../providers/sqlite3/queries/category.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import makeRunner from '../runner.js';
@@ -20,6 +28,12 @@ export default function setOff(provider) {
const listCatIdsSql = isSqlite
? SQLITE_LIST_CATEGORY_IDS
: MSSQL_LIST_CATEGORY_IDS;
const enqueueCategoriesSql = isSqlite
? SQLITE_ENQUEUE_SUBTREE_CATEGORIES
: MSSQL_ENQUEUE_SUBTREE_CATEGORIES;
const enqueueArticlesSql = isSqlite
? SQLITE_ENQUEUE_SUBTREE_ARTICLES
: MSSQL_ENQUEUE_SUBTREE_ARTICLES;
const touchSql = isSqlite
? `WITH RECURSIVE cats AS (
@@ -182,6 +196,8 @@ export default function setOff(provider) {
await runner.query(touchSql, { categoryId });
await runner.query(touchArticlesSql, { categoryId });
await runner.query(enqueueCategoriesSql, { id: categoryId, companyId });
await runner.query(enqueueArticlesSql, { id: categoryId, companyId });
const result = await runner.query(listCatIdsSql, { posterminalId });

View File

@@ -8,6 +8,14 @@ import {
SET_ON as SQLITE_SET_ON,
LIST_CATEGORY_IDS as SQLITE_LIST_CATEGORY_IDS,
} from '../../providers/sqlite3/queries/posterminal.js';
import {
ENQUEUE_SUBTREE_CATEGORIES_SYNC as MSSQL_ENQUEUE_SUBTREE_CATEGORIES,
ENQUEUE_SUBTREE_ARTICLES_SYNC as MSSQL_ENQUEUE_SUBTREE_ARTICLES,
} from '../../providers/mssql/queries/category.js';
import {
ENQUEUE_SUBTREE_CATEGORIES_SYNC as SQLITE_ENQUEUE_SUBTREE_CATEGORIES,
ENQUEUE_SUBTREE_ARTICLES_SYNC as SQLITE_ENQUEUE_SUBTREE_ARTICLES,
} from '../../providers/sqlite3/queries/category.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import makeRunner from '../runner.js';
@@ -20,6 +28,12 @@ export default function setOn(provider) {
const listCatIdsSql = isSqlite
? SQLITE_LIST_CATEGORY_IDS
: MSSQL_LIST_CATEGORY_IDS;
const enqueueCategoriesSql = isSqlite
? SQLITE_ENQUEUE_SUBTREE_CATEGORIES
: MSSQL_ENQUEUE_SUBTREE_CATEGORIES;
const enqueueArticlesSql = isSqlite
? SQLITE_ENQUEUE_SUBTREE_ARTICLES
: MSSQL_ENQUEUE_SUBTREE_ARTICLES;
const touchSql = isSqlite
? `WITH RECURSIVE cats AS (
SELECT id FROM category WHERE id = @categoryId
@@ -166,6 +180,8 @@ export default function setOn(provider) {
await runner.query(touchSql, { categoryId });
await runner.query(touchArticlesSql, { categoryId });
await runner.query(enqueueCategoriesSql, { id: categoryId, companyId });
await runner.query(enqueueArticlesSql, { id: categoryId, companyId });
const result = await runner.query(listCatIdsSql, { posterminalId });

View File

@@ -10,6 +10,8 @@ import {
} from '../../providers/sqlite3/queries/posterminal.js';
import { GET_COMPANY_ROOT_CATEGORY as MSSQL_ROOT } from '../../providers/mssql/queries/company.js';
import { GET_COMPANY_ROOT_CATEGORY as SQLITE_ROOT } from '../../providers/sqlite3/queries/company.js';
import { ENQUEUE_SUBTREE_CATEGORIES_SYNC as MSSQL_ENQUEUE_SUBTREE_CATEGORIES } from '../../providers/mssql/queries/category.js';
import { ENQUEUE_SUBTREE_CATEGORIES_SYNC as SQLITE_ENQUEUE_SUBTREE_CATEGORIES } from '../../providers/sqlite3/queries/category.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import makeRunner from '../runner.js';
@@ -23,6 +25,16 @@ export default function setOnAll(provider) {
? SQLITE_LIST_CATEGORY_IDS
: MSSQL_LIST_CATEGORY_IDS;
const rootSql = isSqlite ? SQLITE_ROOT : MSSQL_ROOT;
const enqueueCategoriesSql = isSqlite
? SQLITE_ENQUEUE_SUBTREE_CATEGORIES
: MSSQL_ENQUEUE_SUBTREE_CATEGORIES;
const enqueueAllArticlesSql = `
INSERT INTO posterminalsyncqueue (posterminal_id, entity_type, entity_id)
SELECT pt.id, 'article', a.id
FROM article a
INNER JOIN posterminal pt ON pt.company_id = a.company_id
WHERE a.company_id = @companyId
`;
const touchAllSql = isSqlite
? `WITH RECURSIVE cats AS (
SELECT id FROM category WHERE id = @rootCategoryId
@@ -100,6 +112,8 @@ export default function setOnAll(provider) {
await runner.query(touchAllSql, { rootCategoryId });
await runner.query(touchAllArticlesSql, { companyId });
await runner.query(enqueueCategoriesSql, { id: rootCategoryId, companyId });
await runner.query(enqueueAllArticlesSql, { companyId });
const result = await runner.query(listCatIdsSql, { posterminalId });

View File

@@ -2,11 +2,13 @@ import {
GET_BY_ID as MSSQL_GET_BY_ID,
CREATE as MSSQL_CREATE,
UPDATE as MSSQL_UPDATE,
SEED_SYNC_QUEUE_FOR_TERMINAL as MSSQL_SEED_SYNC_QUEUE,
} from '../../providers/mssql/queries/posterminal.js';
import {
GET_BY_ID as SQLITE_GET_BY_ID,
CREATE as SQLITE_CREATE,
UPDATE as SQLITE_UPDATE,
SEED_SYNC_QUEUE_FOR_TERMINAL as SQLITE_SEED_SYNC_QUEUE,
} from '../../providers/sqlite3/queries/posterminal.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import makeRunner from '../runner.js';
@@ -18,6 +20,7 @@ export default function upsert(provider) {
const getByIdSql = isSqlite ? SQLITE_GET_BY_ID : MSSQL_GET_BY_ID;
const createSql = isSqlite ? SQLITE_CREATE : MSSQL_CREATE;
const updateSql = isSqlite ? SQLITE_UPDATE : MSSQL_UPDATE;
const seedSyncQueueSql = isSqlite ? SQLITE_SEED_SYNC_QUEUE : MSSQL_SEED_SYNC_QUEUE;
/**
* Creates or updates a posterminal for the user's selected company.
@@ -143,6 +146,11 @@ export default function upsert(provider) {
lastseenAt,
};
await runner.query(seedSyncQueueSql, {
posterminalId: row.id,
companyId,
});
return {
id: row.id,
name: row.name,