eust-conciliation
Version:
119 lines (96 loc) • 4.91 kB
text/typescript
/* eslint-disable no-unused-vars */
/* eslint-disable no-await-in-loop */
/* eslint-disable no-restricted-syntax */
import { Inject, Injectable } from '@severo-tech/injection-decorator';
import { Agent, AgentType } from '../../../../domain/agent';
import { PromisesUtil } from '../../../utils';
import { ConciliationBase } from './conciliation-base';
import { Debit } from '../../../../domain/debit';
import { IAgentClient, IDebitClient, IInvoiceClient } from '../../../contracts';
import { IConfig } from '../../../contracts/config';
interface IGroupedDebit {
cnpj: string;
value: number;
debits: Debit[];
}
()
export class ConciliationOneToMany 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, user: Agent, startDate: Date, endDate: Date): Promise<void> {
this.logger.info(`"ConciliationOneToMany.execute" - Conciliating One User to Many Transmitters debits - UserCode [${user.code}]`);
await this.executeBy((debit) => this.groupDebitsByTransmitterCNPJ(debit), year, month, user, startDate, endDate);
await this.executeBy((debit) => this.groupDebitsByTransmitterRootCNPJ(debit), year, month, user, startDate, endDate);
await this.executeByInvoice(year, month, user, startDate, endDate);
this.logger.info('"ConciliationOneToMany.execute" - Finished One-To-Many debits conciliation');
}
private async executeBy(groupMethod: (debits: Debit[]) => Promise<IGroupedDebit[]>, year: number, month: number, user: Agent, startDate: Date, endDate: Date): Promise<void> {
const debits = await this.debitClient.find({
year,
month,
userCode: user.code,
reconciled: false,
});
const groupedDebits = await groupMethod(debits);
this.logger.info(`"ConciliationOneToMany.execute" - Grouped ${groupedDebits.length} Debits to process`);
const { maxParallelExecution } = this.config.service;
await this.promisesUtil.groupExecute(groupedDebits, maxParallelExecution, async (group: IGroupedDebit): Promise<void> => {
await this.tryToConciliateDebits(startDate, endDate, group.debits, group.cnpj, user.cnpj, group.value);
});
}
private async executeByInvoice(year: number, month: number, user: Agent, startDate: Date, endDate: Date): Promise<void> {
const debits = await this.debitClient.find({
year,
month,
userCode: user.code,
reconciled: false,
});
const groupedDebits = await this.groupDebitsByTransmitterRootCNPJ(debits);
this.logger.info(`"ConciliationOneToMany.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.cnpj, user.cnpj);
});
}
private async groupDebitsByTransmitterCNPJ(debits: Debit[]): Promise<IGroupedDebit[]> {
let groupMap = new Map<string, IGroupedDebit>();
for (const debit of debits) {
if (debit.value > 0) { // Groups only debits that haven't been reconciled so far.
const [transmitter] = await this.agentClient.find({ code: debit.transmitterCode, type: AgentType.Transmitter });
if (transmitter) {
const { cnpj } = transmitter;
groupMap = this.setGroupMap(groupMap, cnpj, debit);
}
}
}
return [...groupMap.values()].filter((el: IGroupedDebit): boolean => el.debits.length > 1);
}
private async groupDebitsByTransmitterRootCNPJ(debits: Debit[]): Promise<IGroupedDebit[]> {
let groupCnpjRootMap = new Map<string, IGroupedDebit>();
for (const debit of debits) {
if (debit.value > 0) { // Groups only debits that haven't been reconciled so far.
const [transmitter] = await this.agentClient.find({ code: debit.transmitterCode, type: AgentType.Transmitter });
if (transmitter) {
const { cnpj } = transmitter;
const cnpjRoot = cnpj.substring(0, 8);
groupCnpjRootMap = this.setGroupMap(groupCnpjRootMap, cnpjRoot, debit);
}
}
}
return [...groupCnpjRootMap.values()].filter((el: IGroupedDebit): boolean => el.debits.length > 1);
}
private setGroupMap(group: Map<string, IGroupedDebit>, cnpj: string, debit: Debit): Map<string, IGroupedDebit> {
const existingGrouped = group.get(cnpj);
return group.set(cnpj, {
cnpj,
debits: [...(existingGrouped?.debits ?? []), debit],
value: +((existingGrouped?.value ?? 0) + debit.value).toFixed(2),
});
}
}