Skip to content

Commit

Permalink
Merge pull request #325 from RJ-SMTR/feat/298-financeiro-columns
Browse files Browse the repository at this point in the history
(prod) Feat/298 financeiro columns
  • Loading branch information
williamfl2007 committed Jun 27, 2024
2 parents b0e2011 + 8503712 commit aae32ae
Show file tree
Hide file tree
Showing 27 changed files with 443 additions and 89 deletions.
2 changes: 2 additions & 0 deletions src/bank-statements/dtos/bank-statement-previous-days.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Ocorrencia } from "src/cnab/entity/pagamento/ocorrencia.entity";
import { SetValue } from "src/utils/decorators/set-value.decorator";

export class BankStatementPreviousDaysDTO {
constructor(dto?: BankStatementPreviousDaysDTO) {
Expand Down Expand Up @@ -38,6 +39,7 @@ export class BankStatementPreviousDaysDTO {
status: string | null;

/** Bank error message */
@SetValue((v) => Ocorrencia.toUserErrors(v))
errors: Ocorrencia[];

// Debug
Expand Down
10 changes: 6 additions & 4 deletions src/bank-statements/dtos/bank-statement.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Ocorrencia } from "src/cnab/entity/pagamento/ocorrencia.entity";
import { SetValue } from "src/utils/decorators/set-value.decorator";

export class BankStatementDTO {
constructor(dto?: BankStatementDTO) {
Expand All @@ -15,7 +16,7 @@ export class BankStatementDTO {
*/

date: string;

/**
* Date when payment was made in bank.
*
Expand All @@ -28,13 +29,14 @@ export class BankStatementDTO {
amount: number;

paidAmount: number;

/** Payment status */
status: string | null;

/** Bank error message */
@SetValue((v) => Ocorrencia.toUserErrors(v))
errors: Ocorrencia[];

// Debug
ticketCount: number;
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class BigqueryOrdemPagamentoRepository {
SELECT
CAST(t.data_ordem AS STRING) AS dataOrdem,
t.id_consorcio AS idConsorcio,
CASE WHEN t.consorcio = 'STPL' THEN 'STPC' ELSE t.consorcio AS consorcio,
t.consorcio,
t.id_operadora AS idOperadora,
t.operadora AS operadora,
t.id_ordem_pagamento AS idOrdemPagamento,
Expand Down
2 changes: 1 addition & 1 deletion src/bigquery/services/bigquery-ordem-pagamento.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class BigqueryOrdemPagamentoService {
const friday = isFriday(today) ? today : nextFriday(today);

const sex = subDays(friday, 7 + daysBefore);
const qui = subDays(friday, 1 + daysBefore);
const qui = subDays(friday, 1);
const ordemPgto = (
await this.bigqueryOrdemPagamentoRepository.findMany({
startDate: sex,
Expand Down
74 changes: 62 additions & 12 deletions src/cnab/cnab.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { Injectable } from '@nestjs/common';
import {
endOfDay,
isFriday,
isSameDay,
nextFriday,
nextThursday,
startOfDay,
subDays,
subDays
} from 'date-fns';
import { BigqueryOrdemPagamentoDTO } from 'src/bigquery/dtos/bigquery-ordem-pagamento.dto';
import { BigqueryOrdemPagamentoService } from 'src/bigquery/services/bigquery-ordem-pagamento.service';
Expand All @@ -24,6 +25,7 @@ import { CustomLogger } from 'src/utils/custom-logger';
import { yearMonthDayToDate } from 'src/utils/date-utils';
import { asNumber } from 'src/utils/pipe-utils';
import { Between } from 'typeorm';
import { ArquivoPublicacao } from './entity/arquivo-publicacao.entity';
import { ClienteFavorecido } from './entity/cliente-favorecido.entity';
import { ItemTransacaoAgrupado } from './entity/pagamento/item-transacao-agrupado.entity';
import { ItemTransacao } from './entity/pagamento/item-transacao.entity';
Expand Down Expand Up @@ -122,7 +124,13 @@ export class CnabService {
* Atualiza a tabela TransacaoView
*/
async updateTransacaoViewBigquery(daysBack = 0) {
const transacoesBq = await this.bigqueryTransacaoService.getFromWeek(daysBack, false);
const transacoesBq = await this.bigqueryTransacaoService.getFromWeek(
daysBack,
false,
);
// BigqueryTransacao.fromJson(
// `${__dirname}/test/cnab-service/data/data/update-transaca-view/bq-transacao-d0.json`,
// );
let chunkSize = 0;
forChunk(transacoesBq, 1000, async (chunk) => {
chunkSize += 1000;
Expand Down Expand Up @@ -165,22 +173,57 @@ export class CnabService {

async compareTransacaoViewPublicacao(daysBefore = 0) {
const transacoesView = await this.getTransacoesViewWeek(daysBefore);
const publicacoes = await this.getPublicacoesWeek(daysBefore);
const publicacoes = this.getUniqueUpdatePublicacoes(
await this.getPublicacoesWeek(daysBefore),
);
for (const publicacao of publicacoes) {
const transacaoViewIds = transacoesView
.filter(
(transacaoView) =>
transacaoView.idOperadora ===
publicacao.itemTransacao.idOperadora &&
transacaoView.idConsorcio === publicacao.itemTransacao.idConsorcio,
)
.map((i) => i.id);
await this.transacaoViewService.updateMany(transacaoViewIds, {
const transacoes = transacoesView.filter(
(transacaoView) =>
transacaoView.idOperadora === publicacao.itemTransacao.idOperadora &&
transacaoView.idConsorcio === publicacao.itemTransacao.idConsorcio &&
isSameDay(
// Se a data é a mesma (d+0 vs d+1)
transacaoView.datetimeProcessamento, // d+0
subDays(publicacao.itemTransacao.dataOrdem, 1), // d+1
),
);
const transacaoIds = transacoes.map((i) => i.id);
await this.transacaoViewService.updateMany(transacaoIds, {
arquivoPublicacao: { id: publicacao.id },
});
}
}

getUniqueUpdatePublicacoes(publicacoes: ArquivoPublicacao[]) {
const unique: ArquivoPublicacao[] = [];
publicacoes.forEach((publicacao) => {
const existing = ArquivoPublicacao.filterUnique(unique, publicacao)[0] as
| ArquivoPublicacao
| undefined;
const ocourences = ArquivoPublicacao.filterUnique(
publicacoes,
publicacao,
).sort(
(a, b) =>
b.itemTransacao.dataOrdem.getTime() -
a.itemTransacao.dataOrdem.getTime(),
);
const paid = ocourences.filter((i) => i.isPago)[0] as
| ArquivoPublicacao
| undefined;
const noErrors = ocourences.filter((i) => !i.getIsError())[0] as
| ArquivoPublicacao
| undefined;
const recent = ocourences[0] as ArquivoPublicacao;

if (!existing) {
const newPublicacao = paid || noErrors || recent;
unique.push(newPublicacao);
}
});
return unique;
}

/**
* Publicacao está associada com a ordem, portanto é sex-qui
*/
Expand All @@ -206,6 +249,13 @@ export class CnabService {
return result;
}

/**
* Salvar:
* - TransacaoAgrupado (CNAB)
* - ItemTransacaoAgrupado ()
* - Transacao
* -
*/
async saveAgrupamentos(
ordem: BigqueryOrdemPagamentoDTO,
pagador: Pagador,
Expand Down
23 changes: 23 additions & 0 deletions src/cnab/dto/pagamento/header-lote.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { IsNotEmpty, ValidateIf } from 'class-validator';
import { Cnab104FormaLancamento } from 'src/cnab/enums/104/cnab-104-forma-lancamento.enum';
import { CnabRegistros104Pgto } from 'src/cnab/interfaces/cnab-240/104/pagamento/cnab-registros-104-pgto.interface';
import { DeepPartial } from 'typeorm';
import { HeaderArquivo } from '../../entity/pagamento/header-arquivo.entity';
import { Pagador } from '../../entity/pagamento/pagador.entity';
Expand Down Expand Up @@ -49,4 +51,25 @@ export class HeaderLoteDTO {
pagador?: DeepPartial<Pagador>;

ocorrenciasCnab?: string;

/**
* Usado apenas para geração do remessa, não é salvo no banco
*
* O formaLancamento depende do codigoBancoFavorecido.
* /
codigoBancoFavorecido: string;
/** Usado apenas para geração do remessa, não é salvo no banco */
formaLancamento: Cnab104FormaLancamento;

/** Usado apenas para geração do remessa, não é salvo no banco */
// itemTransacaoAgrupados: ItemTransacaoAgrupado[] = [];

/**
* Usado apenas para geração do remessa, não é salvo no banco
*
* Após armazenar os itemTransacaoAgrupados, gera os respectivos detalhes
* e armazena neste DTO para gerar o CNAB.
*/
registros104: CnabRegistros104Pgto[] = [];
}
15 changes: 15 additions & 0 deletions src/cnab/entity/arquivo-publicacao.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
UpdateDateColumn,
} from 'typeorm';
import { ItemTransacao } from './pagamento/item-transacao.entity';
import { isSameDay } from 'date-fns';

/**
* Unique Jaé FK: idOrdemPagamento, idConsorcio, idOperadora
Expand Down Expand Up @@ -76,4 +77,18 @@ export class ArquivoPublicacao extends EntityHelper {
setReadValues() {
this.valorRealEfetivado = asNullableStringOrNumber(this.valorRealEfetivado);
}

/** Evita acessar o itemTransacao.DetalheA.Ocorrencia para saber se teve erro. */
getIsError() {
return !this.isPago && this.dataEfetivacao;
}

public static filterUnique(publicacoes: ArquivoPublicacao[], compare: ArquivoPublicacao) {
return publicacoes.filter(
(p) =>
p.itemTransacao.idConsorcio === compare.itemTransacao.idConsorcio &&
p.itemTransacao.idOperadora === compare.itemTransacao.idOperadora &&
isSameDay(p.itemTransacao.dataOrdem, compare.itemTransacao.dataOrdem),
);
}
}
5 changes: 4 additions & 1 deletion src/cnab/entity/pagamento/header-lote.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@ export class HeaderLote extends EntityHelper {
codigoConvenioBanco: string | null;

@Column({ type: String, unique: false, nullable: true })
tipoCompromisso: string | null;
tipoCompromisso: string;

@Column({ type: String, unique: false, nullable: true })
parametroTransmissao: string;

@Column({ type: String, unique: false, nullable: true })
formaLancamento: string;

@ManyToOne(() => Pagador, { eager: true })
@JoinColumn({ foreignKeyConstraintName: 'FK_HeaderLote_pagador_ManyToOne' })
pagador: Pagador;
Expand Down
13 changes: 13 additions & 0 deletions src/cnab/entity/pagamento/item-transacao-agrupado.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ import {
import { ClienteFavorecido } from '../cliente-favorecido.entity';
import { TransacaoAgrupado } from './transacao-agrupado.entity';

/**
* Representa um destinatário, a ser pago pelo remetente (TransacaoAgrupado).
*
* Esta tabela contém a soma de todas as transações (ItemTransacao)
* a serem feitas neste CNAB (TransacaoAgrupado).
*
* Colunas:
* - dataOrdem: sexta de pagamento (baseado no BigqueryOrdemPgto.dataOrdem (dia da ordem D+1))
*
* Identificador:
* - TransacaoAgrupado (CNAB / remetente)
* - ClienteFavorecido (destinatário)
*/
@Entity()
export class ItemTransacaoAgrupado extends EntityHelper {
constructor(dto?: DeepPartial<ItemTransacaoAgrupado>) {
Expand Down
12 changes: 12 additions & 0 deletions src/cnab/entity/pagamento/item-transacao.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ import { ClienteFavorecido } from '../cliente-favorecido.entity';
import { ItemTransacaoAgrupado } from './item-transacao-agrupado.entity';
import { Transacao } from './transacao.entity';

/**
* Representa uma BqOrdemPgto (ArquivoPublicacao)
*
* Colunas:
* - dataOrdem: BqOrdemPgto.dataOrdem
*
* Identificador:
* - ItemTransacaoAgrupado
* - dataTransacao
* - dataProcessamento
* - clienteFavorecido
*/
@Entity()
export class ItemTransacao extends EntityHelper {
constructor(dto?: DeepPartial<ItemTransacao>) {
Expand Down
22 changes: 22 additions & 0 deletions src/cnab/entity/pagamento/ocorrencia.entity.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { OcorrenciaEnum } from 'src/cnab/enums/ocorrencia.enum';
import { Ocorrencia } from './ocorrencia.entity';

describe('Ocorrencia', () => {
describe('formatToUserErrors', () => {
it('Deve esconder 2 erros técnicos, e mostrar 1 erro genérico no lugar', () => {
const ocorrencias = [
Ocorrencia.fromEnum(OcorrenciaEnum['AG']),
Ocorrencia.fromEnum(OcorrenciaEnum['02']),
Ocorrencia.fromEnum(OcorrenciaEnum['03']),
];

const expectedOutput = [
Ocorrencia.fromEnum(OcorrenciaEnum['AG']),
Ocorrencia.fromEnum(OcorrenciaEnum[' ']),
];

const formattedErrors = Ocorrencia.toUserErrors(ocorrencias);
expect(formattedErrors).toEqual(expectedOutput);
});
});
});
38 changes: 38 additions & 0 deletions src/cnab/entity/pagamento/ocorrencia.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ import {
import { DetalheA } from './detalhe-a.entity';
import { Exclude } from 'class-transformer';

const userErrors = [
'AG',
'AL',
'AM',
'AN',
'AO',
'AS',
'BG',
'DA',
'DB',
'ZA',
'ZY',
];

@Entity()
export class Ocorrencia extends EntityHelper {
constructor(ocorrencias?: DeepPartial<Ocorrencia>) {
Expand All @@ -21,6 +35,13 @@ export class Ocorrencia extends EntityHelper {
}
}

public static fromEnum(value: OcorrenciaEnum) {
return new Ocorrencia({
code: Enum.getKey(OcorrenciaEnum, value),
message: value,
});
}

@Exclude()
@PrimaryGeneratedColumn({ primaryKeyConstraintName: 'PK_Ocorrencia_id' })
id: number;
Expand Down Expand Up @@ -85,4 +106,21 @@ export class Ocorrencia extends EntityHelper {
}
return joined;
}

/**
* Oculta erros técnicos do usuário, exibindo uma mensagem genérica no lugar
*/
public static toUserErrors(ocorrencias: Ocorrencia[]) {
let newOcorrencias = ocorrencias.map((j) =>
!userErrors.includes(j.code)
? new Ocorrencia({ ...j, code: ' ', message: OcorrenciaEnum[' '] })
: j,
);
newOcorrencias = newOcorrencias.reduce(
(l: Ocorrencia[], j) =>
l.map((k) => k.code).includes(j.code) ? l : [...l, j],
[],
);
return newOcorrencias;
}
}
1 change: 1 addition & 0 deletions src/cnab/entity/pagamento/transacao-agrupado.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export class TransacaoAgrupado extends EntityHelper {
})
id: number;

/** sexta de pagamento (baseado no BigqueryOrdemPgto.dataOrdem) */
@Column({ type: Date, unique: false, nullable: true })
dataOrdem: Date;

Expand Down
Loading

0 comments on commit aae32ae

Please sign in to comment.