Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
stage-reset-demo.sql — очистка орги от транзакционных данных (KEEP каталог/ сотрудники/точки). fix-internal-ean13.sql — пересчёт неверной контрольной цифры у уже выданных внутренних EAN-13 (на стенде исправлен 41 код, список — docs/ean13-fixed-20261008.txt). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
65 lines
3.6 KiB
PL/PgSQL
65 lines
3.6 KiB
PL/PgSQL
-- deploy/fix-internal-ean13.sql
|
||
-- Исправление контрольной цифры у внутренних EAN-13 (префикс «2»), которые
|
||
-- веб-генератор выдавал с НЕверной контрольной цифрой (баг digitsChecksum:
|
||
-- веса считались слева, а для 12-значного тела чётность переворачивается).
|
||
-- Фикс генератора — в src/food-market.web/src/lib/barcode.ts; этот скрипт
|
||
-- чинит УЖЕ ВЫДАННЫЕ коды, не теряя связь с товаром (та же строка product_barcodes,
|
||
-- тот же ProductId — меняется только последняя цифра Code).
|
||
--
|
||
-- Идемпотентно. Пропускает коды, у которых исправленный вариант уже занят
|
||
-- в этой организации (во избежание нарушения unique(OrganizationId,Code)) —
|
||
-- такие выводятся отдельно для ручного разбора.
|
||
--
|
||
-- Запуск: ssh nns@192.168.1.190 "docker exec -i food-market-stage-postgres \
|
||
-- psql -U food_market -d food_market" < deploy/fix-internal-ean13.sql
|
||
|
||
CREATE OR REPLACE FUNCTION pg_temp.ean13_check(body text) RETURNS int AS $f$
|
||
DECLARE s int := 0; w int := 3; i int;
|
||
BEGIN
|
||
IF body !~ '^[0-9]{12}$' THEN RETURN -1; END IF;
|
||
FOR i IN REVERSE 12..1 LOOP
|
||
s := s + substr(body,i,1)::int * w;
|
||
w := CASE WHEN w=3 THEN 1 ELSE 3 END;
|
||
END LOOP;
|
||
RETURN (10 - s % 10) % 10;
|
||
END $f$ LANGUAGE plpgsql IMMUTABLE;
|
||
|
||
-- Отчёт: что будет исправлено (старый → новый), с товаром и организацией.
|
||
SELECT pb."OrganizationId", pb."ProductId", p."Name" AS product,
|
||
pb."Code" AS old_code,
|
||
substr(pb."Code",1,12) || pg_temp.ean13_check(substr(pb."Code",1,12))::text AS new_code
|
||
FROM product_barcodes pb
|
||
JOIN products p ON p."Id" = pb."ProductId"
|
||
WHERE pb."Code" ~ '^2[0-9]{12}$'
|
||
AND substr(pb."Code",13,1)::int <> pg_temp.ean13_check(substr(pb."Code",1,12))
|
||
ORDER BY pb."OrganizationId", p."Name";
|
||
|
||
-- Конфликты: исправленный код уже занят в этой орге — НЕ трогаем.
|
||
SELECT pb."Code" AS old_code,
|
||
substr(pb."Code",1,12) || pg_temp.ean13_check(substr(pb."Code",1,12))::text AS new_code,
|
||
pb."OrganizationId"
|
||
FROM product_barcodes pb
|
||
WHERE pb."Code" ~ '^2[0-9]{12}$'
|
||
AND substr(pb."Code",13,1)::int <> pg_temp.ean13_check(substr(pb."Code",1,12))
|
||
AND EXISTS (
|
||
SELECT 1 FROM product_barcodes x
|
||
WHERE x."OrganizationId" = pb."OrganizationId"
|
||
AND x."Code" = substr(pb."Code",1,12) || pg_temp.ean13_check(substr(pb."Code",1,12))::text
|
||
AND x."Id" <> pb."Id");
|
||
|
||
-- Собственно исправление (без конфликтных).
|
||
UPDATE product_barcodes pb
|
||
SET "Code" = substr(pb."Code",1,12) || pg_temp.ean13_check(substr(pb."Code",1,12))::text
|
||
WHERE pb."Code" ~ '^2[0-9]{12}$'
|
||
AND substr(pb."Code",13,1)::int <> pg_temp.ean13_check(substr(pb."Code",1,12))
|
||
AND NOT EXISTS (
|
||
SELECT 1 FROM product_barcodes x
|
||
WHERE x."OrganizationId" = pb."OrganizationId"
|
||
AND x."Code" = substr(pb."Code",1,12) || pg_temp.ean13_check(substr(pb."Code",1,12))::text
|
||
AND x."Id" <> pb."Id");
|
||
|
||
-- Контроль: сколько осталось неверных (должно стать = числу конфликтных).
|
||
SELECT count(*) AS remaining_wrong FROM product_barcodes
|
||
WHERE "Code" ~ '^2[0-9]{12}$'
|
||
AND substr("Code",13,1)::int <> pg_temp.ean13_check(substr("Code",1,12));
|