feat(barcode): авто-генерация EAN-13 при добавлении штрихкода
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 26s
CI / Web (React + Vite) (push) Successful in 24s
Docker Images / API image (push) Successful in 32s
Docker Images / Web image (push) Successful in 26s
Docker Images / Deploy stage (push) Successful in 19s
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 26s
CI / Web (React + Vite) (push) Successful in 24s
Docker Images / API image (push) Successful in 32s
Docker Images / Web image (push) Successful in 26s
Docker Images / Deploy stage (push) Successful in 19s
Новый штрихкод в товаре сразу получает валидный EAN-13 с префиксом "2" (зарезервирован под внутренние штрихкоды магазина, не конфликтует с GTIN производителей). Пользователь может заменить на реальный считанный — поле остаётся редактируемым. Утилита lib/barcode.ts::generateEan13InternalPrefix2() генерирует 11 случайных цифр после "2" и дописывает контрольную сумму EAN-13. Уникальность штрихкода в организации уже обеспечивает IX_product_barcodes_OrganizationId_Code. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
81c586342c
commit
e60cd928d2
21
src/food-market.web/src/lib/barcode.ts
Normal file
21
src/food-market.web/src/lib/barcode.ts
Normal file
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ import {
|
||||||
import { useOrgSettings } from '@/lib/useOrgSettings'
|
import { useOrgSettings } from '@/lib/useOrgSettings'
|
||||||
import { BarcodeType, Packaging, type Product } from '@/lib/types'
|
import { BarcodeType, Packaging, type Product } from '@/lib/types'
|
||||||
import { ProductImageGallery } from '@/components/ProductImageGallery'
|
import { ProductImageGallery } from '@/components/ProductImageGallery'
|
||||||
|
import { generateEan13InternalPrefix2 } from '@/lib/barcode'
|
||||||
|
|
||||||
interface PriceRow { id?: string; priceTypeId: string; amount: number; currencyId: string }
|
interface PriceRow { id?: string; priceTypeId: string; amount: number; currencyId: string }
|
||||||
interface BarcodeRow { id?: string; code: string; type: BarcodeType; isPrimary: boolean }
|
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) })
|
setForm({ ...form, prices: form.prices.map((p, ix) => ix === i ? { ...p, ...patch } : p) })
|
||||||
|
|
||||||
const addBarcode = () => setForm({ ...form, barcodes: [...form.barcodes, {
|
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) =>
|
const removeBarcode = (i: number) =>
|
||||||
setForm({ ...form, barcodes: form.barcodes.filter((_, ix) => ix !== i) })
|
setForm({ ...form, barcodes: form.barcodes.filter((_, ix) => ix !== i) })
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue