diff --git a/src/bigquery/entities/ordem-pagamento.bigquery-entity.ts b/src/bigquery/entities/ordem-pagamento.bigquery-entity.ts index 136dba9f..4727e8fa 100644 --- a/src/bigquery/entities/ordem-pagamento.bigquery-entity.ts +++ b/src/bigquery/entities/ordem-pagamento.bigquery-entity.ts @@ -1,3 +1,6 @@ +import { HttpStatus } from "@nestjs/common"; +import { CommonHttpException } from "src/utils/http-exception/common-http-exception"; + export class BigqueryOrdemPagamento { /** Data da ordem de pagamento (partição) */ data_ordem: string | null; @@ -85,4 +88,275 @@ export class BigqueryOrdemPagamento { /** Código de controle de versão do dado (SHA Github) */ versao: string | null; + + /** + * Get field validated + * @throws `HttpException` + */ + getDataOrdem(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): string { + if (!this.data_ordem) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'data_ordem', args); + } + return this.data_ordem; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getDataPagamento(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): string { + if (!this.data_pagamento) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'data_pagamento', args); + } + return this.data_pagamento; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getConsorcio(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): string { + if (!this.consorcio) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'consorcio', args); + } + return this.consorcio; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getOperadora(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): string { + if (!this.operadora) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'operadora', args); + } + return this.operadora; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getServico(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): string { + if (!this.servico) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'servico', args); + } + return this.servico; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getIdOrdemRessarcimento(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): string { + if (!this.id_ordem_ressarcimento) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'id_ordem_ressarcimento', args); + } + return this.id_ordem_ressarcimento; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getQuantidadeTransacaoRateioCredito(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): number { + if (this.quantidade_transacao_rateio_credito === null + || this.quantidade_transacao_rateio_credito === undefined) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'quantidade_transacao_rateio_credito', args); + } + return this.quantidade_transacao_rateio_credito; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getValorRateioCredito(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): number { + if (this.valor_rateio_credito === null + || this.valor_rateio_credito === undefined) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'valor_rateio_credito', args); + } + return this.valor_rateio_credito; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getQuantidadeTransacaoRateioDebito(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): number { + if (this.quantidade_transacao_rateio_debito === null + || this.quantidade_transacao_rateio_debito === undefined) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'quantidade_transacao_rateio_debito', args); + } + return this.quantidade_transacao_rateio_debito; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getValorRateioDebito(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): number { + if (this.valor_rateio_debito === null + || this.valor_rateio_debito === undefined) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'valor_rateio_debito', args); + } + return this.valor_rateio_debito; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getQuantidadeTotalTransacao(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): number { + if (this.quantidade_total_transacao === null + || this.quantidade_total_transacao === undefined) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'quantidade_total_transacao', args); + } + return this.quantidade_total_transacao; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getValorTotalTransacaoBruto(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): number { + if (this.valor_total_transacao_bruto === null + || this.valor_total_transacao_bruto === undefined) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'valor_total_transacao_bruto', args); + } + return this.valor_total_transacao_bruto; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getValorDescontoTaxa(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): number { + if (this.valor_desconto_taxa === null + || this.valor_desconto_taxa === undefined) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'valor_desconto_taxa', args); + } + return this.valor_desconto_taxa; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getValorTotalTransacaoLiquido(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): number { + if (this.valor_total_transacao_liquido === null + || this.valor_total_transacao_liquido === undefined) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', 'valor_total_transacao_liquido', args); + } + return this.valor_total_transacao_liquido; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getQuantidadeTotalTransacaoCaptura(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): number { + if (this.quantidade_total_transacao_captura === null + || this.quantidade_total_transacao_captura === undefined) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', + 'quantidade_total_transacao_captura', + args); + } + return this.quantidade_total_transacao_captura; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getValorTotalTransacaoCaptura(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): number { + if (this.valor_total_transacao_captura === null + || this.valor_total_transacao_captura === undefined) { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', + 'valor_total_transacao_captura', + args); + } + return this.valor_total_transacao_captura; + } + + /** + * Get field validated + * @throws `HttpException` + */ + getIndicadorOrdemValida(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): boolean { + if (typeof this.indicador_ordem_valida !== 'boolean') { + throw CommonHttpException.invalidField( + 'BigqueryOrdemPagamento', + 'indicador_ordem_valida', + args); + } + return this.indicador_ordem_valida; + } } diff --git a/src/bigquery/repository/transacao.repository.ts b/src/bigquery/repository/transacao.repository.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/cnab/cnab-caixa.service.ts b/src/cnab/cnab-caixa.service.ts deleted file mode 100644 index e51b4517..00000000 --- a/src/cnab/cnab-caixa.service.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { CnabFile } from './types/cnab-file.type'; -import { getCnabRegistros, stringifyCnabRegistro } from './utils/cnab-utils'; -import { CNAB_EOL } from './cnab-consts'; - -@Injectable() -export class CnabRemessaService { - /** - * Generate CNAB Remessa text content from CnabFile - */ - generateRemessaCnab(cnab: CnabFile): string { - const plainCnab = getCnabRegistros(cnab); - const cnabTextList: string[] = []; - for (const registro of plainCnab) { - cnabTextList.push(stringifyCnabRegistro(registro)); - } - return cnabTextList.join(CNAB_EOL); - } -} diff --git a/src/cnab/cnab.module.ts b/src/cnab/cnab.module.ts index 4c485ed3..7131efc5 100644 --- a/src/cnab/cnab.module.ts +++ b/src/cnab/cnab.module.ts @@ -1,7 +1,7 @@ import { Module } from '@nestjs/common'; -import { CnabService } from './cnab.service'; +import { CnabService } from './service/cnab.service'; @Module({ providers: [CnabService], }) -export class CnabModule {} +export class CnabModule { } diff --git a/src/cnab/cnab.service.ts b/src/cnab/cnab.service.ts deleted file mode 100644 index 38b1abbb..00000000 --- a/src/cnab/cnab.service.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class CnabService {} diff --git a/src/cnab/dto/detalhe-a.dto.ts b/src/cnab/dto/detalhe-a.dto.ts index 576ce121..0efb94f9 100644 --- a/src/cnab/dto/detalhe-a.dto.ts +++ b/src/cnab/dto/detalhe-a.dto.ts @@ -41,7 +41,7 @@ export class DetalheADTO { @ValidateIf(isCreate) @IsNotEmpty() - num_doc_lancamento?: string; + num_doc_lancamento?: number; @ValidateIf(isCreate) @IsNotEmpty() diff --git a/src/cnab/dto/detalhe-b.dto.ts b/src/cnab/dto/detalhe-b.dto.ts index 018d2e2f..ae31c32e 100644 --- a/src/cnab/dto/detalhe-b.dto.ts +++ b/src/cnab/dto/detalhe-b.dto.ts @@ -13,9 +13,10 @@ export class DetalheBDTO { @ValidateIf(isCreate) @IsNotEmpty() - nsr?: string; + nsr?: number; @ValidateIf(isCreate) @IsNotEmpty() data_vencimento?: Date; } + diff --git a/src/cnab/dto/item-transacao.dto.ts b/src/cnab/dto/item-transacao.dto.ts index 33a6a17e..3e834375 100644 --- a/src/cnab/dto/item-transacao.dto.ts +++ b/src/cnab/dto/item-transacao.dto.ts @@ -1,8 +1,35 @@ +import { IsNotEmpty, ValidateIf } from "class-validator"; + +function isCreate(object: ItemTransacaoDTO): boolean { + return object.id_item_transacao === undefined; +} + export class ItemTransacaoDTO { - id_item_transacao: number; - dt_transacao: Date; - dt_processamento; - dt_captura; - modo: string; - id_cliente_favorecido:number; + constructor(dto?: ItemTransacaoDTO) { + if (dto) { + Object.assign(this, dto); + } + } + + id_item_transacao?: number; + + @ValidateIf(isCreate) + @IsNotEmpty() + dt_transacao?: Date; + + @ValidateIf(isCreate) + @IsNotEmpty() + dt_processamento?: Date; + + @ValidateIf(isCreate) + @IsNotEmpty() + dt_captura?: Date; + + @ValidateIf(isCreate) + @IsNotEmpty() + modo?: string; + + @ValidateIf(isCreate) + @IsNotEmpty() + id_cliente_favorecido?: number; } \ No newline at end of file diff --git a/src/cnab/dto/transacao.dto.ts b/src/cnab/dto/transacao.dto.ts index bdeee6d8..4c5e4222 100644 --- a/src/cnab/dto/transacao.dto.ts +++ b/src/cnab/dto/transacao.dto.ts @@ -9,11 +9,11 @@ export class TransacaoDTO { @ValidateIf(isCreate) @IsNotEmpty() - dt_ordem?: string; + dt_ordem?: Date; @ValidateIf(isCreate) @IsNotEmpty() - dt_pagamento?: string; + dt_pagamento?: Date; @ValidateIf(isCreate) @IsNotEmpty() @@ -72,7 +72,7 @@ export class TransacaoDTO { vlr_total_transacao_captura?: number; @ValidateIf(isCreate) - indicador_ordem_valida?: string; + indicador_ordem_valida?: boolean; @ValidateIf(isCreate) @IsNotEmpty() diff --git a/src/cnab/entity/detalhe-a.entity.ts b/src/cnab/entity/detalhe-a.entity.ts index fb6ee3ec..65eeb848 100644 --- a/src/cnab/entity/detalhe-a.entity.ts +++ b/src/cnab/entity/detalhe-a.entity.ts @@ -5,34 +5,55 @@ import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; export class DetalheA extends EntityHelper { @PrimaryGeneratedColumn() id_detalhe_a: number; + @Column({ type: Number, unique: false, nullable: true }) id_header_lote: number; + @Column({ type: String, unique: false, nullable: true }) lote_servico: string; + @Column({ type: Number, unique: false, nullable: true }) id_cliente_favorecido: number; + @Column({ type: String, unique: false, nullable: true }) tipo_finalidade_conta: string; + @Column({ type: Date, unique: false, nullable: true }) dt_vencimento: Date; + @Column({ type: String, unique: false, nullable: true }) tipo_moeda: string; + + @Column({ type: Number, unique: false, nullable: true }) + qtde_moeda: number; + @Column({ type: String, unique: false, nullable: true }) valor_lancamento: number; + @Column({ type: String, unique: false, nullable: true }) - num_doc_lancamento: string; + num_doc_lancamento: number; + @Column({ type: String, unique: false, nullable: true }) qtde_parcelas: number; + @Column({ type: String, unique: false, nullable: true }) indicador_bloqueio: string; + @Column({ type: String, unique: false, nullable: true }) indicador_forma_parcelamento: string; + @Column({ type: Date, unique: false, nullable: true }) periodo_vencimento: Date; + @Column({ type: String, unique: false, nullable: true }) num_parcela: number; + @Column({ type: Date, unique: false, nullable: true }) data_efetivacao: Date; + @Column({ type: Number, unique: false, nullable: true }) valor_real_efetivado: number; + + @Column({ type: Number, unique: false, nullable: false }) + nsr: number; } diff --git a/src/cnab/entity/detalhe-b.entiy.ts b/src/cnab/entity/detalhe-b.entiy.ts index 3f542796..fe360d66 100644 --- a/src/cnab/entity/detalhe-b.entiy.ts +++ b/src/cnab/entity/detalhe-b.entiy.ts @@ -1,18 +1,25 @@ import { EntityHelper } from 'src/utils/entity-helper'; -import { DeepPartial, Entity } from 'typeorm'; +import { Column, DeepPartial, Entity, PrimaryGeneratedColumn } from 'typeorm'; +import { DetalheBDTO } from '../dto/detalhe-b.dto'; @Entity() export class DetalheB extends EntityHelper { - constructor(detalheB?: DetalheB | DeepPartial) { + constructor(detalheB?: DetalheB | DeepPartial | DetalheBDTO) { super(); if (detalheB !== undefined) { Object.assign(this, detalheB); } } + @PrimaryGeneratedColumn() id_detalhe_b: number; + id_detalhe_a: number; - nsr: string; + + @Column({ type: Number, unique: false, nullable: false }) + nsr: number; + + @Column({ type: Date, unique: false, nullable: false }) data_vencimento: Date; public getLogInfo(): string { diff --git a/src/cnab/entity/item-transacao.entity.ts b/src/cnab/entity/item-transacao.entity.ts index 83aa15da..7c59bba4 100644 --- a/src/cnab/entity/item-transacao.entity.ts +++ b/src/cnab/entity/item-transacao.entity.ts @@ -1,19 +1,62 @@ -import { EntityHelper} from 'src/utils/entity-helper'; -import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; +import { EntityHelper } from 'src/utils/entity-helper'; +import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; +import { ItemTransacaoDTO } from '../dto/item-transacao.dto'; +import { Transacao } from './transacao.entity'; +import { CommonHttpException } from 'src/utils/http-exception/common-http-exception'; +import { HttpStatus } from 'aws-sdk/clients/lambda'; @Entity() export class ItemTransacao extends EntityHelper { + + constructor(dto?: ItemTransacaoDTO) { + super(); + if (dto) { + Object.assign(this, dto); + } + } + @PrimaryGeneratedColumn() id_item_transacao: number; + @ManyToOne(() => Transacao, { + eager: true + }) + transacao: Transacao; + @Column({ type: String, unique: false, nullable: true }) dt_transacao: string; - @Column({ type: String, unique: false, nullable: true }) - dt_processamento: string; + + @Column({ type: Date, unique: false, nullable: true }) + dt_processamento: Date; + @Column({ type: Date, unique: false, nullable: true }) - dt_captura: Date; + dt_captura: Date; + @Column({ type: String, unique: false, nullable: true }) modo: string; + @Column({ type: String, unique: false, nullable: true }) id_cliente_favorecido: number; + + @Column({ type: Number, unique: false, nullable: true }) + valor_item_transacao: number; + + + /** + * Get field validated + * @throws `HttpException` + */ + getDtTransacao(args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }): string { + if (!this.dt_transacao) { + throw CommonHttpException.invalidField( + 'ItemTransacao', + 'dt_transacao', + args); + } + return this.dt_transacao; + } + } \ No newline at end of file diff --git a/src/cnab/entity/transacao.entity.ts b/src/cnab/entity/transacao.entity.ts index c146995e..19eb1600 100644 --- a/src/cnab/entity/transacao.entity.ts +++ b/src/cnab/entity/transacao.entity.ts @@ -28,10 +28,10 @@ export class Transacao extends EntityHelper { @Column({ type: String, unique: false, nullable: true, length: 150 }) servico: string; - @Column({ type: Number, unique: true, nullable: true, length: 150 }) - id_ordem_ressarcimento: number; + @Column({ type: String, unique: true, nullable: true, length: 150 }) + id_ordem_ressarcimento: string; - @Column({ type: Number, unique: false, nullable: true, length: 150 }) + @Column({ type: Number, unique: false, nullable: true }) qtde_transacao_rateio_credito: number; @Column({ @@ -97,8 +97,8 @@ export class Transacao extends EntityHelper { }) vlr_total_transacao_captura: number; - @Column({ type: String, unique: false, nullable: true, length: 100 }) - indicador_ordem_valida: string; + @Column({ type: Boolean, unique: false, nullable: true, length: 100 }) + indicador_ordem_valida: boolean; @Column({ type: Number, unique: false, nullable: true }) id_pagador: number; diff --git a/src/cnab/interfaces/cnab-tables.interface.ts b/src/cnab/interfaces/cnab-tables.interface.ts index 6797abc0..e29fbc10 100644 --- a/src/cnab/interfaces/cnab-tables.interface.ts +++ b/src/cnab/interfaces/cnab-tables.interface.ts @@ -1,11 +1,15 @@ import { HeaderArquivoDTO } from '../dto/header-arquivo.dto'; import { HeaderLoteDTO } from '../dto/header-lote.dto'; import { ItemTransacao } from '../entity/item-transacao.entity'; +import { ICnab240_104RegistroAB } from './cnab-240/104/cnab-240-104-registro-a-b.interface'; export interface ICnabTables { headerArquivo: HeaderArquivoDTO; lotes: { headerLote: HeaderLoteDTO; - detalhes: ItemTransacao[]; + detalhes: { + itemTransacao: ItemTransacao, + registroAB: ICnab240_104RegistroAB, + }[]; }[]; } diff --git a/src/cnab/repository/cliente-favorecido.repository.ts b/src/cnab/repository/cliente-favorecido.repository.ts index 6a1e50a2..d1f89fa0 100644 --- a/src/cnab/repository/cliente-favorecido.repository.ts +++ b/src/cnab/repository/cliente-favorecido.repository.ts @@ -4,6 +4,7 @@ import { EntityCondition } from 'src/utils/types/entity-condition.type'; import { Repository, UpdateResult } from 'typeorm'; import { SaveClienteFavorecidoDTO } from '../dto/cliente-favorecido.dto'; import { ClienteFavorecido } from '../entity/cliente-favorecido.entity'; +import { CommonHttpException } from 'src/utils/http-exception/common-http-exception'; @Injectable() export class ClienteFavorecidoRepository { @@ -14,7 +15,7 @@ export class ClienteFavorecidoRepository { constructor( @InjectRepository(ClienteFavorecido) private clienteFavorecidoRepository: Repository, - ) {} + ) { } async save(dto: SaveClienteFavorecidoDTO): Promise { if (dto.id_cliente_favorecido === undefined) { @@ -52,14 +53,16 @@ export class ClienteFavorecidoRepository { return updatePayload; } - public async findOne( - fields: - | EntityCondition - | EntityCondition[], + public async getOne( + fields: EntityCondition | EntityCondition[], ): Promise { - return await this.clienteFavorecidoRepository.findOne({ + const result = await this.clienteFavorecidoRepository.findOne({ where: fields, }); + if (!result) { + throw CommonHttpException.notFound(Object.keys(fields).join(',')); + } + else return result; } public async findAll( diff --git a/src/cnab/repository/detalhe-a.repository.ts b/src/cnab/repository/detalhe-a.repository.ts index f583562e..5333df44 100644 --- a/src/cnab/repository/detalhe-a.repository.ts +++ b/src/cnab/repository/detalhe-a.repository.ts @@ -14,17 +14,17 @@ export class DetalheARepository { constructor( @InjectRepository(DetalheA) - private DetalheARepository: Repository, - ) {} + private detalheARepository: Repository, + ) { } public async save(dto: DetalheADTO): Promise { - return await this.DetalheARepository.save(dto); + return await this.detalheARepository.save(dto); } public async findOne( fields: EntityCondition | EntityCondition[], ): Promise> { - return await this.DetalheARepository.findOne({ + return await this.detalheARepository.findOne({ where: fields, }); } @@ -32,8 +32,27 @@ export class DetalheARepository { public async findMany( fields: EntityCondition | EntityCondition[], ): Promise { - return await this.DetalheARepository.find({ + return await this.detalheARepository.find({ where: fields, }); } + + /** + * Get next 'Número Documento Atribuído pela Empresa'. + * + * For each registro A, J etc in the same date, you must set unique number from 1 then add 1. + * + * > Número do Documento Atribuído pela Empresa - número do agendamento atribuído pela empresa. + * > Este número deverá evoluir de 1 em 1 para cada registro dentro do arquivo. + */ + public async getNextNumeroDocumento(dataEfetivacao: Date): Promise { + const result = await this.detalheARepository + .createQueryBuilder('detalheA') + .select('MAX(detalheA.num_doc_lancamento)', 'maxNumDocLancamento') + .where('detalheA.data_efetivacao = :dataEfetivacao', { dataEfetivacao }) + .getRawOne(); + + const maxNumDocLancamento = result.maxNumDocLancamento || 0; + return maxNumDocLancamento + 1; + } } diff --git a/src/cnab/repository/detalhe-b.repository.ts b/src/cnab/repository/detalhe-b.repository.ts index ef4a0616..31b92503 100644 --- a/src/cnab/repository/detalhe-b.repository.ts +++ b/src/cnab/repository/detalhe-b.repository.ts @@ -2,10 +2,9 @@ import { Injectable, Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { EntityCondition } from 'src/utils/types/entity-condition.type'; import { Nullable } from 'src/utils/types/nullable.type'; -import { Repository, UpdateResult } from 'typeorm'; -import { DetalheB } from '../entity/detalhe-b.entiy'; -import { SaveDetalheBDTO } from '../dto/save-detalhe-b.dto'; +import { Repository } from 'typeorm'; import { DetalheBDTO } from '../dto/detalhe-b.dto'; +import { DetalheB } from '../entity/detalhe-b.entiy'; @Injectable() export class DetalheBRepository { @@ -37,14 +36,4 @@ export class DetalheBRepository { where: fields, }); } - - async update(id: number, updateDto: SaveDetalheBDTO): Promise { - const updatePayload = await this.DetalheBRepository.update( - { id_detalhe_b: id }, - updateDto, - ); - const updatedItem = new DetalheB({ id_detalhe_b: id, ...updateDto }); - this.logger.log(`DetalheB atualizado: ${updatedItem.getLogInfo()}`); - return updatePayload; - } } diff --git a/src/cnab/repository/item-transacao.repository.ts b/src/cnab/repository/item-transacao.repository.ts index edaec056..82f75c77 100644 --- a/src/cnab/repository/item-transacao.repository.ts +++ b/src/cnab/repository/item-transacao.repository.ts @@ -5,33 +5,40 @@ import { Nullable } from 'src/utils/types/nullable.type'; import { Repository } from 'typeorm'; import { ItemTransacao } from '../entity/item-transacao.entity'; import { ItemTransacaoDTO } from '../dto/item-transacao.dto'; +import { validateDTO } from 'src/utils/validation-utils'; @Injectable() export class ItemTransacaoRepository { - + private logger: Logger = new Logger('ItemTransacaoRepository', { timestamp: true, }); constructor( @InjectRepository(ItemTransacao) - private itemtransacaoRepository: Repository, - ) {} + private itemTransacaoRepository: Repository, + ) { } public async save(itemTransacao: ItemTransacaoDTO): Promise { - return await this.itemtransacaoRepository.save(itemTransacao); + await validateDTO(ItemTransacaoDTO, itemTransacao); + const itemTransacaoEntity = new ItemTransacao(itemTransacao); + return await this.itemTransacaoRepository.save(itemTransacaoEntity); } public async findOne( fields: EntityCondition | EntityCondition[], ): Promise> { - return await this.itemtransacaoRepository.findOne({ + return await this.itemTransacaoRepository.findOne({ where: fields, }); } public async findAll(): Promise { - return await this.itemtransacaoRepository.find(); + return await this.itemTransacaoRepository.find(); + } + + public async findMany(fields: EntityCondition | EntityCondition[]): Promise { + return await this.itemTransacaoRepository.find({ where: fields }); } } \ No newline at end of file diff --git a/src/cnab/repository/transacao.repository.ts b/src/cnab/repository/transacao.repository.ts index 75062669..632166e2 100644 --- a/src/cnab/repository/transacao.repository.ts +++ b/src/cnab/repository/transacao.repository.ts @@ -17,8 +17,8 @@ export class TransacaoRepository { private transacaoRepository: Repository, ) {} - public async save(transacaoDTO: TransacaoDTO): Promise { - return this.transacaoRepository.save(transacaoDTO); + public async save(dto: TransacaoDTO): Promise { + return this.transacaoRepository.save(dto); } diff --git a/src/cnab/service/Item-transacao.service.ts b/src/cnab/service/Item-transacao.service.ts deleted file mode 100644 index 3520cffd..00000000 --- a/src/cnab/service/Item-transacao.service.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ItemTransacaoRepository } from '../repository/item-transacao.repository'; -import { ItemTransacao } from './../entity/item-transacao.entity'; -export class ItemTransacaoService { - constructor(private itemTransacaoRepository: ItemTransacaoRepository) {} - - public async getByIdTransacao( - id_transacao: number, - ): Promise { - return await this.itemTransacaoRepository.find(id_transacao); - } -} diff --git a/src/cnab/service/cliente-favorecido.service.ts b/src/cnab/service/cliente-favorecido.service.ts index 78313512..5d9b08c5 100644 --- a/src/cnab/service/cliente-favorecido.service.ts +++ b/src/cnab/service/cliente-favorecido.service.ts @@ -15,7 +15,7 @@ export class ClienteFavorecidoService { constructor( private usersService: UsersService, private clienteFavorecidoRepository: ClienteFavorecidoRepository, - ) {} + ) { } /** * All ClienteFavoecidos will be created or updated from users based of cpfCnpj. @@ -24,7 +24,7 @@ export class ClienteFavorecidoService { public async updateAllFromUsers(): Promise { const allUsers = await this.usersService.findMany({}); for (const user of allUsers) { - const favorecido = await this.clienteFavorecidoRepository.findOne({ + const favorecido = await this.clienteFavorecidoRepository.getOne({ cpf_cnpj: user.getCpfCnpj(), }); await this.saveFavorecidoFromUser( @@ -34,9 +34,9 @@ export class ClienteFavorecidoService { } } - - public async findCpfCnpj(cpf_cnpj:string):Promise { - return await this.clienteFavorecidoRepository.findOne(cpf_cnpj); + + public async getCpfCnpj(cpf_cnpj: string): Promise { + return await this.clienteFavorecidoRepository.getOne({ cpf_cnpj: cpf_cnpj }); } diff --git a/src/cnab/cnab.service.spec.ts b/src/cnab/service/cnab.service.spec.ts similarity index 100% rename from src/cnab/cnab.service.spec.ts rename to src/cnab/service/cnab.service.spec.ts diff --git a/src/cnab/service/cnab.service.ts b/src/cnab/service/cnab.service.ts new file mode 100644 index 00000000..76a27d20 --- /dev/null +++ b/src/cnab/service/cnab.service.ts @@ -0,0 +1,19 @@ +import { Injectable } from '@nestjs/common'; +import { HeaderArquivoService } from './header-arquivo.service'; +import { TransacaoService } from './transacao.service'; + +@Injectable() +export class CnabService { + constructor( + private readonly headerArquivoService: HeaderArquivoService, + private readonly transacaoService: TransacaoService, + ) { } + + public async updateTransacaoFromJae() { + await this.transacaoService.updateTransacaoFromJae() + } + + public async sendNewCNABs() { + await this.headerArquivoService.saveRemessa() + } +} diff --git a/src/cnab/service/detalhe-a.service.ts b/src/cnab/service/detalhe-a.service.ts index f43bed81..08e31f5e 100644 --- a/src/cnab/service/detalhe-a.service.ts +++ b/src/cnab/service/detalhe-a.service.ts @@ -29,7 +29,8 @@ export class DetalheAService { return await this.detalheARepository.findMany(fields); } - private getNextNumeroDocumento(): number { - return 1; + public async getNextNumeroDocumento(dataEfetivacao: Date): Promise { + return await this.detalheARepository.getNextNumeroDocumento(dataEfetivacao); } + } diff --git a/src/cnab/service/header-arquivo.service.ts b/src/cnab/service/header-arquivo.service.ts index 8b2fc131..c8d1ba96 100644 --- a/src/cnab/service/header-arquivo.service.ts +++ b/src/cnab/service/header-arquivo.service.ts @@ -27,13 +27,14 @@ import { } from '../utils/cnab-104-utils'; import { HeaderLoteDTO } from './../dto/header-lote.dto'; import { HeaderArquivo } from './../entity/header-arquivo.entity'; -import { ItemTransacaoService } from './Item-transacao.service'; +import { ItemTransacaoService } from './item-transacao.service'; import { Cnab104Service } from './cnab-104.service'; import { DetalheAService } from './detalhe-a.service'; import { DetalheBService } from './detalhe-b.service'; import { HeaderLoteService } from './header-lote.service'; import { PagadorService } from './pagador.service'; import { TransacaoService } from './transacao.service'; +import { SftpService } from '../sftp/sftp.service'; @Injectable() export class HeaderArquivoService { @@ -51,36 +52,35 @@ export class HeaderArquivoService { private detalheBService: DetalheBService, private cnab104Service: Cnab104Service, private banksService: BanksService, - ) {} + private sftpService: SftpService, + ) { } public async saveRemessa(): Promise { - // gerarCnab() const listAllTransacao = await this.transacaoService.getAll(); for (const transacao of listAllTransacao) { if (!this.headerArquivoExists(transacao.id_transacao)) { - // gerarHeaderArquivoCnab - const headerArquivo = await this.transacaoToHeaderArquivoDTO( - transacao, - 'remessa', - ); - await this.headerArquivoRepository.save(headerArquivo); - // gerarHeaderLoteArquivoCnab - const headerLoteDTO = this.transacaoToHeaderLoteDTO( - transacao, - headerArquivo, - ); - await this.headerLoteService.save(headerLoteDTO); - const listItem = await this.itemTransacaoService.getByIdTransacao( - transacao.id_transacao, - ); - for (const itemTransacao of listItem) { - await this.saveDetalhes(itemTransacao, headerLoteDTO); - } + const { cnabString, cnabTables } = await this.generateCnab(transacao); + await this.performSaveRemessa(cnabTables); + await this.sendCnabSFTP(cnabString); } } } - public async getCnabResult(transacao: Transacao): Promise<{ + private async sendCnabSFTP(cnabString: string) { + await this.sftpService.submitFromString(cnabString, 'arquivo/123-wip-rem.txt'); + } + + private async performSaveRemessa(cnabTables: ICnabTables) { + const headerLote = cnabTables.lotes[0].headerLote; + const detalhes = cnabTables.lotes[0].detalhes; + await this.headerArquivoRepository.save(cnabTables.headerArquivo); + await this.headerLoteService.save(headerLote); + for (const { itemTransacao, registroAB } of detalhes) { + await this.saveDetalhes(itemTransacao, headerLote, registroAB); + } + } + + public async generateCnab(transacao: Transacao): Promise<{ cnabString: string; cnabTables: ICnabTables; }> { @@ -93,10 +93,11 @@ export class HeaderArquivoService { transacao, headerArquivoDTO, ); + const headerArquivo104 = await this.getHeaderArquivo104(headerArquivoDTO); const trailerArquivo104 = structuredClone(trailerArquivoTemplate); - // mount file + // mount file and tables const cnab104: ICnab240_104File = { headerArquivo: headerArquivo104, lotes: [ @@ -119,27 +120,31 @@ export class HeaderArquivoService { }; // mount file details - const listItem = await this.itemTransacaoService.getByIdTransacao( + const listItem = await this.itemTransacaoService.findManyByIdTransacao( transacao.id_transacao, ); for (const itemTransacao of listItem) { - cnabTables.lotes[0].detalhes.push(itemTransacao); cnab104.lotes[0].registros.push( this.getDetalhes104(itemTransacao, headerLoteDTO), ); } // process file - const cnabFile104 = getProcessedCnab104(cnab104); + const processedCnab104 = getProcessedCnab104(cnab104); const cnabString = stringifyCnab104File(cnab104); // update cnabTables this.updateHeaderLoteDTOFrom104( cnabTables.lotes[0].headerLote, - cnabFile104.lotes[0].headerLote, + processedCnab104.lotes[0].headerLote, ); - // for (const itemTransacao of listItem) { - // } + for (let i = 0; i < listItem.length; i++) { + const itemTransacao = listItem[i]; + cnabTables.lotes[0].detalhes.push({ + itemTransacao: itemTransacao, + registroAB: processedCnab104.lotes[0].registros[i] as ICnab240_104RegistroAB, + }); + } return { cnabString: cnabString, @@ -193,6 +198,8 @@ export class HeaderArquivoService { /** * Get Cnab 240 DetalheA, DetalheB for Caixa + * + * indicadorBloqueio = DataFixa (see `detalheATemplate`) */ public getDetalhes104( itemTransacao: ItemTransacao, @@ -202,7 +209,6 @@ export class HeaderArquivoService { detalheA.dataEfetivacao.value = itemTransacao.dt_transacao; detalheA.dataVencimento.value = itemTransacao.dt_processamento; detalheA.loteServico.value = headerLoteDTO.lote_servico; - // (template) indicadorBloqueio = DataFixa detalheA.periodoDiaVencimento.value = itemTransacao.dt_processamento; detalheA.valorLancamento.value = itemTransacao.valor_item_transacao; detalheA.valorRealEfetivado.value = itemTransacao.valor_item_transacao; @@ -231,7 +237,7 @@ export class HeaderArquivoService { tipo_arquivo: string, ): Promise { const dto = new HeaderArquivoDTO(); - const pagador = await this.pagadorService.getOneById(transacao.id_pagador); + const pagador = await this.pagadorService.getOneByIdPagador(transacao.id_pagador); dto.agencia = pagador.agencia; dto.cod_banco = String(headerArquivoTemplate.codigoBanco.value); dto.cod_convenio = String(headerArquivoTemplate.codigoConvenioBanco.value); @@ -279,8 +285,10 @@ export class HeaderArquivoService { headerLoteDTO: HeaderLoteDTO, registroAB: ICnab240_104RegistroAB, ): Promise { + const dataTransacao = new Date(itemTransacao.getDtTransacao()); + const detalheA = new DetalheADTO(); - detalheA.data_efetivacao = itemTransacao.dt_transacao; + detalheA.data_efetivacao = dataTransacao; detalheA.dt_vencimento = itemTransacao.dt_processamento; detalheA.id_header_lote = headerLoteDTO.id_header_lote; detalheA.indicador_bloqueio = String( @@ -291,10 +299,9 @@ export class HeaderArquivoService { detalheATemplate.indicadorFormaParcelamento.value, ); detalheA.lote_servico = headerLoteDTO.lote_servico; - (detalheA.num_doc_lancamento = String( - registroAB.detalheA.numeroDocumento.value, - )), - (detalheA.periodo_vencimento = itemTransacao.dt_processamento); + detalheA.num_doc_lancamento = + await this.detalheAService.getNextNumeroDocumento(dataTransacao); + detalheA.periodo_vencimento = itemTransacao.dt_processamento; detalheA.num_parcela = Number(registroAB.detalheA.numeroParcela.value); detalheA.qtde_parcelas = Number( registroAB.detalheA.quantidadeParcelas.value, @@ -303,13 +310,14 @@ export class HeaderArquivoService { registroAB.detalheA.finalidadeDOC.value, ); detalheA.tipo_moeda = String(registroAB.detalheA.tipoMoeda.value); + detalheA.qtde_moeda = Number(registroAB.detalheA.quantidadeMoeda.value); detalheA.valor_lancamento = itemTransacao.valor_item_transacao; detalheA.valor_real_efetivado = itemTransacao.valor_item_transacao; const saveDetalheA = this.detalheAService.save(detalheA); const detalheB = new DetalheBDTO(); detalheB.data_vencimento = itemTransacao.dt_processamento; - // detalheB.nsr = // this.geraLoteServico(); auto incrementar no banco // pegar da geracao do arquivo e salvar + detalheB.nsr = Number(registroAB.detalheB.nsr.value); detalheB.id_detalhe_a = (await saveDetalheA).id_detalhe_a; await this.detalheBService.save(detalheB); } diff --git a/src/cnab/service/item-transacao.service.ts b/src/cnab/service/item-transacao.service.ts index fea3c6d3..9b0586e3 100644 --- a/src/cnab/service/item-transacao.service.ts +++ b/src/cnab/service/item-transacao.service.ts @@ -1,18 +1,23 @@ -// WIP - -import { Injectable } from '@nestjs/common'; -import { ItemTransacaoRepository } from '../repository/item-transacao.repository'; import { ItemTransacaoDTO } from '../dto/item-transacao.dto'; -import { ItemTransacao } from '../entity/item-transacao.entity'; - +import { ItemTransacaoRepository } from '../repository/item-transacao.repository'; +import { ItemTransacao } from './../entity/item-transacao.entity'; +import { Injectable } from '@nestjs/common'; @Injectable() export class ItemTransacaoService { - constructor( - private itemtransacaoRepository: ItemTransacaoRepository - ) {} - - public async save(itemTransacaoDTO:ItemTransacaoDTO): Promise { - return await this.itemtransacaoRepository.save(itemTransacaoDTO); + constructor(private itemTransacaoRepository: ItemTransacaoRepository) { } + + public async findManyByIdTransacao( + id_transacao: number, + ): Promise { + return await this.itemTransacaoRepository.findMany({ + transacao: { + id_transacao: id_transacao + } + }); + } + + public async save(dto: ItemTransacaoDTO): Promise { + return await this.itemTransacaoRepository.save(dto); } -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/cnab/service/pagador.service.ts b/src/cnab/service/pagador.service.ts index cadc7159..5313e25c 100644 --- a/src/cnab/service/pagador.service.ts +++ b/src/cnab/service/pagador.service.ts @@ -3,7 +3,6 @@ import { CommonHttpException } from 'src/utils/http-exception/common-http-except import { Pagador } from '../entity/pagador.entity'; import { PagadorContaEnum } from '../enums/pagador/pagador.enum'; import { PagadorRepository } from '../repository/pagador.repository'; -import { Nullable } from 'src/utils/types/nullable.type'; @Injectable() export class PagadorService { @@ -29,4 +28,19 @@ export class PagadorService { return pagador; } } + + public async getOneByIdPagador( + id_pagador: number, + ): Promise { + const pagador = await this.pagadorRepository.findOne({ id_pagador: id_pagador }); + if (!pagador) { + throw CommonHttpException.errorDetails( + 'Pagador.conta not found', + { pagadorConta: id_pagador }, + HttpStatus.NOT_FOUND, + ); + } else { + return pagador; + } + } } \ No newline at end of file diff --git a/src/cnab/service/transacao.service.ts b/src/cnab/service/transacao.service.ts index 356ad581..aeed12e7 100644 --- a/src/cnab/service/transacao.service.ts +++ b/src/cnab/service/transacao.service.ts @@ -1,15 +1,15 @@ -import { TransacaoDTO } from './../dto/transacao.dto'; import { Injectable } from '@nestjs/common'; import { BigqueryOrdemPagamento } from 'src/bigquery/entities/ordem-pagamento.bigquery-entity'; import { BigqueryOrdemPagamentoService } from 'src/bigquery/services/bigquery-ordem-pagamento.service'; +import { ItemTransacaoDTO } from '../dto/item-transacao.dto'; +import { Transacao } from '../entity/transacao.entity'; import { PagadorContaEnum } from '../enums/pagador/pagador.enum'; import { TransacaoRepository } from '../repository/transacao.repository'; +import { TransacaoDTO } from './../dto/transacao.dto'; import { ClienteFavorecidoService } from './cliente-favorecido.service'; -import { PagadorService } from './pagador.service'; import { ItemTransacaoService } from './item-transacao.service'; -import { ItemTransacaoDTO } from '../dto/item-transacao.dto'; -import { stringToDate } from 'src/utils/date-utils'; +import { PagadorService } from './pagador.service'; @Injectable() export class TransacaoService { @@ -19,71 +19,72 @@ export class TransacaoService { private clienteFavorecidoService: ClienteFavorecidoService, private pagadorService: PagadorService, private bigqueryOrdemPagamentoService: BigqueryOrdemPagamentoService, - ) {} - public async insereTransacoes() { + ) { } + public async updateTransacaoFromJae() { //Atualiza todos os favorecidos await this.clienteFavorecidoService.updateAllFromUsers(); - + const ordensPagamento = await this.bigqueryOrdemPagamentoService.getCurrentWeek(); const pagador = await this.pagadorService.getOneByConta(PagadorContaEnum.JAE); - let idOrdemAux=""; + let idOrdemAux = ""; - ordensPagamento.forEach(async ordemPagamento => { - let saveTransacaoDTO; - if((ordemPagamento.id_ordem_pagamento as string)!==idOrdemAux){ - const transacaoDTO = await this.ordemPagamentoToTransacao(ordemPagamento, pagador.id_pagador); - saveTransacaoDTO = await this.transacaoRepository.save(transacaoDTO); + for (const ordemPagamento of ordensPagamento) { + if ((ordemPagamento.id_ordem_pagamento as string) !== idOrdemAux) { + const transacaoDTO = this.ordemPagamentoToTransacao(ordemPagamento, pagador.id_pagador); + const saveTransacaoDTO = await this.transacaoRepository.save(transacaoDTO); + const favorecido = await this.clienteFavorecidoService.getCpfCnpj(ordemPagamento.id_operadora as string); + const itemTransacaoDTO = this.ordemPagamentoToItemTransacaoDTO(ordemPagamento, + saveTransacaoDTO.id_transacao, favorecido.id_cliente_favorecido) + await this.itemTransacaoService.save(itemTransacaoDTO); + idOrdemAux = ordemPagamento.id_ordem_pagamento as string; } - const favorecido = await this.clienteFavorecidoService.findCpfCnpj(ordemPagamento.id_operadora as string); - const itemTransacao = await this.ordemPagamentoToItemTransacao(ordemPagamento, - saveTransacaoDTO.id_transacao,favorecido.id_cliente_favorecido) - void this.itemTransacaoService.save(itemTransacao); - idOrdemAux = ordemPagamento.id_ordem_pagamento as string; - }); + } } /** * Para cada BigqueryOrdemPagamento insere em Transacao * @returns `id_transacao` do item criado */ - public async ordemPagamentoToTransacao(ordemPagamento: BigqueryOrdemPagamento,id_pagador: number, - ): Promise { - const transacao = new TransacaoDTO(); - transacao.dt_ordem= ordemPagamento.data_ordem as string, - transacao.dt_pagamento= ordemPagamento.data_pagamento as string, - transacao.nome_consorcio= ordemPagamento.consorcio as string, - transacao.nome_operadora= ordemPagamento.operadora as string, - transacao.servico= ordemPagamento.servico as string, - transacao.id_ordem_ressarcimento= ordemPagamento.id_ordem_ressarcimento as string, - transacao.qtde_transacao_rateio_credito = ordemPagamento.quantidade_transacao_rateio_credito as number, - transacao.vlr_rateio_credito= ordemPagamento.valor_rateio_credito as number, - transacao.qtde_transacao_rateio_debito= ordemPagamento.valor_rateio_debito as number, - transacao.vlr_rateio_debito= ordemPagamento.valor_rateio_debito as number, - transacao.quantidade_total_transacao= ordemPagamento.quantidade_total_transacao as number, - transacao.vlr_total_transacao_bruto= ordemPagamento.valor_total_transacao_bruto as number, - transacao.vlr_desconto_taxa= ordemPagamento.valor_desconto_taxa as number, - transacao.vlr_total_transacao_liquido= ordemPagamento.valor_total_transacao_liquido as number, - transacao.qtde_total_transacao_captura= ordemPagamento.quantidade_total_transacao_captura as number, - transacao.vlr_total_transacao_captura= ordemPagamento.valor_total_transacao_captura as number, - transacao.indicador_ordem_valida= String(ordemPagamento.indicador_ordem_valida) - transacao.id_pagador = id_pagador; - return await transacao; + public ordemPagamentoToTransacao(ordemPagamento: BigqueryOrdemPagamento, id_pagador: number, + ): TransacaoDTO { + const transacao = new TransacaoDTO(); + transacao.dt_ordem = new Date(ordemPagamento.getDataOrdem()); + transacao.dt_pagamento = new Date(ordemPagamento.getDataPagamento()); + transacao.nome_consorcio = ordemPagamento.getConsorcio(); + transacao.nome_operadora = ordemPagamento.getOperadora(); + transacao.servico = ordemPagamento.getServico(); + transacao.id_ordem_ressarcimento = ordemPagamento.getIdOrdemRessarcimento(); + transacao.qtde_transacao_rateio_credito = ordemPagamento.getQuantidadeTransacaoRateioCredito(); + transacao.vlr_rateio_credito = ordemPagamento.getValorRateioCredito(); + transacao.qtde_transacao_rateio_debito = ordemPagamento.getValorRateioDebito(); + transacao.vlr_rateio_debito = ordemPagamento.getValorRateioDebito(); + transacao.quantidade_total_transacao = ordemPagamento.getQuantidadeTotalTransacao(); + transacao.vlr_total_transacao_bruto = ordemPagamento.getValorTotalTransacaoBruto(); + transacao.vlr_desconto_taxa = ordemPagamento.getValorDescontoTaxa(); + transacao.vlr_total_transacao_liquido = ordemPagamento.getValorTotalTransacaoLiquido(); + transacao.qtde_total_transacao_captura = ordemPagamento.getQuantidadeTotalTransacaoCaptura(); + transacao.vlr_total_transacao_captura = ordemPagamento.getValorTotalTransacaoCaptura(); + transacao.indicador_ordem_valida = ordemPagamento.getIndicadorOrdemValida(); + transacao.id_pagador = id_pagador; + return transacao; + } + + public ordemPagamentoToItemTransacaoDTO(ordemPagamento: BigqueryOrdemPagamento, id_transacao: number, + id_cliente_favorecido: number): ItemTransacaoDTO { + const itemTransacao = new ItemTransacaoDTO({ + dt_captura: new Date(ordemPagamento.getDataOrdem()), + dt_processamento: new Date(ordemPagamento.getDataPagamento()), + dt_transacao: new Date(ordemPagamento.getDataPagamento()), + id_cliente_favorecido: id_cliente_favorecido, + id_item_transacao: id_transacao, + modo: 'WIP: incluir coluna "modo" no resultado de BigqueryOrdemPagamento', + }); + return itemTransacao; } - public async ordemPagamentoToItemTransacao(ordemPagamento: BigqueryOrdemPagamento,id_transacao:number, - id_cliente_favorecido: number): Promise { - const itemTransacao = new ItemTransacaoDTO(); - itemTransacao.dt_captura = stringToDate(ordemPagamento.data_ordem as string); - itemTransacao.dt_processamento = stringToDate(ordemPagamento.data_pagamento as string); - itemTransacao.dt_transacao = stringToDate(ordemPagamento.data_pagamento as string); - itemTransacao.id_tipo_pagamento = parseInt(ordemPagamento.id_ordem_pagamento as string); - itemTransacao.id_transacao = id_transacao; - itemTransacao.nome_consorcio = ordemPagamento.consorcio as string; - itemTransacao.tipo_transacao = ordemPagamento.servico as string; - itemTransacao.valor_item_transacao = ordemPagamento.valor_total_transacao_liquido as number; - itemTransacao.id_cliente_favorecido = id_cliente_favorecido; - return await itemTransacao; + public async getAll(): Promise { + return await this.transacaoRepository.getAll(); } } \ No newline at end of file diff --git a/src/cnab/sftp/sftp.service.ts b/src/cnab/sftp/sftp.service.ts index c425f179..a14e8af8 100644 --- a/src/cnab/sftp/sftp.service.ts +++ b/src/cnab/sftp/sftp.service.ts @@ -3,25 +3,42 @@ import { SftpClientService } from 'nest-sftp'; import { ConnectConfig } from 'ssh2'; export class SftpService { - private readonly logger: Logger; - constructor(private readonly sftpClient: SftpClientService) { - this.logger = new Logger(); - } + private readonly logger: Logger; + constructor(private readonly sftpClient: SftpClientService) { + this.logger = new Logger(); + } - async download( - remotePath: string, - localPath: string, - ): Promise { - return await this.sftpClient.download(remotePath, localPath) as unknown as Promise; - } - - // change connection to a different user/password prior to upload - async submit( - remotePath: string, - localPath: string, - submitConfig: ConnectConfig, - ): Promise { - await this.sftpClient.resetConnection(submitConfig); - return await this.sftpClient.upload(remotePath, localPath); + public async download( + remotePath: string, + localPath: string, + ): Promise { + return await this.sftpClient.download(remotePath, localPath) as unknown as Promise; + } + + public async downloadToString(remotePath: string): Promise { + try { + const buffer = await this.sftpClient.download(remotePath); + const content = buffer.toString('utf-8'); + return content; + } catch (error) { + this.logger.error(`Error downloading file from SFTP: ${error.message}`); + throw error; } -} \ No newline at end of file + } + + /** + * Change connection to a different user/password prior to upload + */ + public async submit( + remotePath: string, + localPath: string, + submitConfig: ConnectConfig, + ): Promise { + await this.sftpClient.resetConnection(submitConfig); + return await this.sftpClient.upload(remotePath, localPath); + } + + async submitFromString(content: string, remotePath: string) { + await this.sftpClient.upload(Buffer.from(content, 'utf-8'), remotePath); + } +} diff --git a/src/cron-jobs/cron-jobs.service.ts b/src/cron-jobs/cron-jobs.service.ts index 0b419e68..ed7328c3 100644 --- a/src/cron-jobs/cron-jobs.service.ts +++ b/src/cron-jobs/cron-jobs.service.ts @@ -2,6 +2,7 @@ import { HttpStatus, Injectable, Logger, OnModuleInit } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { SchedulerRegistry } from '@nestjs/schedule'; import { CronJob, CronJobParameters } from 'cron'; +import { CnabService } from 'src/cnab/service/cnab.service'; import { InviteStatus } from 'src/mail-history-statuses/entities/mail-history-status.entity'; import { InviteStatusEnum } from 'src/mail-history-statuses/mail-history-status.enum'; import { MailHistory } from 'src/mail-history/entities/mail-history.entity'; @@ -27,6 +28,8 @@ export enum CrobJobsEnum { sendStatusReport = 'sendStatusReport', pollDb = 'pollDb', bulkResendInvites = 'bulkResendInvites', + updateTransacaoFromJae = 'updateTransacaoFromJae', + sendNewCNABs = 'sendNewCNABs', } interface ICronJob { @@ -53,7 +56,8 @@ export class CronJobsService implements OnModuleInit { private mailService: MailService, private mailHistoryService: MailHistoryService, private usersService: UsersService, - ) {} + private cnabService: CnabService, + ) { } onModuleInit() { const THIS_CLASS_WITH_METHOD = `${CronJobsService.name}.${this.onModuleInit.name}`; @@ -107,6 +111,24 @@ export class CronJobsService implements OnModuleInit { }, }, }, + { + name: CrobJobsEnum.updateTransacaoFromJae, + cronJobParameters: { + cronTime: '45 14 * * *', // 14:45 GMT = 11:45BRT (GMT-3) + onTick: async () => { + await this.bulkResendInvites(); + }, + }, + }, + { + name: CrobJobsEnum.sendNewCNABs, + cronJobParameters: { + cronTime: '45 14 * * *', // 14:45 GMT = 11:45BRT (GMT-3) + onTick: async () => { + await this.sendNewCNABs(); + }, + }, + }, ); for (const jobConfig of this.jobsConfig) { @@ -149,7 +171,7 @@ export class CronJobsService implements OnModuleInit { this.logger.log( formatLog( `Tarefa cancelada pois 'setting.${appSettings.any__activate_auto_send_invite.name}' = 'false'.` + - ` Para ativar, altere na tabela 'setting'`, + ` Para ativar, altere na tabela 'setting'`, THIS_METHOD, ), ); @@ -165,8 +187,8 @@ export class CronJobsService implements OnModuleInit { this.logger.log( formatLog( `Iniciando tarefa - a enviar: ${unsent.length},` + - ` enviado: ${sentToday.length}/${dailyQuota()},` + - ` falta enviar: ${remainingQuota}`, + ` enviado: ${sentToday.length}/${dailyQuota()},` + + ` falta enviar: ${remainingQuota}`, THIS_METHOD, ), ); @@ -326,7 +348,7 @@ export class CronJobsService implements OnModuleInit { this.logger.log( formatLog( `Tarefa cancelada pois 'setting.${appSettings.any__mail_report_enabled.name}' = 'false'.` + - ` Para ativar, altere na tabela 'setting'`, + ` Para ativar, altere na tabela 'setting'`, THIS_METHOD, ), ); @@ -345,7 +367,7 @@ export class CronJobsService implements OnModuleInit { this.logger.log( formatLog( `Tarefa cancelada pois 'setting.${appSettings.any__mail_report_enabled.name}' = 'false'.` + - ` Para ativar, altere na tabela 'setting'`, + ` Para ativar, altere na tabela 'setting'`, THIS_METHOD, ), ); @@ -361,7 +383,7 @@ export class CronJobsService implements OnModuleInit { this.logger.error( formatLog( `Tarefa cancelada pois a configuração 'mail.statusReportRecipients'` + - ` não foi encontrada (retornou: ${mailRecipients}).`, + ` não foi encontrada (retornou: ${mailRecipients}).`, 'sendStatusReport()', ), ); @@ -372,7 +394,7 @@ export class CronJobsService implements OnModuleInit { this.logger.error( formatLog( `Tarefa cancelada pois a configuração 'mail.statusReportRecipients'` + - ` não contém uma lista de emails válidos. Retornou: ${mailRecipients}.`, + ` não contém uma lista de emails válidos. Retornou: ${mailRecipients}.`, THIS_METHOD, ), ); @@ -446,7 +468,7 @@ export class CronJobsService implements OnModuleInit { this.logger.log( formatLog( `Tarefa cancelada pois setting.${appSettings.any__poll_db_enabled.name}' = 'false'` + - ` Para ativar, altere na tabela 'setting'`, + ` Para ativar, altere na tabela 'setting'`, THIS_METHOD, ), ); @@ -503,8 +525,8 @@ export class CronJobsService implements OnModuleInit { this.logger.log( formatLog( `Alteração encontrada em` + - ` setting.'${args.setting.name}': ` + - `${job?.cronJobParameters.cronTime} --> ${setting}.`, + ` setting.'${args.setting.name}': ` + + `${job?.cronJobParameters.cronTime} --> ${setting}.`, thisMethod, ), ); @@ -583,7 +605,7 @@ export class CronJobsService implements OnModuleInit { formatLog( String( 'Enviando emails específicos para ' + - `${notRegisteredUsers.length} usuários não totalmente registrados`, + `${notRegisteredUsers.length} usuários não totalmente registrados`, ), THIS_METHOD, ), @@ -638,4 +660,12 @@ export class CronJobsService implements OnModuleInit { ); } } + + async updateTransacaoFromJae() { + await this.cnabService.updateTransacaoFromJae(); + } + + async sendNewCNABs() { + await this.cnabService.sendNewCNABs(); + } } diff --git a/src/utils/http-exception/common-http-exception.ts b/src/utils/http-exception/common-http-exception.ts index 71211f02..403be4da 100644 --- a/src/utils/http-exception/common-http-exception.ts +++ b/src/utils/http-exception/common-http-exception.ts @@ -16,6 +16,25 @@ export const CommonHttpException = { }, httpStatusCode, ), + invalidField: ( + entity: string, + fieldName: string, + args?: { + errorMessage?: string; + httpStatusCode?: HttpStatus; + }, + ) => + new HttpException( + { + error: { + message: `${entity} tem o campo '${fieldName}' vazio`, + user: { + [fieldName]: args?.errorMessage || 'Campo vazio', + }, + }, + }, + args?.httpStatusCode || HttpStatus.UNPROCESSABLE_ENTITY, + ), errorDetails: ( error: string, details: object, @@ -37,17 +56,17 @@ export const CommonHttpException = { httpStatusCode, ), notFound: ( - notFoundItem: string, + notFoundProp: string, httpStatusCode: HttpStatus = HttpStatus.NOT_FOUND, error?: string, ) => new HttpException( { error: error || getHttpStatusMessage(httpStatusCode), - ...(notFoundItem + ...(notFoundProp ? { details: { - [notFoundItem]: 'not found', + [notFoundProp]: 'not found', }, } : {}),