From a3cf68eb115b3f4586825454f04aaa6bd91e0053 Mon Sep 17 00:00:00 2001 From: nns <278048682+nurdotnet@users.noreply.github.com> Date: Sat, 25 Apr 2026 21:05:56 +0500 Subject: [PATCH] feat(web): product card pricing UI + settings toggles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - OrganizationSettingsPage: 2 новые галки — «Несколько типов цен (Опт, VIP и т.п.)» (multiplePriceTypesEnabled) и «Показывать «Эталонную цену» на товаре» (showReferencePriceOnProduct). - ProductEditPage: • «Эталонная цена» с подписью «не обязательное поле»; рендерится только при showReferencePriceOnProduct=true. • «Себестоимость» — readonly MoneyInput, всегда виден; подпись «расчётная (скользящее среднее)». • Заголовок секции цен меняется: «Цены продажи» при multipleEnabled, иначе «Розничная цена». • Кнопка «Привести к себестоимости» (только для existing товара) — POST /api/catalog/products/{id}/recalc-retail. После 200 — обновляем дефолтный PriceType в form.prices, инвалидируем кэш. После 400 — показываем сообщение в общий error. - useOrgSettings.ts: добавлены поля multiplePriceTypesEnabled и showReferencePriceOnProduct. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/food-market.web/src/lib/useOrgSettings.ts | 2 + .../src/pages/OrganizationSettingsPage.tsx | 22 +++++++ .../src/pages/ProductEditPage.tsx | 60 ++++++++++++++++--- 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/src/food-market.web/src/lib/useOrgSettings.ts b/src/food-market.web/src/lib/useOrgSettings.ts index 85a7d24..03f0df3 100644 --- a/src/food-market.web/src/lib/useOrgSettings.ts +++ b/src/food-market.web/src/lib/useOrgSettings.ts @@ -15,6 +15,8 @@ export interface OrgSettings { showMarkedOnProduct: boolean showMinMaxStock: boolean allowFractionalPrices: boolean + multiplePriceTypesEnabled: boolean + showReferencePriceOnProduct: boolean } export function useOrgSettings() { diff --git a/src/food-market.web/src/pages/OrganizationSettingsPage.tsx b/src/food-market.web/src/pages/OrganizationSettingsPage.tsx index 6495173..79ffe3c 100644 --- a/src/food-market.web/src/pages/OrganizationSettingsPage.tsx +++ b/src/food-market.web/src/pages/OrganizationSettingsPage.tsx @@ -45,6 +45,8 @@ export function OrganizationSettingsPage() { showMarkedOnProduct: form.showMarkedOnProduct, showMinMaxStock: form.showMinMaxStock, allowFractionalPrices: form.allowFractionalPrices, + multiplePriceTypesEnabled: form.multiplePriceTypesEnabled, + showReferencePriceOnProduct: form.showReferencePriceOnProduct, } return (await api.put('/api/organization/settings', payload)).data }, @@ -150,6 +152,26 @@ export function OrganizationSettingsPage() { Включи если хочешь использовать цены с двумя знаками после запятой (1500.50 ₸). По умолчанию — целые тенге, без копеек.

+ + setForm({ ...form, multiplePriceTypesEnabled: v })} + /> +

+ Если включено — в меню появляется «Типы цен», на карточке товара — + список цен по всем типам. По умолчанию одна розничная цена. +

+ + setForm({ ...form, showReferencePriceOnProduct: v })} + /> +

+ Справочная цена закупа — необязательное поле. Авто-заполняется первой + проведённой приёмкой и через 30 дней без приёмок переписывается на текущую себестоимость. +

diff --git a/src/food-market.web/src/pages/ProductEditPage.tsx b/src/food-market.web/src/pages/ProductEditPage.tsx index 63ecb5f..41376d9 100644 --- a/src/food-market.web/src/pages/ProductEditPage.tsx +++ b/src/food-market.web/src/pages/ProductEditPage.tsx @@ -317,14 +317,26 @@ export function ProductEditPage() {
- + {org.data?.showReferencePriceOnProduct && ( + + setForm({ ...form, referencePrice: n == null ? '' : String(n) })} + currencyCode={currencies.data?.find((c) => c.id === form.purchaseCurrencyId)?.code ?? org.data?.defaultCurrencyCode ?? undefined} + currencySymbol={currencies.data?.find((c) => c.id === form.purchaseCurrencyId)?.symbol ?? org.data?.defaultCurrencySymbol ?? undefined} + /> +

не обязательное поле

+
+ )} + setForm({ ...form, referencePrice: n == null ? '' : String(n) })} - currencyCode={currencies.data?.find((c) => c.id === form.purchaseCurrencyId)?.code ?? org.data?.defaultCurrencyCode ?? undefined} - currencySymbol={currencies.data?.find((c) => c.id === form.purchaseCurrencyId)?.symbol ?? org.data?.defaultCurrencySymbol ?? undefined} - + value={existing.data?.cost ?? 0} + onChange={() => {}} + disabled + currencyCode={org.data?.defaultCurrencyCode ?? undefined} + currencySymbol={org.data?.defaultCurrencySymbol ?? undefined} /> +

расчётная (скользящее среднее)

{org.data?.multiCurrencyEnabled && ( @@ -359,8 +371,40 @@ export function ProductEditPage() { )}
Добавить} + title={org.data?.multiplePriceTypesEnabled ? 'Цены продажи' : 'Розничная цена'} + action={ +
+ {!isNew && id && ( + + )} + {org.data?.multiplePriceTypesEnabled && ( + + )} +
+ } > {form.prices.length === 0 ? (
Цен ещё нет. Добавь хотя бы розничную.