import { ICompany } from '../dictionary/models/ICompany'; import { IEmployeeOrganization } from '../dictionary/models/IEmployeeOrganization'; import { IFioParts, splitFio } from './fio'; /** Одна компания, от имени которой подписывается документ. */ export interface ISigningCompany { /** БИН компании: от её имени документ идёт в Sigex. */ bin: string; name: string; /** Должность сотрудника именно в этой компании. */ position: string; } /** Компания сотрудника, по которой документ отправить нельзя, и почему. */ export interface ISkippedCompany { name: string; reason: string; } /** Кто подписывает и по каким компаниям. */ export interface ISigningTargets { iin: string; name: IFioParts; /** По документу на каждую компанию, где у сотрудника есть БИН в справочнике. */ companies: ISigningCompany[]; /** Компании, по которым документ не отправить (нет БИН в справочнике и т. п.). */ skipped: ISkippedCompany[]; } /** * Определяет подписанта и компании по справочникам api.tnsu.kz: ИИН и ФИО — из Employee/ByEmail, * БИН — из Dictionary/Companies по CompanyId. * * Сотрудник может работать в нескольких компаниях (на один e-mail — несколько записей), и заявление * подписывается по каждой из них отдельно: у каждой компании свой документ со своей должностью. * Одна и та же компания дважды не попадает. Компания без БИН не роняет остальные — она уходит в * skipped с причиной. Ошибка бросается, только если подписать нельзя вовсе: нет человека, ИИН, ФИО * или ни одной компании. */ export function resolveSigningTargets(records: IEmployeeOrganization[], companies: ICompany[]): ISigningTargets { if (records.length === 0) { throw new Error('сотрудника нет в кадровом справочнике — ИИН для подписания взять неоткуда'); } // Человек один на все записи: ИИН и ФИО берём из первой, где они есть. const iin = (records.find((r) => (r.iin || '').trim())?.iin || '').trim(); if (!iin) { throw new Error('в кадровом справочнике у сотрудника не указан ИИН'); } const fio = records.find((r) => (r.fio || '').trim())?.fio || ''; const name = splitFio(fio); if (!name) { throw new Error(`не удалось разобрать Ф.И.О. «${fio}» на фамилию и имя`); } const byId = new Map(companies.map((c) => [c.Id.toLowerCase(), c])); const result: ISigningCompany[] = []; const skipped: ISkippedCompany[] = []; const seen = new Set(); for (const record of records) { if (!record.companyId) continue; const company = byId.get(record.companyId.toLowerCase()); const bin = (company?.Bin || '').trim(); const companyName = company?.Name || record.company; if (!bin) { if (!seen.has(`name:${companyName}`)) { seen.add(`name:${companyName}`); skipped.push({ name: companyName, reason: 'в справочнике компаний нет БИН' }); } continue; } if (seen.has(bin)) continue; seen.add(bin); result.push({ bin, name: companyName, position: record.position }); } if (result.length === 0 && skipped.length === 0) { throw new Error('в карточке сотрудника не указана компания'); } return { iin, name, companies: result, skipped }; }