Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 995f65f524 | |||
| 5298e55a7b | |||
| db28ba1137 | |||
| 6a05e88ba1 | |||
| 09eaa6192c |
@@ -1,7 +1,7 @@
|
||||
import { ObjectType, Field, InputType, registerEnumType } from '@nestjs/graphql';
|
||||
import { IsOptional, IsString, IsIn, Matches, MaxLength } from 'class-validator';
|
||||
import { ReportType } from '../../domain/enums/report-type.enum';
|
||||
import { SFR_REG_NUMBER_PATTERN } from '../../domain/patterns';
|
||||
import { SFR_REG_NUMBER_PATTERN, PFR_REG_NUMBER_PATTERN } from '../../domain/patterns';
|
||||
|
||||
export enum RequisiteSource {
|
||||
DATABASE = 'database',
|
||||
@@ -44,6 +44,7 @@ export class ReportRequisitesViewDTO {
|
||||
@Field(() => RequisiteFieldViewDTO) oktmo!: RequisiteFieldViewDTO;
|
||||
@Field(() => RequisiteFieldViewDTO) okpo!: RequisiteFieldViewDTO;
|
||||
@Field(() => RequisiteFieldViewDTO) sfrRegNumber!: RequisiteFieldViewDTO;
|
||||
@Field(() => RequisiteFieldViewDTO) pfrRegNumber!: RequisiteFieldViewDTO;
|
||||
@Field(() => RequisiteFieldViewDTO) chairmanPosition!: RequisiteFieldViewDTO;
|
||||
@Field(() => RequisiteFieldViewDTO) signerSnils!: RequisiteFieldViewDTO;
|
||||
@Field(() => RequisiteFieldViewDTO) signerRepDoc!: RequisiteFieldViewDTO;
|
||||
@@ -66,7 +67,10 @@ export class ReportRequisitesViewDTO {
|
||||
* ОКТМО — `\d{8}` или `\d{11}`
|
||||
* ОКПО — `\d{8}` или `\d{10}`
|
||||
* СНИЛС — `\d{3}-\d{3}-\d{3} \d{2}` (14 симв.) или 11 цифр подряд
|
||||
* РегНом СФР — `\d{3}-\d{3}-\d{6}` (14 симв. с тире) или 10 цифр подряд
|
||||
* РегНом СФР — `\d{10}` (10 цифр подряд, без тире)
|
||||
* РегНом ПФР — `\d{3}-\d{3}-\d{6}` (14 симв. с тире), только этот формат —
|
||||
* отдельное поле от РегНом СФР, требуется для ЕФС-1 (внешние
|
||||
* бухгалтерские системы сверяют его при приёме отчёта)
|
||||
*/
|
||||
@InputType('UpdateReportRequisitesInput')
|
||||
export class UpdateReportRequisitesInputDTO {
|
||||
@@ -100,12 +104,18 @@ export class UpdateReportRequisitesInputDTO {
|
||||
@Matches(/^\d{8}(\d{2})?$/, { message: 'ОКПО — 8 или 10 цифр' })
|
||||
okpo?: string | null;
|
||||
|
||||
@Field(() => String, { nullable: true, description: 'Рег. номер СФР — XXX-XXX-XXXXXX или 10 цифр' })
|
||||
@Field(() => String, { nullable: true, description: 'Рег. номер СФР — 10 цифр' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Matches(SFR_REG_NUMBER_PATTERN, { message: 'Рег. номер СФР — XXX-XXX-XXXXXX или 10 цифр' })
|
||||
@Matches(SFR_REG_NUMBER_PATTERN, { message: 'Рег. номер СФР — 10 цифр' })
|
||||
sfrRegNumber?: string | null;
|
||||
|
||||
@Field(() => String, { nullable: true, description: 'Рег. номер ПФР — XXX-XXX-XXXXXX (для ЕФС-1, отдельно от рег. номера СФР)' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Matches(PFR_REG_NUMBER_PATTERN, { message: 'Рег. номер ПФР — XXX-XXX-XXXXXX' })
|
||||
pfrRegNumber?: string | null;
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
|
||||
+8
-1
@@ -21,6 +21,7 @@ import {
|
||||
OKTMO_PATTERN,
|
||||
OKVED_PATTERN,
|
||||
SFR_REG_NUMBER_PATTERN,
|
||||
PFR_REG_NUMBER_PATTERN,
|
||||
SNILS_PATTERN,
|
||||
DATE_DDMMYYYY_PATTERN,
|
||||
} from '../../domain/patterns';
|
||||
@@ -200,9 +201,14 @@ export class ZeroReportSignerEditsInputDTO {
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
@IsOptional()
|
||||
@Matches(SFR_REG_NUMBER_PATTERN, { message: 'Рег.номер СФР — XXX-XXX-XXXXXX или 10 цифр' })
|
||||
@Matches(SFR_REG_NUMBER_PATTERN, { message: 'Рег.номер СФР — 10 цифр' })
|
||||
sfrRegNumber!: string | null;
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
@IsOptional()
|
||||
@Matches(PFR_REG_NUMBER_PATTERN, { message: 'Рег.номер ПФР — XXX-XXX-XXXXXX' })
|
||||
pfrRegNumber!: string | null;
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@@ -219,6 +225,7 @@ export class ZeroReportSignerEditsDTO {
|
||||
@Field(() => String, { nullable: true }) repDoc!: string | null;
|
||||
@Field(() => String, { nullable: true }) snils!: string | null;
|
||||
@Field(() => String, { nullable: true }) sfrRegNumber!: string | null;
|
||||
@Field(() => String, { nullable: true }) pfrRegNumber!: string | null;
|
||||
@Field(() => String, { nullable: true }) chairmanPosition!: string | null;
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -53,6 +53,7 @@ export class ReportRequisitesResolver {
|
||||
oktmo: input.oktmo ?? undefined,
|
||||
okpo: input.okpo ?? undefined,
|
||||
sfr_reg_number: input.sfrRegNumber ?? undefined,
|
||||
pfr_reg_number: input.pfrRegNumber ?? undefined,
|
||||
chairman_position: input.chairmanPosition ?? undefined,
|
||||
signer_snils: input.signerSnils ?? undefined,
|
||||
signer_rep_doc: input.signerRepDoc ?? undefined,
|
||||
@@ -109,6 +110,7 @@ function toView(m: MergedRequisites): ReportRequisitesViewDTO {
|
||||
oktmo: f(m.oktmo),
|
||||
okpo: f(m.okpo),
|
||||
sfrRegNumber: f(m.sfrRegNumber),
|
||||
pfrRegNumber: f(m.pfrRegNumber),
|
||||
chairmanPosition: f(m.chairmanPosition),
|
||||
signerSnils: f(m.signerSnils),
|
||||
signerRepDoc: f(m.signerRepDoc),
|
||||
|
||||
+8
@@ -51,6 +51,14 @@ export interface ZeroReportSignerShape {
|
||||
snils: string | null;
|
||||
/** Регистрационный номер в СФР — обязателен для ЕФС-1. */
|
||||
sfrRegNumber: string | null;
|
||||
/**
|
||||
* Регистрационный номер в ПФР (XXX-XXX-XXXXXX) — обязателен для ЕФС-1,
|
||||
* попадает и в <ЕФС8:РегНомер>, и в имя файла. Отдельное поле от
|
||||
* sfrRegNumber: сторонние бухгалтерские системы (СБИС и др.) при приёме
|
||||
* ЕФС-1 сверяют номер отправителя именно с рег. номером ПФР организации,
|
||||
* не с 10-значным номером СФР.
|
||||
*/
|
||||
pfrRegNumber: string | null;
|
||||
/** Должность председателя — для ЕФС-1 (<УТ8:Должность>). */
|
||||
chairmanPosition: string | null;
|
||||
}
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ export interface ReportInput {
|
||||
correctionNumber?: number;
|
||||
/** СНИЛС председателя (для ПСВ) */
|
||||
signerSnils?: string;
|
||||
/** Регистрационный номер страхователя в СФР/ПФР (для ЕФС-1). */
|
||||
/** Регистрационный номер страхователя в СФР (для ЕФС-1). Legacy-путь — актуальные генераторы берут ZeroReportSignerShape.pfrRegNumber отдельно. */
|
||||
sfrRegNumber?: string;
|
||||
/** Должность руководителя для подачи в СФР (по умолчанию «Председатель Совета»). */
|
||||
chairmanPosition?: string;
|
||||
|
||||
@@ -43,9 +43,19 @@ export const OKPO_PATTERN = /^\d{8}(\d{2})?$/;
|
||||
// СНИЛС: XXX-XXX-XXX YY (с пробелом/тире) или 11 цифр подряд.
|
||||
export const SNILS_PATTERN = /^(\d{3}-\d{3}-\d{3} \d{2}|\d{11})$/;
|
||||
|
||||
// Регистрационный номер СФР: действующий XXX-XXX-XXXXXX (3-3-6, 12 цифр)
|
||||
// или прежний — 10 цифр без разделителей (ТипРегНомерОбщ в XSD ЕФС-1).
|
||||
export const SFR_REG_NUMBER_PATTERN = /^(\d{3}-\d{3}-\d{6}|\d{10})$/;
|
||||
// Регистрационный номер страхователя в СФР: только 10 цифр без разделителей
|
||||
// (унифицированный номер СФР, ТипРегНомерОбщ в XSD ЕФС-1). Формат
|
||||
// XXX-XXX-XXXXXX сюда больше не входит — он теперь отдельное поле
|
||||
// PFR_REG_NUMBER_PATTERN, чтобы два похожих номера не путались в одной маске.
|
||||
export const SFR_REG_NUMBER_PATTERN = /^\d{10}$/;
|
||||
|
||||
// Регистрационный номер страхователя в ПФР: только формат XXX-XXX-XXXXXX
|
||||
// (3-3-6, 12 цифр с тире) — старый/«действующий» формат, который сверяют
|
||||
// сторонние бухгалтерские системы (СБИС и др.) при приёме ЕФС-1. Это
|
||||
// отдельное поле от sfrRegNumber (10-значный унифицированный номер СФР):
|
||||
// внешние системы могут не знать организацию по 10-значному номеру, но
|
||||
// знать по этому.
|
||||
export const PFR_REG_NUMBER_PATTERN = /^\d{3}-\d{3}-\d{6}$/;
|
||||
|
||||
/** Дата в формате `DD.MM.YYYY` (XSD `xs:date`-совместимый ФНС-формат). */
|
||||
export const DATE_DDMMYYYY_PATTERN = /^\d{2}\.\d{2}\.\d{4}$/;
|
||||
|
||||
+2
@@ -10,6 +10,7 @@ export interface ReportRequisitesRecord {
|
||||
oktmo: string | null;
|
||||
okpo: string | null;
|
||||
sfr_reg_number: string | null;
|
||||
pfr_reg_number: string | null;
|
||||
chairman_position: string | null;
|
||||
signer_snils: string | null;
|
||||
signer_rep_doc: string | null;
|
||||
@@ -28,6 +29,7 @@ export interface UpsertReportRequisitesInput {
|
||||
oktmo?: string | null;
|
||||
okpo?: string | null;
|
||||
sfr_reg_number?: string | null;
|
||||
pfr_reg_number?: string | null;
|
||||
chairman_position?: string | null;
|
||||
signer_snils?: string | null;
|
||||
signer_rep_doc?: string | null;
|
||||
|
||||
+27
-7
@@ -203,7 +203,12 @@ export class ReportEditsBuilderService {
|
||||
|
||||
return {
|
||||
header: {
|
||||
idFile: this.generateGenericFileName(reportType, merged.inn.value ?? '', merged.kpp.value ?? ''),
|
||||
idFile: this.generateGenericFileName(
|
||||
reportType,
|
||||
merged.inn.value ?? '',
|
||||
merged.kpp.value ?? '',
|
||||
merged.pfrRegNumber.value,
|
||||
),
|
||||
versProgram: 'Платформа отчётности кооператива 1.0',
|
||||
docDate: formatDate(new Date()),
|
||||
reportYear: year,
|
||||
@@ -230,6 +235,7 @@ export class ReportEditsBuilderService {
|
||||
repDoc: merged.signerRepDoc.value,
|
||||
snils: merged.signerSnils.value,
|
||||
sfrRegNumber: merged.sfrRegNumber.value,
|
||||
pfrRegNumber: merged.pfrRegNumber.value,
|
||||
chairmanPosition:
|
||||
merged.chairmanPosition.value || merged.chairmanPositionFromOrg.value,
|
||||
},
|
||||
@@ -243,19 +249,33 @@ export class ReportEditsBuilderService {
|
||||
return 1;
|
||||
}
|
||||
|
||||
private generateGenericFileName(reportType: ReportType, inn: string, kpp: string): string {
|
||||
// Упрощённый префикс по типу отчёта — точный формат имени зависит от
|
||||
// формы (NO_NDFL6.2_..., СФР_..._ЕФС-1_...), но для предварительного
|
||||
// idFile достаточно. Генератор сам перезапишет его при необходимости.
|
||||
private generateGenericFileName(
|
||||
reportType: ReportType,
|
||||
inn: string,
|
||||
kpp: string,
|
||||
pfrRegNumber?: string | null,
|
||||
): string {
|
||||
// Префикс = первые два underscore-сегмента имени XSD (например,
|
||||
// 'NO_NDFL6.2_1_231_...xsd' → 'NO_NDFL6.2', 'UT_UVISCHSUMNAL_...xsd' →
|
||||
// 'UT_UVISCHSUMNAL') — это и есть код формата в имени файла по формату
|
||||
// ФНС/СФР. Брать только первый сегмент нельзя: для всех форм с 'NO_'
|
||||
// в начале он всегда равен 'NO' и код формы (NDFL6.2/RASCHSV/PERSSVFL/
|
||||
// USN) терялся — импорт стороннего ПО (Сбер и др.) отклонял файл как
|
||||
// нераспознанный по имени.
|
||||
const xsd = REPORT_CONFIG[reportType]?.xsdFile ?? 'REPORT';
|
||||
const prefix = xsd.split('_')[0] ?? 'REPORT';
|
||||
const prefix = xsd.split('_').slice(0, 2).join('_') || 'REPORT';
|
||||
const now = new Date();
|
||||
const dateStr = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}`;
|
||||
const unit = `${inn}${kpp}`;
|
||||
const tax = kpp.substring(0, 4);
|
||||
const uuid = randomUUID();
|
||||
if (reportType === ReportType.FSS4) {
|
||||
return `СФР_0000000000_ЕФС-1_${dateStr}_${uuid}`;
|
||||
// Сегмент отправителя в имени файла — рег. номер ПФР организации, не
|
||||
// заглушка из нулей: сторонние бухгалтерские системы (СБИС и др.)
|
||||
// сверяют этот сегмент со своим профилем организации и отклоняют файл,
|
||||
// если он не совпадает ни с известным им номером ПФР, ни с номером
|
||||
// СФР. См. также <ЕФС8:РегНомер> в fss4.generator.ts — то же значение.
|
||||
return `СФР_${pfrRegNumber || '0000000000'}_ЕФС-1_${dateStr}_${uuid}`;
|
||||
}
|
||||
return `${prefix}_${tax}_${tax}_${unit}_${dateStr}_${uuid}`;
|
||||
}
|
||||
|
||||
+5
@@ -39,6 +39,8 @@ export interface MergedRequisites {
|
||||
oktmo: RequisiteField;
|
||||
okpo: RequisiteField;
|
||||
sfrRegNumber: RequisiteField;
|
||||
/** Рег. номер страхователя в ПФР (XXX-XXX-XXXXXX) — отдельный от sfrRegNumber, требуется для ЕФС-1. */
|
||||
pfrRegNumber: RequisiteField;
|
||||
chairmanPosition: RequisiteField;
|
||||
signerSnils: RequisiteField;
|
||||
signerRepDoc: RequisiteField;
|
||||
@@ -94,6 +96,7 @@ const REQUIRED_BY_TYPE: Record<ReportType, RequiredFieldSpec[]> = {
|
||||
[ReportType.FSS4]: [
|
||||
{ key: 'oktmo', label: 'ОКТМО', source: 'manual' },
|
||||
{ key: 'sfrRegNumber', label: 'Регистрационный номер в СФР', source: 'manual' },
|
||||
{ key: 'pfrRegNumber', label: 'Регистрационный номер в ПФР', source: 'manual' },
|
||||
{ key: 'chairmanPosition', label: 'Должность руководителя', source: 'manual' },
|
||||
],
|
||||
[ReportType.PSV]: [{ key: 'signerSnils', label: 'СНИЛС подписанта', source: 'manual' }],
|
||||
@@ -152,6 +155,7 @@ export class ReportRequisitesService {
|
||||
oktmo: mn(manual?.oktmo),
|
||||
okpo: mn(manual?.okpo),
|
||||
sfrRegNumber: mn(manual?.sfr_reg_number),
|
||||
pfrRegNumber: mn(manual?.pfr_reg_number),
|
||||
chairmanPosition: mn(manual?.chairman_position),
|
||||
signerSnils: mn(manual?.signer_snils),
|
||||
signerRepDoc: mn(manual?.signer_rep_doc),
|
||||
@@ -218,6 +222,7 @@ export class ReportRequisitesService {
|
||||
oktmo: input.oktmo ?? undefined,
|
||||
okpo: input.okpo ?? undefined,
|
||||
sfr_reg_number: input.sfr_reg_number ?? undefined,
|
||||
pfr_reg_number: input.pfr_reg_number ?? undefined,
|
||||
chairman_position: input.chairman_position ?? undefined,
|
||||
signer_snils: input.signer_snils ?? undefined,
|
||||
signer_rep_doc: input.signer_rep_doc ?? undefined,
|
||||
|
||||
+4
@@ -5,6 +5,7 @@ import { Entity, Column, PrimaryColumn, UpdateDateColumn } from 'typeorm';
|
||||
*
|
||||
* Хранятся поля, которых нет в профиле организации (`IOrganizationData` в
|
||||
* основной БД кооператива): ОКВЭД, ОКФС, ОКОПФ, ОКТМО, ОКПО, регномер СФР,
|
||||
* регномер ПФР (для ЕФС-1 — отдельный от regномера СФР, см. patterns.ts),
|
||||
* должность руководителя, СНИЛС подписанта, описание доверенности. Плюс
|
||||
* возможные override'ы телефона и адреса (если в отчётности нужен не тот,
|
||||
* что в профиле организации).
|
||||
@@ -34,6 +35,9 @@ export class ReportRequisitesEntity {
|
||||
@Column({ type: 'varchar', length: 32, nullable: true })
|
||||
sfr_reg_number?: string | null;
|
||||
|
||||
@Column({ type: 'varchar', length: 32, nullable: true })
|
||||
pfr_reg_number?: string | null;
|
||||
|
||||
@Column({ type: 'varchar', length: 255, nullable: true })
|
||||
chairman_position?: string | null;
|
||||
|
||||
|
||||
+14
-2
@@ -68,6 +68,13 @@ export class Fss4Generator implements IReportGenerator {
|
||||
const errors: string[] = [];
|
||||
if (!edits.signer.sfrRegNumber) {
|
||||
errors.push('Для ЕФС-1 обязателен рег. номер страхователя в СФР (поле signer.sfrRegNumber)');
|
||||
}
|
||||
if (!edits.signer.pfrRegNumber) {
|
||||
// pfrRegNumber, а не sfrRegNumber, идёт в <ЕФС8:РегНомер> и в имя
|
||||
// файла — см. комментарий у strah.ele('ЕФС8:РегНомер') ниже.
|
||||
errors.push('Для ЕФС-1 обязателен рег. номер страхователя в ПФР (поле signer.pfrRegNumber)');
|
||||
}
|
||||
if (errors.length) {
|
||||
return { reportType: this.reportType, xml: '', fileName, errors, isValid: false };
|
||||
}
|
||||
try {
|
||||
@@ -100,8 +107,13 @@ export class Fss4Generator implements IReportGenerator {
|
||||
const efs1 = edsfr.ele('ЕФС-1');
|
||||
|
||||
const strah = efs1.ele('Страхователь');
|
||||
// sfrRegNumber гарантированно определён — guard в generate() выше.
|
||||
strah.ele('ЕФС8:РегНомер').txt(signer.sfrRegNumber ?? '').up();
|
||||
// Тег «Действующий регистрационный номер страхователя» (см. XSD
|
||||
// efs-types.xsd/ТипСтрахователь) — сюда идёт номер ПФР, а не СФР:
|
||||
// сторонние бухгалтерские системы (СБИС и др.) при приёме ЕФС-1 сверяют
|
||||
// рег. номер отправителя в имени файла и в этом теге со своим профилем
|
||||
// организации, где обычно заведён именно старый номер ПФР (XXX-XXX-XXXXXX).
|
||||
// pfrRegNumber гарантированно определён — guard в generate() выше.
|
||||
strah.ele('ЕФС8:РегНомер').txt(signer.pfrRegNumber ?? '').up();
|
||||
strah.ele('ЕФС8:Наименование').txt(organization.orgName).up();
|
||||
strah.ele('УТ8:ИНН').txt(organization.inn).up();
|
||||
strah.ele('УТ8:КПП').txt(organization.kpp).up();
|
||||
|
||||
+2
@@ -39,6 +39,7 @@ export class ReportRequisitesTypeormRepository implements ReportRequisitesReposi
|
||||
if (input.oktmo !== undefined) row.oktmo = input.oktmo;
|
||||
if (input.okpo !== undefined) row.okpo = input.okpo;
|
||||
if (input.sfr_reg_number !== undefined) row.sfr_reg_number = input.sfr_reg_number;
|
||||
if (input.pfr_reg_number !== undefined) row.pfr_reg_number = input.pfr_reg_number;
|
||||
if (input.chairman_position !== undefined) row.chairman_position = input.chairman_position;
|
||||
if (input.signer_snils !== undefined) row.signer_snils = input.signer_snils;
|
||||
if (input.signer_rep_doc !== undefined) row.signer_rep_doc = input.signer_rep_doc;
|
||||
@@ -66,6 +67,7 @@ export class ReportRequisitesTypeormRepository implements ReportRequisitesReposi
|
||||
oktmo: entity.oktmo ?? null,
|
||||
okpo: entity.okpo ?? null,
|
||||
sfr_reg_number: entity.sfr_reg_number ?? null,
|
||||
pfr_reg_number: entity.pfr_reg_number ?? null,
|
||||
chairman_position: entity.chairman_position ?? null,
|
||||
signer_snils: entity.signer_snils ?? null,
|
||||
signer_rep_doc: entity.signer_rep_doc ?? null,
|
||||
|
||||
@@ -202,6 +202,7 @@ const zeroBaseEdits: ZeroReportEditsShape = {
|
||||
repDoc: 'Доверенность №1 от 01.01.2024',
|
||||
snils: '123-456-789 00',
|
||||
sfrRegNumber: '7701234567',
|
||||
pfrRegNumber: '087-701-579643',
|
||||
chairmanPosition: 'Председатель Совета',
|
||||
},
|
||||
};
|
||||
@@ -581,6 +582,21 @@ describe('ЕФС-1 (Fss4Generator, СФР)', () => {
|
||||
expect(result.errors.join('|')).toContain('sfrRegNumber');
|
||||
});
|
||||
|
||||
it('возвращает ошибку без pfrRegNumber', () => {
|
||||
const result = gen.generate({
|
||||
...withPeriod(1),
|
||||
signer: { ...zeroBaseEdits.signer, pfrRegNumber: null },
|
||||
});
|
||||
expect(result.isValid).toBe(false);
|
||||
expect(result.errors.join('|')).toContain('pfrRegNumber');
|
||||
});
|
||||
|
||||
it('использует pfrRegNumber (не sfrRegNumber) в <ЕФС8:РегНомер> — сторонние бухгалтерские системы сверяют именно рег. номер ПФР', () => {
|
||||
const result = gen.generate(withPeriod(1));
|
||||
expect(result.xml).toContain('<ЕФС8:РегНомер>087-701-579643</ЕФС8:РегНомер>');
|
||||
expect(result.xml).not.toContain('<ЕФС8:РегНомер>7701234567</ЕФС8:РегНомер>');
|
||||
});
|
||||
|
||||
it('эхом возвращает header.idFile в result.fileName', () => {
|
||||
const result = gen.generate({
|
||||
...withPeriod(1),
|
||||
|
||||
@@ -4821,6 +4821,7 @@ export const ReturnTypes: Record<string,any> = {
|
||||
oktmo:"RequisiteFieldView",
|
||||
okved:"RequisiteFieldView",
|
||||
orgName:"RequisiteFieldView",
|
||||
pfrRegNumber:"RequisiteFieldView",
|
||||
phone:"RequisiteFieldView",
|
||||
sfrRegNumber:"RequisiteFieldView",
|
||||
signerFirstName:"RequisiteFieldView",
|
||||
@@ -5063,6 +5064,7 @@ export const ReturnTypes: Record<string,any> = {
|
||||
firstName:"String",
|
||||
lastName:"String",
|
||||
middleName:"String",
|
||||
pfrRegNumber:"String",
|
||||
repDoc:"String",
|
||||
sfrRegNumber:"String",
|
||||
snils:"String",
|
||||
|
||||
@@ -9043,6 +9043,7 @@ validateReportEdits?: [{ editsJson: string | Variable<any, string>, reportType:
|
||||
oktmo?:ValueTypes["RequisiteFieldView"],
|
||||
okved?:ValueTypes["RequisiteFieldView"],
|
||||
orgName?:ValueTypes["RequisiteFieldView"],
|
||||
pfrRegNumber?:ValueTypes["RequisiteFieldView"],
|
||||
phone?:ValueTypes["RequisiteFieldView"],
|
||||
sfrRegNumber?:ValueTypes["RequisiteFieldView"],
|
||||
signerFirstName?:ValueTypes["RequisiteFieldView"],
|
||||
@@ -10179,8 +10180,10 @@ validateReportEdits?: [{ editsJson: string | Variable<any, string>, reportType:
|
||||
oktmo?: string | undefined | null | Variable<any, string>,
|
||||
/** ОКВЭД — напр. 94.99, 46.73.7 */
|
||||
okved?: string | undefined | null | Variable<any, string>,
|
||||
/** Рег. номер ПФР — XXX-XXX-XXXXXX (для ЕФС-1, отдельно от рег. номера СФР) */
|
||||
pfrRegNumber?: string | undefined | null | Variable<any, string>,
|
||||
phoneOverride?: string | undefined | null | Variable<any, string>,
|
||||
/** Рег. номер СФР — XXX-XXX-XXXXXX */
|
||||
/** Рег. номер СФР — 10 цифр */
|
||||
sfrRegNumber?: string | undefined | null | Variable<any, string>,
|
||||
signerRepDoc?: string | undefined | null | Variable<any, string>,
|
||||
/** СНИЛС — XXX-XXX-XXX YY или 11 цифр */
|
||||
@@ -10482,6 +10485,7 @@ validateReportEdits?: [{ editsJson: string | Variable<any, string>, reportType:
|
||||
firstName?:boolean | `@${string}`,
|
||||
lastName?:boolean | `@${string}`,
|
||||
middleName?:boolean | `@${string}`,
|
||||
pfrRegNumber?:boolean | `@${string}`,
|
||||
repDoc?:boolean | `@${string}`,
|
||||
sfrRegNumber?:boolean | `@${string}`,
|
||||
snils?:boolean | `@${string}`,
|
||||
@@ -18204,6 +18208,7 @@ validateReportEdits?: [{ editsJson: string, reportType: ResolverInputTypes["Repo
|
||||
oktmo?:ResolverInputTypes["RequisiteFieldView"],
|
||||
okved?:ResolverInputTypes["RequisiteFieldView"],
|
||||
orgName?:ResolverInputTypes["RequisiteFieldView"],
|
||||
pfrRegNumber?:ResolverInputTypes["RequisiteFieldView"],
|
||||
phone?:ResolverInputTypes["RequisiteFieldView"],
|
||||
sfrRegNumber?:ResolverInputTypes["RequisiteFieldView"],
|
||||
signerFirstName?:ResolverInputTypes["RequisiteFieldView"],
|
||||
@@ -19317,8 +19322,10 @@ validateReportEdits?: [{ editsJson: string, reportType: ResolverInputTypes["Repo
|
||||
oktmo?: string | undefined | null,
|
||||
/** ОКВЭД — напр. 94.99, 46.73.7 */
|
||||
okved?: string | undefined | null,
|
||||
/** Рег. номер ПФР — XXX-XXX-XXXXXX (для ЕФС-1, отдельно от рег. номера СФР) */
|
||||
pfrRegNumber?: string | undefined | null,
|
||||
phoneOverride?: string | undefined | null,
|
||||
/** Рег. номер СФР — XXX-XXX-XXXXXX */
|
||||
/** Рег. номер СФР — 10 цифр */
|
||||
sfrRegNumber?: string | undefined | null,
|
||||
signerRepDoc?: string | undefined | null,
|
||||
/** СНИЛС — XXX-XXX-XXX YY или 11 цифр */
|
||||
@@ -19614,6 +19621,7 @@ validateReportEdits?: [{ editsJson: string, reportType: ResolverInputTypes["Repo
|
||||
firstName?:boolean | `@${string}`,
|
||||
lastName?:boolean | `@${string}`,
|
||||
middleName?:boolean | `@${string}`,
|
||||
pfrRegNumber?:boolean | `@${string}`,
|
||||
repDoc?:boolean | `@${string}`,
|
||||
sfrRegNumber?:boolean | `@${string}`,
|
||||
snils?:boolean | `@${string}`,
|
||||
@@ -27847,6 +27855,7 @@ export type ModelTypes = {
|
||||
oktmo: ModelTypes["RequisiteFieldView"],
|
||||
okved: ModelTypes["RequisiteFieldView"],
|
||||
orgName: ModelTypes["RequisiteFieldView"],
|
||||
pfrRegNumber: ModelTypes["RequisiteFieldView"],
|
||||
phone: ModelTypes["RequisiteFieldView"],
|
||||
sfrRegNumber: ModelTypes["RequisiteFieldView"],
|
||||
signerFirstName: ModelTypes["RequisiteFieldView"],
|
||||
@@ -28930,8 +28939,10 @@ export type ModelTypes = {
|
||||
oktmo?: string | undefined | null,
|
||||
/** ОКВЭД — напр. 94.99, 46.73.7 */
|
||||
okved?: string | undefined | null,
|
||||
/** Рег. номер ПФР — XXX-XXX-XXXXXX (для ЕФС-1, отдельно от рег. номера СФР) */
|
||||
pfrRegNumber?: string | undefined | null,
|
||||
phoneOverride?: string | undefined | null,
|
||||
/** Рег. номер СФР — XXX-XXX-XXXXXX */
|
||||
/** Рег. номер СФР — 10 цифр */
|
||||
sfrRegNumber?: string | undefined | null,
|
||||
signerRepDoc?: string | undefined | null,
|
||||
/** СНИЛС — XXX-XXX-XXX YY или 11 цифр */
|
||||
@@ -29214,6 +29225,7 @@ export type ModelTypes = {
|
||||
firstName: string,
|
||||
lastName: string,
|
||||
middleName?: string | undefined | null,
|
||||
pfrRegNumber?: string | undefined | null,
|
||||
repDoc?: string | undefined | null,
|
||||
sfrRegNumber?: string | undefined | null,
|
||||
snils?: string | undefined | null,
|
||||
@@ -37955,6 +37967,7 @@ export type GraphQLTypes = {
|
||||
oktmo: GraphQLTypes["RequisiteFieldView"],
|
||||
okved: GraphQLTypes["RequisiteFieldView"],
|
||||
orgName: GraphQLTypes["RequisiteFieldView"],
|
||||
pfrRegNumber: GraphQLTypes["RequisiteFieldView"],
|
||||
phone: GraphQLTypes["RequisiteFieldView"],
|
||||
sfrRegNumber: GraphQLTypes["RequisiteFieldView"],
|
||||
signerFirstName: GraphQLTypes["RequisiteFieldView"],
|
||||
@@ -39090,8 +39103,10 @@ export type GraphQLTypes = {
|
||||
oktmo?: string | undefined | null,
|
||||
/** ОКВЭД — напр. 94.99, 46.73.7 */
|
||||
okved?: string | undefined | null,
|
||||
/** Рег. номер ПФР — XXX-XXX-XXXXXX (для ЕФС-1, отдельно от рег. номера СФР) */
|
||||
pfrRegNumber?: string | undefined | null,
|
||||
phoneOverride?: string | undefined | null,
|
||||
/** Рег. номер СФР — XXX-XXX-XXXXXX */
|
||||
/** Рег. номер СФР — 10 цифр */
|
||||
sfrRegNumber?: string | undefined | null,
|
||||
signerRepDoc?: string | undefined | null,
|
||||
/** СНИЛС — XXX-XXX-XXX YY или 11 цифр */
|
||||
@@ -39395,6 +39410,7 @@ export type GraphQLTypes = {
|
||||
firstName: string,
|
||||
lastName: string,
|
||||
middleName?: string | undefined | null,
|
||||
pfrRegNumber?: string | undefined | null,
|
||||
repDoc?: string | undefined | null,
|
||||
sfrRegNumber?: string | undefined | null,
|
||||
snils?: string | undefined | null,
|
||||
|
||||
+60
-8
@@ -116,6 +116,21 @@ q-dialog(
|
||||
span(v-if='isValid') Форма валидна
|
||||
span(v-else) Ошибок: {{ errorsCount }}
|
||||
|
||||
//- Явный список ошибок полей — страховка на случай, если конкретное
|
||||
//- поле формы не подсвечивается инлайн (не все секции формы ещё
|
||||
//- подключены к fieldErrors). Без этого списка счётчик показывал
|
||||
//- «Ошибок: N» без единой подсказки, где именно искать.
|
||||
q-list.error-list.q-mb-sm(
|
||||
v-if='!isValid && fieldErrorEntries.length'
|
||||
dense bordered separator
|
||||
)
|
||||
q-item(v-for='err in fieldErrorEntries' :key='err.key' dense)
|
||||
q-item-section(avatar top)
|
||||
q-icon(name='fa-solid fa-circle-exclamation' color='negative' size='14px')
|
||||
q-item-section
|
||||
q-item-label.text-caption.text-weight-medium {{ err.label }}
|
||||
q-item-label(caption) {{ err.message }}
|
||||
|
||||
.text-subtitle2.q-mb-sm Действия
|
||||
|
||||
q-btn.q-mb-sm(
|
||||
@@ -126,7 +141,6 @@ q-dialog(
|
||||
:loading='isGenerating'
|
||||
@click='downloadXml'
|
||||
no-caps
|
||||
stack
|
||||
)
|
||||
q-tooltip Сохраняет черновик, генерирует XML, валидирует XSD и скачивает файл
|
||||
q-btn.q-mb-sm(
|
||||
@@ -137,7 +151,6 @@ q-dialog(
|
||||
:loading='pdfLoading'
|
||||
@click='downloadPdf'
|
||||
no-caps
|
||||
stack
|
||||
)
|
||||
q-tooltip(v-if='!hasPdfPaperView') PDF-экспорт для {{ reportTitle }} пока не поддерживается
|
||||
q-tooltip(v-else) Заполненный отчёт в PDF (из бумажного вида)
|
||||
@@ -152,7 +165,6 @@ q-dialog(
|
||||
:disable='isLoading'
|
||||
@click='regenerate'
|
||||
no-caps
|
||||
stack
|
||||
)
|
||||
q-tooltip Подтянуть актуальные данные из реестра; ваши правки сохраняются
|
||||
|
||||
@@ -164,7 +176,6 @@ q-dialog(
|
||||
label='Удалить черновик'
|
||||
@click='clearDraft'
|
||||
no-caps
|
||||
stack
|
||||
)
|
||||
q-tooltip Вернуть форму к дефолтам
|
||||
|
||||
@@ -192,7 +203,6 @@ q-dialog(
|
||||
:loading='markLoading'
|
||||
@click='clearMark'
|
||||
no-caps
|
||||
stack
|
||||
)
|
||||
q-tooltip Вернуть обычный статус периода
|
||||
|
||||
@@ -207,7 +217,6 @@ q-dialog(
|
||||
:loading='markLoading'
|
||||
@click='clearMark'
|
||||
no-caps
|
||||
stack
|
||||
)
|
||||
q-tooltip Вернуть обычный статус периода
|
||||
|
||||
@@ -220,7 +229,6 @@ q-dialog(
|
||||
:loading='markLoading'
|
||||
@click='markSubmittedExternally'
|
||||
no-caps
|
||||
stack
|
||||
)
|
||||
q-tooltip Если отчёт уже сдан в бумаге / через стороннюю систему. В архив XML не попадает, но ячейка станет зелёной.
|
||||
q-btn(
|
||||
@@ -231,7 +239,6 @@ q-dialog(
|
||||
:loading='markLoading'
|
||||
@click='markNotRequired'
|
||||
no-caps
|
||||
stack
|
||||
)
|
||||
q-tooltip Отметить, что этот период сдавать не нужно — ячейка станет серой
|
||||
|
||||
@@ -484,6 +491,7 @@ interface ZeroReportEdits {
|
||||
repDoc: string | null
|
||||
snils: string | null
|
||||
sfrRegNumber: string | null
|
||||
pfrRegNumber: string | null
|
||||
chairmanPosition: string | null
|
||||
}
|
||||
}
|
||||
@@ -513,6 +521,34 @@ const errorsCount = computed(() => {
|
||||
return count
|
||||
})
|
||||
|
||||
// Человекочитаемые названия секций формы — для расшифровки JSONPath из
|
||||
// серверной ошибки валидации (см. error-list ниже).
|
||||
const FIELD_SECTION_LABELS: Record<string, string> = {
|
||||
header: 'Шапка',
|
||||
organization: 'Организация',
|
||||
signer: 'Подписант',
|
||||
balance: 'Баланс',
|
||||
notes: 'Пояснения',
|
||||
}
|
||||
|
||||
function humanizeFieldPath(path: string): string {
|
||||
const [section, ...rest] = path.split('.')
|
||||
const sectionLabel = FIELD_SECTION_LABELS[section] ?? section
|
||||
return rest.length ? `${sectionLabel} → ${rest.join(' → ')}` : sectionLabel
|
||||
}
|
||||
|
||||
interface FieldErrorEntry { key: string; label: string; message: string }
|
||||
|
||||
const fieldErrorEntries = computed<FieldErrorEntry[]>(() => {
|
||||
const out: FieldErrorEntry[] = []
|
||||
for (const [path, messages] of Object.entries(fieldErrors.value)) {
|
||||
messages.forEach((message, i) => {
|
||||
out.push({ key: `${path}#${i}`, label: humanizeFieldPath(path), message })
|
||||
})
|
||||
}
|
||||
return out
|
||||
})
|
||||
|
||||
const saveStatusColor = computed(() => {
|
||||
if (isSaving.value) return 'orange'
|
||||
if (hasDraft.value) return 'positive'
|
||||
@@ -839,6 +875,22 @@ function goToRequisites(): void {
|
||||
}
|
||||
}
|
||||
|
||||
.error-list {
|
||||
background: var(--p-surface-1, #fff);
|
||||
border-color: var(--p-neg-soft);
|
||||
max-height: 220px;
|
||||
overflow-y: auto;
|
||||
|
||||
:deep(.q-item) {
|
||||
min-height: unset;
|
||||
padding: 6px 8px;
|
||||
}
|
||||
|
||||
:deep(.q-item__label--caption) {
|
||||
color: var(--p-ink-2);
|
||||
}
|
||||
}
|
||||
|
||||
.mark-hint {
|
||||
font-size: var(--p-fs-meta, 12px);
|
||||
color: var(--p-ink-2);
|
||||
|
||||
@@ -46,11 +46,11 @@ q-form.settings-page(@submit.prevent='save' @validation-error='onValidationError
|
||||
@update:value='v => (manualInput[f.key] = v)'
|
||||
)
|
||||
|
||||
//- СФР (ЕФС-1)
|
||||
//- СФР/ПФР (ЕФС-1)
|
||||
q-card.q-mt-md(flat)
|
||||
q-card-section.q-py-sm
|
||||
.text-h6 СФР (для ЕФС-1)
|
||||
.text-caption.t-muted Регистрационный номер СФР и должность председателя
|
||||
.text-h6 СФР/ПФР (для ЕФС-1)
|
||||
.text-caption.t-muted Регистрационные номера страхователя и должность председателя
|
||||
|
||||
q-separator
|
||||
|
||||
@@ -60,14 +60,27 @@ q-form.settings-page(@submit.prevent='save' @validation-error='onValidationError
|
||||
id='field-sfrRegNumber'
|
||||
label='Рег. номер СФР'
|
||||
:value='manualInput.sfrRegNumber'
|
||||
placeholder='XXX-XXX-XXXXXX или 10 цифр'
|
||||
digits-extra-chars='-'
|
||||
:max-length='14'
|
||||
placeholder='10 цифр'
|
||||
mask='##########'
|
||||
:max-length='10'
|
||||
:exact-lengths='[10]'
|
||||
:pattern='SFR_REG_PATTERN'
|
||||
pattern-message='Формат: XXX-XXX-XXXXXX (12 цифр) или 10 цифр без разделителей'
|
||||
pattern-message='Формат: 10 цифр без разделителей'
|
||||
required
|
||||
@update:value='v => (manualInput.sfrRegNumber = v)'
|
||||
)
|
||||
RequisiteField.col-md-6.col-12(
|
||||
id='field-pfrRegNumber'
|
||||
label='Рег. номер ПФР'
|
||||
:value='manualInput.pfrRegNumber'
|
||||
placeholder='XXX-XXX-XXXXXX'
|
||||
mask='###-###-######'
|
||||
:max-length='14'
|
||||
:pattern='PFR_REG_PATTERN'
|
||||
pattern-message='Формат: XXX-XXX-XXXXXX (12 цифр с тире)'
|
||||
required
|
||||
@update:value='v => (manualInput.pfrRegNumber = v)'
|
||||
)
|
||||
RequisiteField.col-md-6.col-12(
|
||||
id='field-chairmanPosition'
|
||||
label='Должность председателя'
|
||||
@@ -164,6 +177,7 @@ type ManualKey =
|
||||
| 'oktmo'
|
||||
| 'okpo'
|
||||
| 'sfrRegNumber'
|
||||
| 'pfrRegNumber'
|
||||
| 'chairmanPosition'
|
||||
| 'signerSnils'
|
||||
| 'signerRepDoc'
|
||||
@@ -177,6 +191,7 @@ const manualInput = reactive<Record<ManualKey, string>>({
|
||||
oktmo: '',
|
||||
okpo: '',
|
||||
sfrRegNumber: '',
|
||||
pfrRegNumber: '',
|
||||
chairmanPosition: '',
|
||||
signerSnils: '',
|
||||
signerRepDoc: '',
|
||||
@@ -266,7 +281,8 @@ const signerTypeOptions = [
|
||||
// пользователь прожал пару цифр и нажал «Сохранить»: mask не мешает
|
||||
// сохранить частичный ввод, паттерн-правило блокирует.
|
||||
const SNILS_PATTERN = /^\d{3}-\d{3}-\d{3} \d{2}$/
|
||||
const SFR_REG_PATTERN = /^(\d{3}-\d{3}-\d{6}|\d{10})$/
|
||||
const SFR_REG_PATTERN = /^\d{10}$/
|
||||
const PFR_REG_PATTERN = /^\d{3}-\d{3}-\d{6}$/
|
||||
|
||||
function getValue(key: keyof IReportRequisitesView): string {
|
||||
const v = requisites.value?.[key] as any
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
@update:model-value='v => emitField("otch", v)'
|
||||
dense outlined
|
||||
input-class='text-right'
|
||||
:error='errFor("otch")'
|
||||
:error-message='msgFor("otch")'
|
||||
)
|
||||
.br-input
|
||||
q-input(
|
||||
@@ -17,6 +19,8 @@
|
||||
@update:model-value='v => emitField("prev", v)'
|
||||
dense outlined
|
||||
input-class='text-right'
|
||||
:error='errFor("prev")'
|
||||
:error-message='msgFor("prev")'
|
||||
)
|
||||
.br-input
|
||||
q-input(
|
||||
@@ -25,6 +29,8 @@
|
||||
@update:model-value='v => emitField("prePrev", v)'
|
||||
dense outlined
|
||||
input-class='text-right'
|
||||
:error='errFor("prePrev")'
|
||||
:error-message='msgFor("prePrev")'
|
||||
)
|
||||
</template>
|
||||
|
||||
@@ -39,6 +45,10 @@ const props = defineProps<{
|
||||
label: string
|
||||
code: string
|
||||
row: BalanceRow | null
|
||||
/** JSONPath строки без учёта суффикса (например "balance.assetsTotal") — для сопоставления с fieldErrors. */
|
||||
basePath?: string
|
||||
/** Серверные ошибки валидации всей формы: ключ = JSONPath поля. */
|
||||
fieldErrors?: Record<string, string[]>
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -58,6 +68,18 @@ function emitField(key: keyof BalanceRow, raw: unknown): void {
|
||||
const next: BalanceRow = { ...base, [key]: clamp(raw) }
|
||||
emit('update', next)
|
||||
}
|
||||
|
||||
function pathFor(key: keyof BalanceRow): string {
|
||||
return props.basePath ? `${props.basePath}.${key}` : key
|
||||
}
|
||||
|
||||
function errFor(key: keyof BalanceRow): boolean {
|
||||
return (props.fieldErrors?.[pathFor(key)]?.length ?? 0) > 0
|
||||
}
|
||||
|
||||
function msgFor(key: keyof BalanceRow): string {
|
||||
return props.fieldErrors?.[pathFor(key)]?.[0] ?? ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
:model-value='editsValue.header.correctionNumber'
|
||||
@update:model-value='v => updateField("header.correctionNumber", clampInt(v, 0, 999))'
|
||||
:rules='[v => (v >= 0 && v <= 999) || "0..999"]'
|
||||
:error='errFor("header.correctionNumber")'
|
||||
:error-message='msgFor("header.correctionNumber")'
|
||||
dense filled
|
||||
)
|
||||
q-input(
|
||||
@@ -18,6 +20,8 @@
|
||||
type='number'
|
||||
:model-value='editsValue.header.reportYear'
|
||||
@update:model-value='v => updateField("header.reportYear", clampInt(v, 2000, 2100))'
|
||||
:error='errFor("header.reportYear")'
|
||||
:error-message='msgFor("header.reportYear")'
|
||||
dense filled
|
||||
)
|
||||
q-input(
|
||||
@@ -26,6 +30,8 @@
|
||||
@update:model-value='v => updateField("header.docDate", v)'
|
||||
mask='##.##.####'
|
||||
:rules='[reportRules.dateDdMmYyyy()]'
|
||||
:error='errFor("header.docDate")'
|
||||
:error-message='msgFor("header.docDate")'
|
||||
dense filled
|
||||
)
|
||||
|
||||
@@ -191,24 +197,32 @@
|
||||
label='Нематериальные, финансовые и др. внеоборотные активы'
|
||||
code='1170'
|
||||
:row='editsValue.balance.nonMaterialAndLongFin'
|
||||
base-path='balance.nonMaterialAndLongFin'
|
||||
:field-errors='props.fieldErrors'
|
||||
@update='row => updateRow("balance.nonMaterialAndLongFin", row)'
|
||||
)
|
||||
BalanceRowEditor(
|
||||
label='Денежные средства и денежные эквиваленты'
|
||||
code='1250'
|
||||
:row='editsValue.balance.cash'
|
||||
base-path='balance.cash'
|
||||
:field-errors='props.fieldErrors'
|
||||
@update='row => updateRow("balance.cash", row)'
|
||||
)
|
||||
BalanceRowEditor(
|
||||
label='Финансовые и другие оборотные активы'
|
||||
code='1260'
|
||||
:row='editsValue.balance.shortTermFin'
|
||||
base-path='balance.shortTermFin'
|
||||
:field-errors='props.fieldErrors'
|
||||
@update='row => updateRow("balance.shortTermFin", row)'
|
||||
)
|
||||
BalanceRowEditor.total(
|
||||
label='БАЛАНС (актив)'
|
||||
code='1600'
|
||||
:row='editsValue.balance.assetsTotal'
|
||||
base-path='balance.assetsTotal'
|
||||
:field-errors='props.fieldErrors'
|
||||
@update='row => updateRow("balance.assetsTotal", row)'
|
||||
)
|
||||
|
||||
@@ -218,12 +232,16 @@
|
||||
label='Целевые средства (паевой фонд + целевые поступления)'
|
||||
code='1350'
|
||||
:row='editsValue.balance.targetFunds'
|
||||
base-path='balance.targetFunds'
|
||||
:field-errors='props.fieldErrors'
|
||||
@update='row => updateRow("balance.targetFunds", row)'
|
||||
)
|
||||
BalanceRowEditor.total(
|
||||
label='БАЛАНС (пассив)'
|
||||
code='1700'
|
||||
:row='editsValue.balance.passivesTotal'
|
||||
base-path='balance.passivesTotal'
|
||||
:field-errors='props.fieldErrors'
|
||||
@update='row => updateRow("balance.passivesTotal", row)'
|
||||
)
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
|
||||
.kv-row
|
||||
.kv-cell
|
||||
.kv-label Регистрационный номер в СФР
|
||||
.kv-value.code {{ header.sfrRegNumber || '—' }}
|
||||
.kv-label Регистрационный номер страхователя
|
||||
.kv-value.code {{ header.pfrRegNumber || '—' }}
|
||||
.kv-cell
|
||||
.kv-label ОГРН
|
||||
.kv-value.code {{ ogrn || '—' }}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
type='number'
|
||||
:model-value='editsValue.header.reportYear'
|
||||
@update:model-value='v => updateField("header.reportYear", clampInt(v, 2000, 2100))'
|
||||
:error='errFor("header.reportYear")'
|
||||
:error-message='msgFor("header.reportYear")'
|
||||
dense filled
|
||||
)
|
||||
q-input(
|
||||
@@ -17,6 +19,8 @@
|
||||
type='number'
|
||||
:model-value='editsValue.header.period'
|
||||
@update:model-value='v => updateField("header.period", clampInt(v, 1, periodKind === "quarter" ? 4 : 12))'
|
||||
:error='errFor("header.period")'
|
||||
:error-message='msgFor("header.period")'
|
||||
dense filled
|
||||
)
|
||||
q-input(
|
||||
@@ -162,8 +166,20 @@
|
||||
:rules='[reportRules.sfrRegNumber()]'
|
||||
:error='errFor("signer.sfrRegNumber")'
|
||||
:error-message='msgFor("signer.sfrRegNumber")'
|
||||
maxlength='10'
|
||||
hint='10 цифр — обязателен для ЕФС-1'
|
||||
dense filled
|
||||
)
|
||||
|
||||
q-input(
|
||||
v-if='needs.sfrExtras'
|
||||
label='Регистрационный номер ПФР'
|
||||
:model-value='editsValue.signer.pfrRegNumber || ""'
|
||||
@update:model-value='v => updateField("signer.pfrRegNumber", v || null)'
|
||||
:rules='[reportRules.pfrRegNumber()]'
|
||||
:error='errFor("signer.pfrRegNumber")'
|
||||
:error-message='msgFor("signer.pfrRegNumber")'
|
||||
maxlength='14'
|
||||
hint='XXX-XXX-XXXXXX или 10 цифр — обязателен для ЕФС-1'
|
||||
dense filled
|
||||
)
|
||||
|
||||
@@ -215,6 +231,7 @@ interface ZeroReportEdits {
|
||||
repDoc: string | null
|
||||
snils: string | null
|
||||
sfrRegNumber: string | null
|
||||
pfrRegNumber: string | null
|
||||
chairmanPosition: string | null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,8 @@ export interface BaseHeader {
|
||||
signerMiddleName: string
|
||||
signerRepDoc: string
|
||||
signerSnils: string
|
||||
sfrRegNumber: string
|
||||
/** Рег. номер ПФР — читается из тега `<РегНомер>` ЕФС-1 (fss4.generator.ts кладёт туда именно ПФР, не СФР). */
|
||||
pfrRegNumber: string
|
||||
}
|
||||
|
||||
export interface UseReportXmlReturn {
|
||||
@@ -117,7 +118,7 @@ export function useReportXml(
|
||||
signerLastName: '', signerFirstName: '', signerMiddleName: '',
|
||||
signerRepDoc: '',
|
||||
signerSnils: '',
|
||||
sfrRegNumber: '',
|
||||
pfrRegNumber: '',
|
||||
}
|
||||
|
||||
if (!doc.value) return withRequisites(empty)
|
||||
@@ -147,7 +148,7 @@ export function useReportXml(
|
||||
signerMiddleName: getAttr('Подписант ФИО', 'Отчество') || getText('Отчество'),
|
||||
signerRepDoc: getAttr('Подписант СвПред', 'НаимДок'),
|
||||
signerSnils: getAttr('ПерсСвФЛ', 'СНИЛС'),
|
||||
sfrRegNumber: getText('РегНомер'),
|
||||
pfrRegNumber: getText('РегНомер'),
|
||||
}
|
||||
return withRequisites(h)
|
||||
})
|
||||
@@ -174,7 +175,7 @@ export function useReportXml(
|
||||
signerFirstName: h.signerFirstName || get('signerFirstName'),
|
||||
signerMiddleName: h.signerMiddleName || get('signerMiddleName'),
|
||||
signerSnils: h.signerSnils || get('signerSnils'),
|
||||
sfrRegNumber: h.sfrRegNumber || get('sfrRegNumber'),
|
||||
pfrRegNumber: h.pfrRegNumber || get('pfrRegNumber'),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,8 +41,11 @@ export const OKPO_PATTERN = /^\d{8}(\d{2})?$/;
|
||||
/** СНИЛС: XXX-XXX-XXX YY или 11 цифр подряд. */
|
||||
export const SNILS_PATTERN = /^(\d{3}-\d{3}-\d{3} \d{2}|\d{11})$/;
|
||||
|
||||
/** Регистрационный номер СФР: действующий XXX-XXX-XXXXXX (3-3-6, 12 цифр) или прежний — 10 цифр без разделителей. */
|
||||
export const SFR_REG_NUMBER_PATTERN = /^(\d{3}-\d{3}-\d{6}|\d{10})$/;
|
||||
/** Регистрационный номер страхователя в СФР: 10 цифр без разделителей (унифицированный номер). */
|
||||
export const SFR_REG_NUMBER_PATTERN = /^\d{10}$/;
|
||||
|
||||
/** Регистрационный номер страхователя в ПФР: XXX-XXX-XXXXXX (3-3-6, 12 цифр с тире) — отдельное поле от SFR_REG_NUMBER_PATTERN, требуется для ЕФС-1. */
|
||||
export const PFR_REG_NUMBER_PATTERN = /^\d{3}-\d{3}-\d{6}$/;
|
||||
|
||||
/** Дата в формате DD.MM.YYYY (ФНС). */
|
||||
export const DATE_DDMMYYYY_PATTERN = /^\d{2}\.\d{2}\.\d{4}$/;
|
||||
@@ -70,7 +73,8 @@ export const reportRules = {
|
||||
okopf: (message = 'ОКОПФ — 5 цифр') => (v: unknown) => OKOPF_PATTERN.test(String(v ?? '')) || message,
|
||||
okpo: (message = 'ОКПО — 8 или 10 цифр') => (v: unknown) => OKPO_PATTERN.test(String(v ?? '')) || message,
|
||||
snils: (message = 'СНИЛС — XXX-XXX-XXX YY или 11 цифр') => (v: unknown) => SNILS_PATTERN.test(String(v ?? '')) || message,
|
||||
sfrRegNumber: (message = 'Рег. номер СФР — XXX-XXX-XXXXXX или 10 цифр') => (v: unknown) => SFR_REG_NUMBER_PATTERN.test(String(v ?? '')) || message,
|
||||
sfrRegNumber: (message = 'Рег. номер СФР — 10 цифр') => (v: unknown) => SFR_REG_NUMBER_PATTERN.test(String(v ?? '')) || message,
|
||||
pfrRegNumber: (message = 'Рег. номер ПФР — XXX-XXX-XXXXXX') => (v: unknown) => PFR_REG_NUMBER_PATTERN.test(String(v ?? '')) || message,
|
||||
dateDdMmYyyy: (message = 'Дата — DD.MM.YYYY') => (v: unknown) => DATE_DDMMYYYY_PATTERN.test(String(v ?? '')) || message,
|
||||
kbk: (message = 'КБК — 20 цифр') => (v: unknown) => KBK_PATTERN.test(String(v ?? '')) || message,
|
||||
/** Непустая строка длиной от `min` до `max` символов. */
|
||||
|
||||
@@ -24,6 +24,7 @@ export const rawReportRequisitesViewSelector = {
|
||||
oktmo: rawRequisiteFieldViewSelector,
|
||||
okpo: rawRequisiteFieldViewSelector,
|
||||
sfrRegNumber: rawRequisiteFieldViewSelector,
|
||||
pfrRegNumber: rawRequisiteFieldViewSelector,
|
||||
chairmanPosition: rawRequisiteFieldViewSelector,
|
||||
signerSnils: rawRequisiteFieldViewSelector,
|
||||
signerRepDoc: rawRequisiteFieldViewSelector,
|
||||
|
||||
@@ -4821,6 +4821,7 @@ export const ReturnTypes: Record<string,any> = {
|
||||
oktmo:"RequisiteFieldView",
|
||||
okved:"RequisiteFieldView",
|
||||
orgName:"RequisiteFieldView",
|
||||
pfrRegNumber:"RequisiteFieldView",
|
||||
phone:"RequisiteFieldView",
|
||||
sfrRegNumber:"RequisiteFieldView",
|
||||
signerFirstName:"RequisiteFieldView",
|
||||
@@ -5063,6 +5064,7 @@ export const ReturnTypes: Record<string,any> = {
|
||||
firstName:"String",
|
||||
lastName:"String",
|
||||
middleName:"String",
|
||||
pfrRegNumber:"String",
|
||||
repDoc:"String",
|
||||
sfrRegNumber:"String",
|
||||
snils:"String",
|
||||
|
||||
@@ -9043,6 +9043,7 @@ validateReportEdits?: [{ editsJson: string | Variable<any, string>, reportType:
|
||||
oktmo?:ValueTypes["RequisiteFieldView"],
|
||||
okved?:ValueTypes["RequisiteFieldView"],
|
||||
orgName?:ValueTypes["RequisiteFieldView"],
|
||||
pfrRegNumber?:ValueTypes["RequisiteFieldView"],
|
||||
phone?:ValueTypes["RequisiteFieldView"],
|
||||
sfrRegNumber?:ValueTypes["RequisiteFieldView"],
|
||||
signerFirstName?:ValueTypes["RequisiteFieldView"],
|
||||
@@ -10179,8 +10180,10 @@ validateReportEdits?: [{ editsJson: string | Variable<any, string>, reportType:
|
||||
oktmo?: string | undefined | null | Variable<any, string>,
|
||||
/** ОКВЭД — напр. 94.99, 46.73.7 */
|
||||
okved?: string | undefined | null | Variable<any, string>,
|
||||
/** Рег. номер ПФР — XXX-XXX-XXXXXX (для ЕФС-1, отдельно от рег. номера СФР) */
|
||||
pfrRegNumber?: string | undefined | null | Variable<any, string>,
|
||||
phoneOverride?: string | undefined | null | Variable<any, string>,
|
||||
/** Рег. номер СФР — XXX-XXX-XXXXXX */
|
||||
/** Рег. номер СФР — 10 цифр */
|
||||
sfrRegNumber?: string | undefined | null | Variable<any, string>,
|
||||
signerRepDoc?: string | undefined | null | Variable<any, string>,
|
||||
/** СНИЛС — XXX-XXX-XXX YY или 11 цифр */
|
||||
@@ -10482,6 +10485,7 @@ validateReportEdits?: [{ editsJson: string | Variable<any, string>, reportType:
|
||||
firstName?:boolean | `@${string}`,
|
||||
lastName?:boolean | `@${string}`,
|
||||
middleName?:boolean | `@${string}`,
|
||||
pfrRegNumber?:boolean | `@${string}`,
|
||||
repDoc?:boolean | `@${string}`,
|
||||
sfrRegNumber?:boolean | `@${string}`,
|
||||
snils?:boolean | `@${string}`,
|
||||
@@ -18204,6 +18208,7 @@ validateReportEdits?: [{ editsJson: string, reportType: ResolverInputTypes["Repo
|
||||
oktmo?:ResolverInputTypes["RequisiteFieldView"],
|
||||
okved?:ResolverInputTypes["RequisiteFieldView"],
|
||||
orgName?:ResolverInputTypes["RequisiteFieldView"],
|
||||
pfrRegNumber?:ResolverInputTypes["RequisiteFieldView"],
|
||||
phone?:ResolverInputTypes["RequisiteFieldView"],
|
||||
sfrRegNumber?:ResolverInputTypes["RequisiteFieldView"],
|
||||
signerFirstName?:ResolverInputTypes["RequisiteFieldView"],
|
||||
@@ -19317,8 +19322,10 @@ validateReportEdits?: [{ editsJson: string, reportType: ResolverInputTypes["Repo
|
||||
oktmo?: string | undefined | null,
|
||||
/** ОКВЭД — напр. 94.99, 46.73.7 */
|
||||
okved?: string | undefined | null,
|
||||
/** Рег. номер ПФР — XXX-XXX-XXXXXX (для ЕФС-1, отдельно от рег. номера СФР) */
|
||||
pfrRegNumber?: string | undefined | null,
|
||||
phoneOverride?: string | undefined | null,
|
||||
/** Рег. номер СФР — XXX-XXX-XXXXXX */
|
||||
/** Рег. номер СФР — 10 цифр */
|
||||
sfrRegNumber?: string | undefined | null,
|
||||
signerRepDoc?: string | undefined | null,
|
||||
/** СНИЛС — XXX-XXX-XXX YY или 11 цифр */
|
||||
@@ -19614,6 +19621,7 @@ validateReportEdits?: [{ editsJson: string, reportType: ResolverInputTypes["Repo
|
||||
firstName?:boolean | `@${string}`,
|
||||
lastName?:boolean | `@${string}`,
|
||||
middleName?:boolean | `@${string}`,
|
||||
pfrRegNumber?:boolean | `@${string}`,
|
||||
repDoc?:boolean | `@${string}`,
|
||||
sfrRegNumber?:boolean | `@${string}`,
|
||||
snils?:boolean | `@${string}`,
|
||||
@@ -27847,6 +27855,7 @@ export type ModelTypes = {
|
||||
oktmo: ModelTypes["RequisiteFieldView"],
|
||||
okved: ModelTypes["RequisiteFieldView"],
|
||||
orgName: ModelTypes["RequisiteFieldView"],
|
||||
pfrRegNumber: ModelTypes["RequisiteFieldView"],
|
||||
phone: ModelTypes["RequisiteFieldView"],
|
||||
sfrRegNumber: ModelTypes["RequisiteFieldView"],
|
||||
signerFirstName: ModelTypes["RequisiteFieldView"],
|
||||
@@ -28930,8 +28939,10 @@ export type ModelTypes = {
|
||||
oktmo?: string | undefined | null,
|
||||
/** ОКВЭД — напр. 94.99, 46.73.7 */
|
||||
okved?: string | undefined | null,
|
||||
/** Рег. номер ПФР — XXX-XXX-XXXXXX (для ЕФС-1, отдельно от рег. номера СФР) */
|
||||
pfrRegNumber?: string | undefined | null,
|
||||
phoneOverride?: string | undefined | null,
|
||||
/** Рег. номер СФР — XXX-XXX-XXXXXX */
|
||||
/** Рег. номер СФР — 10 цифр */
|
||||
sfrRegNumber?: string | undefined | null,
|
||||
signerRepDoc?: string | undefined | null,
|
||||
/** СНИЛС — XXX-XXX-XXX YY или 11 цифр */
|
||||
@@ -29214,6 +29225,7 @@ export type ModelTypes = {
|
||||
firstName: string,
|
||||
lastName: string,
|
||||
middleName?: string | undefined | null,
|
||||
pfrRegNumber?: string | undefined | null,
|
||||
repDoc?: string | undefined | null,
|
||||
sfrRegNumber?: string | undefined | null,
|
||||
snils?: string | undefined | null,
|
||||
@@ -37955,6 +37967,7 @@ export type GraphQLTypes = {
|
||||
oktmo: GraphQLTypes["RequisiteFieldView"],
|
||||
okved: GraphQLTypes["RequisiteFieldView"],
|
||||
orgName: GraphQLTypes["RequisiteFieldView"],
|
||||
pfrRegNumber: GraphQLTypes["RequisiteFieldView"],
|
||||
phone: GraphQLTypes["RequisiteFieldView"],
|
||||
sfrRegNumber: GraphQLTypes["RequisiteFieldView"],
|
||||
signerFirstName: GraphQLTypes["RequisiteFieldView"],
|
||||
@@ -39090,8 +39103,10 @@ export type GraphQLTypes = {
|
||||
oktmo?: string | undefined | null,
|
||||
/** ОКВЭД — напр. 94.99, 46.73.7 */
|
||||
okved?: string | undefined | null,
|
||||
/** Рег. номер ПФР — XXX-XXX-XXXXXX (для ЕФС-1, отдельно от рег. номера СФР) */
|
||||
pfrRegNumber?: string | undefined | null,
|
||||
phoneOverride?: string | undefined | null,
|
||||
/** Рег. номер СФР — XXX-XXX-XXXXXX */
|
||||
/** Рег. номер СФР — 10 цифр */
|
||||
sfrRegNumber?: string | undefined | null,
|
||||
signerRepDoc?: string | undefined | null,
|
||||
/** СНИЛС — XXX-XXX-XXX YY или 11 цифр */
|
||||
@@ -39395,6 +39410,7 @@ export type GraphQLTypes = {
|
||||
firstName: string,
|
||||
lastName: string,
|
||||
middleName?: string | undefined | null,
|
||||
pfrRegNumber?: string | undefined | null,
|
||||
repDoc?: string | undefined | null,
|
||||
sfrRegNumber?: string | undefined | null,
|
||||
snils?: string | undefined | null,
|
||||
|
||||
Reference in New Issue
Block a user