Compare commits
2 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26a76e5aea | ||
|
|
2d1a9c8f75 |
|
|
@ -2,6 +2,10 @@ namespace foodmarket.Domain.Catalog;
|
||||||
|
|
||||||
public enum CounterpartyKind
|
public enum CounterpartyKind
|
||||||
{
|
{
|
||||||
|
/// <summary>Не указано — дефолт для импортированных без явной классификации.
|
||||||
|
/// MoySklad сам не имеет встроенного поля Supplier/Customer, оно ставится
|
||||||
|
/// через теги или группы, и часто отсутствует. Не выдумываем за пользователя.</summary>
|
||||||
|
Unspecified = 0,
|
||||||
Supplier = 1,
|
Supplier = 1,
|
||||||
Customer = 2,
|
Customer = 2,
|
||||||
Both = 3,
|
Both = 3,
|
||||||
|
|
|
||||||
|
|
@ -39,17 +39,14 @@ public async Task<MoySkladImportResult> ImportCounterpartiesAsync(string token,
|
||||||
{
|
{
|
||||||
var orgId = _tenant.OrganizationId ?? throw new InvalidOperationException("No tenant organization in context.");
|
var orgId = _tenant.OrganizationId ?? throw new InvalidOperationException("No tenant organization in context.");
|
||||||
|
|
||||||
// Map MoySklad tag set → local CounterpartyKind. If no tags say otherwise, assume Both.
|
// MoySklad НЕ имеет поля "Поставщик/Покупатель" у контрагентов вообще — это
|
||||||
|
// не наша выдумка, проверено через API: counterparty entity содержит только
|
||||||
|
// group (группа доступа), tags (произвольные), state (пользовательская цепочка
|
||||||
|
// статусов), companyType (legal/individual/entrepreneur). Никакой role/kind.
|
||||||
|
// Поэтому при импорте ВСЕГДА ставим Unspecified — пользователь сам решит.
|
||||||
|
// Параметр tags оставлен ради совместимости сигнатуры, не используется.
|
||||||
static foodmarket.Domain.Catalog.CounterpartyKind ResolveKind(IReadOnlyList<string>? tags)
|
static foodmarket.Domain.Catalog.CounterpartyKind ResolveKind(IReadOnlyList<string>? tags)
|
||||||
{
|
=> foodmarket.Domain.Catalog.CounterpartyKind.Unspecified;
|
||||||
if (tags is null || tags.Count == 0) return foodmarket.Domain.Catalog.CounterpartyKind.Both;
|
|
||||||
var lower = tags.Select(t => t.ToLowerInvariant()).ToList();
|
|
||||||
var hasSupplier = lower.Any(t => t.Contains("постав"));
|
|
||||||
var hasCustomer = lower.Any(t => t.Contains("покуп") || t.Contains("клиент"));
|
|
||||||
if (hasSupplier && !hasCustomer) return foodmarket.Domain.Catalog.CounterpartyKind.Supplier;
|
|
||||||
if (hasCustomer && !hasSupplier) return foodmarket.Domain.Catalog.CounterpartyKind.Customer;
|
|
||||||
return foodmarket.Domain.Catalog.CounterpartyKind.Both;
|
|
||||||
}
|
|
||||||
|
|
||||||
static foodmarket.Domain.Catalog.CounterpartyType ResolveType(string? companyType)
|
static foodmarket.Domain.Catalog.CounterpartyType ResolveType(string? companyType)
|
||||||
=> companyType switch
|
=> companyType switch
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ export interface PagedResult<T> {
|
||||||
totalPages: number
|
totalPages: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CounterpartyKind = { Supplier: 1, Customer: 2, Both: 3 } as const
|
export const CounterpartyKind = { Unspecified: 0, Supplier: 1, Customer: 2, Both: 3 } as const
|
||||||
export type CounterpartyKind = (typeof CounterpartyKind)[keyof typeof CounterpartyKind]
|
export type CounterpartyKind = (typeof CounterpartyKind)[keyof typeof CounterpartyKind]
|
||||||
|
|
||||||
export const CounterpartyType = { LegalEntity: 1, Individual: 2 } as const
|
export const CounterpartyType = { LegalEntity: 1, Individual: 2 } as const
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ export const useCountries = () => useLookup<Country>('countries', '/api/catalog/
|
||||||
export const useCurrencies = () => useLookup<Currency>('currencies', '/api/catalog/currencies')
|
export const useCurrencies = () => useLookup<Currency>('currencies', '/api/catalog/currencies')
|
||||||
export const useStores = () => useLookup<Store>('stores', '/api/catalog/stores')
|
export const useStores = () => useLookup<Store>('stores', '/api/catalog/stores')
|
||||||
export const usePriceTypes = () => useLookup<PriceType>('price-types', '/api/catalog/price-types')
|
export const usePriceTypes = () => useLookup<PriceType>('price-types', '/api/catalog/price-types')
|
||||||
export const useSuppliers = () => useQuery({
|
// MoySklad-style: контрагент один, может быть и поставщиком, и покупателем
|
||||||
queryKey: ['lookup:suppliers'],
|
// в разных документах. Не фильтруем по Kind — пользователь сам выбирает.
|
||||||
queryFn: async () => (await api.get<PagedResult<Counterparty>>('/api/catalog/counterparties?pageSize=500&kind=1')).data.items,
|
export const useCounterparties = () => useLookup<Counterparty>('counterparties', '/api/catalog/counterparties')
|
||||||
staleTime: 5 * 60 * 1000,
|
// Алиас для обратной совместимости со старым кодом форм Supply/RetailSale.
|
||||||
})
|
export const useSuppliers = useCounterparties
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,9 @@ interface Form {
|
||||||
}
|
}
|
||||||
|
|
||||||
const blankForm: Form = {
|
const blankForm: Form = {
|
||||||
name: '', legalName: '', kind: CounterpartyKind.Supplier, type: CounterpartyType.LegalEntity,
|
// Kind по умолчанию Unspecified — MoySklad не имеет такого поля у контрагентов,
|
||||||
|
// не выдумываем за пользователя. Пусть выберет вручную если нужно.
|
||||||
|
name: '', legalName: '', kind: CounterpartyKind.Unspecified, type: CounterpartyType.LegalEntity,
|
||||||
bin: '', iin: '', taxNumber: '', countryId: '',
|
bin: '', iin: '', taxNumber: '', countryId: '',
|
||||||
address: '', phone: '', email: '',
|
address: '', phone: '', email: '',
|
||||||
bankName: '', bankAccount: '', bik: '',
|
bankName: '', bankAccount: '', bik: '',
|
||||||
|
|
@ -44,9 +46,10 @@ const blankForm: Form = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const kindLabel: Record<CounterpartyKind, string> = {
|
const kindLabel: Record<CounterpartyKind, string> = {
|
||||||
|
[CounterpartyKind.Unspecified]: '—',
|
||||||
[CounterpartyKind.Supplier]: 'Поставщик',
|
[CounterpartyKind.Supplier]: 'Поставщик',
|
||||||
[CounterpartyKind.Customer]: 'Покупатель',
|
[CounterpartyKind.Customer]: 'Покупатель',
|
||||||
[CounterpartyKind.Both]: 'Оба',
|
[CounterpartyKind.Both]: 'Поставщик + Покупатель',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CounterpartiesPage() {
|
export function CounterpartiesPage() {
|
||||||
|
|
@ -138,9 +141,10 @@ export function CounterpartiesPage() {
|
||||||
</Field>
|
</Field>
|
||||||
<Field label="Роль">
|
<Field label="Роль">
|
||||||
<Select value={form.kind} onChange={(e) => setForm({ ...form, kind: Number(e.target.value) as CounterpartyKind })}>
|
<Select value={form.kind} onChange={(e) => setForm({ ...form, kind: Number(e.target.value) as CounterpartyKind })}>
|
||||||
|
<option value={CounterpartyKind.Unspecified}>Не указано</option>
|
||||||
<option value={CounterpartyKind.Supplier}>Поставщик</option>
|
<option value={CounterpartyKind.Supplier}>Поставщик</option>
|
||||||
<option value={CounterpartyKind.Customer}>Покупатель</option>
|
<option value={CounterpartyKind.Customer}>Покупатель</option>
|
||||||
<option value={CounterpartyKind.Both}>Оба</option>
|
<option value={CounterpartyKind.Both}>Поставщик + Покупатель</option>
|
||||||
</Select>
|
</Select>
|
||||||
</Field>
|
</Field>
|
||||||
<Field label="Тип лица">
|
<Field label="Тип лица">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue