UNPKG

eust-conciliation

Version:
157 lines (128 loc) 6.91 kB
/* eslint-disable no-unused-vars */ /* eslint-disable no-restricted-syntax */ /* eslint-disable no-await-in-loop */ import { Inject, Injectable } from '@severo-tech/injection-decorator'; import { ConciliationBase } from './conciliation-base'; import { PromisesUtil } from '../../../utils'; import { Debit } from '../../../../domain/debit'; import { AgentType } from '../../../../domain/agent'; import { IAgentClient, IDebitClient, IInvoiceClient } from '../../../contracts'; import { IConfig } from '../../../contracts/config'; interface IGroupedDebit { emitterDocument: string; recipientDocument: string; value: number; debits: Debit[]; } @Injectable() export class ConciliationManyToMany extends ConciliationBase { @Inject('Agent01EUSTClient') private readonly agentClient!: IAgentClient; @Inject('Debit01EUSTClient') private readonly debitClient!: IDebitClient; @Inject('PromisesUtil') private readonly promisesUtil!: PromisesUtil; @Inject('EnvConfig') private readonly config!: IConfig; public async execute(year: number, month: number, startDate: Date, endDate: Date): Promise<void> { this.logger.info('"ConciliationManyToMany.execute" - Conciliating Many Users to Many Transmitters debits'); await this.executeBy((debits) => this.groupDebitsByUserCNPJAndTransmitterCNPJ(debits), year, month, startDate, endDate); await this.executeBy((debits) => this.groupDebitsByUserCNPJAndTransmitterRoot(debits), year, month, startDate, endDate); await this.executeBy((debits) => this.groupDebitsByUserRootAndTransmitterCNPJ(debits), year, month, startDate, endDate); await this.executeBy((debits) => this.groupDebitsByUserRootAndTransmitterRoot(debits), year, month, startDate, endDate); await this.executeByInvoice(year, month, startDate, endDate); this.logger.info('"ConciliationManyToMany.execute" - Finished Many-To-Many debits conciliation'); } public async executeBy(groupMethod: (debits: Debit[]) => Promise<IGroupedDebit[]>, year: number, month: number, startDate: Date, endDate: Date): Promise<void> { const debits = await this.debitClient.find({ year, month, reconciled: false, }); const groups = await groupMethod(debits); this.logger.info(`"ConciliationManyToMany.execute" - Grouped ${groups.length} Debits to process`); const { maxParallelExecution } = this.config.service; await this.promisesUtil.groupExecute(groups, maxParallelExecution, async (group: IGroupedDebit): Promise<void> => { await this.tryToConciliateDebits(startDate, endDate, group.debits, group.emitterDocument, group.recipientDocument, group.value); }); } private async executeByInvoice(year: number, month: number, startDate: Date, endDate: Date): Promise<void> { const debits = await this.debitClient.find({ year, month, reconciled: false, }); const groupedDebits = await this.groupDebitsByUserRootAndTransmitterRoot(debits); this.logger.info(`"ConciliationManyToMany.executeByInvoice" - Grouped ${groupedDebits.length} Debits to process`); const { maxParallelExecution } = this.config.service; await this.promisesUtil.groupExecute(groupedDebits, maxParallelExecution, async (group: IGroupedDebit): Promise<void> => { await this.tryToConciliateInvoice(startDate, endDate, group.debits, group.emitterDocument, group.recipientDocument); }); } private async groupDebitsByUserCNPJAndTransmitterCNPJ(debits: Debit[]): Promise<IGroupedDebit[]> { let debitsMap = new Map<string, IGroupedDebit>(); for (const debit of debits) { if (debit.value > 0) { const [transmitter] = await this.agentClient.find({ code: debit.transmitterCode, type: AgentType.Transmitter }); if (transmitter) { const [agent] = await this.agentClient.find({ code: debit.userCode, type: AgentType.User }); debitsMap = this.setGroupMap(debitsMap, transmitter.cnpj, agent.cnpj, debit); } } } return [...debitsMap.values()].filter((el: IGroupedDebit): boolean => el.debits.length > 1); } private async groupDebitsByUserCNPJAndTransmitterRoot(debits: Debit[]): Promise<IGroupedDebit[]> { let debitsMap = new Map<string, IGroupedDebit>(); for (const debit of debits) { if (debit.value > 0) { const [transmitter] = await this.agentClient.find({ code: debit.transmitterCode, type: AgentType.Transmitter }); if (transmitter) { const [agent] = await this.agentClient.find({ code: debit.userCode, type: AgentType.User }); const recipientDocRoot = agent.cnpj.substring(0, 8); debitsMap = this.setGroupMap(debitsMap, transmitter.cnpj, recipientDocRoot, debit); } } } return [...debitsMap.values()].filter((el: IGroupedDebit): boolean => el.debits.length > 1); } private async groupDebitsByUserRootAndTransmitterCNPJ(debits: Debit[]): Promise<IGroupedDebit[]> { let debitsMap = new Map<string, IGroupedDebit>(); for (const debit of debits) { if (debit.value > 0) { const [transmitter] = await this.agentClient.find({ code: debit.transmitterCode, type: AgentType.Transmitter }); if (transmitter) { const [agent] = await this.agentClient.find({ code: debit.userCode, type: AgentType.User }); const emitterDocRoot = transmitter.cnpj.substring(0, 8); debitsMap = this.setGroupMap(debitsMap, emitterDocRoot, agent.cnpj, debit); } } } return [...debitsMap.values()].filter((el: IGroupedDebit): boolean => el.debits.length > 1); } private async groupDebitsByUserRootAndTransmitterRoot(debits: Debit[]): Promise<IGroupedDebit[]> { let debitsMap = new Map<string, IGroupedDebit>(); for (const debit of debits) { if (debit.value > 0) { const [transmitter] = await this.agentClient.find({ code: debit.transmitterCode, type: AgentType.Transmitter }); if (transmitter) { const [agent] = await this.agentClient.find({ code: debit.userCode, type: AgentType.User }); const recipientDocRoot = agent.cnpj.substring(0, 8); const emitterDocRoot = transmitter.cnpj.substring(0, 8); debitsMap = this.setGroupMap(debitsMap, emitterDocRoot, recipientDocRoot, debit); } } } return [...debitsMap.values()].filter((el: IGroupedDebit): boolean => el.debits.length > 1); } private setGroupMap(groupMap: Map<string, IGroupedDebit>, emitterDocument: string, recipientDocument: string, debit: Debit): Map<string, IGroupedDebit> { const mapKey = `${recipientDocument}-${emitterDocument}`; const existingGrouped = groupMap.get(mapKey); return groupMap.set(mapKey, { emitterDocument, recipientDocument, debits: [...(existingGrouped?.debits ?? []), debit], value: +((existingGrouped?.value ?? 0) + debit.value).toFixed(2), }); } }