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