Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e58c173ee | |||
| c1ce7a095d | |||
| 995f65f524 | |||
| 5298e55a7b | |||
| db28ba1137 | |||
| 6a05e88ba1 | |||
| 09eaa6192c | |||
| 81df662cfa | |||
| 845c13605d | |||
| 76b4988da8 | |||
| 3db80a30e9 | |||
| 1b457b8f87 | |||
| ba6d3d1310 | |||
| 8e01373179 | |||
| 024d46ff64 | |||
| ed9b0879d5 | |||
| c94043e77f | |||
| c1a8f3e637 | |||
| 15fdf35dd3 | |||
| 79b89695d1 | |||
| 7b27d0805c | |||
| e089dbd3fb | |||
| 5de7e7c65b | |||
| bfbcd2d57f | |||
| ff5df68bce | |||
| a948f07a1b | |||
| 85bd044cd6 |
@@ -390,6 +390,18 @@ jobs:
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm lerna run build
|
||||
|
||||
# schema.gql не коммитится и не создаётся ничем в этом job'е, а
|
||||
# @coopenomics/sdk's prepublishOnly (pnpm run docs → generate-index-comments.ts)
|
||||
# читает components/controller/schema.gql и падает ENOENT без него — валя весь
|
||||
# lerna publish (атомарный) молча с 30 мая. Скрипт изолированный (GraphQLSchemaBuilderModule,
|
||||
# без TypeORM/Mongo/Redis) — не требует БД, но типизация controller'а резолвится через
|
||||
# dist соседних workspace-пакетов (cooptypes/factory/notifications/inter) — ОБЯЗАТЕЛЬНО
|
||||
# после `lerna run build`, иначе ts-node падает на их устаревших dist-типах.
|
||||
- name: Generate controller schema.gql (required by sdk prepublishOnly)
|
||||
working-directory: components/controller
|
||||
run: pnpm run generate-schema
|
||||
|
||||
- run: pnpm lerna publish from-package --yes
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
@@ -45,6 +45,14 @@ RUN corepack enable && npm install -g lerna --no-fund --no-audit
|
||||
# выкидывает node_modules/dist/.git, поэтому `COPY .` лёгкий.
|
||||
COPY . .
|
||||
|
||||
# electron (devDep desktop → @vue/devtools) и puppeteer нигде в build/runtime
|
||||
# не запускаются (unbuild/tsc/vite их не трогают) — только их JS-обёртка нужна
|
||||
# для типов. Их postinstall тянет тяжёлые бинарники (Electron zip с GitHub
|
||||
# Releases, Chromium) по сети — периодически валит билд TLS-таймаутом.
|
||||
# Отключаем сами загрузки, пакеты всё равно ставятся.
|
||||
ENV ELECTRON_SKIP_BINARY_DOWNLOAD=1 \
|
||||
PUPPETEER_SKIP_DOWNLOAD=true
|
||||
|
||||
# Используем существующий lockfile. Если он не совпадает с workspace —
|
||||
# падать сразу, не дрейфовать незаметно.
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coopenomics/blago-cli",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"description": "CLI синхронизации артефактов Благорост с бэкендом через @coopenomics/sdk",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
|
||||
@@ -35,7 +35,14 @@ RUN npm install -g pnpm@10.33.0
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN pnpm install --frozen-lockfile --filter "@coopenomics/boot..."
|
||||
# --ignore-scripts + точечный rebuild: --filter ограничивает только то, какие
|
||||
# проекты получают node_modules, но НЕ то, для каких пакетов общего lockfile
|
||||
# store выполняет lifecycle-скрипты при --frozen-lockfile. Без --ignore-scripts
|
||||
# сюда тянутся electron/puppeteer (из @coopenomics/desktop/notifications,
|
||||
# boot их не использует) — тяжёлые сетевые загрузки, изредка валящие билд по
|
||||
# TLS-таймауту. rebuild --filter уже честно скопирован на подграф boot.
|
||||
RUN pnpm install --frozen-lockfile --filter "@coopenomics/boot..." --ignore-scripts \
|
||||
&& pnpm rebuild --filter "@coopenomics/boot..."
|
||||
|
||||
# Билд графа: cooptypes/factory собирают свои dist/, boot собирает
|
||||
# свой bundle с inlined workspace-deps.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@coopenomics/boot",
|
||||
"type": "module",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@9.0.6",
|
||||
"description": "CLI-утилита инициализации блокчейна и кооператива",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coopenomics/cleos",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"private": true,
|
||||
"description": "Обёртка над кошельком cleos для EOSIO блокчейна",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coopenomics/contracts",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -72,6 +72,9 @@ export default {
|
||||
try {
|
||||
mongo = await mongoose.createConnection(config.mongoose.url).asPromise();
|
||||
const db = mongo.db;
|
||||
if (!db) {
|
||||
throw new Error('Подключение к MongoDB установлено, но db не инициализирована');
|
||||
}
|
||||
const collection = db.collection(COLLECTION_NAME);
|
||||
await collection.createIndex({ hash: 1 }, { unique: true });
|
||||
await collection.updateOne(
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "create-nodejs-express-app",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "create-nodejs-express-app",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@a2seven/yoo-checkout": "^1.1.4",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coopenomics/controller",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"description": "Бэкенд GraphQL API кооператива на NestJS",
|
||||
"private": true,
|
||||
"bin": "bin/createNodejsApp.js",
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
## Возможности
|
||||
|
||||
✨ **Удобное общение** - групповые чаты, личные сообщения, голосовые и видео-звонки
|
||||
🔐 **Безопасность** - сообщения зашифрованы и защищены
|
||||
👥 **Для всех участников** - каждый член кооператива автоматически получает доступ к чату пайщиков своего кооператива и общему чату кооперативной экономики.
|
||||
👥 **Для членов совета** - каждый член совета добавляется в зашифрованный чат совета своего кооператива.
|
||||
📱 **На всех устройствах** - работает на компьютере, телефоне и планшете
|
||||
⚡ **Быстрая установка** - просто установите расширение, и оно заработает
|
||||
- ✨ **Удобное общение** — групповые чаты, личные сообщения, голосовые и видео-звонки
|
||||
- 🔐 **Безопасность** — сообщения зашифрованы и защищены
|
||||
- 👥 **Для всех участников** — каждый член кооператива автоматически получает доступ к чату пайщиков своего кооператива и общему чату кооперативной экономики
|
||||
- 👥 **Для членов совета** — каждый член совета добавляется в зашифрованный чат совета своего кооператива
|
||||
- 📱 **На всех устройствах** — работает на компьютере, телефоне и планшете
|
||||
- ⚡ **Быстрая установка** — просто установите расширение, и оно заработает
|
||||
|
||||
@@ -1,6 +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, PFR_REG_NUMBER_PATTERN } from '../../domain/patterns';
|
||||
|
||||
export enum RequisiteSource {
|
||||
DATABASE = 'database',
|
||||
@@ -43,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;
|
||||
@@ -65,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 симв. с тире)
|
||||
* РегНом СФР — `\d{10}` (10 цифр подряд, без тире)
|
||||
* РегНом ПФР — `\d{3}-\d{3}-\d{6}` (14 симв. с тире), только этот формат —
|
||||
* отдельное поле от РегНом СФР, требуется для ЕФС-1 (внешние
|
||||
* бухгалтерские системы сверяют его при приёме отчёта)
|
||||
*/
|
||||
@InputType('UpdateReportRequisitesInput')
|
||||
export class UpdateReportRequisitesInputDTO {
|
||||
@@ -99,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' })
|
||||
@Field(() => String, { nullable: true, description: 'Рег. номер СФР — 10 цифр' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Matches(/^\d{3}-\d{3}-\d{6}$/, { message: 'Рег. номер СФР — XXX-XXX-XXXXXX (14 симв.)' })
|
||||
@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' })
|
||||
@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,8 +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).
|
||||
export const SFR_REG_NUMBER_PATTERN = /^\d{3}-\d{3}-\d{6}$/;
|
||||
// Регистрационный номер страхователя в СФР: только 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;
|
||||
|
||||
|
||||
+15
-4
@@ -66,8 +66,14 @@ export class Fss4Generator implements IReportGenerator {
|
||||
const edits = input as ZeroReportEditsShape;
|
||||
const fileName = edits.header.idFile;
|
||||
const errors: string[] = [];
|
||||
if (!edits.signer.sfrRegNumber) {
|
||||
errors.push('Для ЕФС-1 обязателен рег. номер страхователя в СФР (поле signer.sfrRegNumber)');
|
||||
if (!edits.signer.pfrRegNumber) {
|
||||
// В документ идёт только pfrRegNumber (см. strah.ele('ЕФС8:РегНомер')
|
||||
// ниже) — sfrRegNumber в ЕФС-1 не используется вовсе, поэтому не
|
||||
// проверяем его здесь, хотя в реквизитах кооператива оно и остаётся
|
||||
// обязательным полем (может понадобиться другим формам/интеграциям).
|
||||
errors.push('Для ЕФС-1 обязателен рег. номер страхователя в ПФР (поле signer.pfrRegNumber)');
|
||||
}
|
||||
if (errors.length) {
|
||||
return { reportType: this.reportType, xml: '', fileName, errors, isValid: false };
|
||||
}
|
||||
try {
|
||||
@@ -100,8 +106,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,
|
||||
|
||||
@@ -62,15 +62,33 @@ async function bootstrap() {
|
||||
// Проверяем, был ли запущен режим миграций
|
||||
const args = process.argv.slice(2);
|
||||
if (args.includes('--migrate')) {
|
||||
await migrateData();
|
||||
process.exit(0);
|
||||
try {
|
||||
await migrateData();
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
// migrateData() уже логирует причину; здесь важен только ненулевой
|
||||
// exit code. В production Sentry.init() ставит свой глобальный
|
||||
// process.on('unhandledRejection', ...) с дефолтным mode: 'warn' —
|
||||
// он перехватывает необработанный reject этого await и НЕ роняет
|
||||
// процесс (в отличие от штатного поведения Node без Sentry). Без
|
||||
// явного process.exit(1) здесь deploy-скрипт получал ложноположительный
|
||||
// exit code 0 при реально упавшей миграции (кейс V2.3.2 на testnet
|
||||
// 2026-07-19 — TS-ошибка компиляции миграции проглатывалась именно так).
|
||||
logger.error('Процесс миграции завершился с ошибкой, выходим с кодом 1', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяем, был ли запущен режим только миграций (для обратной совместимости)
|
||||
if (args.includes('--migrations-only')) {
|
||||
await migrateData();
|
||||
logger.info('Режим только миграций - миграции выполнены, сервер не будет запущен');
|
||||
process.exit(0);
|
||||
try {
|
||||
await migrateData();
|
||||
logger.info('Режим только миграций - миграции выполнены, сервер не будет запущен');
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
logger.error('Процесс миграции завершился с ошибкой, выходим с кодом 1', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Подключение к MongoDB
|
||||
|
||||
@@ -202,6 +202,7 @@ const zeroBaseEdits: ZeroReportEditsShape = {
|
||||
repDoc: 'Доверенность №1 от 01.01.2024',
|
||||
snils: '123-456-789 00',
|
||||
sfrRegNumber: '7701234567',
|
||||
pfrRegNumber: '087-701-579643',
|
||||
chairmanPosition: 'Председатель Совета',
|
||||
},
|
||||
};
|
||||
@@ -564,7 +565,7 @@ describe('ЕФС-1 (Fss4Generator, СФР)', () => {
|
||||
expect(gen.reportType).toBe(ReportType.FSS4);
|
||||
});
|
||||
|
||||
it('генерирует XML при переданном sfrRegNumber', () => {
|
||||
it('генерирует XML при переданном pfrRegNumber', () => {
|
||||
const result = gen.generate(withPeriod(1));
|
||||
expect(result.isValid).toBe(true);
|
||||
expect(result.xml).toContain('<?xml');
|
||||
@@ -572,13 +573,27 @@ describe('ЕФС-1 (Fss4Generator, СФР)', () => {
|
||||
expect(result.xml).toContain('<ЭДСФР');
|
||||
});
|
||||
|
||||
it('возвращает ошибку без sfrRegNumber', () => {
|
||||
it('генерируется без sfrRegNumber — ЕФС-1 его не использует', () => {
|
||||
const result = gen.generate({
|
||||
...withPeriod(1),
|
||||
signer: { ...zeroBaseEdits.signer, sfrRegNumber: null },
|
||||
});
|
||||
expect(result.isValid).toBe(true);
|
||||
});
|
||||
|
||||
it('возвращает ошибку без pfrRegNumber', () => {
|
||||
const result = gen.generate({
|
||||
...withPeriod(1),
|
||||
signer: { ...zeroBaseEdits.signer, pfrRegNumber: null },
|
||||
});
|
||||
expect(result.isValid).toBe(false);
|
||||
expect(result.errors.join('|')).toContain('sfrRegNumber');
|
||||
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', () => {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "cooptypes",
|
||||
"type": "module",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"description": "Shared TypeScript типы и интерфейсы экосистемы кооперативов",
|
||||
"author": "Alex Ant <dacom.dark.sun@gmail.com>",
|
||||
"license": "MIT",
|
||||
|
||||
+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);
|
||||
|
||||
@@ -36,9 +36,10 @@ const props = defineProps<{
|
||||
mask?: string
|
||||
/** Подставлять плейсхолдеры маски при вводе */
|
||||
fillMask?: boolean
|
||||
/** Разрешить только цифры и точку (ОКВЭД: 94.99, 46.73.7). Блокирует
|
||||
* keypress/paste — буквы вообще не появляются в поле. */
|
||||
digitsDotsOnly?: boolean
|
||||
/** Разрешить только цифры + перечисленные доп. символы (напр. '.' для
|
||||
* ОКВЭД: 94.99, 46.73.7; '-' для Рег. номера СФР). Блокирует
|
||||
* keypress/paste — посторонние символы вообще не появляются в поле. */
|
||||
digitsExtraChars?: string
|
||||
/** HTML maxlength. */
|
||||
maxLength?: number
|
||||
/** Допустимые точные длины (ИЛИ). Напр. `[8, 11]` для ОКТМО. */
|
||||
@@ -60,12 +61,20 @@ const labelText = computed(() =>
|
||||
)
|
||||
|
||||
const inputModeComputed = computed<'numeric' | 'decimal' | 'text'>(() => {
|
||||
if (props.digitsDotsOnly) return 'decimal'
|
||||
// '.' — десятичная клавиатура мобильных устройств её показывает; для
|
||||
// прочих доп.символов (напр. '-') нужна полная клавиатура — 'text'.
|
||||
if (props.digitsExtraChars === '.') return 'decimal'
|
||||
if (props.digitsExtraChars) return 'text'
|
||||
// mask из одних `#` = чистая цифровая клавиатура на мобиле.
|
||||
if (props.mask && /^#+$/.test(props.mask)) return 'numeric'
|
||||
return 'text'
|
||||
})
|
||||
|
||||
/** Экранирует спецсимволы regex, чтобы вставить строку в символьный класс `[...]`. */
|
||||
function escapeForCharClass(chars: string): string {
|
||||
return chars.replace(/[\]\\^-]/g, '\\$&')
|
||||
}
|
||||
|
||||
const NAV_KEYS = new Set([
|
||||
'Backspace',
|
||||
'Delete',
|
||||
@@ -81,19 +90,21 @@ const NAV_KEYS = new Set([
|
||||
])
|
||||
|
||||
// Блокируем keypress не-допустимых символов — буквы не попадают в поле даже
|
||||
// на миллисекунды. Работает только для digitsDotsOnly (для чисто цифровых
|
||||
// на миллисекунды. Работает только для digitsExtraChars (для чисто цифровых
|
||||
// полей используем Quasar-mask — он нативно блокирует не-# символы).
|
||||
function onKeydown(e: KeyboardEvent): void {
|
||||
if (!props.digitsDotsOnly) return
|
||||
if (!props.digitsExtraChars) return
|
||||
if (e.ctrlKey || e.metaKey || e.altKey) return
|
||||
if (NAV_KEYS.has(e.key)) return
|
||||
if (!/^[\d.]$/.test(e.key)) e.preventDefault()
|
||||
const re = new RegExp(`^[\\d${escapeForCharClass(props.digitsExtraChars)}]$`)
|
||||
if (!re.test(e.key)) e.preventDefault()
|
||||
}
|
||||
|
||||
function onPaste(e: ClipboardEvent): void {
|
||||
if (!props.digitsDotsOnly) return
|
||||
if (!props.digitsExtraChars) return
|
||||
const text = e.clipboardData?.getData('text') ?? ''
|
||||
if (!/^[\d.]*$/.test(text)) e.preventDefault()
|
||||
const re = new RegExp(`^[\\d${escapeForCharClass(props.digitsExtraChars)}]*$`)
|
||||
if (!re.test(text)) e.preventDefault()
|
||||
}
|
||||
|
||||
const rules = computed(() => {
|
||||
@@ -128,7 +139,10 @@ function onInput(raw: string | number | null): void {
|
||||
// Фоллбек-фильтр на случай programmatic ввода (drop/autofill). Для ручного
|
||||
// набора актуальна либо mask (q-input сам режет), либо keydown-блокер.
|
||||
let s = String(raw ?? '')
|
||||
if (props.digitsDotsOnly) s = s.replace(/[^\d.]+/g, '')
|
||||
if (props.digitsExtraChars) {
|
||||
const re = new RegExp(`[^\\d${escapeForCharClass(props.digitsExtraChars)}]+`, 'g')
|
||||
s = s.replace(re, '')
|
||||
}
|
||||
if (props.maxLength && s.length > props.maxLength) s = s.slice(0, props.maxLength)
|
||||
emit('update:value', s)
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ q-form.settings-page(@submit.prevent='save' @validation-error='onValidationError
|
||||
:value='manualInput[f.key]'
|
||||
:placeholder='f.placeholder'
|
||||
:mask='f.mask'
|
||||
:digits-dots-only='f.digitsDotsOnly'
|
||||
:digits-extra-chars='f.digitsExtraChars'
|
||||
:max-length='f.maxLength'
|
||||
:exact-lengths='f.exactLengths'
|
||||
:pattern='f.pattern'
|
||||
@@ -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,13 +60,27 @@ q-form.settings-page(@submit.prevent='save' @validation-error='onValidationError
|
||||
id='field-sfrRegNumber'
|
||||
label='Рег. номер СФР'
|
||||
:value='manualInput.sfrRegNumber'
|
||||
placeholder='XXX-XXX-XXXXXX'
|
||||
mask='###-###-######'
|
||||
placeholder='10 цифр'
|
||||
mask='##########'
|
||||
:max-length='10'
|
||||
:exact-lengths='[10]'
|
||||
:pattern='SFR_REG_PATTERN'
|
||||
pattern-message='Формат: XXX-XXX-XXXXXX (12 цифр)'
|
||||
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='Должность председателя'
|
||||
@@ -163,6 +177,7 @@ type ManualKey =
|
||||
| 'oktmo'
|
||||
| 'okpo'
|
||||
| 'sfrRegNumber'
|
||||
| 'pfrRegNumber'
|
||||
| 'chairmanPosition'
|
||||
| 'signerSnils'
|
||||
| 'signerRepDoc'
|
||||
@@ -176,6 +191,7 @@ const manualInput = reactive<Record<ManualKey, string>>({
|
||||
oktmo: '',
|
||||
okpo: '',
|
||||
sfrRegNumber: '',
|
||||
pfrRegNumber: '',
|
||||
chairmanPosition: '',
|
||||
signerSnils: '',
|
||||
signerRepDoc: '',
|
||||
@@ -202,7 +218,7 @@ interface ClassifierField {
|
||||
label: string
|
||||
placeholder?: string
|
||||
mask?: string
|
||||
digitsDotsOnly?: boolean
|
||||
digitsExtraChars?: string
|
||||
maxLength?: number
|
||||
exactLengths?: number[]
|
||||
pattern?: RegExp
|
||||
@@ -212,13 +228,13 @@ interface ClassifierField {
|
||||
// Placeholder'ы — правило ввода (кол-во цифр), а не конкретные примеры.
|
||||
// Для цифровых полей фиксированной/короткой длины — используем Quasar-mask
|
||||
// (`#` = только цифра, буквы блокируются на keypress нативно).
|
||||
// Для ОКВЭД (цифры + точка переменной длины) — digitsDotsOnly с @keydown-блокером.
|
||||
// Для ОКВЭД (цифры + точка переменной длины) — digitsExtraChars='.' с @keydown-блокером.
|
||||
const classifierFields: ClassifierField[] = [
|
||||
{
|
||||
key: 'okved',
|
||||
label: 'ОКВЭД',
|
||||
placeholder: 'XX.XX или XX.XX.XX',
|
||||
digitsDotsOnly: true,
|
||||
digitsExtraChars: '.',
|
||||
maxLength: 8,
|
||||
pattern: /^\d{2}(\.\d{1,2}){0,2}$/,
|
||||
patternMessage: 'Формат: XX.XX или XX.XX.XX',
|
||||
@@ -265,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}$/
|
||||
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(
|
||||
@@ -32,14 +36,12 @@
|
||||
|
||||
.editor-section
|
||||
h3.section-title Организация
|
||||
.text-caption.t-muted.q-mb-sm Данные берутся из Реквизитов — правка доступна только там
|
||||
|
||||
q-input(
|
||||
label='Наименование организации'
|
||||
:model-value='editsValue.organization.orgName'
|
||||
@update:model-value='v => updateField("organization.orgName", v)'
|
||||
:rules='[reportRules.length(1, 1000)]'
|
||||
:error='errFor("organization.orgName")'
|
||||
:error-message='msgFor("organization.orgName")'
|
||||
readonly disable
|
||||
dense filled
|
||||
)
|
||||
|
||||
@@ -47,30 +49,20 @@
|
||||
q-input(
|
||||
label='ИНН'
|
||||
:model-value='editsValue.organization.inn'
|
||||
@update:model-value='v => updateField("organization.inn", v)'
|
||||
:rules='[reportRules.innUl()]'
|
||||
:error='errFor("organization.inn")'
|
||||
:error-message='msgFor("organization.inn")'
|
||||
readonly disable
|
||||
dense filled
|
||||
)
|
||||
q-input(
|
||||
label='КПП'
|
||||
:model-value='editsValue.organization.kpp'
|
||||
@update:model-value='v => updateField("organization.kpp", String(v || "").toUpperCase())'
|
||||
:rules='[reportRules.kpp()]'
|
||||
:error='errFor("organization.kpp")'
|
||||
:error-message='msgFor("organization.kpp")'
|
||||
readonly disable
|
||||
dense filled
|
||||
maxlength='9'
|
||||
)
|
||||
q-input(
|
||||
v-if='needs.oktmo'
|
||||
label='ОКТМО'
|
||||
:model-value='editsValue.organization.oktmo || ""'
|
||||
@update:model-value='v => updateField("organization.oktmo", v || null)'
|
||||
:rules='[reportRules.oktmo()]'
|
||||
:error='errFor("organization.oktmo")'
|
||||
:error-message='msgFor("organization.oktmo")'
|
||||
readonly disable
|
||||
dense filled
|
||||
)
|
||||
|
||||
@@ -78,29 +70,24 @@
|
||||
q-input(
|
||||
label='ОКВЭД'
|
||||
:model-value='editsValue.organization.okved || ""'
|
||||
@update:model-value='v => updateField("organization.okved", v || null)'
|
||||
:rules='[reportRules.okved()]'
|
||||
:error='errFor("organization.okved")'
|
||||
:error-message='msgFor("organization.okved")'
|
||||
readonly disable
|
||||
dense filled
|
||||
)
|
||||
q-input(
|
||||
label='ОГРН'
|
||||
:model-value='editsValue.organization.ogrn || ""'
|
||||
@update:model-value='v => updateField("organization.ogrn", v || null)'
|
||||
:rules='[reportRules.optionalRegex(/^\\d{13}$/, "ОГРН ЮЛ — 13 цифр")]'
|
||||
:error='errFor("organization.ogrn")'
|
||||
:error-message='msgFor("organization.ogrn")'
|
||||
readonly disable
|
||||
dense filled
|
||||
)
|
||||
|
||||
.editor-section
|
||||
h3.section-title Подписант
|
||||
.text-caption.t-muted.q-mb-sm Данные берутся из Реквизитов — правка доступна только там
|
||||
|
||||
q-option-group(
|
||||
:model-value='editsValue.signer.type'
|
||||
@update:model-value='v => updateField("signer.type", v)'
|
||||
:options='signerTypeOptions'
|
||||
disable
|
||||
inline
|
||||
)
|
||||
|
||||
@@ -108,25 +95,19 @@
|
||||
q-input(
|
||||
label='Фамилия'
|
||||
:model-value='editsValue.signer.lastName'
|
||||
@update:model-value='v => updateField("signer.lastName", v)'
|
||||
readonly disable
|
||||
dense filled
|
||||
:rules='[v => !!v || "обязательно"]'
|
||||
:error='errFor("signer.lastName")'
|
||||
:error-message='msgFor("signer.lastName")'
|
||||
)
|
||||
q-input(
|
||||
label='Имя'
|
||||
:model-value='editsValue.signer.firstName'
|
||||
@update:model-value='v => updateField("signer.firstName", v)'
|
||||
readonly disable
|
||||
dense filled
|
||||
:rules='[v => !!v || "обязательно"]'
|
||||
:error='errFor("signer.firstName")'
|
||||
:error-message='msgFor("signer.firstName")'
|
||||
)
|
||||
q-input(
|
||||
label='Отчество'
|
||||
:model-value='editsValue.signer.middleName || ""'
|
||||
@update:model-value='v => updateField("signer.middleName", v || null)'
|
||||
readonly disable
|
||||
dense filled
|
||||
)
|
||||
|
||||
@@ -134,10 +115,7 @@
|
||||
v-if='editsValue.signer.type === "representative"'
|
||||
label='Документ, подтверждающий полномочия'
|
||||
:model-value='editsValue.signer.repDoc || ""'
|
||||
@update:model-value='v => updateField("signer.repDoc", v || null)'
|
||||
:rules='[reportRules.length(1, 120)]'
|
||||
:error='errFor("signer.repDoc")'
|
||||
:error-message='msgFor("signer.repDoc")'
|
||||
readonly disable
|
||||
dense filled
|
||||
)
|
||||
|
||||
@@ -145,25 +123,15 @@
|
||||
v-if='needs.snils'
|
||||
label='СНИЛС председателя'
|
||||
:model-value='editsValue.signer.snils || ""'
|
||||
@update:model-value='v => updateField("signer.snils", v || null)'
|
||||
:rules='[reportRules.snils()]'
|
||||
:error='errFor("signer.snils")'
|
||||
:error-message='msgFor("signer.snils")'
|
||||
mask='###-###-### ##'
|
||||
hint='Обязателен для ПСВ — попадает в ПерсСвФЛ @СНИЛС'
|
||||
readonly disable
|
||||
dense filled
|
||||
)
|
||||
|
||||
q-input(
|
||||
v-if='needs.sfrExtras'
|
||||
label='Регистрационный номер СФР'
|
||||
:model-value='editsValue.signer.sfrRegNumber || ""'
|
||||
@update:model-value='v => updateField("signer.sfrRegNumber", v || null)'
|
||||
:rules='[reportRules.sfrRegNumber()]'
|
||||
:error='errFor("signer.sfrRegNumber")'
|
||||
:error-message='msgFor("signer.sfrRegNumber")'
|
||||
mask='###-###-######'
|
||||
hint='XXX-XXX-XXXXXX — обязателен для ЕФС-1'
|
||||
label='Регистрационный номер ПФР'
|
||||
:model-value='editsValue.signer.pfrRegNumber || ""'
|
||||
readonly disable
|
||||
dense filled
|
||||
)
|
||||
|
||||
@@ -171,19 +139,15 @@
|
||||
v-if='needs.sfrExtras'
|
||||
label='Должность подписанта'
|
||||
:model-value='editsValue.signer.chairmanPosition || ""'
|
||||
@update:model-value='v => updateField("signer.chairmanPosition", v || null)'
|
||||
hint='По умолчанию — "Председатель Совета"'
|
||||
readonly disable
|
||||
dense filled
|
||||
)
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { Selectors } from '@coopenomics/sdk'
|
||||
import type { IReportType } from 'src/entities/Report'
|
||||
|
||||
const { reportRules } = Selectors
|
||||
|
||||
type SignerType = 'chairman' | 'representative'
|
||||
|
||||
interface ZeroReportEdits {
|
||||
@@ -215,6 +179,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'),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coopenomics/desktop",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"description": "Рабочий стол кооператива — Vue 3 + Quasar Framework",
|
||||
"productName": "Desktop App",
|
||||
"author": "Alex Ant <dacom.dark.sun@gmail.com>",
|
||||
|
||||
@@ -7,18 +7,19 @@ BaseDialog(
|
||||
:close-on-backdrop='false',
|
||||
:close-on-escape='false'
|
||||
)
|
||||
div.row.justify-center
|
||||
div(style="padding-bottom: 100px;").col-md-8.col-col-xs-12
|
||||
div.row.justify-center.select-branch-overlay__content
|
||||
div.col-md-8.col-xs-12
|
||||
|
||||
div(v-if="step === 1")
|
||||
p.q-mt-lg
|
||||
| Кооператив перешёл на двухэтапную систему управления на основании общего собрания уполномоченных председателей кооперативных участков...
|
||||
Form(
|
||||
Loader(v-if="branchesLoading" text="Загружаем список кооперативных участков...")
|
||||
Form#select-branch-form(
|
||||
v-else
|
||||
:handler-submit="next"
|
||||
:is-submitting="isSubmitting"
|
||||
:showSubmit="!isLoading"
|
||||
:showSubmit="false"
|
||||
:showCancel="false"
|
||||
:button-submit-txt="'Продолжить'"
|
||||
)
|
||||
BranchSelector(
|
||||
v-model:selectedBranch="selectedBranch"
|
||||
@@ -27,15 +28,29 @@ BaseDialog(
|
||||
|
||||
div(v-else-if="step === 2")
|
||||
Loader(v-if="isLoading" :text="`Формируем документ...`")
|
||||
DocumentHtmlReader(v-else :html="document.html")
|
||||
|
||||
div(v-else)
|
||||
DocumentHtmlReader(:html="document.html")
|
||||
q-btn(@click="back" flat) назад
|
||||
q-btn(@click="sign" color="primary") подписать
|
||||
template(#footer)
|
||||
.select-branch-overlay__actions(v-if="step === 1 && !branchesLoading")
|
||||
BaseButton(
|
||||
variant='primary',
|
||||
type='submit',
|
||||
form='select-branch-form',
|
||||
:loading='isLoading',
|
||||
:disabled='!selectedBranch || isLoading',
|
||||
) Продолжить
|
||||
.select-branch-overlay__actions(v-else-if="step === 2 && !isLoading")
|
||||
BaseButton(variant='ghost', @click='back') назад
|
||||
BaseButton(
|
||||
variant='primary',
|
||||
:loading='isSubmitting',
|
||||
@click='sign'
|
||||
) подписать
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { BaseDialog } from 'src/shared/ui/base/BaseDialog'
|
||||
import { BaseButton } from 'src/shared/ui/base/BaseButton'
|
||||
import { Form } from 'src/shared/ui/Form'
|
||||
import { Loader } from 'src/shared/ui/Loader'
|
||||
import { BranchSelector } from 'src/shared/ui/BranchSelector'
|
||||
@@ -53,12 +68,30 @@ BaseDialog(
|
||||
document,
|
||||
isSubmitting,
|
||||
isLoading,
|
||||
branchesLoading,
|
||||
next,
|
||||
back,
|
||||
sign
|
||||
} = useSelectBranchProcess()
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* Кнопки в слоте footer BaseDialog — вне скроллящегося body,
|
||||
поэтому «Продолжить» / «подписать» всегда видны на мобильных. */
|
||||
.select-branch-overlay__actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
gap: var(--p-2, 8px);
|
||||
justify-content: flex-end;
|
||||
flex-wrap: wrap;
|
||||
padding-bottom: env(safe-area-inset-bottom, 0px);
|
||||
}
|
||||
|
||||
.select-branch-overlay__content {
|
||||
padding-bottom: var(--p-2, 8px);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.digital-document .header{
|
||||
text-align: center;
|
||||
|
||||
@@ -236,9 +236,7 @@ const goToCooperativeSite = () => {
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* Адаптивность */
|
||||
|
||||
@@ -20,31 +20,62 @@ export function useSelectBranchProcess() {
|
||||
const system = useSystemStore()
|
||||
const session = useSessionStore()
|
||||
const branchStore = useBranchStore()
|
||||
const { selectBranch } = useSelectBranch()
|
||||
const { isVisible, selectBranch } = useSelectBranch()
|
||||
|
||||
const branches = computed(() => branchStore.publicBranches)
|
||||
const branchesLoading = ref(false)
|
||||
|
||||
// Вотчер на авторизацию
|
||||
const loadBranches = async () => {
|
||||
if (!session.isAuth || !system.info.coopname) return
|
||||
|
||||
try {
|
||||
branchesLoading.value = true
|
||||
await branchStore.loadPublicBranches({ coopname: system.info.coopname })
|
||||
} catch (e: unknown) {
|
||||
FailAlert(e)
|
||||
} finally {
|
||||
branchesLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Загрузка при входе
|
||||
watch(
|
||||
() => session.isAuth,
|
||||
(isAuth, wasAuth) => {
|
||||
if (isAuth && !wasAuth) {
|
||||
branchStore.loadPublicBranches({ coopname: system.info.coopname })
|
||||
void loadBranches()
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
// Перезагрузка при переходе в мажоритарный режим или показе оверлея
|
||||
watch(
|
||||
[() => isVisible.value, () => system.info?.cooperator_account?.is_branched],
|
||||
([visible, branched]) => {
|
||||
if (visible && branched && session.isAuth) {
|
||||
void loadBranches()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const next = async () => {
|
||||
isLoading.value = true
|
||||
document.value = await digitalDocument.generate<Cooperative.Registry.SelectBranchStatement.Action>({
|
||||
registry_id: Cooperative.Registry.SelectBranchStatement.registry_id,
|
||||
coopname: system.info.coopname,
|
||||
username: session.username,
|
||||
braname: selectedBranch.value,
|
||||
})
|
||||
isLoading.value = false
|
||||
step.value++
|
||||
if (!selectedBranch.value || isLoading.value) return
|
||||
|
||||
try {
|
||||
isLoading.value = true
|
||||
document.value = await digitalDocument.generate<Cooperative.Registry.SelectBranchStatement.Action>({
|
||||
registry_id: Cooperative.Registry.SelectBranchStatement.registry_id,
|
||||
coopname: system.info.coopname,
|
||||
username: session.username,
|
||||
braname: selectedBranch.value,
|
||||
})
|
||||
step.value++
|
||||
} catch (e: unknown) {
|
||||
FailAlert(e)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const back = () => {
|
||||
@@ -80,6 +111,7 @@ export function useSelectBranchProcess() {
|
||||
document,
|
||||
isSubmitting,
|
||||
isLoading,
|
||||
branchesLoading,
|
||||
next,
|
||||
back,
|
||||
sign,
|
||||
|
||||
@@ -9,7 +9,6 @@ div
|
||||
emit-value
|
||||
standout="bg-teal text-white"
|
||||
map-options
|
||||
@update:model-value="$emit('update:selectedBranch', $event)"
|
||||
)
|
||||
|
||||
template(v-slot:option="scope")
|
||||
@@ -27,22 +26,13 @@ div
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { type IPublicBranch } from 'src/entities/Branch/model';
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
defineProps({
|
||||
branches: {
|
||||
type: Object as () => IPublicBranch[],
|
||||
required: true,
|
||||
},
|
||||
modelValue: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
})
|
||||
|
||||
const selectedBranch = ref(props.modelValue)
|
||||
|
||||
watch(() => props.modelValue, (newVal) => {
|
||||
selectedBranch.value = newVal
|
||||
})
|
||||
const selectedBranch = defineModel<string>('selectedBranch', { default: '' })
|
||||
</script>
|
||||
|
||||
@@ -77,6 +77,9 @@ const maxWidthBySize: Record<BaseDialogSize, string> = {
|
||||
max-width: none;
|
||||
max-height: none;
|
||||
}
|
||||
.base-dialog--maximized .base-dialog__foot {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.base-dialog__head {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
|
||||
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@coopenomics/docs-harness",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@coopenomics/docs-harness",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.59.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coopenomics/docs-harness",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"private": true,
|
||||
"description": "Playwright harness для съёмки скриншотов в документацию (см. bin/shoot.mjs)",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@coopenomics/docs",
|
||||
"type": "module",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@9.9.0",
|
||||
"description": "Документация для монорепозитория",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@coopenomics/factory",
|
||||
"type": "module",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"description": "Фабрика юридических документов кооператива",
|
||||
"author": "Alex Ant <chairman.voskhod@gmail.com>",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@coopenomics/inter",
|
||||
"type": "module",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"description": "Контракты и DI-токены для связи расширений контроллера без прямых зависимостей",
|
||||
"author": "Alex Ant <dacom.dark.sun@gmail.com>",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"local": "049_migrate_phase2_progwallets.ts",
|
||||
"test": "051_edit_selected_draft.ts",
|
||||
"prod": "051_edit_selected_draft.ts"
|
||||
"test": "052_edit_selected_draft.ts",
|
||||
"prod": "052_edit_selected_draft.ts"
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ import { api } from '../src/eos'
|
||||
|
||||
export class InitialMigration implements Migration {
|
||||
async run(): Promise {
|
||||
const ids = [100]
|
||||
const ids = [994, 995, 996, 998, 999, 1000]
|
||||
|
||||
for (const id of ids) {
|
||||
try {
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "migrator",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"description": "Утилита миграции данных между версиями",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coopenomics/notifications",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"description": "Каталог типобезопасных типов уведомлений и шаблонов Центра уведомлений",
|
||||
"type": "module",
|
||||
"private": false,
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "pkg-placeholder",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pkg-placeholder",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^2.16.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@coopenomics/parser",
|
||||
"type": "module",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@9.0.6",
|
||||
"description": "Индексатор блокчейна через State History Plugin",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@coopenomics/sdk",
|
||||
"type": "module",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"private": false,
|
||||
"packageManager": "pnpm@9.9.0",
|
||||
"description": "TypeScript SDK для работы с API кооператива",
|
||||
|
||||
@@ -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). */
|
||||
export const SFR_REG_NUMBER_PATTERN = /^\d{3}-\d{3}-\d{6}$/;
|
||||
/** Регистрационный номер страхователя в СФР: 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') => (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,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coopenomics/setup",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"private": true,
|
||||
"description": "Интерактивный мастер настройки окружения",
|
||||
"main": "index.js",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||
"version": "2026.6.24",
|
||||
"version": "2026.7.21-1",
|
||||
"packages": [
|
||||
"components/*",
|
||||
"components/controller/src/plugins/*"
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@
|
||||
"deploy": "lerna run deploy --scope @coopenomics/boot --",
|
||||
"clear": "lerna run clear --scope @coopenomics/boot",
|
||||
"enter": "lerna run run --scope @coopenomics/cleos",
|
||||
"build:lib": "lerna run build --scope @coopenomics/factory --scope @coopenomics/cooptypes",
|
||||
"build:lib": "lerna run build --scope @coopenomics/cooptypes --scope @coopenomics/factory --scope @coopenomics/inter",
|
||||
"build:contracts:all": "lerna run build:all --scope @coopenomics/contracts",
|
||||
"build:contract": "lerna run build:one --scope @coopenomics/contracts --",
|
||||
"build:contracts:all:test": "lerna run build:all:test --scope @coopenomics/contracts",
|
||||
|
||||
Reference in New Issue
Block a user