fix(money-input): корректное обновление allowFractionalPrices без перелогина
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 28s
CI / Web (React + Vite) (push) Successful in 25s
Docker Images / API image (push) Successful in 33s
Docker Images / Web image (push) Successful in 25s
Docker Images / Deploy stage (push) Successful in 18s

Главная причина бага: useOrgSettings имел staleTime=5 минут. Когда
пользователь переключал галку в /settings/organization, инвалидация
ключа `/api/organization/settings` помечала кэш stale, но MoneyInput
в открытой форме товара продолжал получать старое значение из кэша
до момента, пока сабскрайбер не делал перефетч. На свежем монтировании
(переход с /settings обратно на /catalog/products/...) перефетча тоже
не происходило, т.к. данные считались всё ещё валидными.

Фикс:
- useOrgSettings: staleTime=0 + refetchOnMount: 'always' +
  refetchOnWindowFocus=true. Каждое монтирование компонента — свежие
  настройки одним лёгким GET'ом. Цена нулевая, цикл «изменил настройку
  — открыл форму — увидел эффект» теперь работает без перезагрузки.
- OrganizationSettingsPage: useEffect синхронизирует form со settings.data
  без условия `!form` — при свежем рефетче форма тоже подтягивает актуальное.

Все вызовы MoneyInput в формах уже не передают allowFractional —
компонент сам читает useOrgSettings, что вместе с фиксом выше даёт
корректное поведение.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
nns 2026-04-25 12:39:25 +05:00
parent 52a420ea3d
commit 9ee0434829
2 changed files with 11 additions and 2 deletions

View file

@ -21,6 +21,12 @@ export function useOrgSettings() {
return useQuery({
queryKey: ['/api/organization/settings'],
queryFn: async () => (await api.get<OrgSettings>('/api/organization/settings')).data,
staleTime: 5 * 60 * 1000,
// Настройки меняются редко, но переключатели вроде AllowFractionalPrices
// должны применяться к открытым в других вкладках формам сразу. Поэтому
// staleTime=0 + refetchOnMount: 'always' — каждый монтирующийся компонент
// получает свежие настройки. Стоимость минимальная: один лёгкий GET.
staleTime: 0,
refetchOnMount: 'always',
refetchOnWindowFocus: true,
})
}

View file

@ -14,7 +14,10 @@ export function OrganizationSettingsPage() {
const countries = useCountries()
const [form, setForm] = useState<OrgSettings | null>(null)
useEffect(() => { if (settings.data && !form) setForm(settings.data) }, [settings.data, form])
// Синхронизируем форму с актуальным снимком настроек: первый раз — после
// загрузки; и каждый раз когда сервер вернул свежую версию (например после
// refetchOnMount или после save в другой вкладке).
useEffect(() => { if (settings.data) setForm(settings.data) }, [settings.data])
// При смене страны подтягиваем её валюту и ставку НДС (оба read-only, из справочника стран).
const onCountryChange = (countryCode: string) => {