fix(supply-lines): show both article and barcode in line subtitle
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 42s
CI / Web (React + Vite) (push) Successful in 35s
Docker API / Build + push API (push) Successful in 44s
Docker Web / Build + push Web (push) Successful in 26s
Docker API / Deploy API on stage (push) Successful in 17s
Docker Web / Deploy Web on stage (push) Successful in 11s

В таблице позиций приёмки под названием товара теперь выводится
и артикул, и основной штрихкод сразу — раньше показывалось что-то
одно (артикул или ничего, без штрихкода).

Формат: «Арт: 17933 · ШК: 4870144022958». Если только одно из двух
— префикс соответствующий, без точки-разделителя. Если ни того ни
другого — subtitle не рендерится. Шрифт мелкий моно серый.

API:
- SupplyLineDto расширен полем ProductBarcode (основной по
  IsPrimary, иначе первый по порядку).
- В проекции GetInternal штрихкод подтягивается через
  p.Barcodes.OrderByDescending(IsPrimary).Select(Code).First().

Frontend:
- types.ts.SupplyLineDto, LineRow в SupplyEditPage и AddedProduct
  в SupplyLineQuickAdd получили поле productBarcode/barcode.
- При добавлении строки через ProductPicker, sticky-input или
  quick-create — primary barcode достаётся из p.barcodes одинаковой
  логикой (sort by IsPrimary desc, [0]).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
nns 2026-04-26 03:03:43 +05:00
parent f9a17ad5c2
commit 290a95c54c
4 changed files with 25 additions and 3 deletions

View file

@ -34,6 +34,7 @@ public record SupplyListRow(
public record SupplyLineDto(
Guid? Id, Guid ProductId, string? ProductName, string? ProductArticle,
string? ProductBarcode,
string? UnitSymbol,
decimal Quantity, decimal UnitPrice, decimal LineTotal, int SortOrder,
bool RetailPriceManuallyOverridden, decimal? RetailPriceOverride,
@ -384,7 +385,10 @@ private async Task<string> GenerateNumberAsync(DateTime date, CancellationToken
where l.SupplyId == id
orderby l.SortOrder
select new SupplyLineDto(
l.Id, l.ProductId, p.Name, p.Article, u.Name,
l.Id, l.ProductId, p.Name, p.Article,
// Основной штрихкод (IsPrimary=true), иначе первый по порядку.
p.Barcodes.OrderByDescending(b => b.IsPrimary).Select(b => b.Code).FirstOrDefault(),
u.Name,
l.Quantity, l.UnitPrice, l.LineTotal, l.SortOrder,
l.RetailPriceManuallyOverridden, l.RetailPriceOverride,
p.Prices

View file

@ -18,6 +18,8 @@ export interface AddedProduct {
id: string
name: string
article: string | null
/** Основной штрихкод (IsPrimary), либо первый по порядку. */
barcode: string | null
referencePrice: number | null
unitName: string | null
cost: number | null
@ -162,10 +164,12 @@ export function SupplyLineQuickAdd({ storeId, disabled, onPick }: Props) {
refocus()
try {
const full = (await api.get<Product>(`/api/catalog/products/${id}`)).data
const primaryBarcode = (full.barcodes ?? []).slice().sort((a, b) => Number(b.isPrimary) - Number(a.isPrimary))[0]?.code ?? null
const incremented = onPick({
id: full.id,
name: full.name,
article: full.article,
barcode: primaryBarcode,
referencePrice: full.referencePrice,
unitName: full.unitName,
cost: full.cost,
@ -240,10 +244,12 @@ export function SupplyLineQuickAdd({ storeId, disabled, onPick }: Props) {
}
const onCreated = async (p: Product) => {
const primaryBarcode = (p.barcodes ?? []).slice().sort((a, b) => Number(b.isPrimary) - Number(a.isPrimary))[0]?.code ?? null
onPick({
id: p.id,
name: p.name,
article: p.article,
barcode: primaryBarcode,
referencePrice: p.referencePrice,
unitName: p.unitName,
cost: p.cost,

View file

@ -92,7 +92,8 @@ export interface SupplyListRow {
export interface SupplyLineDto {
id: string | null; productId: string;
productName: string | null; productArticle: string | null; unitName: string | null;
productName: string | null; productArticle: string | null; productBarcode: string | null;
unitName: string | null;
quantity: number; unitPrice: number; lineTotal: number; sortOrder: number;
retailPriceManuallyOverridden: boolean; retailPriceOverride: number | null;
currentRetailPrice: number | null;

View file

@ -16,6 +16,7 @@ interface LineRow {
productId: string
productName: string
productArticle: string | null
productBarcode: string | null
unitName: string | null
quantity: number
unitPrice: number
@ -96,6 +97,7 @@ export function SupplyEditPage() {
productId: l.productId,
productName: l.productName ?? '',
productArticle: l.productArticle,
productBarcode: l.productBarcode,
unitName: l.unitName,
quantity: l.quantity,
unitPrice: l.unitPrice,
@ -196,12 +198,14 @@ export function SupplyEditPage() {
const addLineFromProduct = (p: Product) => {
const defaultRetail = p.prices?.[0]?.amount ?? null
const primaryBarcode = (p.barcodes ?? []).slice().sort((a, b) => Number(b.isPrimary) - Number(a.isPrimary))[0]?.code ?? null
setForm({
...form,
lines: [...form.lines, {
productId: p.id,
productName: p.name,
productArticle: p.article,
productBarcode: primaryBarcode,
unitName: p.unitName,
quantity: 1,
unitPrice: p.referencePrice ?? p.cost ?? 0,
@ -231,6 +235,7 @@ export function SupplyEditPage() {
productId: p.id,
productName: p.name,
productArticle: p.article,
productBarcode: p.barcode,
unitName: p.unitName,
quantity: 1,
unitPrice: p.referencePrice ?? p.cost ?? 0,
@ -399,7 +404,13 @@ export function SupplyEditPage() {
<tr key={i} className="border-b border-slate-100 dark:border-slate-800">
<td className="py-2 pr-3">
<div className="font-medium">{l.productName}</div>
{l.productArticle && <div className="text-xs text-slate-400 font-mono">{l.productArticle}</div>}
{(l.productArticle || l.productBarcode) && (
<div className="text-xs text-slate-400 font-mono">
{l.productArticle && <span>Арт: {l.productArticle}</span>}
{l.productArticle && l.productBarcode && <span className="mx-1.5">·</span>}
{l.productBarcode && <span>ШК: {l.productBarcode}</span>}
</div>
)}
</td>
<td className="py-2 px-3 text-slate-500">{l.unitName}</td>
<td className="py-2 px-3">