food-market/deploy/fix-internal-ean13.sql
nns 6f10896d8c
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
chore(deploy): SQL-скрипты очистки Демо и исправления внутренних EAN-13
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>
2026-10-08 02:10:11 +05:00

65 lines
3.6 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 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));