food-market/tests/e2e/lib/barcode.ts
nns 37cd9aa94b test(e2e): починка контрактов supply/sale + EAN-13 + bug-hunt + full-pass отчёт
Контракты до фикса не совпадали с реальными:
- Product: unitId/groupId/retailPrice → unitOfMeasureId/productGroupId/prices[],
  плюс обязательный barcodes[] (генерим валидный EAN-13).
- Supply: counterpartyId/docDate/lines.price → supplierId/date/lines.unitPrice,
  плюс обязательный currencyId.
- RetailSale: путь /api/sales/retail-sales 404 → /api/sales/retail; payload
  обновлён под RetailSaleInput (storeId, currencyId, payment, paidCash и т.п.).

Шаги 9-12 теперь полностью проходят (не skip). Добавлены deep-bug-hunt'ы:
- Supply без supplierId / с пустым lines[]
- двойной post Supply / RetailSale → 409
- stock_movements vs Stocks.Quantity консистентность
- RetailPoint с несуществующим storeId
- продажа qty>остатка (выявил блокирующий баг — продаёт)
- discount на line, отрицательные qty/price
- stock_movements.Type = RetailSale (2)

Отчёт: tests/e2e/reports/full-cycle-2026-05-08-full-pass.md
Финальный счёт 10 ✓ / 2 ✗ / 0 ⚠ / 0 ◯ — две ✗ это РЕАЛЬНЫЕ баги:
[HIGH] step11 oversell проходит /post (нужна валидация qty≤stock)
[MEDIUM] step08 Supply без supplierId → 500 вместо 400
2026-05-08 11:01:56 +05:00

29 lines
1.2 KiB
TypeScript
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.

/**
* EAN-13 generator для e2e: префикс "20" (внутренний магазинный, как и
* в src/food-market.web/src/lib/barcode.ts), 10 цифр payload + checksum.
* Использует индекс шага вместо рандома, чтобы прогон был детерминированным
* и легче отлавливать дубликаты в отчёте.
*/
function ean13Checksum(twelve: string): number {
let sum = 0
for (let i = 0; i < 12; i++) {
const d = twelve.charCodeAt(i) - 48
sum += i % 2 === 0 ? d : d * 3
}
return (10 - (sum % 10)) % 10
}
/**
* Сгенерировать валидный EAN-13. Префикс "20" — резерв для внутренних
* штрихкодов магазина (in-store). Тело: timestamp.slice(-7) + index в
* 3-значной форме, итого 10 цифр payload. Получаем 13-значный код с
* контрольной суммой.
*/
export function generateEan13(index: number): string {
const ts = Date.now().toString().slice(-7)
const idx = String(index).padStart(3, '0')
const body = '20' + ts + idx
return body + ean13Checksum(body).toString()
}