refactor(retail-points): rename «Точка продаж» → «Касса» + перенос
складов и касс в раздел «Настройки организации»; useOrgInfra хук UI-переименование: - RetailPointsPage: title «Кассы», description обновлён, лейблы «Новая касса» / «Удалить кассу?»; доменная сущность RetailPoint и URL /api/catalog/retail-points сохранены — DTO/БД не трогаем. - В сайдбаре пункты «Склады» и «Кассы» перенесены из бывшей группы «Склады» в группу «Настройки организации» (рядом с «Общие»). Старые пункты верхнего уровня убраны. useOrgInfra() — общий хук: - возвращает stores, cashRegisters, defaultStoreId, defaultCashId - showStorePicker / showCashPicker = length > 1 (умное скрытие селекторов в формах документов когда инфра одна). В SupplyEditPage скрытие склада уже работало через (stores.data?.length ?? 0) > 1 — оставил как есть, новый хук для будущих документов (продажи, инвентаризации). Сидер default Store + RetailPoint per Organization уже есть в DevDataSeeder.cs (Основной склад MAIN + Касса 1 POS-1) — дополнять не нужно. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
dc4b5360b9
commit
cec76ecaaf
|
|
@ -37,10 +37,6 @@ function buildNav(): NavSection[] {
|
|||
{ group: 'Контрагенты', items: [
|
||||
{ to: '/catalog/counterparties', icon: Users, label: 'Контрагенты' },
|
||||
]},
|
||||
{ group: 'Склады', items: [
|
||||
{ to: '/catalog/stores', icon: Warehouse, label: 'Склады' },
|
||||
{ to: '/catalog/retail-points', icon: StoreIcon, label: 'Точки продаж' },
|
||||
]},
|
||||
{ group: 'Остатки', items: [
|
||||
{ to: '/inventory/stock', icon: Boxes, label: 'Остатки' },
|
||||
{ to: '/inventory/movements', icon: History, label: 'Движения' },
|
||||
|
|
@ -57,8 +53,10 @@ function buildNav(): NavSection[] {
|
|||
{ group: 'Импорт', items: [
|
||||
{ to: '/admin/import/moysklad', icon: Download, label: 'МойСклад' },
|
||||
]},
|
||||
{ group: 'Настройки', items: [
|
||||
{ to: '/settings/organization', icon: Settings, label: 'Организация' },
|
||||
{ group: 'Настройки организации', items: [
|
||||
{ to: '/settings/organization', icon: Settings, label: 'Общие' },
|
||||
{ to: '/catalog/stores', icon: Warehouse, label: 'Склады' },
|
||||
{ to: '/catalog/retail-points', icon: StoreIcon, label: 'Кассы' },
|
||||
]},
|
||||
]
|
||||
}
|
||||
|
|
|
|||
34
src/food-market.web/src/lib/useOrgInfra.ts
Normal file
34
src/food-market.web/src/lib/useOrgInfra.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { useStores } from '@/lib/useLookups'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { api } from '@/lib/api'
|
||||
import type { PagedResult, RetailPoint } from '@/lib/types'
|
||||
|
||||
/** Инфраструктура организации (склады, кассы) для умного скрытия селекторов
|
||||
* в формах документов: если у организации только 1 склад/касса — выбор не
|
||||
* показывается, форма автоматически подставляет единственное значение.
|
||||
* Появится 2-й — пикер вернётся. */
|
||||
export function useOrgInfra() {
|
||||
const stores = useStores()
|
||||
const cashRegisters = useQuery({
|
||||
queryKey: ['lookup:retail-points'],
|
||||
queryFn: async () =>
|
||||
(await api.get<PagedResult<RetailPoint>>('/api/catalog/retail-points?pageSize=500')).data.items,
|
||||
staleTime: 0,
|
||||
refetchOnMount: 'always',
|
||||
refetchOnWindowFocus: true,
|
||||
})
|
||||
|
||||
const storesList = stores.data ?? []
|
||||
const cashList = cashRegisters.data ?? []
|
||||
const mainStore = storesList.find((s) => s.isMain) ?? storesList[0]
|
||||
|
||||
return {
|
||||
stores: storesList,
|
||||
cashRegisters: cashList,
|
||||
isLoading: stores.isLoading || cashRegisters.isLoading,
|
||||
showStorePicker: storesList.length > 1,
|
||||
showCashPicker: cashList.length > 1,
|
||||
defaultStoreId: mainStore?.id ?? null,
|
||||
defaultCashId: cashList[0]?.id ?? null,
|
||||
}
|
||||
}
|
||||
|
|
@ -55,8 +55,8 @@ export function RetailPointsPage() {
|
|||
return (
|
||||
<>
|
||||
<ListPageShell
|
||||
title="Точки продаж"
|
||||
description="Кассовые точки. Привязаны к складу, с которого идут продажи."
|
||||
title="Кассы"
|
||||
description="Кассовые точки продаж. Каждая привязана к складу, с которого списывается товар."
|
||||
actions={
|
||||
<>
|
||||
<SearchBar value={search} onChange={setSearch} />
|
||||
|
|
@ -96,12 +96,12 @@ export function RetailPointsPage() {
|
|||
<Modal
|
||||
open={!!form}
|
||||
onClose={() => setForm(null)}
|
||||
title={form?.id ? 'Редактировать точку продаж' : 'Новая точка продаж'}
|
||||
title={form?.id ? 'Редактировать кассу' : 'Новая касса'}
|
||||
footer={
|
||||
<>
|
||||
{form?.id && (
|
||||
<Button variant="danger" size="sm" onClick={async () => {
|
||||
if (confirm('Удалить точку продаж?')) {
|
||||
if (confirm('Удалить кассу?')) {
|
||||
await remove.mutateAsync(form.id!)
|
||||
setForm(null)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue