diff --git a/src/food-market.web/src/lib/barcode.ts b/src/food-market.web/src/lib/barcode.ts new file mode 100644 index 0000000..37767ad --- /dev/null +++ b/src/food-market.web/src/lib/barcode.ts @@ -0,0 +1,21 @@ +// EAN-13 утилиты. +// +// Внутренние штрихкоды магазина начинаются с "2" — это зарезервированный +// префикс для in-store use, он не пересекается с GTIN реальных товаров +// от производителей. + +function ean13Checksum(first12: string): number { + let sum = 0 + for (let i = 0; i < 12; i++) { + const d = first12.charCodeAt(i) - 48 + sum += i % 2 === 0 ? d : d * 3 + } + return (10 - (sum % 10)) % 10 +} + +/** Сгенерировать внутренний EAN-13 с префиксом "2" и случайной серединой. */ +export function generateEan13InternalPrefix2(): string { + let body = '2' + for (let i = 0; i < 11; i++) body += Math.floor(Math.random() * 10).toString() + return body + ean13Checksum(body).toString() +} diff --git a/src/food-market.web/src/pages/ProductEditPage.tsx b/src/food-market.web/src/pages/ProductEditPage.tsx index 7695df9..7e072e8 100644 --- a/src/food-market.web/src/pages/ProductEditPage.tsx +++ b/src/food-market.web/src/pages/ProductEditPage.tsx @@ -11,6 +11,7 @@ import { import { useOrgSettings } from '@/lib/useOrgSettings' import { BarcodeType, Packaging, type Product } from '@/lib/types' import { ProductImageGallery } from '@/components/ProductImageGallery' +import { generateEan13InternalPrefix2 } from '@/lib/barcode' interface PriceRow { id?: string; priceTypeId: string; amount: number; currencyId: string } interface BarcodeRow { id?: string; code: string; type: BarcodeType; isPrimary: boolean } @@ -167,7 +168,7 @@ export function ProductEditPage() { setForm({ ...form, prices: form.prices.map((p, ix) => ix === i ? { ...p, ...patch } : p) }) const addBarcode = () => setForm({ ...form, barcodes: [...form.barcodes, { - code: '', type: BarcodeType.Ean13, isPrimary: form.barcodes.length === 0, + code: generateEan13InternalPrefix2(), type: BarcodeType.Ean13, isPrimary: form.barcodes.length === 0, }] }) const removeBarcode = (i: number) => setForm({ ...form, barcodes: form.barcodes.filter((_, ix) => ix !== i) })