eust-conciliation
Version:
157 lines (128 loc) • 6.91 kB
text/typescript
/* 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[];
}
()
export class ConciliationManyToMany extends ConciliationBase {
('Agent01EUSTClient')
private readonly agentClient!: IAgentClient;
('Debit01EUSTClient')
private readonly debitClient!: IDebitClient;
('PromisesUtil')
private readonly promisesUtil!: PromisesUtil;
('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),
});
}
}