This commit is contained in:
seb
2026-10-22 23:30:15 +02:00
parent e9b4ac5d79
commit d6e5da93cb
9 changed files with 42 additions and 1 deletions

View File

@@ -222,6 +222,12 @@ SET unit_id = @unitId, unitamount = @unitamount, updated_at = SYSUTCDATETIME()
WHERE id = @articleId WHERE id = @articleId
`; `;
export const TOUCH_UPDATED_AT = `
UPDATE article
SET updated_at = SYSUTCDATETIME()
WHERE id = @articleId
`;
export const CREATE = ` export const CREATE = `
INSERT INTO article (company_id, sku, unit_id, unitamount, weight, track_stock) INSERT INTO article (company_id, sku, unit_id, unitamount, weight, track_stock)
OUTPUT INSERTED.id OUTPUT INSERTED.id

View File

@@ -9,7 +9,7 @@ export const {
GET_CATEGORY_ID_BY_SKU, GET_CATEGORY_TREE_FLAT, GET_ID_BY_SKU, GET_CATEGORY_ID_BY_SKU, GET_CATEGORY_TREE_FLAT, GET_ID_BY_SKU,
LIST_CHILDREN_BY_PARENT_ID, LIST_CHILDREN_BY_PARENT_ID,
SET_PARENT_SORT, SET_PARENT_SORT,
SET_IS_PARENT, TOGGLE_PARENT, UNLINK_CHILD, UPDATE_BRAND, UPDATE_PARENT_BY_SKU, UPDATE_TRACK_STOCK, UPDATE_UNIT, SET_IS_PARENT, TOGGLE_PARENT, TOUCH_UPDATED_AT, UNLINK_CHILD, UPDATE_BRAND, UPDATE_PARENT_BY_SKU, UPDATE_TRACK_STOCK, UPDATE_UNIT,
UPDATE_UNITAMOUNT, UPDATE_UNIT_AND_AMOUNT, UPDATE_WEIGHT, UPDATE_UNITAMOUNT, UPDATE_UNIT_AND_AMOUNT, UPDATE_WEIGHT,
} = queries; } = queries;

View File

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

View File

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

View File

@@ -1,5 +1,7 @@
import * as mssqlPic from '../../providers/mssql/queries/articlepic.js'; import * as mssqlPic from '../../providers/mssql/queries/articlepic.js';
import * as sqlitePic from '../../providers/sqlite3/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 resolveArticleBySku from './resolveArticleBySku.js'; import resolveArticleBySku from './resolveArticleBySku.js';
import { recordImageOrderHistory } from '../articlehistory/record.js'; import { recordImageOrderHistory } from '../articlehistory/record.js';
import makeRunner from '../runner.js'; import makeRunner from '../runner.js';
@@ -8,6 +10,7 @@ export default function orderImages(provider) {
const resolve = resolveArticleBySku(provider); const resolve = resolveArticleBySku(provider);
const isSqlite = provider?.dialect === 'sqlite3'; const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqlitePic : mssqlPic; const queries = isSqlite ? sqlitePic : mssqlPic;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
/** /**
* Reorders the images of an article by its SKU. * Reorders the images of an article by its SKU.
@@ -69,6 +72,7 @@ export default function orderImages(provider) {
companyuserId, companyuserId,
fullHashes, fullHashes,
}); });
await runner.query(touchArticleSql, { articleId });
} }
return { fullHashes }; return { fullHashes };

View File

@@ -1,10 +1,12 @@
import { import {
ADD_CATEGORY as MSSQL_ADD_CATEGORY, ADD_CATEGORY as MSSQL_ADD_CATEGORY,
DELETE_CATEGORIES_BY_ARTICLE as MSSQL_DELETE_CATEGORIES, DELETE_CATEGORIES_BY_ARTICLE as MSSQL_DELETE_CATEGORIES,
TOUCH_UPDATED_AT as MSSQL_TOUCH,
} from '../../providers/mssql/queries/article.js'; } from '../../providers/mssql/queries/article.js';
import { import {
ADD_CATEGORY as SQLITE_ADD_CATEGORY, ADD_CATEGORY as SQLITE_ADD_CATEGORY,
DELETE_CATEGORIES_BY_ARTICLE as SQLITE_DELETE_CATEGORIES, DELETE_CATEGORIES_BY_ARTICLE as SQLITE_DELETE_CATEGORIES,
TOUCH_UPDATED_AT as SQLITE_TOUCH,
} from '../../providers/sqlite3/queries/article.js'; } from '../../providers/sqlite3/queries/article.js';
import resolveCategoryAccess from '../category/resolveCategoryAccess.js'; import resolveCategoryAccess from '../category/resolveCategoryAccess.js';
import queryBySku from './queryBySku.js'; import queryBySku from './queryBySku.js';
@@ -20,6 +22,7 @@ export default function setCategoryIdsBySku(provider) {
const addCategorySql = isSqlite ? SQLITE_ADD_CATEGORY : MSSQL_ADD_CATEGORY; const addCategorySql = isSqlite ? SQLITE_ADD_CATEGORY : MSSQL_ADD_CATEGORY;
const deleteCategoriesSql = isSqlite ? SQLITE_DELETE_CATEGORIES : MSSQL_DELETE_CATEGORIES; const deleteCategoriesSql = isSqlite ? SQLITE_DELETE_CATEGORIES : MSSQL_DELETE_CATEGORIES;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
/** /**
* Replaces the category membership of an article by its SKU. * Replaces the category membership of an article by its SKU.
@@ -91,6 +94,9 @@ export default function setCategoryIdsBySku(provider) {
newCategoryIds: normalized, newCategoryIds: normalized,
}); });
// Touch article updated_at so POS and other consumers pick up category assignment changes
await runner.query(touchArticleSql, { articleId });
const article = await load(articleId, languageId, runner); const article = await load(articleId, languageId, runner);
if (!article) { if (!article) {
throw new Error('Article not found'); throw new Error('Article not found');

View File

@@ -2,11 +2,13 @@ import {
ADD_EAN as MSSQL_ADD_EAN, ADD_EAN as MSSQL_ADD_EAN,
DELETE_EANS_BY_ARTICLE as MSSQL_DELETE_EANS, DELETE_EANS_BY_ARTICLE as MSSQL_DELETE_EANS,
EAN_EXISTS_FOR_OTHER_ARTICLE as MSSQL_CHECK_CONFLICT, EAN_EXISTS_FOR_OTHER_ARTICLE as MSSQL_CHECK_CONFLICT,
TOUCH_UPDATED_AT as MSSQL_TOUCH,
} from '../../providers/mssql/queries/article.js'; } from '../../providers/mssql/queries/article.js';
import { import {
ADD_EAN as SQLITE_ADD_EAN, ADD_EAN as SQLITE_ADD_EAN,
DELETE_EANS_BY_ARTICLE as SQLITE_DELETE_EANS, DELETE_EANS_BY_ARTICLE as SQLITE_DELETE_EANS,
EAN_EXISTS_FOR_OTHER_ARTICLE as SQLITE_CHECK_CONFLICT, EAN_EXISTS_FOR_OTHER_ARTICLE as SQLITE_CHECK_CONFLICT,
TOUCH_UPDATED_AT as SQLITE_TOUCH,
} from '../../providers/sqlite3/queries/article.js'; } from '../../providers/sqlite3/queries/article.js';
import { isUniqueConstraintError } from '../../providers/provider.js'; import { isUniqueConstraintError } from '../../providers/provider.js';
import queryBySku from './queryBySku.js'; import queryBySku from './queryBySku.js';
@@ -22,6 +24,7 @@ export default function setEansBySku(provider) {
const addEanSql = isSqlite ? SQLITE_ADD_EAN : MSSQL_ADD_EAN; const addEanSql = isSqlite ? SQLITE_ADD_EAN : MSSQL_ADD_EAN;
const deleteEansSql = isSqlite ? SQLITE_DELETE_EANS : MSSQL_DELETE_EANS; const deleteEansSql = isSqlite ? SQLITE_DELETE_EANS : MSSQL_DELETE_EANS;
const checkConflictSql = isSqlite ? SQLITE_CHECK_CONFLICT : MSSQL_CHECK_CONFLICT; const checkConflictSql = isSqlite ? SQLITE_CHECK_CONFLICT : MSSQL_CHECK_CONFLICT;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
/** /**
* Replaces the EAN list of an article by its SKU. * Replaces the EAN list of an article by its SKU.
@@ -98,6 +101,9 @@ export default function setEansBySku(provider) {
newEans: normalized, newEans: normalized,
}); });
// Touch article updated_at so POS and other consumers pick up the barcode change
await runner.query(touchArticleSql, { articleId });
const article = await load(articleId, languageId, runner); const article = await load(articleId, languageId, runner);
if (!article) { if (!article) {
throw new Error('Article not found'); throw new Error('Article not found');

View File

@@ -6,6 +6,8 @@ import {
CREATE as SQLITE_CREATE_PRICE, CREATE as SQLITE_CREATE_PRICE,
DELETE_BY_ARTICLE_AND_CUSTOMERGROUP as SQLITE_DELETE_PRICE, DELETE_BY_ARTICLE_AND_CUSTOMERGROUP as SQLITE_DELETE_PRICE,
} from '../../providers/sqlite3/queries/price.js'; } from '../../providers/sqlite3/queries/price.js';
import { TOUCH_UPDATED_AT as MSSQL_TOUCH } from '../../providers/mssql/queries/article.js';
import { TOUCH_UPDATED_AT as SQLITE_TOUCH } from '../../providers/sqlite3/queries/article.js';
import taxEnsure from '../tax/ensure.js'; import taxEnsure from '../tax/ensure.js';
import queryBySku from './queryBySku.js'; import queryBySku from './queryBySku.js';
import resolveArticleBySku from './resolveArticleBySku.js'; import resolveArticleBySku from './resolveArticleBySku.js';
@@ -65,6 +67,7 @@ export default function setPricesBySku(provider) {
const createPriceSql = isSqlite ? SQLITE_CREATE_PRICE : MSSQL_CREATE_PRICE; const createPriceSql = isSqlite ? SQLITE_CREATE_PRICE : MSSQL_CREATE_PRICE;
const deletePriceSql = isSqlite ? SQLITE_DELETE_PRICE : MSSQL_DELETE_PRICE; const deletePriceSql = isSqlite ? SQLITE_DELETE_PRICE : MSSQL_DELETE_PRICE;
const touchArticleSql = isSqlite ? SQLITE_TOUCH : MSSQL_TOUCH;
/** /**
* Replaces the price list of an article by its SKU. * Replaces the price list of an article by its SKU.
@@ -141,6 +144,9 @@ export default function setPricesBySku(provider) {
newPrices: normalized, newPrices: normalized,
}); });
// Touch article updated_at so POS and other consumers pick up the price change
await runner.query(touchArticleSql, { articleId });
const article = await load(articleId, languageId, runner); const article = await load(articleId, languageId, runner);
if (!article) { if (!article) {
throw new Error('Article not found'); throw new Error('Article not found');

View File

@@ -232,6 +232,9 @@ export default function updateBySku(provider) {
}); });
} }
// Touch article updated_at so all consumers pick up changes
await runner.query(articleQueries.TOUCH_UPDATED_AT, { articleId });
const article = await load(articleId, languageId, runner); const article = await load(articleId, languageId, runner);
if (!article) { if (!article) {
throw new Error('Article not found'); throw new Error('Article not found');