feat(org-settings): валюта read-only, тянется из страны (как НДС)
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 30s
CI / Web (React + Vite) (push) Successful in 22s
Docker Images / API image (push) Successful in 40s
Docker Images / Web image (push) Successful in 24s
Docker Images / Deploy stage (push) Successful in 11s

- Currency в настройках больше не выбирается, показывается disabled
  как "KZT (₸)", источник правды — Country.DefaultCurrencyId.
- Backend: OrgSettingsInput больше не принимает DefaultCurrencyId;
  Update синхронизирует Organization.DefaultCurrencyId со страной.
- UX: страна — единственный редактируемый вход, определяет и НДС, и валюту.
- Мульти-валютный режим (Organization.MultiCurrencyEnabled) остаётся
  галкой; выбор валюты в закупках/продажах/карточке товара по-прежнему
  скрыт когда флаг выключен.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
nns 2026-04-24 12:08:30 +05:00
parent 9d8c386def
commit 51bef16758
2 changed files with 15 additions and 23 deletions

View file

@ -32,10 +32,10 @@ public record OrgSettingsDto(
decimal VatRate,
bool ShowVatEnabledOnProduct);
// DefaultCurrencyId не принимается — он read-only, выводится из страны (Country.DefaultCurrencyId).
public record OrgSettingsInput(
string Name,
string CountryCode,
Guid? DefaultCurrencyId,
bool MultiCurrencyEnabled,
bool ShowVatEnabledOnProduct);
@ -62,7 +62,11 @@ public async Task<ActionResult<OrgSettingsDto>> Update([FromBody] OrgSettingsInp
o.Name = input.Name;
o.CountryCode = input.CountryCode;
o.DefaultCurrencyId = input.DefaultCurrencyId;
// Валюта организации жёстко следует за страной — не принимается от клиента.
o.DefaultCurrencyId = await _db.Countries
.Where(c => c.Code == input.CountryCode)
.Select(c => c.DefaultCurrencyId)
.FirstOrDefaultAsync(ct);
o.MultiCurrencyEnabled = input.MultiCurrencyEnabled;
o.ShowVatEnabledOnProduct = input.ShowVatEnabledOnProduct;
await _db.SaveChangesAsync(ct);

View file

@ -5,31 +5,27 @@ import { api } from '@/lib/api'
import { PageHeader } from '@/components/PageHeader'
import { Button } from '@/components/Button'
import { Field, TextInput, Select, Checkbox } from '@/components/Field'
import { useCurrencies, useCountries } from '@/lib/useLookups'
import { useCountries } from '@/lib/useLookups'
import { useOrgSettings, type OrgSettings } from '@/lib/useOrgSettings'
export function OrganizationSettingsPage() {
const qc = useQueryClient()
const settings = useOrgSettings()
const currencies = useCurrencies()
const countries = useCountries()
const [form, setForm] = useState<OrgSettings | null>(null)
useEffect(() => { if (settings.data && !form) setForm(settings.data) }, [settings.data, form])
// При смене страны подтягиваем её валюту и ставку НДС (оба из справочника стран).
// При смене страны подтягиваем её валюту и ставку НДС (оба read-only, из справочника стран).
const onCountryChange = (countryCode: string) => {
if (!form) return
const country = countries.data?.find((c) => c.code === countryCode)
const currency = country?.defaultCurrencyId
? currencies.data?.find((c) => c.id === country.defaultCurrencyId)
: undefined
setForm({
...form,
countryCode,
defaultCurrencyId: currency?.id ?? country?.defaultCurrencyId ?? null,
defaultCurrencyCode: currency?.code ?? country?.defaultCurrencyCode ?? null,
defaultCurrencySymbol: currency?.symbol ?? country?.defaultCurrencySymbol ?? null,
defaultCurrencyId: country?.defaultCurrencyId ?? null,
defaultCurrencyCode: country?.defaultCurrencyCode ?? null,
defaultCurrencySymbol: country?.defaultCurrencySymbol ?? null,
vatRate: country?.vatRate ?? 0,
})
}
@ -40,7 +36,6 @@ export function OrganizationSettingsPage() {
const payload = {
name: form.name,
countryCode: form.countryCode,
defaultCurrencyId: form.defaultCurrencyId,
multiCurrencyEnabled: form.multiCurrencyEnabled,
showVatEnabledOnProduct: form.showVatEnabledOnProduct,
}
@ -71,17 +66,10 @@ export function OrganizationSettingsPage() {
</Select>
</Field>
<Field label="Валюта по умолчанию">
<Select
value={form.defaultCurrencyId ?? ''}
onChange={(e) => {
const id = e.target.value
const c = currencies.data?.find((x) => x.id === id)
setForm({ ...form, defaultCurrencyId: id || null, defaultCurrencyCode: c?.code ?? null, defaultCurrencySymbol: c?.symbol ?? null })
}}
>
<option value=""></option>
{currencies.data?.map((c) => <option key={c.id} value={c.id}>{c.code} ({c.symbol})</option>)}
</Select>
<TextInput
value={form.defaultCurrencyCode ? `${form.defaultCurrencyCode} (${form.defaultCurrencySymbol ?? ''})` : '—'}
disabled
/>
</Field>
</div>