feat(G1/SP3c): блок платёжных реквизитов + статус-чип + валидация (поля по типу лица)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-06-19 07:58:47 +03:00
parent c4bd6db523
commit dec1c95092
@@ -46,6 +46,19 @@ const requiresInn = computed(
() => form.subject_type === 'sole_proprietor' || form.subject_type === 'legal_entity',
);
const isLegalEntity = computed(() => form.subject_type === 'legal_entity');
const isSoleProprietor = computed(() => form.subject_type === 'sole_proprietor');
// Блок платёжных реквизитов виден, как только выбран тип лица.
const showPayment = computed(() => form.subject_type !== null);
// КПП — только юрлицо; ОГРН/ОГРНИП и юр.адрес — юрлицо и ИП; банк — всегда (когда showPayment).
const showKpp = computed(() => isLegalEntity.value);
const showOgrn = computed(() => isLegalEntity.value || isSoleProprietor.value);
const showLegalAddress = computed(() => isLegalEntity.value || isSoleProprietor.value);
const ogrnLabel = computed(() => (isSoleProprietor.value ? 'ОГРНИП' : 'ОГРН'));
const isCompleted = computed(() => Boolean(form.requisites_completed_at));
onMounted(async () => {
loading.value = true;
try {
@@ -90,6 +103,28 @@ function validateClient(): boolean {
if (!form.contact_name || form.contact_name.trim() === '') e.contact_name = ['Укажите контактное имя'];
if (!form.contact_phone || form.contact_phone.trim() === '') e.contact_phone = ['Укажите телефон'];
if (requiresInn.value && (!form.inn || form.inn.trim() === '')) e.inn = ['ИНН обязателен для ИП и юрлица'];
// Платёжные поля — необязательные; проверяем формат только если заполнены.
const kpp = form.kpp?.trim() ?? '';
if (kpp !== '' && !/^\d{9}$/.test(kpp)) e.kpp = ['КПП — 9 цифр'];
const ogrn = form.ogrn?.trim() ?? '';
if (ogrn !== '') {
const len = isSoleProprietor.value ? 15 : 13;
if (!new RegExp(`^\\d{${len}}$`).test(ogrn)) {
e.ogrn = [isSoleProprietor.value ? 'ОГРНИП — 15 цифр' : 'ОГРН — 13 цифр'];
}
}
const bik = form.bank_bik?.trim() ?? '';
if (bik !== '' && !/^\d{9}$/.test(bik)) e.bank_bik = ['БИК — 9 цифр'];
const acc = form.bank_account?.trim() ?? '';
if (acc !== '' && !/^\d{20}$/.test(acc)) e.bank_account = ['Расчётный счёт — 20 цифр'];
const corr = form.corr_account?.trim() ?? '';
if (corr !== '' && !/^\d{20}$/.test(corr)) e.corr_account = ['Корр. счёт — 20 цифр'];
errors.value = e;
return Object.keys(e).length === 0;
}
@@ -231,6 +266,104 @@ async function save(): Promise<void> {
</v-col>
</v-row>
<template v-if="showPayment">
<v-divider class="my-5" />
<div class="d-flex align-center ga-3 mb-1">
<h3 class="text-subtitle-1 ma-0">Реквизиты для оплаты</h3>
<v-chip
:color="isCompleted ? 'success' : undefined"
size="small"
variant="tonal"
data-testid="requisites-payment-status"
>
{{ isCompleted ? 'Готово к оплате' : 'Не заполнено' }}
</v-chip>
</div>
<p class="text-body-2 text-medium-emphasis mb-4">
Нужны для выставления счёта и договора. Можно заполнить позже.
</p>
<v-row dense>
<v-col v-if="showKpp" cols="12" md="6">
<v-text-field
v-model="form.kpp"
label="КПП"
inputmode="numeric"
variant="outlined"
density="comfortable"
:error-messages="errors.kpp"
data-testid="requisites-kpp"
/>
</v-col>
<v-col v-if="showOgrn" cols="12" md="6">
<v-text-field
v-model="form.ogrn"
:label="ogrnLabel"
inputmode="numeric"
variant="outlined"
density="comfortable"
:error-messages="errors.ogrn"
data-testid="requisites-ogrn"
/>
</v-col>
<v-col v-if="showLegalAddress" cols="12">
<v-text-field
v-model="form.legal_address"
label="Юридический адрес"
variant="outlined"
density="comfortable"
:error-messages="errors.legal_address"
data-testid="requisites-legal-address"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="form.bank_name"
label="Наименование банка"
variant="outlined"
density="comfortable"
:error-messages="errors.bank_name"
data-testid="requisites-bank-name"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="form.bank_bik"
label="БИК"
inputmode="numeric"
variant="outlined"
density="comfortable"
:error-messages="errors.bank_bik"
data-testid="requisites-bank-bik"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="form.bank_account"
label="Расчётный счёт"
inputmode="numeric"
variant="outlined"
density="comfortable"
:error-messages="errors.bank_account"
data-testid="requisites-bank-account"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="form.corr_account"
label="Корреспондентский счёт"
inputmode="numeric"
variant="outlined"
density="comfortable"
:error-messages="errors.corr_account"
data-testid="requisites-corr-account"
/>
</v-col>
</v-row>
</template>
<div class="d-flex ga-2 mt-4">
<v-btn
color="primary"