- lib/barcode.ts: новая утилита generateBarcode(type) — валидные коды под все форматы (EAN-13 с префиксом 2, EAN-8 с checksum, UPC-A с checksum, UPC-E 8 цифр, Code128/Code39 12 буквенно-цифровых). - ProductEditPage: при смене типа штрихкода в dropdown поле кода регенерируется под новый формат. - Field.tsx: единая высота h-10 и leading-none для TextInput/Select чтобы Страна/Валюта/НДС в настройках были одного размера. TextArea оставлен с h-auto для multiline. - Pagination.tsx: рядом с ← → добавлен input «Страница [N] из M» для прыжка на произвольную страницу (Enter / blur применяют). - ProductEditPage: блок мин/макс остатков теперь показывается только при org.showMinMaxStock (сама настройка добавится следующим коммитом). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
74 lines
2.8 KiB
TypeScript
74 lines
2.8 KiB
TypeScript
// Штрихкод-утилиты: генерация валидных кодов под разные форматы.
|
||
//
|
||
// Внутренние EAN-13 магазина начинаются с "2" — зарезервированный префикс
|
||
// для in-store use, не пересекается с GTIN реальных товаров.
|
||
|
||
import { BarcodeType } from '@/lib/types'
|
||
|
||
function digitsChecksum(first: string, weightAtOdd: number): number {
|
||
// Общая EAN/UPC-подобная формула: сумма с чередующимися весами, остаток от 10.
|
||
// Нечётные позиции (с индекса 0) — weightAtOdd, чётные — 1.
|
||
let sum = 0
|
||
for (let i = 0; i < first.length; i++) {
|
||
const d = first.charCodeAt(i) - 48
|
||
sum += i % 2 === 0 ? d * weightAtOdd : d
|
||
}
|
||
return (10 - (sum % 10)) % 10
|
||
}
|
||
|
||
function randomDigits(n: number): string {
|
||
let s = ''
|
||
for (let i = 0; i < n; i++) s += Math.floor(Math.random() * 10).toString()
|
||
return s
|
||
}
|
||
|
||
function randomAlnum(n: number): string {
|
||
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||
let s = ''
|
||
for (let i = 0; i < n; i++) s += alphabet[Math.floor(Math.random() * alphabet.length)]
|
||
return s
|
||
}
|
||
|
||
function ean13(): string {
|
||
const body = '2' + randomDigits(11)
|
||
return body + digitsChecksum(body, 3).toString()
|
||
}
|
||
|
||
function ean8(): string {
|
||
// EAN-8: 7 цифр + checksum. Веса: нечётные×3, чётные×1 (с индекса 0).
|
||
const body = randomDigits(7)
|
||
return body + digitsChecksum(body, 3).toString()
|
||
}
|
||
|
||
function upca(): string {
|
||
// UPC-A: 11 цифр + checksum. Та же формула что у EAN-13.
|
||
const body = randomDigits(11)
|
||
return body + digitsChecksum(body, 3).toString()
|
||
}
|
||
|
||
function upce(): string {
|
||
// Упрощённая генерация: 8 случайных цифр (реальный UPC-E строится через
|
||
// сжатие UPC-A по спецправилам; для внутренних нужд достаточно числовой
|
||
// последовательности нужной длины).
|
||
return randomDigits(8)
|
||
}
|
||
|
||
/** Сгенерировать внутренний EAN-13 с префиксом "2" и случайной серединой. */
|
||
export function generateEan13InternalPrefix2(): string {
|
||
return ean13()
|
||
}
|
||
|
||
/** Сгенерировать штрихкод под указанный формат. */
|
||
export function generateBarcode(type: BarcodeType): string {
|
||
switch (type) {
|
||
case BarcodeType.Ean13: return ean13()
|
||
case BarcodeType.Ean8: return ean8()
|
||
case BarcodeType.Upca: return upca()
|
||
case BarcodeType.Upce: return upce()
|
||
case BarcodeType.Code128:
|
||
case BarcodeType.Code39: return randomAlnum(12)
|
||
case BarcodeType.Other:
|
||
default: return ean13()
|
||
}
|
||
}
|