diff --git a/src/cnab/cnab-remessa.service.ts b/src/cnab/cnab-caixa.service.ts similarity index 71% rename from src/cnab/cnab-remessa.service.ts rename to src/cnab/cnab-caixa.service.ts index 798e5783..e51b4517 100644 --- a/src/cnab/cnab-remessa.service.ts +++ b/src/cnab/cnab-caixa.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@nestjs/common'; import { CnabFile } from './types/cnab-file.type'; -import { getCnabRegistros, stringifyRegistro } from './cnab-utils'; +import { getCnabRegistros, stringifyCnabRegistro } from './utils/cnab-utils'; +import { CNAB_EOL } from './cnab-consts'; @Injectable() export class CnabRemessaService { @@ -11,9 +12,8 @@ export class CnabRemessaService { const plainCnab = getCnabRegistros(cnab); const cnabTextList: string[] = []; for (const registro of plainCnab) { - cnabTextList.push(stringifyRegistro(registro)); + cnabTextList.push(stringifyCnabRegistro(registro)); } - const CNAB_EOL = '\r\n'; return cnabTextList.join(CNAB_EOL); } } diff --git a/src/cnab/cnab-consts.ts b/src/cnab/cnab-consts.ts index 9af87267..f2bfeacb 100644 --- a/src/cnab/cnab-consts.ts +++ b/src/cnab/cnab-consts.ts @@ -1,37 +1,2 @@ -import { cnab240_104DetalheATemplate } from './templates/240/104/cnab-240-104-detalhe-a-template.const'; -import { cnab240_104DetalheBTemplate } from './templates/240/104/cnab-240-104-detalhe-b-template.const'; -import { cnab240_104HeaderArquivoTemplate } from './templates/240/104/cnab-240-104-header-arquivo-template.const'; -import { cnab240_104HeaderLoteTemplate } from './templates/240/104/cnab-240-104-header-lote-template.const'; -import { cnab240_104TrailerArquivoTemplate } from './templates/240/104/cnab-240-104-trailer-arquivo-template.const'; -import { cnab240_104TrailerLoteTemplate } from './templates/240/104/cnab-240-104-trailer-lote-template.const'; - export const CNAB_SUPPORTED_FORMATS = [240]; -export const CNAB_YAML_DIR = './yaml'; -export const CNAB_BANK = { - caixa: { - code: '104', - remessa: { - 240: ['header_arquivo', 'detalhe', 'trailer_arquivo'], - }, - retorno: { - 240: ['header_arquivo', 'detalhe', 'trailer_arquivo'], - }, - }, -}; - -export const CNAB_MODULES = { - caixa: { - remessa: { - 240: { - templates: [ - cnab240_104HeaderArquivoTemplate, - cnab240_104HeaderLoteTemplate, - cnab240_104DetalheATemplate, - cnab240_104DetalheBTemplate, - cnab240_104TrailerLoteTemplate, - cnab240_104TrailerArquivoTemplate, - ], - }, - }, - }, -}; +export const CNAB_EOL = '\r\n'; diff --git a/src/cnab/cnab-utils.ts b/src/cnab/cnab-utils.ts deleted file mode 100644 index d4419483..00000000 --- a/src/cnab/cnab-utils.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { Exception } from 'handlebars'; -import { CNAB_SUPPORTED_FORMATS } from './cnab-consts'; -import { getCnabPictureValue, parseField } from './cnab-field-utils'; -import { CnabField } from './types/cnab-field.type'; -import { CnabFile, isCnabFile } from './types/cnab-file.type'; -import { CnabLote, isCnabLote } from './types/cnab-lote.type'; -import { CnabRegistro } from './types/cnab-registro.type'; - -/** - * Convert CNAB Registro into CNAB file line - */ -export function stringifyRegistro(registro: CnabRegistro) { - let line = ''; - const registros = Object.values(registro.fields); - for (const i in registros) { - const current = registros[i]; - validateRegistroPosition( - current, - registros[Number(i) - 1], - Boolean(registros[Number(i) + 1]), - ); - line += getCnabPictureValue(current); - } - return line; -} - -export function parseRegistro( - cnab: string, - registro: CnabRegistro, - textStart = 0, -): CnabRegistro { - const regEntries = Object.entries(registro.fields); - const newRegistro: CnabRegistro = { fields: {} }; - for (let i = 0; i < regEntries.length; i++) { - const [key, field] = regEntries[i]; - validateRegistroPosition( - field, - regEntries[i - 1][1], - Boolean(regEntries[i + 1][1]), - ); - newRegistro[key] = parseField(cnab, field, textStart); - } - return newRegistro; -} - -/** - * Validates if current item position matches position of previous item. - */ -export function validateRegistroPosition( - current: CnabField, - previous: CnabField | undefined, - hasNext: boolean, -) { - if (!previous && current.pos[0] !== 1) { - throw new Error( - `First CnabField position start should be 1 but is ${current.pos[0]}`, - ); - } - if (!hasNext && !CNAB_SUPPORTED_FORMATS.includes(current.pos[1])) { - throw new Error( - 'Last CnabField position end should be one of these values' + - `${CNAB_SUPPORTED_FORMATS} but is ${current.pos[1]}`, - ); - } else if (previous && current.pos[0] !== previous?.pos[1] + 1) { - throw new Error( - 'Current start and previous end item positions' + - `should be both ${current.pos[0]} but are: previousEnd: ` + - `${previous.pos[1]}, currentStart: ${current.pos[0]}`, - ); - } -} - -export function getCnabRegistros(cnab: CnabFile | CnabLote): CnabRegistro[] { - const plainRegistros: CnabRegistro[] = []; - - if (isCnabLote(cnab)) { - plainRegistros.push(...getCnabRegistrosFromLote(cnab as CnabLote)); - } else if (isCnabFile(cnab)) { - plainRegistros.push(...getCnabRegistrosFromCnabFile(cnab as CnabFile)); - } else { - throw new Exception('Unsupported object type.'); - } - return plainRegistros; -} - -function getCnabRegistrosFromCnabFile(file: CnabFile): CnabRegistro[] { - return [ - file.headerArquivo, - ...file.lotes.reduce((l, i) => [...l, ...getCnabRegistrosFromLote(i)], []), - file.trailerArquivo, - ]; -} - -function getCnabRegistrosFromLote(lote: CnabLote): CnabRegistro[] { - return [lote.headerLote, ...lote.registros, lote.trailerLote]; -} - -export function stringifyCnab(cnab: CnabFile): string { - return getCnabRegistros(cnab) - .reduce((l, i) => [...l, stringifyRegistro(i)], []) - .join('\r\n'); -} - -// export function parseCnab(str: string): CnabFile { - -// } diff --git a/src/cnab/enums/caixa/camara-compensacao-caixa.enum.ts b/src/cnab/enums/104/cnab-104-camara-compensacao.enum.ts similarity index 72% rename from src/cnab/enums/caixa/camara-compensacao-caixa.enum.ts rename to src/cnab/enums/104/cnab-104-camara-compensacao.enum.ts index 0d3569ab..86e5ad9c 100644 --- a/src/cnab/enums/caixa/camara-compensacao-caixa.enum.ts +++ b/src/cnab/enums/104/cnab-104-camara-compensacao.enum.ts @@ -1,4 +1,4 @@ -export enum CamaraCompensacaoCaixa { +export enum Cnab104CamaraCompensacao { Ted = '018', DocEOp = '700', CreditoContaEGuiaDepositoJudiciario = '000', diff --git a/src/cnab/enums/104/cnab-104-codigo-segmento.enum.ts b/src/cnab/enums/104/cnab-104-codigo-segmento.enum.ts new file mode 100644 index 00000000..47de0e26 --- /dev/null +++ b/src/cnab/enums/104/cnab-104-codigo-segmento.enum.ts @@ -0,0 +1,4 @@ +export enum Cnab104CodigoSegmento { + A = 'A', + B = 'B', +} diff --git a/src/cnab/enums/caixa/finalidade-doc-caixa.enum.ts b/src/cnab/enums/104/cnab-104-finalidade-doc.enum.ts similarity index 92% rename from src/cnab/enums/caixa/finalidade-doc-caixa.enum.ts rename to src/cnab/enums/104/cnab-104-finalidade-doc.enum.ts index 99b53304..cb558d20 100644 --- a/src/cnab/enums/caixa/finalidade-doc-caixa.enum.ts +++ b/src/cnab/enums/104/cnab-104-finalidade-doc.enum.ts @@ -1,4 +1,4 @@ -export enum FinalidadDocCaixa { +export enum Cnab104FinalidadeDoc { CreditoConta = '01', PagamentoAluguelCondominio = '02', PagamentoDuplicataTitulos = '03', diff --git a/src/cnab/enums/caixa/finalidade-ted-caixa.enum.ts b/src/cnab/enums/104/cnab-104-finalidade-ted.enum.ts similarity index 63% rename from src/cnab/enums/caixa/finalidade-ted-caixa.enum.ts rename to src/cnab/enums/104/cnab-104-finalidade-ted.enum.ts index 1503b9f5..30d897f9 100644 --- a/src/cnab/enums/caixa/finalidade-ted-caixa.enum.ts +++ b/src/cnab/enums/104/cnab-104-finalidade-ted.enum.ts @@ -1,4 +1,4 @@ -export enum FinalidadeTedCaixa { +export enum Cnab104FinalidadeTed { SemConta = '0', ContaCorrente = '1', Poupanca = '2', diff --git a/src/cnab/enums/caixa/forma-lancamento-caixa.enum.ts b/src/cnab/enums/104/cnab-104-forma-lancamento.enum.ts similarity index 92% rename from src/cnab/enums/caixa/forma-lancamento-caixa.enum.ts rename to src/cnab/enums/104/cnab-104-forma-lancamento.enum.ts index 62638362..b12e980e 100644 --- a/src/cnab/enums/caixa/forma-lancamento-caixa.enum.ts +++ b/src/cnab/enums/104/cnab-104-forma-lancamento.enum.ts @@ -1,4 +1,4 @@ -export enum FormaLancamentoCaixa { +export enum Cnab104FormaLancamento { CreditoContaCorrente = '01', ChequePagamento = '02', DOC = '03', diff --git a/src/cnab/enums/caixa/inficador-parcelamento-caixa.enum.ts b/src/cnab/enums/104/cnab-104-indicador-parcelamento.enum.ts similarity index 56% rename from src/cnab/enums/caixa/inficador-parcelamento-caixa.enum.ts rename to src/cnab/enums/104/cnab-104-indicador-parcelamento.enum.ts index e1dfe957..fab818b8 100644 --- a/src/cnab/enums/caixa/inficador-parcelamento-caixa.enum.ts +++ b/src/cnab/enums/104/cnab-104-indicador-parcelamento.enum.ts @@ -1,4 +1,4 @@ -export enum IndicadorParcelamentoCaixa { +export enum Cnab104IndicadorParcelamento { DataFixa = '1', Periodico = '2', DiaUtil = '3', diff --git a/src/cnab/enums/caixa/tipo-compromisso-caixa.enum.ts b/src/cnab/enums/104/cnab-104-tipo-compromisso.enum.ts similarity index 80% rename from src/cnab/enums/caixa/tipo-compromisso-caixa.enum.ts rename to src/cnab/enums/104/cnab-104-tipo-compromisso.enum.ts index e81e0d87..bb6283bf 100644 --- a/src/cnab/enums/caixa/tipo-compromisso-caixa.enum.ts +++ b/src/cnab/enums/104/cnab-104-tipo-compromisso.enum.ts @@ -1,4 +1,4 @@ -export enum TipoCompromissoCaixa { +export enum Cnab104TipoCompromisso { PagamentoFornecedores = '01', PagamentoSalarios = '02', Autopagamento = '03', diff --git a/src/cnab/enums/caixa/tipo-movimento-caixa.enum.ts b/src/cnab/enums/104/cnab-104-tipo-movimento.enum.ts similarity index 52% rename from src/cnab/enums/caixa/tipo-movimento-caixa.enum.ts rename to src/cnab/enums/104/cnab-104-tipo-movimento.enum.ts index 4b78166a..d6b04f2c 100644 --- a/src/cnab/enums/caixa/tipo-movimento-caixa.enum.ts +++ b/src/cnab/enums/104/cnab-104-tipo-movimento.enum.ts @@ -1,4 +1,4 @@ -export enum TipoMovimentoCaixa { +export enum Cnab104TipoMovimento { Inclusao = '0', Exclusao = '9', } diff --git a/src/cnab/enums/caixa/tipo-servico-caixa.enum.ts b/src/cnab/enums/104/cnab-104-tipo-servico.enum.ts similarity index 92% rename from src/cnab/enums/caixa/tipo-servico-caixa.enum.ts rename to src/cnab/enums/104/cnab-104-tipo-servico.enum.ts index 24032d12..35f28500 100644 --- a/src/cnab/enums/caixa/tipo-servico-caixa.enum.ts +++ b/src/cnab/enums/104/cnab-104-tipo-servico.enum.ts @@ -1,4 +1,4 @@ -export enum TipoServicoCaixa { +export enum Cnab104TipoServico { Optantes = '00', DebitosRecebimento = '05', PagamentoDividendos = '10', diff --git a/src/cnab/enums/caixa/codigo-registro-cnab-caixa.enum.ts b/src/cnab/enums/all/cnab-all-codigo-registro.enum.ts similarity index 60% rename from src/cnab/enums/caixa/codigo-registro-cnab-caixa.enum.ts rename to src/cnab/enums/all/cnab-all-codigo-registro.enum.ts index 4df67660..fda09b5f 100644 --- a/src/cnab/enums/caixa/codigo-registro-cnab-caixa.enum.ts +++ b/src/cnab/enums/all/cnab-all-codigo-registro.enum.ts @@ -1,9 +1,10 @@ -export enum CodigoRegistroCnabCaixa { +export enum CnabAllCodigoRegistro { HeaderArquivo = '0', + HeaderLote = '1', /** Se aplica a todos os segmentos de detalhe. */ DetalheSegmento = '3', TrailerLote = '5', - TailerArquivo = '9', + TrailerArquivo = '9', } diff --git a/src/cnab/interfaces/cnab-240/104/cnab-240-104-detalhe-a.interface.ts b/src/cnab/interfaces/cnab-240/104/cnab-240-104-detalhe-a.interface.ts index 086a6de1..ff7f4f4e 100644 --- a/src/cnab/interfaces/cnab-240/104/cnab-240-104-detalhe-a.interface.ts +++ b/src/cnab/interfaces/cnab-240/104/cnab-240-104-detalhe-a.interface.ts @@ -1,11 +1,17 @@ -import { CnabField } from '../../../types/cnab-field.type'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { + CnabField, + CnabFieldAs, + CnabFields, +} from '../../../types/cnab-field.type'; +import { Cnab104CodigoSegmento } from 'src/cnab/enums/104/cnab-104-codigo-segmento.enum'; -export interface ICnab240_104DetalheA { +export interface ICnab240_104DetalheA extends CnabFields { codigoBanco: CnabField; loteServico: CnabField; - codigoRegistro: CnabField; + codigoRegistro: CnabFieldAs; nsr: CnabField; - codigoSegmento: CnabField; + codigoSegmento: CnabFieldAs; tipoMovimento: CnabField; codigoInstrucaoMovimento: CnabField; camaraCompensacao: CnabField; @@ -34,7 +40,7 @@ export interface ICnab240_104DetalheA { valorRealEfetivado: CnabField; informacao2: CnabField; finalidadeDOC: CnabField; - usoFebraban: CnabField; + usoExclusivoFebraban: CnabField; avisoAoFavorecido: CnabField; /** Status do retorno CNAB */ ocorrencias: CnabField; diff --git a/src/cnab/interfaces/cnab-240/104/cnab-240-104-detalhe-b.interface.ts b/src/cnab/interfaces/cnab-240/104/cnab-240-104-detalhe-b.interface.ts index 83e3d939..383f3596 100644 --- a/src/cnab/interfaces/cnab-240/104/cnab-240-104-detalhe-b.interface.ts +++ b/src/cnab/interfaces/cnab-240/104/cnab-240-104-detalhe-b.interface.ts @@ -1,11 +1,17 @@ -import { CnabField } from '../../../types/cnab-field.type'; +import { CnabAllCodigoRegistro as CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { + CnabField, + CnabFieldAs, + CnabFields, +} from '../../../types/cnab-field.type'; +import { Cnab104CodigoSegmento } from 'src/cnab/enums/104/cnab-104-codigo-segmento.enum'; -export interface ICnab240CaixaDetalheB { +export interface ICnab240_104DetalheB extends CnabFields { codigoBanco: CnabField; loteServico: CnabField; - codigoRegistro: CnabField; + codigoRegistro: CnabFieldAs; nsr: CnabField; - codigoSegmento: CnabField; + codigoSegmento: CnabFieldAs; usoExclusivoFebraban: CnabField; tipoInscricao: CnabField; numeroInscricao: CnabField; diff --git a/src/cnab/interfaces/cnab-240/104/cnab-240-104-file.interface.ts b/src/cnab/interfaces/cnab-240/104/cnab-240-104-file.interface.ts new file mode 100644 index 00000000..c30fbb7b --- /dev/null +++ b/src/cnab/interfaces/cnab-240/104/cnab-240-104-file.interface.ts @@ -0,0 +1,9 @@ +import { ICnab240_104HeaderArquivo } from './cnab-240-104-header-arquivo.interface'; +import { ICnab240_104Lote } from './cnab-240-104-lote.interface'; +import { ICnab240_104TrailerArquivo } from './cnab-240-104-trailer-arquivo.interface'; + +export interface ICnab240_104File { + headerArquivo: ICnab240_104HeaderArquivo; + lotes: ICnab240_104Lote[]; + trailerArquivo: ICnab240_104TrailerArquivo; +} diff --git a/src/cnab/interfaces/cnab-240/104/cnab-240-104-header-arquivo.interface.ts b/src/cnab/interfaces/cnab-240/104/cnab-240-104-header-arquivo.interface.ts index bd9f50d4..62618b44 100644 --- a/src/cnab/interfaces/cnab-240/104/cnab-240-104-header-arquivo.interface.ts +++ b/src/cnab/interfaces/cnab-240/104/cnab-240-104-header-arquivo.interface.ts @@ -1,9 +1,14 @@ -import { CnabField } from '../../../types/cnab-field.type'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { + CnabField, + CnabFieldAs, + CnabFields, +} from '../../../types/cnab-field.type'; -export interface ICnab240CaixaHeaderArquivo { +export interface ICnab240_104HeaderArquivo extends CnabFields { codigoBanco: CnabField; loteServico: CnabField; - codigoRegistro: CnabField; + codigoRegistro: CnabFieldAs; filler: CnabField; tipoInscricao: CnabField; numeroInscricao: CnabField; diff --git a/src/cnab/interfaces/cnab-240/104/cnab-240-104-header-lote.interface.ts b/src/cnab/interfaces/cnab-240/104/cnab-240-104-header-lote.interface.ts index 41c03490..a5dfd259 100644 --- a/src/cnab/interfaces/cnab-240/104/cnab-240-104-header-lote.interface.ts +++ b/src/cnab/interfaces/cnab-240/104/cnab-240-104-header-lote.interface.ts @@ -1,9 +1,14 @@ -import { CnabField } from '../../../types/cnab-field.type'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { + CnabField, + CnabFieldAs, + CnabFields, +} from '../../../types/cnab-field.type'; -export interface ICnab240CaixaHeaderLote { +export interface ICnab240_104HeaderLote extends CnabFields { codigoBanco: CnabField; loteServico: CnabField; - codigoRegistro: CnabField; + codigoRegistro: CnabFieldAs; tipoOperacao: CnabField; tipoServico: CnabField; formaLancamento: CnabField; diff --git a/src/cnab/interfaces/cnab-240/104/cnab-240-104-lote.interface.ts b/src/cnab/interfaces/cnab-240/104/cnab-240-104-lote.interface.ts new file mode 100644 index 00000000..d0942817 --- /dev/null +++ b/src/cnab/interfaces/cnab-240/104/cnab-240-104-lote.interface.ts @@ -0,0 +1,9 @@ +import { ICnab240_104HeaderLote } from './cnab-240-104-header-lote.interface'; +import { ICnab240_104Registro } from './cnab-240-104-registro.interface'; +import { ICnab240_104TrailerLote } from './cnab-240-104-trailer-lote.interface'; + +export interface ICnab240_104Lote { + headerLote: ICnab240_104HeaderLote; + registros: ICnab240_104Registro[]; + trailerLote: ICnab240_104TrailerLote; +} diff --git a/src/cnab/interfaces/cnab-240/104/cnab-240-104-registro-a-b.interface.ts b/src/cnab/interfaces/cnab-240/104/cnab-240-104-registro-a-b.interface.ts new file mode 100644 index 00000000..e2646e68 --- /dev/null +++ b/src/cnab/interfaces/cnab-240/104/cnab-240-104-registro-a-b.interface.ts @@ -0,0 +1,7 @@ +import { ICnab240_104DetalheA } from './cnab-240-104-detalhe-a.interface'; +import { ICnab240_104DetalheB } from './cnab-240-104-detalhe-b.interface'; + +export interface ICnab240_104RegistroAB { + detalheA: ICnab240_104DetalheA; + detalheB: ICnab240_104DetalheB; +} diff --git a/src/cnab/interfaces/cnab-240/104/cnab-240-104-registro.interface.ts b/src/cnab/interfaces/cnab-240/104/cnab-240-104-registro.interface.ts new file mode 100644 index 00000000..99160adc --- /dev/null +++ b/src/cnab/interfaces/cnab-240/104/cnab-240-104-registro.interface.ts @@ -0,0 +1,7 @@ +import { ICnab240_104DetalheA } from './cnab-240-104-detalhe-a.interface'; +import { ICnab240_104DetalheB } from './cnab-240-104-detalhe-b.interface'; + +export interface ICnab240_104Registro { + detalheA?: ICnab240_104DetalheA; + detalheB?: ICnab240_104DetalheB; +} diff --git a/src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-arquivo.interface.ts b/src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-arquivo.interface.ts index 352d887c..49a52682 100644 --- a/src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-arquivo.interface.ts +++ b/src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-arquivo.interface.ts @@ -1,9 +1,14 @@ -import { CnabField } from '../../../types/cnab-field.type'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { + CnabField, + CnabFieldAs, + CnabFields, +} from '../../../types/cnab-field.type'; -export interface ICnab240CaixaTrailerArquivo { +export interface ICnab240_104TrailerArquivo extends CnabFields { codigoBanco: CnabField; loteServico: CnabField; - codigoRegistro: CnabField; + codigoRegistro: CnabFieldAs; usoExclusivoFebraban: CnabField; quantidadeLotesArquivo: CnabField; quantidadeRegistrosArquivo: CnabField; diff --git a/src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-lote.interface.ts b/src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-lote.interface.ts index 2b1ab6c2..9ff63ab0 100644 --- a/src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-lote.interface.ts +++ b/src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-lote.interface.ts @@ -1,10 +1,15 @@ -import { CnabField } from '../../../types/cnab-field.type'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { + CnabField, + CnabFieldAs, + CnabFields, +} from '../../../types/cnab-field.type'; -export interface ICnab240CaixaTrailerLote { +export interface ICnab240_104TrailerLote extends CnabFields { codigoBanco: CnabField; /** O mesmo valor que o `HeaderLote.loteServico` deste lote. */ loteServico: CnabField; - codigoRegistro: CnabField; + codigoRegistro: CnabFieldAs; usoExclusivoFebraban: CnabField; quantidadeRegistrosLote: CnabField; /** Soma de todos os valores: detalhe A, I, O, N */ diff --git a/src/cnab/interfaces/cnab-detalhe-base.interface.ts b/src/cnab/interfaces/cnab-detalhe-base.interface.ts deleted file mode 100644 index ed38a479..00000000 --- a/src/cnab/interfaces/cnab-detalhe-base.interface.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { CnabField } from '../types/cnab-field.type'; -import { ICnabRegistroBase } from './cnab-registro-base.interface'; - -export interface ICnabDetalheBase extends ICnabRegistroBase { - nsr: CnabField; - codigoSegmento: CnabField; -} diff --git a/src/cnab/interfaces/cnab-field-map-detalhe.interface.ts b/src/cnab/interfaces/cnab-field-map-detalhe.interface.ts new file mode 100644 index 00000000..790ff888 --- /dev/null +++ b/src/cnab/interfaces/cnab-field-map-detalhe.interface.ts @@ -0,0 +1,6 @@ +import { ICnabFieldMap } from './cnab-field-map.interface'; + +export interface ICnabFieldMapDetalhe extends ICnabFieldMap { + detalheLoteRegistroSequenceField: string; + detalheSegmentoField: string; +} diff --git a/src/cnab/interfaces/cnab-field-map-trailer-arquivo.interface.ts b/src/cnab/interfaces/cnab-field-map-trailer-arquivo.interface.ts new file mode 100644 index 00000000..0886d230 --- /dev/null +++ b/src/cnab/interfaces/cnab-field-map-trailer-arquivo.interface.ts @@ -0,0 +1,6 @@ +import { ICnabFieldMap } from './cnab-field-map.interface'; + +export interface ICnabFieldMapTrailerArquivo extends ICnabFieldMap { + trailerArquivoLoteCountField: string; + trailerArquivoRegistroCountField: string; +} diff --git a/src/cnab/interfaces/cnab-field-map-trailer-lote.interface.ts b/src/cnab/interfaces/cnab-field-map-trailer-lote.interface.ts new file mode 100644 index 00000000..018cd4ab --- /dev/null +++ b/src/cnab/interfaces/cnab-field-map-trailer-lote.interface.ts @@ -0,0 +1,5 @@ +import { ICnabFieldMap } from './cnab-field-map.interface'; + +export interface ICnabFieldMapTrailerLote extends ICnabFieldMap { + trailerLoteRegistroCountField: string; +} diff --git a/src/cnab/interfaces/cnab-field-map.interface.ts b/src/cnab/interfaces/cnab-field-map.interface.ts new file mode 100644 index 00000000..218e2489 --- /dev/null +++ b/src/cnab/interfaces/cnab-field-map.interface.ts @@ -0,0 +1,75 @@ +export interface ICnabFieldMap { + // ALL REGISTROS + + /** + * For all Registros + * + * Represents"LoteServico" or similar fields. + * + * Each **Lote** has one unique combination of `tipoCompromisso` and `formaLancamento`. + * + * - **For Header Arquivo:** value is 0000. + * - **For Header/Trailer Lote and Detalhes:** Count current Lote. Example: (1, 2, 3). + * - **For Trailer Arquivo:** value is 9999. + * + * @example "1", "2", "3" + */ + registroLoteSequenceField: string; + + /** + * For all Registros + * + * Represents "CodigoRegistro" field or similar. + * + * @example "0", "1", "3", "5", "9" + * + */ + registroIdField: string; + + // FOR TRAILER LOTE + + /** + * For Trailer Lote + * + * Represents the count of all Registro in Lote + */ + trailerLoteRegistroCountField?: string; + + // FOR REGISTO DETALHE + + /** + * For Segmento Detalhe Registros + * + * Represents NSR (_NĂºmero Sequencial de Registro, no Lote_) + * + * For each Lote, count starting from 1 for each Registro + * + * @example "1", "2", "3" + */ + detalheLoteRegistroSequenceField?: string; + + /** + * For Segmento Detalhe Registros + * + * Represents Detalhe's unique code + * + * @example "A", "B", "J" + */ + detalheSegmentoField?: string; + + // TRAILER ARQUIVO FIELDS + + /** + * For Trailer Arquivo + * + * Represents the count of lote in CnabFile (Registro type = 1) + */ + trailerArquivoLoteCountField?: string; + + /** + * For Trailer Arquivo + * + * Represents the count of all Registro in file (types 1, 3, 5 or 9) + */ + trailerArquivoRegistroCountField?: string; +} diff --git a/src/cnab/interfaces/cnab-registro-base.interface.ts b/src/cnab/interfaces/cnab-registro-base.interface.ts deleted file mode 100644 index 2b1f4aa4..00000000 --- a/src/cnab/interfaces/cnab-registro-base.interface.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { CnabField } from '../types/cnab-field.type'; - -export interface ICnabRegistroBase { - loteServico: CnabField; - codigoRegistro: CnabField; -} diff --git a/src/cnab/interfaces/cnab-registro-field-map.interface.ts b/src/cnab/interfaces/cnab-registro-field-map.interface.ts deleted file mode 100644 index 7b0b2d08..00000000 --- a/src/cnab/interfaces/cnab-registro-field-map.interface.ts +++ /dev/null @@ -1,35 +0,0 @@ -export interface ICnabRegistroFieldMap { - // REGISTRO FIELDS - - /** - * Represents"LoteServico" or similar fields. - * - * Each **Lote** has one unique combination of `tipoCompromisso` and `formaLancamento`. - * - * Also represents the amount of Lotes field in Trailer - */ - registroLoteField: string; - - /** - * Represents "CodigoRegistro" field or similar. - * - * Also represents the amount of Lotes field in Trailer - * - * @example "1", "3", "5" - * - */ - registroCodigoField: string; - - // SOME DETAILS AND TRAILER_ARQUIVO FIELDS - - /** Represents individual or sum of unique recipient bank accounts */ - registroRecipientAccountField?: string; - - // DETALHES FIELDS - - /** For each Lote, count starting from 1 for each Registro */ - detalheNsrField?: string; - - /** @example "A", "B", "J" */ - detalhesSegmentoField?: string; -} diff --git a/src/cnab/templates/240/104/cnab-240-104-detalhe-a-template.const.ts b/src/cnab/templates/cnab-240/104/cnab-240-104-detalhe-a-template.const.ts similarity index 84% rename from src/cnab/templates/240/104/cnab-240-104-detalhe-a-template.const.ts rename to src/cnab/templates/cnab-240/104/cnab-240-104-detalhe-a-template.const.ts index e5e19952..2ed628c8 100644 --- a/src/cnab/templates/240/104/cnab-240-104-detalhe-a-template.const.ts +++ b/src/cnab/templates/cnab-240/104/cnab-240-104-detalhe-a-template.const.ts @@ -1,11 +1,21 @@ +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; import { ICnab240_104DetalheA } from '../../../interfaces/cnab-240/104/cnab-240-104-detalhe-a.interface'; +import { Cnab104CodigoSegmento } from 'src/cnab/enums/104/cnab-104-codigo-segmento.enum'; export const cnab240_104DetalheATemplate: ICnab240_104DetalheA = { codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, loteServico: { pos: [4, 7], picture: '9(004)', value: '0000' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '3' }, + codigoRegistro: { + pos: [8, 8], + picture: '9(001)', + value: CnabAllCodigoRegistro.DetalheSegmento, + }, nsr: { pos: [9, 13], picture: '9(005)', value: ' ' }, - codigoSegmento: { pos: [14, 14], picture: 'X(001)', value: 'A' }, + codigoSegmento: { + pos: [14, 14], + picture: 'X(001)', + value: Cnab104CodigoSegmento.A, + }, tipoMovimento: { pos: [15, 15], picture: '9(001)', value: '0' }, codigoInstrucaoMovimento: { pos: [16, 17], picture: '9(002)', value: '00' }, camaraCompensacao: { pos: [18, 20], picture: '9(003)', value: '000' }, @@ -66,7 +76,11 @@ export const cnab240_104DetalheATemplate: ICnab240_104DetalheA = { value: ' ', }, finalidadeDOC: { pos: [218, 219], picture: '9(002)', value: '00' }, - usoFebraban: { pos: [220, 229], picture: 'X(010)', value: ' ' }, + usoExclusivoFebraban: { + pos: [220, 229], + picture: 'X(010)', + value: ' ', + }, avisoAoFavorecido: { pos: [230, 230], picture: '9(001)', value: '0' }, ocorrencias: { pos: [231, 240], picture: 'X(010)', value: ' ' }, }; diff --git a/src/cnab/templates/240/104/cnab-240-104-detalhe-b-template.const.ts b/src/cnab/templates/cnab-240/104/cnab-240-104-detalhe-b-template.const.ts similarity index 76% rename from src/cnab/templates/240/104/cnab-240-104-detalhe-b-template.const.ts rename to src/cnab/templates/cnab-240/104/cnab-240-104-detalhe-b-template.const.ts index 0ee5df10..ba590a0f 100644 --- a/src/cnab/templates/240/104/cnab-240-104-detalhe-b-template.const.ts +++ b/src/cnab/templates/cnab-240/104/cnab-240-104-detalhe-b-template.const.ts @@ -1,11 +1,21 @@ -import { ICnab240CaixaDetalheB } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-detalhe-b.interface'; +import { Cnab104CodigoSegmento } from 'src/cnab/enums/104/cnab-104-codigo-segmento.enum'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { ICnab240_104DetalheB } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-detalhe-b.interface'; -export const cnab240_104DetalheBTemplate: ICnab240CaixaDetalheB = { +export const cnab240_104DetalheBTemplate: ICnab240_104DetalheB = { codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, loteServico: { pos: [4, 7], picture: '9(004)', value: '0000' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '0' }, + codigoRegistro: { + pos: [8, 8], + picture: '9(001)', + value: CnabAllCodigoRegistro.DetalheSegmento, + }, nsr: { pos: [9, 13], picture: '9(005)', value: '00000' }, - codigoSegmento: { pos: [14, 14], picture: 'X(001)', value: ' ' }, + codigoSegmento: { + pos: [14, 14], + picture: 'X(001)', + value: Cnab104CodigoSegmento.B, + }, usoExclusivoFebraban: { pos: [15, 17], picture: 'X(003)', value: ' ' }, tipoInscricao: { pos: [18, 18], picture: '9(001)', value: '0' }, numeroInscricao: { diff --git a/src/cnab/templates/240/104/cnab-240-104-header-arquivo-template.const.ts b/src/cnab/templates/cnab-240/104/cnab-240-104-header-arquivo-template.const.ts similarity index 90% rename from src/cnab/templates/240/104/cnab-240-104-header-arquivo-template.const.ts rename to src/cnab/templates/cnab-240/104/cnab-240-104-header-arquivo-template.const.ts index f562a0cf..bcdea98f 100644 --- a/src/cnab/templates/240/104/cnab-240-104-header-arquivo-template.const.ts +++ b/src/cnab/templates/cnab-240/104/cnab-240-104-header-arquivo-template.const.ts @@ -1,6 +1,7 @@ -import { ICnab240CaixaHeaderArquivo } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-header-arquivo.interface'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { ICnab240_104HeaderArquivo } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-header-arquivo.interface'; -export const cnab240_104HeaderArquivoTemplate: ICnab240CaixaHeaderArquivo = { +export const cnab240_104HeaderArquivoTemplate: ICnab240_104HeaderArquivo = { codigoBanco: { pos: [1, 3], picture: '9(003)', @@ -14,7 +15,7 @@ export const cnab240_104HeaderArquivoTemplate: ICnab240CaixaHeaderArquivo = { codigoRegistro: { pos: [8, 8], picture: '9(001)', - value: '0', + value: CnabAllCodigoRegistro.HeaderArquivo, }, filler: { pos: [9, 17], diff --git a/src/cnab/templates/240/104/cnab-240-104-header-lote-template.const.ts b/src/cnab/templates/cnab-240/104/cnab-240-104-header-lote-template.const.ts similarity index 86% rename from src/cnab/templates/240/104/cnab-240-104-header-lote-template.const.ts rename to src/cnab/templates/cnab-240/104/cnab-240-104-header-lote-template.const.ts index 1508f13b..a4d7deb6 100644 --- a/src/cnab/templates/240/104/cnab-240-104-header-lote-template.const.ts +++ b/src/cnab/templates/cnab-240/104/cnab-240-104-header-lote-template.const.ts @@ -1,9 +1,14 @@ -import { ICnab240CaixaHeaderLote } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-header-lote.interface'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { ICnab240_104HeaderLote } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-header-lote.interface'; -export const cnab240_104HeaderLoteTemplate: ICnab240CaixaHeaderLote = { +export const cnab240_104HeaderLoteTemplate: ICnab240_104HeaderLote = { codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, loteServico: { pos: [4, 7], picture: '9(004)', value: '0001' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '1' }, + codigoRegistro: { + pos: [8, 8], + picture: '9(001)', + value: CnabAllCodigoRegistro.HeaderLote, + }, tipoOperacao: { pos: [9, 9], picture: 'X(001)', value: ' ' }, tipoServico: { pos: [10, 11], picture: '9(002)', value: '00' }, formaLancamento: { pos: [12, 13], picture: '9(002)', value: '00' }, diff --git a/src/cnab/templates/240/104/cnab-240-104-trailer-arquivo-template.const.ts b/src/cnab/templates/cnab-240/104/cnab-240-104-trailer-arquivo-template.const.ts similarity index 59% rename from src/cnab/templates/240/104/cnab-240-104-trailer-arquivo-template.const.ts rename to src/cnab/templates/cnab-240/104/cnab-240-104-trailer-arquivo-template.const.ts index dd776b13..587ca33c 100644 --- a/src/cnab/templates/240/104/cnab-240-104-trailer-arquivo-template.const.ts +++ b/src/cnab/templates/cnab-240/104/cnab-240-104-trailer-arquivo-template.const.ts @@ -1,9 +1,14 @@ -import { ICnab240CaixaTrailerArquivo } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-arquivo.interface'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { ICnab240_104TrailerArquivo } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-arquivo.interface'; -export const cnab240_104TrailerArquivoTemplate: ICnab240CaixaTrailerArquivo = { +export const cnab240_104TrailerArquivoTemplate: ICnab240_104TrailerArquivo = { codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, loteServico: { pos: [4, 7], picture: '9(004)', value: '9999' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '9' }, + codigoRegistro: { + pos: [8, 8], + picture: '9(001)', + value: CnabAllCodigoRegistro.TrailerArquivo, + }, usoExclusivoFebraban: { pos: [9, 17], picture: 'X(009)', value: ' ' }, quantidadeLotesArquivo: { pos: [18, 23], picture: '9(006)', value: '000000' }, quantidadeRegistrosArquivo: { diff --git a/src/cnab/templates/240/104/cnab-240-104-trailer-lote-template.const.ts b/src/cnab/templates/cnab-240/104/cnab-240-104-trailer-lote-template.const.ts similarity index 66% rename from src/cnab/templates/240/104/cnab-240-104-trailer-lote-template.const.ts rename to src/cnab/templates/cnab-240/104/cnab-240-104-trailer-lote-template.const.ts index 922870a5..0e278bab 100644 --- a/src/cnab/templates/240/104/cnab-240-104-trailer-lote-template.const.ts +++ b/src/cnab/templates/cnab-240/104/cnab-240-104-trailer-lote-template.const.ts @@ -1,9 +1,14 @@ -import { ICnab240CaixaTrailerLote } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-lote.interface'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { ICnab240_104TrailerLote } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-lote.interface'; -export const cnab240_104TrailerLoteTemplate: ICnab240CaixaTrailerLote = { +export const cnab240_104TrailerLoteTemplate: ICnab240_104TrailerLote = { codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, loteServico: { pos: [4, 7], picture: '9(004)', value: '0000' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '5' }, + codigoRegistro: { + pos: [8, 8], + picture: '9(001)', + value: CnabAllCodigoRegistro.TrailerLote, + }, usoExclusivoFebraban: { pos: [9, 17], picture: 'X(009)', value: ' ' }, quantidadeRegistrosLote: { pos: [18, 23], diff --git a/src/cnab/templates/cnab-all/cnab-all-104-registro-field-map-template.ts b/src/cnab/templates/cnab-all/cnab-all-104-registro-field-map-template.ts new file mode 100644 index 00000000..fbbd9671 --- /dev/null +++ b/src/cnab/templates/cnab-all/cnab-all-104-registro-field-map-template.ts @@ -0,0 +1,34 @@ +import { ICnabFieldMapDetalhe } from 'src/cnab/interfaces/cnab-field-map-detalhe.interface'; +import { ICnabFieldMapTrailerArquivo } from 'src/cnab/interfaces/cnab-field-map-trailer-arquivo.interface'; +import { ICnabFieldMapTrailerLote } from 'src/cnab/interfaces/cnab-field-map-trailer-lote.interface'; +import { ICnabFieldMap } from 'src/cnab/interfaces/cnab-field-map.interface'; + +const registro: ICnabFieldMap = { + registroIdField: 'codigoRegistro', + registroLoteSequenceField: 'loteServico', +}; + +const trailerArquivo: ICnabFieldMapTrailerArquivo = { + ...registro, + trailerArquivoLoteCountField: 'quantidadeLotesArquivo', + trailerArquivoRegistroCountField: 'quantidadeRegistrosArquivo', +}; + +const trailerLote: ICnabFieldMapTrailerLote = { + ...registro, + trailerLoteRegistroCountField: 'quantidadeRegistrosLote', +}; + +const detalheLote: ICnabFieldMapDetalhe = { + ...registro, + detalheLoteRegistroSequenceField: 'nsr', + detalheSegmentoField: 'codigoSegmento', +}; + +export const cnabAll104FieldMapTemplate = { + headerArquivo: registro, + headerLote: registro, + detalheLote: detalheLote, + trailerLote: trailerLote, + trailerArquivo: trailerArquivo, +}; diff --git a/src/cnab/test/templates/240/104/cnab-240-104-detalhe-a-template-test.const.ts b/src/cnab/test/templates/240/104/cnab-240-104-detalhe-a-template-test.const.ts index 3b83c656..5a278308 100644 --- a/src/cnab/test/templates/240/104/cnab-240-104-detalhe-a-template-test.const.ts +++ b/src/cnab/test/templates/240/104/cnab-240-104-detalhe-a-template-test.const.ts @@ -1,11 +1,21 @@ +import { Cnab104CodigoSegmento } from 'src/cnab/enums/104/cnab-104-codigo-segmento.enum'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; import { ICnab240_104DetalheA } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-detalhe-a.interface'; export const cnab240_104DetalheATemplateTest: ICnab240_104DetalheA = { codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, loteServico: { pos: [4, 7], picture: '9(004)', value: '0001' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '3' }, + codigoRegistro: { + pos: [8, 8], + picture: '9(001)', + value: CnabAllCodigoRegistro.DetalheSegmento, + }, nsr: { pos: [9, 13], picture: '9(005)', value: '00001' }, - codigoSegmento: { pos: [14, 14], picture: 'X(001)', value: 'A' }, + codigoSegmento: { + pos: [14, 14], + picture: 'X(001)', + value: Cnab104CodigoSegmento.A, + }, tipoMovimento: { pos: [15, 15], picture: '9(001)', value: '0' }, codigoInstrucaoMovimento: { pos: [16, 17], picture: '9(002)', value: '00' }, camaraCompensacao: { pos: [18, 20], picture: '9(003)', value: '000' }, @@ -31,7 +41,7 @@ export const cnab240_104DetalheATemplateTest: ICnab240_104DetalheA = { pos: [94, 101], picture: '9(008)', value: '05022023', - dateFormat: 'ddMMyyyy', + dateFormat: { input: 'ddMMyyyy', output: 'ddMMyyyy' }, }, tipoMoeda: { pos: [102, 104], picture: 'X(003)', value: 'BRL' }, quantidadeMoeda: { @@ -42,7 +52,7 @@ export const cnab240_104DetalheATemplateTest: ICnab240_104DetalheA = { valorLancamento: { pos: [120, 134], picture: '9(013)V99', - value: '000000001347272', + value: 1200.12, }, numeroDocumentoBanco: { pos: [135, 143], @@ -71,7 +81,11 @@ export const cnab240_104DetalheATemplateTest: ICnab240_104DetalheA = { value: ' ', }, finalidadeDOC: { pos: [218, 219], picture: '9(002)', value: '01' }, - usoFebraban: { pos: [220, 229], picture: 'X(010)', value: ' ' }, + usoExclusivoFebraban: { + pos: [220, 229], + picture: 'X(010)', + value: ' ', + }, avisoAoFavorecido: { pos: [230, 230], picture: '9(001)', value: '0' }, ocorrencias: { pos: [231, 240], picture: 'X(010)', value: ' ' }, }; diff --git a/src/cnab/test/templates/240/104/cnab-240-104-detalhe-b-template-test.const.ts b/src/cnab/test/templates/240/104/cnab-240-104-detalhe-b-template-test.const.ts index c13c2662..a93aca00 100644 --- a/src/cnab/test/templates/240/104/cnab-240-104-detalhe-b-template-test.const.ts +++ b/src/cnab/test/templates/240/104/cnab-240-104-detalhe-b-template-test.const.ts @@ -1,11 +1,21 @@ -import { ICnab240CaixaDetalheB } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-detalhe-b.interface'; +import { Cnab104CodigoSegmento } from 'src/cnab/enums/104/cnab-104-codigo-segmento.enum'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { ICnab240_104DetalheB } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-detalhe-b.interface'; -export const cnab240_104DetalheBTemplateTest: ICnab240CaixaDetalheB = { +export const cnab240_104DetalheBTemplateTest: ICnab240_104DetalheB = { codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, loteServico: { pos: [4, 7], picture: '9(004)', value: '0001' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '3' }, + codigoRegistro: { + pos: [8, 8], + picture: '9(001)', + value: CnabAllCodigoRegistro.DetalheSegmento, + }, nsr: { pos: [9, 13], picture: '9(005)', value: '00002' }, - codigoSegmento: { pos: [14, 14], picture: 'X(001)', value: 'B' }, + codigoSegmento: { + pos: [14, 14], + picture: 'X(001)', + value: Cnab104CodigoSegmento.B, + }, usoExclusivoFebraban: { pos: [15, 17], picture: 'X(003)', value: ' ' }, tipoInscricao: { pos: [18, 18], picture: '9(001)', value: ' ' }, numeroInscricao: { @@ -29,12 +39,12 @@ export const cnab240_104DetalheBTemplateTest: ICnab240CaixaDetalheB = { pos: [128, 135], picture: '9(008)', value: '06022023', - dateFormat: 'ddMMyyyy', + dateFormat: { input: 'ddMMyyyy', output: 'ddMMyyyy' }, }, valorDocumento: { pos: [136, 150], picture: '9(013)V99', - value: '000000001347272', + value: 1200.12, }, valorAbatimento: { pos: [151, 165], diff --git a/src/cnab/test/templates/240/104/cnab-240-104-header-arquivo-template-test.const.ts b/src/cnab/test/templates/240/104/cnab-240-104-header-arquivo-template-test.const.ts index 8b8d1bc7..464681f6 100644 --- a/src/cnab/test/templates/240/104/cnab-240-104-header-arquivo-template-test.const.ts +++ b/src/cnab/test/templates/240/104/cnab-240-104-header-arquivo-template-test.const.ts @@ -1,175 +1,175 @@ -import { ICnab240CaixaHeaderArquivo } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-header-arquivo.interface'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { ICnab240_104HeaderArquivo } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-header-arquivo.interface'; -export const cnab240_104HeaderArquivoTemplateTest: ICnab240CaixaHeaderArquivo = - { - codigoBanco: { - pos: [1, 3], - picture: '9(003)', - value: '104', - }, - loteServico: { - pos: [4, 7], - picture: '9(004)', - value: '0090', - }, - codigoRegistro: { - pos: [8, 8], - picture: '9(001)', - value: '0', - }, - filler: { - pos: [9, 17], - picture: 'X(009)', - value: ' ', - }, - tipoInscricao: { - pos: [18, 18], - picture: '9(001)', - value: '2', - }, - numeroInscricao: { - pos: [19, 32], - picture: '9(014)', - value: '00012345600111', - }, - codigoConvenioBanco: { - pos: [33, 38], - picture: '9(006)', - value: '112007', - }, - parametroTransmissao: { - pos: [39, 40], - picture: '9(002)', - value: '09', - }, - ambienteCliente: { - pos: [41, 41], - picture: 'X(001)', - value: 'P', - }, - ambienteCaixa: { - pos: [42, 42], - picture: 'X(001)', - value: ' ', - }, - origemAplicativo: { - pos: [43, 45], - picture: 'X(003)', - value: ' ', - }, - numeroVersao: { - pos: [46, 49], - picture: '9(004)', - value: '0000', - }, - filler2: { - pos: [50, 52], - picture: 'X(003)', - value: ' ', - }, - agenciaContaCorrente: { - pos: [53, 57], - picture: '9(005)', - value: '00955', - }, - dvAgencia: { - pos: [58, 58], - picture: '9(001)', - value: '5', - }, - numeroConta: { - pos: [59, 70], - picture: 'X(012)', - value: '000000000003', - }, - dvConta: { - pos: [71, 71], - picture: 'X(001)', - value: '2', - }, - dvAgenciaConta: { - pos: [72, 72], - picture: 'X(001)', - value: ' ', - }, - nomeEmpresa: { - pos: [73, 102], - picture: 'X(030)', - value: 'CONVE DE PAGAMENTOSSA E OEBSA', - }, - nomeBanco: { - pos: [103, 132], - picture: 'X(030)', - value: 'CAIXA ', - }, - filler3: { - pos: [133, 142], - picture: 'X(010)', - value: ' ', - }, - tipoArquivo: { - pos: [143, 143], - picture: '9(001)', - value: ' 2', - }, - dataGeracaoArquivo: { - pos: [144, 151], - picture: '9(008)', - value: '06022027', - }, - horaGeracaoArquivo: { - pos: [152, 157], - picture: '9(006)', - value: '102342', - }, - nsa: { - pos: [158, 163], - picture: '9(006)', - value: '000101', - }, - versaoLeiauteArquivo: { - pos: [164, 166], - picture: '9(003)', - value: '000', - }, - densidadeGravacao: { - pos: [167, 171], - picture: '9(005)', - value: '01600', - }, - reservadoBanco: { - pos: [172, 191], - picture: 'X(020)', - value: ' ', - }, - reservadoEmpresa: { - pos: [192, 211], - picture: 'X(020)', - value: ' ', - }, - usoExclusivoFebraban: { - pos: [212, 222], - picture: 'X(011)', - value: ' ', - }, - identidadeCobranca: { - pos: [223, 225], - picture: 'X(003)', - value: ' ', - }, - usoExclusivoVan: { - pos: [226, 228], - picture: '9(003)', - value: '000', - }, - tipoServico: { - pos: [229, 230], - picture: 'X(002)', - value: ' ', - }, - ocorrenciaCobrancaSemPapel: { - pos: [231, 240], - picture: 'X(010)', - value: ' ', - }, - }; +export const cnab240_104HeaderArquivoTemplateTest: ICnab240_104HeaderArquivo = { + codigoBanco: { + pos: [1, 3], + picture: '9(003)', + value: '104', + }, + loteServico: { + pos: [4, 7], + picture: '9(004)', + value: '0090', + }, + codigoRegistro: { + pos: [8, 8], + picture: '9(001)', + value: CnabAllCodigoRegistro.HeaderArquivo, + }, + filler: { + pos: [9, 17], + picture: 'X(009)', + value: ' ', + }, + tipoInscricao: { + pos: [18, 18], + picture: '9(001)', + value: '2', + }, + numeroInscricao: { + pos: [19, 32], + picture: '9(014)', + value: '00012345600111', + }, + codigoConvenioBanco: { + pos: [33, 38], + picture: '9(006)', + value: '112007', + }, + parametroTransmissao: { + pos: [39, 40], + picture: '9(002)', + value: '09', + }, + ambienteCliente: { + pos: [41, 41], + picture: 'X(001)', + value: 'P', + }, + ambienteCaixa: { + pos: [42, 42], + picture: 'X(001)', + value: ' ', + }, + origemAplicativo: { + pos: [43, 45], + picture: 'X(003)', + value: ' ', + }, + numeroVersao: { + pos: [46, 49], + picture: '9(004)', + value: '0000', + }, + filler2: { + pos: [50, 52], + picture: 'X(003)', + value: ' ', + }, + agenciaContaCorrente: { + pos: [53, 57], + picture: '9(005)', + value: '00955', + }, + dvAgencia: { + pos: [58, 58], + picture: '9(001)', + value: '5', + }, + numeroConta: { + pos: [59, 70], + picture: 'X(012)', + value: '000000000003', + }, + dvConta: { + pos: [71, 71], + picture: 'X(001)', + value: '2', + }, + dvAgenciaConta: { + pos: [72, 72], + picture: 'X(001)', + value: ' ', + }, + nomeEmpresa: { + pos: [73, 102], + picture: 'X(030)', + value: 'CONVE DE PAGAMENTOSSA E OEBSA', + }, + nomeBanco: { + pos: [103, 132], + picture: 'X(030)', + value: 'CAIXA ', + }, + filler3: { + pos: [133, 142], + picture: 'X(010)', + value: ' ', + }, + tipoArquivo: { + pos: [143, 143], + picture: '9(001)', + value: ' 2', + }, + dataGeracaoArquivo: { + pos: [144, 151], + picture: '9(008)', + value: '06022027', + }, + horaGeracaoArquivo: { + pos: [152, 157], + picture: '9(006)', + value: '102342', + }, + nsa: { + pos: [158, 163], + picture: '9(006)', + value: '000101', + }, + versaoLeiauteArquivo: { + pos: [164, 166], + picture: '9(003)', + value: '000', + }, + densidadeGravacao: { + pos: [167, 171], + picture: '9(005)', + value: '01600', + }, + reservadoBanco: { + pos: [172, 191], + picture: 'X(020)', + value: ' ', + }, + reservadoEmpresa: { + pos: [192, 211], + picture: 'X(020)', + value: ' ', + }, + usoExclusivoFebraban: { + pos: [212, 222], + picture: 'X(011)', + value: ' ', + }, + identidadeCobranca: { + pos: [223, 225], + picture: 'X(003)', + value: ' ', + }, + usoExclusivoVan: { + pos: [226, 228], + picture: '9(003)', + value: '000', + }, + tipoServico: { + pos: [229, 230], + picture: 'X(002)', + value: ' ', + }, + ocorrenciaCobrancaSemPapel: { + pos: [231, 240], + picture: 'X(010)', + value: ' ', + }, +}; diff --git a/src/cnab/test/templates/240/104/cnab-240-104-header-lote-template-test.const.ts b/src/cnab/test/templates/240/104/cnab-240-104-header-lote-template-test.const.ts index ff6f65f2..ded90b22 100644 --- a/src/cnab/test/templates/240/104/cnab-240-104-header-lote-template-test.const.ts +++ b/src/cnab/test/templates/240/104/cnab-240-104-header-lote-template-test.const.ts @@ -1,9 +1,14 @@ -import { ICnab240CaixaHeaderLote } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-header-lote.interface'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { ICnab240_104HeaderLote } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-header-lote.interface'; -export const cnab240_104HeaderLoteTemplateTest: ICnab240CaixaHeaderLote = { +export const cnab240_104HeaderLoteTemplateTest: ICnab240_104HeaderLote = { codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, loteServico: { pos: [4, 7], picture: '9(004)', value: '0001' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '1' }, + codigoRegistro: { + pos: [8, 8], + picture: '9(001)', + value: CnabAllCodigoRegistro.HeaderLote, + }, tipoOperacao: { pos: [9, 9], picture: 'X(001)', value: 'C' }, tipoServico: { pos: [10, 11], picture: '9(002)', value: '30' }, formaLancamento: { pos: [12, 13], picture: '9(002)', value: '01' }, diff --git a/src/cnab/test/templates/240/104/cnab-240-104-trailer-arquivo-template-test.const.ts b/src/cnab/test/templates/240/104/cnab-240-104-trailer-arquivo-template-test.const.ts index 0c7a2bb6..3f82e051 100644 --- a/src/cnab/test/templates/240/104/cnab-240-104-trailer-arquivo-template-test.const.ts +++ b/src/cnab/test/templates/240/104/cnab-240-104-trailer-arquivo-template-test.const.ts @@ -1,10 +1,15 @@ -import { ICnab240CaixaTrailerArquivo } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-arquivo.interface'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { ICnab240_104TrailerArquivo } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-arquivo.interface'; -export const cnab240_104TrailerArquivoTemplateTest: ICnab240CaixaTrailerArquivo = +export const cnab240_104TrailerArquivoTemplateTest: ICnab240_104TrailerArquivo = { codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, loteServico: { pos: [4, 7], picture: '9(004)', value: '9999' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '5' }, + codigoRegistro: { + pos: [8, 8], + picture: '9(001)', + value: CnabAllCodigoRegistro.TrailerArquivo, + }, usoExclusivoFebraban: { pos: [9, 17], picture: 'X(009)', diff --git a/src/cnab/test/templates/240/104/cnab-240-104-trailer-lote-template-test.const.ts b/src/cnab/test/templates/240/104/cnab-240-104-trailer-lote-template-test.const.ts index 9f58fa0a..f170d92f 100644 --- a/src/cnab/test/templates/240/104/cnab-240-104-trailer-lote-template-test.const.ts +++ b/src/cnab/test/templates/240/104/cnab-240-104-trailer-lote-template-test.const.ts @@ -1,9 +1,14 @@ -import { ICnab240CaixaTrailerLote } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-lote.interface'; +import { CnabAllCodigoRegistro } from 'src/cnab/enums/all/cnab-all-codigo-registro.enum'; +import { ICnab240_104TrailerLote } from 'src/cnab/interfaces/cnab-240/104/cnab-240-104-trailer-lote.interface'; -export const cnab240_104TrailerLoteTemplateTest: ICnab240CaixaTrailerLote = { +export const cnab240_104TrailerLoteTemplateTest: ICnab240_104TrailerLote = { codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, loteServico: { pos: [4, 7], picture: '9(004)', value: '0000' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '5' }, + codigoRegistro: { + pos: [8, 8], + picture: '9(001)', + value: CnabAllCodigoRegistro.TrailerLote, + }, usoExclusivoFebraban: { pos: [9, 17], picture: 'X(009)', value: ' ' }, quantidadeRegistrosLote: { pos: [18, 23], diff --git a/src/cnab/test/templates/240/104/example-240-104.rem b/src/cnab/test/templates/240/104/example-240-104.rem index c2b9ee6f..ff2c179a 100644 --- a/src/cnab/test/templates/240/104/example-240-104.rem +++ b/src/cnab/test/templates/240/104/example-240-104.rem @@ -1,6 +1,16 @@ 10400900 20001234560011111200709P 0000 0095550000000000032 CONVE DE PAGAMENTOSSA E OEBSACAIXA 20602202710234200010100001600 000 -10400011C3001041 20001234560011111200702000201 0095550000000000032 CONVE DE PAGAMENTOSSA E PENSA RUA ALMIR PEDRAS -1040001300001A0000001040095550031993933180 TEREZINHA SEVERIANA 000027 105022023BRL000000000000000000000001347272000000000 01N1060000000000000000000000000 01 0 -1040001300002B000100097654026005RUA ALAMEDA 00104APTO 315 CENTRO RIO DE JANEIRO 22544010RJ06022023000000001347272000000000000000000000000000000000000000000000000000000000000 -10400015 00000200000000000000020000000000000000000000 -10499995 000001000001000000 \ No newline at end of file +10400011C3001041 20001234560011111200702000201 0095550000000000032 CONVE DE PAGAMENTOSSA E PENSA RUA ALMIR PEDRAS 00000000000000000000 00000 +1040001300001A0000001040095550031993933180 TEREZINHA SEVERIANA 000027 105022023BRL000000000000000000000000120012000000000 01N1060000000000000000000000000 01 0 +1040001300002B 000000000000000 00104APTO 315 CENTRO RIO DE JANEIRO 22544010RJ06022023000000000120012000000000000000000000000000000000000000000000000000000000000 +1040001300003A0000001040095550031993933180 TEREZINHA SEVERIANA 000027 105022023BRL000000000000000000000000120012000000000 01N1060000000000000000000000000 01 0 +1040001300004B 000000000000000 00104APTO 315 CENTRO RIO DE JANEIRO 22544010RJ06022023000000000120012000000000000000000000000000000000000000000000000000000000000 +10400015 000004000000000000240024000000000000000000000000 +10400021C3001041 20001234560011111200702000201 0095550000000000032 CONVE DE PAGAMENTOSSA E PENSA RUA ALMIR PEDRAS 00000000000000000000 00000 +1040002300001A0000001040095550031993933180 TEREZINHA SEVERIANA 000027 105022023BRL000000000000000000000000120012000000000 01N1060000000000000000000000000 01 0 +1040002300002B 000000000000000 00104APTO 315 CENTRO RIO DE JANEIRO 22544010RJ06022023000000000120012000000000000000000000000000000000000000000000000000000000000 +1040002300003A0000001040095550031993933180 TEREZINHA SEVERIANA 000027 105022023BRL000000000000000000000000120012000000000 01N1060000000000000000000000000 01 0 +1040002300004B 000000000000000 00104APTO 315 CENTRO RIO DE JANEIRO 22544010RJ06022023000000000120012000000000000000000000000000000000000000000000000000000000000 +1040002300005A0000001040095550031993933180 TEREZINHA SEVERIANA 000027 105022023BRL000000000000000000000000120012000000000 01N1060000000000000000000000000 01 0 +1040002300006B 000000000000000 00104APTO 315 CENTRO RIO DE JANEIRO 22544010RJ06022023000000000120012000000000000000000000000000000000000000000000000000000000000 +10400025 000006000000000000360036000000000000000000000000 +10499999 000002000016000000 \ No newline at end of file diff --git a/src/cnab/test/templates/240/generic/cnab-240-generic-detalhe-a-template-test.const.ts b/src/cnab/test/templates/240/generic/cnab-240-generic-detalhe-a-template-test.const.ts index 68819ddd..c5700982 100644 --- a/src/cnab/test/templates/240/generic/cnab-240-generic-detalhe-a-template-test.const.ts +++ b/src/cnab/test/templates/240/generic/cnab-240-generic-detalhe-a-template-test.const.ts @@ -1,16 +1,17 @@ import { CnabFields } from 'src/cnab/types/cnab-field.type'; export const cnab240GenericDetalheATemplateTest: CnabFields = { - codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, - loteServico: { pos: [4, 7], picture: '9(004)', value: '0001' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '3' }, - nsr: { pos: [9, 13], picture: '9(005)', value: '00001' }, - codigoSegmento: { pos: [14, 14], picture: 'X(001)', value: 'A' }, - filler: { pos: [15, 119], picture: 'X(105)', value: ' ' }, - valorLancamento: { - pos: [120, 134], - picture: '9(013)V99', - value: '000000001000010', + codigoRegistro: { pos: [1, 1], picture: '9(001)', value: '0' }, + loteServico: { pos: [2, 5], picture: '9(004)', value: '' }, + quantidadeRegistrosLote: { pos: [6, 11], picture: '9(006)', value: '0' }, + codigoSegmento: { pos: [12, 12], picture: 'X(001)', value: 'A' }, + nsr: { pos: [13, 17], picture: '9(005)', value: '' }, + quantidadeLotesArquivo: { pos: [18, 23], picture: '9(006)', value: '' }, + quantidadeRegistrosArquivo: { + pos: [24, 29], + picture: '9(006)', + value: '', }, - usoFebraban: { pos: [135, 240], picture: 'X(105)', value: ' ' }, + info: { pos: [30, 39], picture: 'X(010)', value: ' ' }, + filler: { pos: [40, 240], picture: 'X(201)', value: ' ' }, }; diff --git a/src/cnab/test/templates/240/generic/cnab-240-generic-detalhe-b-template-test.const.ts b/src/cnab/test/templates/240/generic/cnab-240-generic-detalhe-b-template-test.const.ts index 76b62ddf..dda622dd 100644 --- a/src/cnab/test/templates/240/generic/cnab-240-generic-detalhe-b-template-test.const.ts +++ b/src/cnab/test/templates/240/generic/cnab-240-generic-detalhe-b-template-test.const.ts @@ -1,16 +1,17 @@ import { CnabFields } from 'src/cnab/types/cnab-field.type'; export const cnab240GenericDetalheBTemplateTest: CnabFields = { - codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, - loteServico: { pos: [4, 7], picture: '9(004)', value: '0001' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '3' }, - nsr: { pos: [9, 13], picture: '9(005)', value: '00002' }, - codigoSegmento: { pos: [14, 14], picture: 'X(001)', value: 'B' }, - usoExclusivoFebraban: { pos: [15, 135], picture: 'X(121)', value: ' ' }, - valorDocumento: { - pos: [136, 150], - picture: '9(013)V99', - value: '000000001000010', + codigoRegistro: { pos: [1, 1], picture: '9(001)', value: '0' }, + quantidadeRegistrosLote: { pos: [6, 11], picture: '9(006)', value: '0' }, + codigoSegmento: { pos: [12, 12], picture: 'X(001)', value: 'B' }, + nsr: { pos: [13, 17], picture: '9(005)', value: '' }, + quantidadeLotesArquivo: { pos: [18, 23], picture: '9(006)', value: '' }, + quantidadeRegistrosArquivo: { + pos: [24, 29], + picture: '9(006)', + value: '', }, - usoExclusivoFebraban2: { pos: [151, 240], picture: 'X(090)', value: ' ' }, + info: { pos: [30, 39], picture: 'X(010)', value: ' ' }, + filler: { pos: [40, 240], picture: 'X(201)', value: ' ' }, + loteServico2: { pos: [2, 5], picture: '9(004)', value: '' }, }; diff --git a/src/cnab/test/templates/240/generic/cnab-240-generic-detalhe-c-template-test.const.ts b/src/cnab/test/templates/240/generic/cnab-240-generic-detalhe-c-template-test.const.ts new file mode 100644 index 00000000..f5b75281 --- /dev/null +++ b/src/cnab/test/templates/240/generic/cnab-240-generic-detalhe-c-template-test.const.ts @@ -0,0 +1,17 @@ +import { CnabFields } from 'src/cnab/types/cnab-field.type'; + +export const cnab240GenericDetalheCTemplateTest: CnabFields = { + codigoRegistro: { pos: [1, 1], picture: '9(001)', value: '0' }, + loteServico: { pos: [2, 5], picture: '9(004)', value: '' }, + quantidadeRegistrosLote: { pos: [6, 11], picture: '9(006)', value: '0' }, + codigoSegmento: { pos: [12, 12], picture: 'X(001)', value: 'C' }, + nsr: { pos: [13, 17], picture: '9(005)', value: '' }, + quantidadeLotesArquivo: { pos: [18, 23], picture: '9(006)', value: '' }, + quantidadeRegistrosArquivo: { + pos: [24, 29], + picture: '9(006)', + value: '', + }, + info: { pos: [30, 39], picture: 'X(010)', value: ' ' }, + filler: { pos: [40, 240], picture: 'X(201)', value: ' ' }, +}; diff --git a/src/cnab/test/templates/240/generic/cnab-240-generic-field-map-template-test.const.ts b/src/cnab/test/templates/240/generic/cnab-240-generic-field-map-template-test.const.ts new file mode 100644 index 00000000..535e2b6e --- /dev/null +++ b/src/cnab/test/templates/240/generic/cnab-240-generic-field-map-template-test.const.ts @@ -0,0 +1,26 @@ +import { ICnabFieldMap } from 'src/cnab/interfaces/cnab-field-map.interface'; + +const base: ICnabFieldMap = { + registroIdField: 'codigoRegistro', + registroLoteSequenceField: 'loteServico', + trailerLoteRegistroCountField: 'quantidadeRegistrosLote', + detalheSegmentoField: 'codigoSegmento', + detalheLoteRegistroSequenceField: 'nsr', + trailerArquivoLoteCountField: 'quantidadeLotesArquivo', + trailerArquivoRegistroCountField: 'quantidadeRegistrosArquivo', +}; + +const detalheB: ICnabFieldMap = { + registroIdField: 'codigoRegistro', + registroLoteSequenceField: 'loteServico2', + trailerLoteRegistroCountField: 'quantidadeRegistrosLote', + detalheSegmentoField: 'codigoSegmento', + detalheLoteRegistroSequenceField: 'nsr', + trailerArquivoLoteCountField: 'quantidadeLotesArquivo', + trailerArquivoRegistroCountField: 'quantidadeRegistrosArquivo', +}; + +export const cnab240GenericFieldMapTemplateTest = { + base: base, + detalheB: detalheB, +}; diff --git a/src/cnab/test/templates/240/generic/cnab-240-generic-header-arquivo-template-test.const.ts b/src/cnab/test/templates/240/generic/cnab-240-generic-header-arquivo-template-test.const.ts index 6fc36cc4..c2b16506 100644 --- a/src/cnab/test/templates/240/generic/cnab-240-generic-header-arquivo-template-test.const.ts +++ b/src/cnab/test/templates/240/generic/cnab-240-generic-header-arquivo-template-test.const.ts @@ -1,10 +1,17 @@ import { CnabFields } from 'src/cnab/types/cnab-field.type'; export const cnab240GenericHeaderArquivoTemplateTest: CnabFields = { - codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, - loteServico: { pos: [4, 7], picture: '9(004)', value: '0090' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '0' }, - filler: { pos: [9, 17], picture: 'X(009)', value: ' ' }, - nsa: { pos: [158, 163], picture: '9(006)', value: '000101' }, - filler2: { pos: [164, 240], picture: 'X(077)', value: ' ' }, + codigoRegistro: { pos: [1, 1], picture: '9(001)', value: '0' }, + loteServico: { pos: [2, 5], picture: '9(004)', value: '' }, + quantidadeRegistrosLote: { pos: [6, 11], picture: '9(006)', value: '0' }, + codigoSegmento: { pos: [12, 12], picture: 'X(001)', value: ' ' }, + nsr: { pos: [13, 17], picture: '9(005)', value: '' }, + quantidadeLotesArquivo: { pos: [18, 23], picture: '9(006)', value: '' }, + quantidadeRegistrosArquivo: { + pos: [24, 29], + picture: '9(006)', + value: '', + }, + info: { pos: [30, 39], picture: 'X(010)', value: ' ' }, + filler: { pos: [40, 240], picture: 'X(201)', value: ' ' }, }; diff --git a/src/cnab/test/templates/240/generic/cnab-240-generic-header-lote-template-test.const.ts b/src/cnab/test/templates/240/generic/cnab-240-generic-header-lote-template-test.const.ts index beffe984..4868bf4b 100644 --- a/src/cnab/test/templates/240/generic/cnab-240-generic-header-lote-template-test.const.ts +++ b/src/cnab/test/templates/240/generic/cnab-240-generic-header-lote-template-test.const.ts @@ -1,8 +1,17 @@ import { CnabFields } from 'src/cnab/types/cnab-field.type'; export const cnab240GenericHeaderLoteTemplateTest: CnabFields = { - codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, - loteServico: { pos: [4, 7], picture: '9(004)', value: '0001' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '1' }, - filler: { pos: [9, 240], picture: 'X(232)', value: ' ' }, + codigoRegistro: { pos: [1, 1], picture: '9(001)', value: '0' }, + loteServico: { pos: [2, 5], picture: '9(004)', value: '' }, + quantidadeRegistrosLote: { pos: [6, 11], picture: '9(006)', value: '0' }, + codigoSegmento: { pos: [12, 12], picture: 'X(001)', value: ' ' }, + nsr: { pos: [13, 17], picture: '9(005)', value: '' }, + quantidadeLotesArquivo: { pos: [18, 23], picture: '9(006)', value: '' }, + quantidadeRegistrosArquivo: { + pos: [24, 29], + picture: '9(006)', + value: '', + }, + info: { pos: [30, 39], picture: 'X(010)', value: ' ' }, + filler: { pos: [40, 240], picture: 'X(201)', value: ' ' }, }; diff --git a/src/cnab/test/templates/240/generic/cnab-240-generic-trailer-arquivo-template-test.const.ts b/src/cnab/test/templates/240/generic/cnab-240-generic-trailer-arquivo-template-test.const.ts index e3e76b1d..e3347a3f 100644 --- a/src/cnab/test/templates/240/generic/cnab-240-generic-trailer-arquivo-template-test.const.ts +++ b/src/cnab/test/templates/240/generic/cnab-240-generic-trailer-arquivo-template-test.const.ts @@ -1,32 +1,17 @@ import { CnabFields } from 'src/cnab/types/cnab-field.type'; export const cnab240GenericTrailerArquivoTemplateTest: CnabFields = { - codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, - loteServico: { pos: [4, 7], picture: '9(004)', value: '9999' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '5' }, - usoExclusivoFebraban: { - pos: [9, 17], - picture: 'X(009)', - value: ' ', - }, - quantidadeLotesArquivo: { - pos: [18, 23], - picture: '9(006)', - value: '000001', - }, + codigoRegistro: { pos: [1, 1], picture: '9(001)', value: '0' }, + loteServico: { pos: [2, 5], picture: '9(004)', value: '' }, + quantidadeRegistrosLote: { pos: [6, 11], picture: '9(006)', value: '0' }, + codigoSegmento: { pos: [12, 12], picture: 'X(001)', value: ' ' }, + nsr: { pos: [13, 17], picture: '9(005)', value: '' }, + quantidadeLotesArquivo: { pos: [18, 23], picture: '9(006)', value: '' }, quantidadeRegistrosArquivo: { pos: [24, 29], picture: '9(006)', - value: '000001', - }, - quantidadeContasConciliacao: { - pos: [30, 35], - picture: '9(006)', - value: '000000', - }, - usoExclusivoFebraban2: { - pos: [36, 240], - picture: 'X(205)', - value: ' '.repeat(205), + value: '', }, + info: { pos: [30, 39], picture: 'X(010)', value: ' ' }, + filler: { pos: [40, 240], picture: 'X(201)', value: ' ' }, }; diff --git a/src/cnab/test/templates/240/generic/cnab-240-generic-trailer-lote-template-test.const.ts b/src/cnab/test/templates/240/generic/cnab-240-generic-trailer-lote-template-test.const.ts index e6b533fb..7827ec25 100644 --- a/src/cnab/test/templates/240/generic/cnab-240-generic-trailer-lote-template-test.const.ts +++ b/src/cnab/test/templates/240/generic/cnab-240-generic-trailer-lote-template-test.const.ts @@ -1,30 +1,17 @@ import { CnabFields } from 'src/cnab/types/cnab-field.type'; export const cnab240GenericTrailerLoteTemplateTest: CnabFields = { - codigoBanco: { pos: [1, 3], picture: '9(003)', value: '104' }, - loteServico: { pos: [4, 7], picture: '9(004)', value: '0000' }, - codigoRegistro: { pos: [8, 8], picture: '9(001)', value: '5' }, - usoExclusivoFebraban: { pos: [9, 17], picture: 'X(009)', value: ' ' }, - quantidadeRegistrosLote: { - pos: [18, 23], + codigoRegistro: { pos: [1, 1], picture: '9(001)', value: '0' }, + loteServico: { pos: [2, 5], picture: '9(004)', value: '' }, + quantidadeRegistrosLote: { pos: [6, 11], picture: '9(006)', value: '0' }, + codigoSegmento: { pos: [12, 12], picture: 'X(001)', value: ' ' }, + nsr: { pos: [13, 17], picture: '9(005)', value: '' }, + quantidadeLotesArquivo: { pos: [18, 23], picture: '9(006)', value: '' }, + quantidadeRegistrosArquivo: { + pos: [24, 29], picture: '9(006)', - value: '000000', + value: '', }, - somatorioValores: { - pos: [24, 41], - picture: '9(016)V99', - value: '0000000000000000', - }, - somatorioQtdeMoeda: { - pos: [42, 59], - picture: '9(013)V99999', - value: '0000000000000', - }, - numeroAvisoDebito: { pos: [60, 65], picture: '9(006)', value: '000000' }, - usoExclusivoFebraban2: { - pos: [66, 230], - picture: 'X(165)', - value: ' '.repeat(165), - }, - ocorrencias: { pos: [231, 240], picture: 'X(010)', value: ' ' }, + info: { pos: [30, 39], picture: 'X(010)', value: ' ' }, + filler: { pos: [40, 240], picture: 'X(201)', value: ' ' }, }; diff --git a/src/cnab/test/templates/240/generic/example-240-104.rem b/src/cnab/test/templates/240/generic/example-240-104.rem deleted file mode 100644 index c2b9ee6f..00000000 --- a/src/cnab/test/templates/240/generic/example-240-104.rem +++ /dev/null @@ -1,6 +0,0 @@ -10400900 20001234560011111200709P 0000 0095550000000000032 CONVE DE PAGAMENTOSSA E OEBSACAIXA 20602202710234200010100001600 000 -10400011C3001041 20001234560011111200702000201 0095550000000000032 CONVE DE PAGAMENTOSSA E PENSA RUA ALMIR PEDRAS -1040001300001A0000001040095550031993933180 TEREZINHA SEVERIANA 000027 105022023BRL000000000000000000000001347272000000000 01N1060000000000000000000000000 01 0 -1040001300002B000100097654026005RUA ALAMEDA 00104APTO 315 CENTRO RIO DE JANEIRO 22544010RJ06022023000000001347272000000000000000000000000000000000000000000000000000000000000 -10400015 00000200000000000000020000000000000000000000 -10499995 000001000001000000 \ No newline at end of file diff --git a/src/cnab/test/templates/240/generic/example-240-generic.rem b/src/cnab/test/templates/240/generic/example-240-generic.rem new file mode 100644 index 00000000..909aa193 --- /dev/null +++ b/src/cnab/test/templates/240/generic/example-240-generic.rem @@ -0,0 +1,15 @@ +00000000000 00000000000000000 +10001000000 00000000000000000 +30001000000A00001000000000000 +30001000000B00002000000000000 +50001000002 00000000000000000 +10002000000 00000000000000000 +30002000000A00001000000000000 +30002000000B00002000000000000 +50002000002 00000000000000000 +10003000000 00000000000000000 +30003000000A00001000000000000 +30003000000B00002000000000000 +30003000000C00003000000000000 +50003000003 00000000000000000 +99999000000 00000000003000015 \ No newline at end of file diff --git a/src/cnab/types/cnab-field.type.ts b/src/cnab/types/cnab-field.type.ts index 1b90d36b..a43c5ec6 100644 --- a/src/cnab/types/cnab-field.type.ts +++ b/src/cnab/types/cnab-field.type.ts @@ -4,14 +4,34 @@ export type CnabField = { pos: [number, number]; picture: string; value: any; - default?: any; + /** Will use date-fns or new Date() date format */ + dateFormat?: ICnabFieldDateFormat; +}; + +export type CnabFieldAs = { + pos: [number, number]; + picture: string; + value: T; /** * date-fns date format * @see{@link https://date-fns.org/v3.3.1/docs/format} */ - dateFormat?: string; }; +/** + * Input: optional. + * - `undefined`: Current date will be used as input of new Date() + * - `string`: Will use date-fns date format + * + * Output: mandatory. Desired string output format. Will use date-fns date format + * + * @see{@link https://date-fns.org/v3.3.1/docs/format} + */ +export interface ICnabFieldDateFormat { + input?: string; + output: string; +} + export type CnabFields = Record; export function isCnabField(value: any) { diff --git a/src/cnab/types/cnab-registro.type.ts b/src/cnab/types/cnab-registro.type.ts index 28294c2d..a7c1572a 100644 --- a/src/cnab/types/cnab-registro.type.ts +++ b/src/cnab/types/cnab-registro.type.ts @@ -1,15 +1,15 @@ import { isArrayContainEqual } from 'src/utils/array-utils'; -import { ICnabRegistroFieldMap } from '../interfaces/cnab-registro-field-map.interface'; +import { ICnabFieldMap } from '../interfaces/cnab-field-map.interface'; import { CnabFields } from './cnab-field.type'; export type CnabRegistro = { fields: CnabFields; - fieldMap?: ICnabRegistroFieldMap; + fieldMap?: ICnabFieldMap; }; export type CnabRegistroMapped = { fields: CnabFields; - fieldMap: ICnabRegistroFieldMap; + fieldMap: ICnabFieldMap; }; export function isCnabRegistro(value: any) { diff --git a/src/cnab/utils/cnab-104-utils.spec.ts b/src/cnab/utils/cnab-104-utils.spec.ts new file mode 100644 index 00000000..d8a5ec89 --- /dev/null +++ b/src/cnab/utils/cnab-104-utils.spec.ts @@ -0,0 +1,139 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { ICnab240_104DetalheA } from '../interfaces/cnab-240/104/cnab-240-104-detalhe-a.interface'; +import { ICnab240_104DetalheB } from '../interfaces/cnab-240/104/cnab-240-104-detalhe-b.interface'; +import { ICnab240_104File } from '../interfaces/cnab-240/104/cnab-240-104-file.interface'; +import { ICnab240_104Lote } from '../interfaces/cnab-240/104/cnab-240-104-lote.interface'; +import { cnab240_104DetalheATemplateTest } from '../test/templates/240/104/cnab-240-104-detalhe-a-template-test.const'; +import { cnab240_104DetalheBTemplateTest } from '../test/templates/240/104/cnab-240-104-detalhe-b-template-test.const'; +import { cnab240_104HeaderArquivoTemplateTest } from '../test/templates/240/104/cnab-240-104-header-arquivo-template-test.const'; +import { cnab240_104HeaderLoteTemplateTest } from '../test/templates/240/104/cnab-240-104-header-lote-template-test.const'; +import { cnab240_104TrailerArquivoTemplateTest } from '../test/templates/240/104/cnab-240-104-trailer-arquivo-template-test.const'; +import { cnab240_104TrailerLoteTemplateTest } from '../test/templates/240/104/cnab-240-104-trailer-lote-template-test.const'; +import { getCnabFileFrom104, stringifyCnab104File } from './cnab-104-utils'; + +describe('cnab-104-utils.ts', () => { + const sc = structuredClone; + const templatesPath = path.join(__dirname, '..', 'test', 'templates'); + const headerArquivo = cnab240_104HeaderArquivoTemplateTest; + const trailerArquivo = cnab240_104TrailerArquivoTemplateTest; + const headerLote = cnab240_104HeaderLoteTemplateTest; + const trailerLote = cnab240_104TrailerLoteTemplateTest; + const detalheA = cnab240_104DetalheATemplateTest; + const detalheB = cnab240_104DetalheBTemplateTest; + + describe('stringifyCnab104File()', () => { + it('should return string version correctly', () => { + // Arrange + const lote: ICnab240_104Lote = { + headerLote: sc(headerLote), + registros: [ + { + detalheA: sc(detalheA), + detalheB: sc(detalheB), + }, + { + detalheA: sc(detalheA), + detalheB: sc(detalheB), + }, + ], + trailerLote: sc(trailerLote), + }; + + const file: ICnab240_104File = { + headerArquivo: sc(headerArquivo), + lotes: [sc(lote), sc(lote)], + trailerArquivo: sc(trailerArquivo), + }; + file.lotes[1].registros.push({ + detalheA: sc(detalheA), + detalheB: sc(detalheB), + }); + + const expectedResponseFilePath = path.join( + templatesPath, + '240', + '104', + 'example-240-104.rem', + ); + const expectedResponse = fs + .readFileSync(expectedResponseFilePath, 'utf-8') + .replace(/\r\n/g, '\n'); + + // Act + const response = stringifyCnab104File(file).replace(/\r\n/g, '\n'); + + // Assert + expect(response).toEqual(expectedResponse); + }); + }); + + describe('getCnabFileFrom104()', () => { + it('should set CnabFields in the right places', () => { + // Arrange + const lote: ICnab240_104Lote = { + headerLote: sc(headerLote), + registros: [ + { + detalheA: sc(detalheA), + detalheB: sc(detalheB), + }, + { + detalheA: sc(detalheA), + detalheB: sc(detalheB), + }, + ], + trailerLote: sc(trailerLote), + }; + const lote0 = sc(lote); + const lote1 = sc(lote); + + lote0.headerLote.usoExclusivoFebraban.value = 'L0H'; + ( + lote0.registros[0].detalheA as ICnab240_104DetalheA + ).usoExclusivoFebraban.value = 'L0R0A'; + ( + lote0.registros[1].detalheB as ICnab240_104DetalheB + ).usoExclusivoFebraban.value = 'L0R1B'; + + lote1.trailerLote.usoExclusivoFebraban.value = 'L1T'; + ( + lote1.registros[0].detalheB as ICnab240_104DetalheB + ).usoExclusivoFebraban.value = 'L1R0B'; + ( + lote1.registros[1].detalheA as ICnab240_104DetalheA + ).usoExclusivoFebraban.value = 'L1R1A'; + + const file: ICnab240_104File = { + headerArquivo: sc(headerArquivo), + lotes: [sc(lote0), sc(lote1)], + trailerArquivo: sc(trailerArquivo), + }; + + // Act + const response = getCnabFileFrom104(file); + + // Assert + expect(response.headerArquivo.fields).toEqual(headerArquivo); + expect( + response.lotes[0].headerLote.fields.usoExclusivoFebraban.value, + ).toEqual('L0H'); + expect( + response.lotes[0].registros[0].fields.usoExclusivoFebraban.value, + ).toEqual('L0R0A'); + expect( + response.lotes[0].registros[3].fields.usoExclusivoFebraban.value, + ).toEqual('L0R1B'); + expect( + response.lotes[1].registros[1].fields.usoExclusivoFebraban.value, + ).toEqual('L1R0B'); + expect( + response.lotes[1].registros[2].fields.usoExclusivoFebraban.value, + ).toEqual('L1R1A'); + expect( + response.lotes[1].trailerLote.fields.usoExclusivoFebraban.value, + ).toEqual('L1T'); + expect(response.trailerArquivo.fields).toEqual(trailerArquivo); + }); + }); +}); diff --git a/src/cnab/utils/cnab-104-utils.ts b/src/cnab/utils/cnab-104-utils.ts new file mode 100644 index 00000000..62cef7d2 --- /dev/null +++ b/src/cnab/utils/cnab-104-utils.ts @@ -0,0 +1,89 @@ +import { ICnab240_104File } from '../interfaces/cnab-240/104/cnab-240-104-file.interface'; +import { ICnab240_104Lote } from '../interfaces/cnab-240/104/cnab-240-104-lote.interface'; +import { ICnab240_104Registro } from '../interfaces/cnab-240/104/cnab-240-104-registro.interface'; +import { cnabAll104FieldMapTemplate as fieldMapTemplate } from '../templates/cnab-all/cnab-all-104-registro-field-map-template'; +import { CnabFile } from '../types/cnab-file.type'; +import { CnabLote } from '../types/cnab-lote.type'; +import { CnabRegistro } from '../types/cnab-registro.type'; +import { stringifyCnabFile } from './cnab-utils'; + +export function stringifyCnab104File(cnab104: ICnab240_104File): string { + const newCnab104 = structuredClone(cnab104); + processCnab104File(newCnab104); + const cnab = getCnabFileFrom104(newCnab104); + return stringifyCnabFile(cnab); +} + +/** + * Process data in CnabFile for Caixa (bank 104) + */ +export function processCnab104File(cnab: ICnab240_104File) { + processCnab104Lotes(cnab.lotes); +} + +function processCnab104Lotes(lotes: ICnab240_104Lote[]) { + for (let i = 0; i < lotes.length; i++) { + processCnab104TrailerLote(lotes[i]); + } +} + +function processCnab104TrailerLote(lote: ICnab240_104Lote) { + const somatorioValores = getSomarioValoresCnabLote(lote); + lote.trailerLote.somatorioValores.value = somatorioValores; +} + +function getSomarioValoresCnabLote(lote: ICnab240_104Lote): number { + return lote.registros.reduce( + (s2, regGroup) => + s2 + Number(regGroup.detalheA?.valorLancamento?.value || 0), + 0, + ); +} + +export function getCnabFileFrom104(cnab: ICnab240_104File): CnabFile { + return { + headerArquivo: { + fields: cnab.headerArquivo, + fieldMap: fieldMapTemplate.headerArquivo, + }, + lotes: getCnabLotesFrom104(cnab.lotes), + trailerArquivo: { + fields: cnab.trailerArquivo, + fieldMap: fieldMapTemplate.trailerArquivo, + }, + }; +} + +function getCnabLotesFrom104(lotes: ICnab240_104Lote[]): CnabLote[] { + return lotes.reduce((l, i) => [...l, getCnabLoteFrom104(i)], []); +} + +function getCnabLoteFrom104(lote: ICnab240_104Lote): CnabLote { + return { + headerLote: { + fields: lote.headerLote, + fieldMap: fieldMapTemplate.headerLote, + }, + registros: getCnabRegistrosFrom104(lote.registros), + trailerLote: { + fields: lote.trailerLote, + fieldMap: fieldMapTemplate.trailerLote, + }, + }; +} + +function getCnabRegistrosFrom104( + registrosGroup: ICnab240_104Registro[], +): CnabRegistro[] { + const baseRegistros: CnabRegistro[] = []; + for (const registros of registrosGroup) { + for (const registro of Object.values(registros).filter((i) => i)) { + const baseRegistro: CnabRegistro = { + fields: registro, + fieldMap: fieldMapTemplate.detalheLote, + }; + baseRegistros.push(baseRegistro); + } + } + return baseRegistros; +} diff --git a/src/cnab/cnab-field-utils.spec.ts b/src/cnab/utils/cnab-field-utils.spec.ts similarity index 96% rename from src/cnab/cnab-field-utils.spec.ts rename to src/cnab/utils/cnab-field-utils.spec.ts index d276cc57..66eb64a2 100644 --- a/src/cnab/cnab-field-utils.spec.ts +++ b/src/cnab/utils/cnab-field-utils.spec.ts @@ -8,8 +8,8 @@ import { getPictureTextSize, validateCnabFieldPositionSize, } from './cnab-field-utils'; -import { CnabFieldType } from './enums/cnab-field-type.enum'; -import { CnabField } from './types/cnab-field.type'; +import { CnabFieldType } from '../enums/cnab-field-type.enum'; +import { CnabField } from '../types/cnab-field.type'; process.env.TZ = 'UTC'; @@ -220,19 +220,19 @@ describe('cnab-utils.ts', () => { picture: '9(8)', pos: [0, 0], value: new Date('2024-03-25'), - dateFormat: 'ddMMyyyy', + dateFormat: { output: 'ddMMyyyy' }, }); const resultDdmmyy = formatDate({ picture: '9(6)', pos: [0, 0], value: new Date('2024-04-26'), - dateFormat: 'ddMMyy', + dateFormat: { output: 'ddMMyy' }, }); const resultHhmmss = formatDate({ picture: '9(6)', pos: [0, 0], value: new Date('2024-05-27 12:13:14'), - dateFormat: 'kkmmss', + dateFormat: { output: 'kkmmss' }, }); // Assert @@ -247,19 +247,19 @@ describe('cnab-utils.ts', () => { picture: '9(6)', pos: [0, 0], value: '2024-01-02 10:11:12', - dateFormat: 'hhmmss', + dateFormat: { output: 'hhmmss' }, }); const resultHmsToHms = formatDate({ picture: '9(6)', pos: [0, 0], value: '13:20:57', - dateFormat: 'HHmmss', + dateFormat: { output: 'HHmmss' }, }); const resultDateToDate = formatDate({ picture: '9(8)', pos: [0, 0], value: '2024-01-03', - dateFormat: 'ddMMyyyy', + dateFormat: { output: 'ddMMyyyy' }, }); const resultNoFormat = () => formatDate({ @@ -386,7 +386,7 @@ describe('cnab-utils.ts', () => { picture: '9(1)', pos: [0, 0], value: '0', - dateFormat: 'ddMMyyyy', + dateFormat: { output: 'ddMMyyyy' }, }); const resultInvalid = () => getCnabFieldType({ diff --git a/src/cnab/cnab-field-utils.ts b/src/cnab/utils/cnab-field-utils.ts similarity index 84% rename from src/cnab/cnab-field-utils.ts rename to src/cnab/utils/cnab-field-utils.ts index 004e39cd..0242312e 100644 --- a/src/cnab/cnab-field-utils.ts +++ b/src/cnab/utils/cnab-field-utils.ts @@ -5,21 +5,31 @@ import { getStringUpperUnaccent, isStringBasicAlnumUpper, } from 'src/utils/string-utils'; -import { CnabFieldType } from './enums/cnab-field-type.enum'; -import { CnabField } from './types/cnab-field.type'; +import { CnabFieldType } from '../enums/cnab-field-type.enum'; +import { CnabField } from '../types/cnab-field.type'; export type CropFillOnCrop = 'error' | 'cropLeft' | 'cropRight'; /** * From CnabField get formatted value applying Picture. * - * And validate Cnab. + * With all validations. */ -export function getCnabPictureValue(item: CnabField) { - validateCnabFieldPositionSize(item); - if (getCnabFieldType(item) === CnabFieldType.Date) { +export function stringifyCnabField(field: CnabField): string { + validateCnabField(field); + return getCnabFieldToString(field); +} + +/** + * From CnabField get formatted value applying Picture. + * + * With necessary validation. + */ +export function getCnabFieldToString(item: CnabField): string { + const cnabFieldType = getCnabFieldType(item); + if (cnabFieldType === CnabFieldType.Date) { return formatDate(item); - } else if (getCnabFieldType(item) === CnabFieldType.Number) { + } else if (cnabFieldType === CnabFieldType.Number) { return formatNumber(item); } else { // Text @@ -60,7 +70,7 @@ export function validateCnabFieldType(item: CnabField) { * 1. "V" + 9999... The number of characters "9 after "V" is the length of decimal; * 2. `V9()`. * - * @throws `HttpException` if picture is invalid (regex has no matches). + * @throws `Error` if picture is invalid (regex has no matches). */ export function getPictureNumberSize(picture: string): { integer: number; @@ -85,7 +95,7 @@ export function getPictureNumberSize(picture: string): { * * If regex doesn't find anything, the value is 0. * - * @throws `HttpException` if picture is invalid (regex has no matches). + * @throws `Error` if picture is invalid (regex has no matches). */ export function getPictureTextSize(picture: string): number { const regexResult = new RegExp(/^X\((\d+?)\)$/g).exec(picture); @@ -148,6 +158,8 @@ export function formatText( /** * Performs basic validation before formatting. + * + * @throws `Error` if field value is invalid */ function validateFormatText(item: CnabField) { if (typeof item.value !== 'string') { @@ -169,6 +181,8 @@ function validateFormatText(item: CnabField) { * For Date object you must use dateFormat, otherwise it will use default date format. * * @see{@link https://date-fns.org/v3.3.1/docs/format} for date format + * + * @throws `Error` if field value is invalid */ export function formatDate( item: CnabField, @@ -179,7 +193,12 @@ export function formatDate( const value = !isDate(item.value) && !item.dateFormat ? String(item.value) - : String(format(stringToDate(item.value), item.dateFormat || 'yymmdd')); + : String( + format( + stringToDate(item.value, item.dateFormat?.input), + item.dateFormat?.output || 'yymmdd', + ), + ); return cropFillCnabField(value, integer, CnabFieldType.Date, onCrop); } @@ -190,8 +209,13 @@ function validateFormatDate(item: CnabField) { if (!item.dateFormat) { throw new Error(`CnabField must have dateFormat.`); } - if (isNaN(stringToDate(item.value).getDate())) { - throw new Error(`CnabField value (${item.value}) is not a valid date.`); + if (isNaN(stringToDate(item.value, item.dateFormat.input).getDate())) { + const dateFormat = item.dateFormat + ? JSON.stringify(item.dateFormat) + : 'undefined'; + throw new Error( + `CnabField value: ${item.value}, dateFormat: ${dateFormat} got an invalid date.`, + ); } } @@ -246,6 +270,13 @@ export function validateCnabText( return isCnabTextValid; } +/** + * Run all validations of CnabField + */ +export function validateCnabField(item: CnabField) { + validateCnabFieldPositionSize(item); +} + /** * Validates if position matches Picture */ @@ -270,7 +301,8 @@ export function validateCnabFieldPositionSize(item: CnabField) { if (pictureSize !== posSize) { throw new Error( `CnabField picture and position doesnt match ` + - `(positionSize: ${posSize}, pictureSize: ${pictureSize})`, + `(positionSize: ${posSize}, pictureSize: ${pictureSize}),` + + `CnabField: ${JSON.stringify(item)}`, ); } } diff --git a/src/cnab/cnab-utils.spec.ts b/src/cnab/utils/cnab-utils.spec.ts similarity index 54% rename from src/cnab/cnab-utils.spec.ts rename to src/cnab/utils/cnab-utils.spec.ts index f5abdd40..2392fbc9 100644 --- a/src/cnab/cnab-utils.spec.ts +++ b/src/cnab/utils/cnab-utils.spec.ts @@ -1,58 +1,99 @@ import { getCnabRegistros, - stringifyCnab, - stringifyRegistro, - validateRegistroPosition, + processCnabFile, + stringifyCnabFile, + stringifyCnabRegistro, + validateCnabRegistroPosition, } from './cnab-utils'; -import { CnabFields } from './types/cnab-field.type'; -import { CnabFile } from './types/cnab-file.type'; -import { CnabLote } from './types/cnab-lote.type'; -import { CnabRegistro } from './types/cnab-registro.type'; +import { CnabFields } from '../types/cnab-field.type'; +import { CnabFile } from '../types/cnab-file.type'; +import { CnabLote } from '../types/cnab-lote.type'; +import { CnabRegistro } from '../types/cnab-registro.type'; +import { ICnabFieldMap } from '../interfaces/cnab-field-map.interface'; +import * as path from 'path'; +import * as fs from 'fs'; +import { cnab240GenericFieldMapTemplateTest } from '../test/templates/240/generic/cnab-240-generic-field-map-template-test.const'; +import { cnab240GenericHeaderArquivoTemplateTest } from '../test/templates/240/generic/cnab-240-generic-header-arquivo-template-test.const'; +import { cnab240GenericTrailerArquivoTemplateTest } from '../test/templates/240/generic/cnab-240-generic-trailer-arquivo-template-test.const'; +import { cnab240GenericHeaderLoteTemplateTest } from '../test/templates/240/generic/cnab-240-generic-header-lote-template-test.const'; +import { cnab240GenericTrailerLoteTemplateTest } from '../test/templates/240/generic/cnab-240-generic-trailer-lote-template-test.const'; +import { cnab240GenericDetalheATemplateTest } from '../test/templates/240/generic/cnab-240-generic-detalhe-a-template-test.const'; +import { cnab240GenericDetalheBTemplateTest } from '../test/templates/240/generic/cnab-240-generic-detalhe-b-template-test.const'; +import { cnab240GenericDetalheCTemplateTest } from '../test/templates/240/generic/cnab-240-generic-detalhe-c-template-test.const'; process.env.TZ = 'UTC'; describe('cnab-utils.ts', () => { - describe('stringifyCnab()', () => { + const templatesPath = path.join(__dirname, '..', 'test', 'templates'); + const sc = structuredClone; + describe('stringifyCnabFile()', () => { it('should return text version of CnabFile accordingly', () => { // Arrange - const fieldsBase: CnabFields = { - a: { pos: [1, 100], picture: '9(98)V99', value: '1' }, - b: { pos: [101, 200], picture: 'X(100)', value: ' ' }, - c: { pos: [201, 240], picture: 'X(40)', value: ' ' }, + const map = cnab240GenericFieldMapTemplateTest.base; + const mapDetalheB = cnab240GenericFieldMapTemplateTest.detalheB; + const headerArquivo: CnabRegistro = { + fields: sc(cnab240GenericHeaderArquivoTemplateTest), + fieldMap: map, + }; + const trailerArquivo: CnabRegistro = { + fields: sc(cnab240GenericTrailerArquivoTemplateTest), + fieldMap: map, + }; + const headerLote: CnabRegistro = { + fields: sc(cnab240GenericHeaderLoteTemplateTest), + fieldMap: map, + }; + const trailerLote: CnabRegistro = { + fields: sc(cnab240GenericTrailerLoteTemplateTest), + fieldMap: map, + }; + const detalheA: CnabRegistro = { + fields: sc(cnab240GenericDetalheATemplateTest), + fieldMap: map, + }; + const detalheB: CnabRegistro = { + fields: sc(cnab240GenericDetalheBTemplateTest), + fieldMap: mapDetalheB, + }; + const detalheC: CnabRegistro = { + fields: sc(cnab240GenericDetalheCTemplateTest), + fieldMap: map, + }; + + const lote: CnabLote = { + headerLote: headerLote, + registros: [sc(detalheA), sc(detalheB)], + trailerLote: trailerLote, }; + + const loteN: CnabLote = { ...sc(lote) }; + loteN.registros.push(detalheC); + const cnab: CnabFile = { - headerArquivo: { fields: fieldsBase }, - lotes: [ - { - headerLote: { fields: fieldsBase }, - registros: [{ fields: fieldsBase }], - trailerLote: { fields: fieldsBase }, - }, - ], - trailerArquivo: { fields: fieldsBase }, + headerArquivo: headerArquivo, + lotes: [sc(lote), sc(lote), sc(loteN)], + trailerArquivo: trailerArquivo, }; + const expectedResponseFilePath = path.join( + templatesPath, + '240', + 'generic', + 'example-240-generic.rem', + ); + const expectedResponse = fs + .readFileSync(expectedResponseFilePath, 'utf-8') + .replace(/\r\n/g, '\n'); // Act - const response = stringifyCnab(cnab); + const response = stringifyCnabFile(cnab).replace(/\r\n/g, '\n'); // Assert - const responseLine = '0'.repeat(97) + '100' + ' '.repeat(140); - const expectedResponse = - responseLine + - '\r\n' + - responseLine + - '\r\n' + - responseLine + - '\r\n' + - responseLine + - '\r\n' + - responseLine; expect(response.length).toEqual(expectedResponse.length); expect(response).toEqual(expectedResponse); }); }); - describe('stringifyRegistro()', () => { + describe('stringifyCnabRegistro()', () => { it('should return text version of Registro accordingly', () => { // Arrange const registro: CnabRegistro = { @@ -65,7 +106,7 @@ describe('cnab-utils.ts', () => { }; // Act - const result = stringifyRegistro(registro); + const result = stringifyCnabRegistro(registro); // Assert expect(result).toEqual('10400013A' + ' '.repeat(231)); @@ -83,18 +124,18 @@ describe('cnab-utils.ts', () => { }; // Act - const result = () => stringifyRegistro(registro); + const result = () => stringifyCnabRegistro(registro); // Assert expect(result).toThrowError(); }); }); - describe('validateRegistroPosition()', () => { + describe('validateCnabRegistroPosition()', () => { it('should return when previous and current CnabFields have valid positions', () => { // Act const result = () => - validateRegistroPosition( + validateCnabRegistroPosition( { picture: 'X(5)', pos: [16, 20], @@ -115,7 +156,7 @@ describe('cnab-utils.ts', () => { it('should return when first CnabField has valid positions', () => { // Act const result = () => - validateRegistroPosition( + validateCnabRegistroPosition( { picture: '9(15)', pos: [1, 15], @@ -132,7 +173,7 @@ describe('cnab-utils.ts', () => { it('should return when last CnabField has valid positions', () => { // Act const result = () => - validateRegistroPosition( + validateCnabRegistroPosition( { picture: '9(1)', pos: [16, 240], @@ -153,7 +194,7 @@ describe('cnab-utils.ts', () => { it('should throw exception when first CnabField has invalid positions', () => { // Act const result = () => - validateRegistroPosition( + validateCnabRegistroPosition( { picture: '9(15)', pos: [0, 14], @@ -170,7 +211,7 @@ describe('cnab-utils.ts', () => { it('should throw exception when last CnabField has invalid positions', () => { // Act const result = () => - validateRegistroPosition( + validateCnabRegistroPosition( { picture: '9(1)', pos: [16, 239], @@ -187,7 +228,7 @@ describe('cnab-utils.ts', () => { it('should throw exception when previous and current CnabFields have invalid positions', () => { // Act const resultEqual = () => - validateRegistroPosition( + validateCnabRegistroPosition( { picture: 'X(5)', pos: [15, 29], @@ -201,7 +242,7 @@ describe('cnab-utils.ts', () => { true, ); const resultLower = () => - validateRegistroPosition( + validateCnabRegistroPosition( { picture: 'X(5)', pos: [14, 28], @@ -215,7 +256,7 @@ describe('cnab-utils.ts', () => { true, ); const resultGreather = () => - validateRegistroPosition( + validateCnabRegistroPosition( { picture: 'X(5)', pos: [17, 31], @@ -324,4 +365,75 @@ describe('cnab-utils.ts', () => { expect(result).toEqual(registros); }); }); + + describe('processCnabFile()', () => { + it('should insert count data correctly', () => { + // Arrange + const map: ICnabFieldMap = { + registroIdField: 'codigoRegistro', + registroLoteSequenceField: 'loteServico', + trailerLoteRegistroCountField: 'quantidadeRegistrosLote', + detalheSegmentoField: 'codigoSegmento', + detalheLoteRegistroSequenceField: 'nsr', + trailerArquivoLoteCountField: 'quantidadeLotesArquivo', + trailerArquivoRegistroCountField: 'quantidadeRegistrosArquivo', + }; + const fieldsBase: CnabFields = { + codigoRegistro: { pos: [1, 1], picture: '9(001)', value: '' }, + loteServico: { pos: [2, 5], picture: '9(004)', value: '' }, + quantidadeRegistrosLote: { pos: [6, 11], picture: '9(006)', value: '' }, + codigoSegmento: { pos: [12, 12], picture: 'X(001)', value: 'N' }, + nsr: { pos: [13, 17], picture: '9(005)', value: '' }, + quantidadeLotesArquivo: { pos: [18, 23], picture: '9(006)', value: '' }, + quantidadeRegistrosArquivo: { + pos: [24, 29], + picture: '9(006)', + value: '', + }, + filler: { pos: [30, 240], picture: 'X(211)', value: ' ' }, + }; + const lote: CnabLote = { + headerLote: { fields: sc(fieldsBase), fieldMap: map }, + registros: [ + { fields: sc(fieldsBase), fieldMap: map }, + { fields: sc(fieldsBase), fieldMap: map }, + ], + trailerLote: { fields: sc(fieldsBase), fieldMap: map }, + }; + const cnab: CnabFile = { + headerArquivo: { fields: sc(fieldsBase), fieldMap: map }, + lotes: [sc(lote), sc(lote), sc(lote)], + trailerArquivo: { fields: sc(fieldsBase), fieldMap: map }, + }; + + // Act + const response = sc(cnab); + processCnabFile(response); + + // Assert + expect(response.lotes[0].registros[0].fields.nsr.value).toEqual(1); + expect(response.lotes[0].registros[1].fields.nsr.value).toEqual(2); + expect(response.lotes[0].registros[0].fields.loteServico.value).toEqual( + 1, + ); + expect(response.lotes[1].registros[0].fields.loteServico.value).toEqual( + 2, + ); + expect(response.lotes[1].registros[1].fields.loteServico.value).toEqual( + 2, + ); + expect(response.lotes[2].registros[0].fields.loteServico.value).toEqual( + 3, + ); + expect( + response.lotes[0].trailerLote.fields.quantidadeRegistrosLote.value, + ).toEqual(2); + expect( + response.trailerArquivo.fields.quantidadeLotesArquivo.value, + ).toEqual(3); + expect( + response.trailerArquivo.fields.quantidadeRegistrosArquivo.value, + ).toEqual(14); + }); + }); }); diff --git a/src/cnab/utils/cnab-utils.ts b/src/cnab/utils/cnab-utils.ts new file mode 100644 index 00000000..0bd393d2 --- /dev/null +++ b/src/cnab/utils/cnab-utils.ts @@ -0,0 +1,260 @@ +import { Exception } from 'handlebars'; +import { CNAB_EOL, CNAB_SUPPORTED_FORMATS } from '../cnab-consts'; +import { CnabAllCodigoRegistro } from '../enums/all/cnab-all-codigo-registro.enum'; +import { ICnabFieldMap } from '../interfaces/cnab-field-map.interface'; +import { CnabField } from '../types/cnab-field.type'; +import { CnabFile, isCnabFile } from '../types/cnab-file.type'; +import { CnabLote, isCnabLote } from '../types/cnab-lote.type'; +import { CnabRegistro } from '../types/cnab-registro.type'; +import { parseField, stringifyCnabField } from './cnab-field-utils'; + +/** + * Validate and stringify Registro + */ +export function stringifyCnabRegistro(registro: CnabRegistro): string { + validateCnabRegistro(registro); + return getCnabFieldList(registro).reduce( + (s, i) => s + stringifyCnabField(i), + '', + ); +} + +export function parseRegistro( + cnab: string, + registro: CnabRegistro, + textStart = 0, +): CnabRegistro { + const regEntries = Object.entries(registro.fields); + const newRegistro: CnabRegistro = { fields: {} }; + for (let i = 0; i < regEntries.length; i++) { + const [key, field] = regEntries[i]; + validateCnabRegistroPosition( + field, + regEntries[i - 1][1], + Boolean(regEntries[i + 1][1]), + ); + newRegistro[key] = parseField(cnab, field, textStart); + } + return newRegistro; +} + +/** + * Get CnabField list sorted ascending by position, from CnabRegistro + */ +export function getCnabFieldList(registro: CnabRegistro): CnabField[] { + const fields = Object.values(registro.fields); + fields.sort((a, b) => a.pos[0] - b.pos[0]); + return fields; +} + +/** + * Run all validations of CnabRegistro + */ +export function validateCnabRegistro(registro: CnabRegistro) { + const fields = getCnabFieldList(registro); + for (const i in fields) { + const field = fields[i]; + validateCnabRegistroPosition( + field, + fields[Number(i) - 1], + Boolean(fields[Number(i) + 1]), + ); + } +} + +/** + * Validates if current item position matches position of previous item. + */ +export function validateCnabRegistroPosition( + current: CnabField, + previous: CnabField | undefined, + hasNext: boolean, +) { + if (!previous && current.pos[0] !== 1) { + throw new Error( + `First CnabField position start should be 1 but is ${current.pos[0]}`, + ); + } + if (!hasNext && !CNAB_SUPPORTED_FORMATS.includes(current.pos[1])) { + throw new Error( + 'Last CnabField position end should be one of these values' + + `${CNAB_SUPPORTED_FORMATS} but is ${current.pos[1]}`, + ); + } else if (previous && current.pos[0] !== previous?.pos[1] + 1) { + throw new Error( + 'Current start and previous end item positions ' + + `should be both ${current.pos[0]} but are: previousEnd: ` + + `${previous.pos[1]}, currentStart: ${current.pos[0]}`, + ); + } +} + +export function getCnabRegistros(cnab: CnabFile | CnabLote): CnabRegistro[] { + const plainRegistros: CnabRegistro[] = []; + + if (isCnabLote(cnab)) { + plainRegistros.push(...getCnabRegistrosFromLote(cnab as CnabLote)); + } else if (isCnabFile(cnab)) { + plainRegistros.push(...getCnabRegistrosFromCnabFile(cnab as CnabFile)); + } else { + throw new Exception('Unsupported object type.'); + } + return plainRegistros; +} + +function getCnabRegistrosFromCnabFile(file: CnabFile): CnabRegistro[] { + return [ + file.headerArquivo, + ...file.lotes.reduce((l, i) => [...l, ...getCnabRegistrosFromLote(i)], []), + file.trailerArquivo, + ]; +} + +function getCnabRegistrosFromLote(lote: CnabLote): CnabRegistro[] { + return [lote.headerLote, ...lote.registros, lote.trailerLote]; +} + +export function stringifyCnabFile(cnab: CnabFile): string { + const treatedCnab = structuredClone(cnab); + processCnabFile(treatedCnab); + return getCnabRegistros(treatedCnab) + .reduce((l, i) => [...l, stringifyCnabRegistro(i)], []) + .join(CNAB_EOL); +} + +/** + * Process data in CnabFile, like sums, countings etc + */ +export function processCnabFile(cnab: CnabFile) { + processCnabHeaderArquivo(cnab); + processCnabLotes(cnab.lotes); + processCnabTrailerArquivo(cnab); +} + +function processCnabHeaderArquivo(cnab: CnabFile) { + setCnabMappedValue( + cnab.headerArquivo, + 'registroIdField', + CnabAllCodigoRegistro.HeaderArquivo, + ); +} + +function processCnabTrailerArquivo(cnab: CnabFile) { + const registrosArq: number = getCnabRegistros(cnab).length; + setCnabMappedValue( + cnab.trailerArquivo, + 'registroIdField', + CnabAllCodigoRegistro.TrailerArquivo, + ); + setCnabMappedValue(cnab.trailerArquivo, 'registroLoteSequenceField', 9999); + setCnabMappedValue( + cnab.trailerArquivo, + 'trailerArquivoRegistroCountField', + registrosArq, + ); + setCnabMappedValue( + cnab.trailerArquivo, + 'trailerArquivoLoteCountField', + cnab.lotes.length, + ); +} + +function processCnabLotes(lotes: CnabLote[]) { + for (let i = 0; i < lotes.length; i++) { + processCnabHeaderLote(lotes, i); + processCnabRegistros(lotes[i], i); + processCnabTrailerLote(lotes, i); + } +} + +function processCnabHeaderLote(lotes: CnabLote[], loteIndex: number) { + setCnabMappedValue( + lotes[loteIndex].headerLote, + 'registroIdField', + CnabAllCodigoRegistro.HeaderLote, + ); + setCnabMappedValue( + lotes[loteIndex].headerLote, + 'registroLoteSequenceField', + loteIndex + 1, + ); +} + +function processCnabTrailerLote(lotes: CnabLote[], loteIndex: number) { + setCnabMappedValue( + lotes[loteIndex].trailerLote, + 'registroIdField', + CnabAllCodigoRegistro.TrailerLote, + ); + setCnabMappedValue( + lotes[loteIndex].trailerLote, + 'registroLoteSequenceField', + loteIndex + 1, + ); + setCnabMappedValue( + lotes[loteIndex].trailerLote, + 'trailerLoteRegistroCountField', + lotes[loteIndex].registros.length, + ); +} + +function processCnabRegistros(lote: CnabLote, loteIndex: number) { + for (let i = 0; i < lote.registros.length; i++) { + setCnabMappedValue( + lote.registros[i], + 'registroIdField', + CnabAllCodigoRegistro.DetalheSegmento, + ); + setCnabMappedValue( + lote.registros[i], + 'registroLoteSequenceField', + loteIndex + 1, + ); + setCnabMappedValue( + lote.registros[i], + 'detalheLoteRegistroSequenceField', + i + 1, + ); + } +} + +/** + * Set value of Registro's CnabField using mapped key + */ +export function setCnabMappedValue( + registro: CnabRegistro, + mapField: keyof ICnabFieldMap, + value: any, +) { + const field = validateCnabMappedField(registro, mapField); + registro.fields[field].value = value; +} + +/** + * Get value of Registro's CnabField using mapped key + */ +export function getCnabMappedValue( + registro: CnabRegistro, + mapField: keyof ICnabFieldMap, +): any { + const field = validateCnabMappedField(registro, mapField); + return registro.fields[field].value; +} + +function validateCnabMappedField( + registro: CnabRegistro, + field: keyof ICnabFieldMap, +): string { + const mapFieldValue = registro.fieldMap?.[field] || ''; + const fieldValue = registro.fields?.[mapFieldValue]; + if (!mapFieldValue) { + throw new Exception('Cnab file should not have any unmapped Registro.'); + } else if (!fieldValue) { + throw new Error( + `Mapped field '${field}: ${mapFieldValue}}, it does not exists in fields: ${Object.keys( + registro.fields, + )}`, + ); + } + return mapFieldValue; +} diff --git a/src/utils/date-utils.ts b/src/utils/date-utils.ts index 95805bf8..d15f05d6 100644 --- a/src/utils/date-utils.ts +++ b/src/utils/date-utils.ts @@ -2,6 +2,7 @@ import { HttpException, HttpStatus } from '@nestjs/common'; import { endOfDay, format, + parse, nextFriday, startOfDay, startOfMonth, @@ -108,9 +109,17 @@ export function getDateYMDString(date: Date): string { * Returns new Date() using allowed date string values. * * And also allows "hh:mm:ss" ( year, month, day values are from now() ); + * + * @param inputFormat date-fns date format. (see {@link https://date-fns.org/v3.3.1/docs/format}) */ -export function stringToDate(value: string, throwIfInvalid = true): Date { - let date = new Date(value); +export function stringToDate( + value: string, + inputFormat?: string, + throwIfInvalid = true, +): Date { + let date = inputFormat + ? parse(value, inputFormat, new Date()) + : new Date(value); if (isNaN(date.getDate())) { date = new Date(`${format(new Date(), 'yyyy-MM-dd')} ${value}`); } diff --git a/src/utils/enum.ts b/src/utils/enum.ts index 74b0f460..8ce7a1d2 100644 --- a/src/utils/enum.ts +++ b/src/utils/enum.ts @@ -1,18 +1,45 @@ -export class Enum { - public static getKey(e: T, value: any): string { - const valueIndex = Object.values(e as any).indexOf(value); - const key = Object.keys(e as any)[valueIndex]; - return key; +/** + * @throws exception if value not exists in enum and there is no defaultValue + */ +function getValue(e: T, value: any, defaultValue?: keyof T): any { + const valueIndex = Object.values(e as any).indexOf(value); + const valueIndexDefault = Object.values(e as any).indexOf(defaultValue); + if (valueIndex === -1 || valueIndexDefault === -1) { + throw new Error(`Value '${value}' does not exist in Enum ${e}.`); } + return e[valueIndex] || e[valueIndexDefault]; +} - public static getKeys(e: T): (keyof T)[] { - const enumType = e; - return Object.keys(enumType as any).filter( - (key) => typeof enumType[key] === 'number', - ) as (keyof T)[]; +function getKey(e: T, value: any): string { + const valueIndex = Object.values(e as any).indexOf(value); + if (valueIndex === -1) { + throw new Error(`Value '${value}' does not exist in Enum ${e}.`); } + const key = Object.keys(e as any)[valueIndex]; + return key; +} - public static getValues(enumType: T): T[keyof T][] { - return this.getKeys(enumType).map((key) => enumType[key]); - } +function findKey(e: T, value: any): string | undefined { + const valueIndex = Object.values(e as any).indexOf(value); + const key: string | undefined = Object.keys(e as any)[valueIndex]; + return key; +} + +function getKeys(e: T): (keyof T)[] { + const enumType = e; + return Object.keys(enumType as any).filter( + (key) => typeof enumType[key] === 'number', + ) as (keyof T)[]; +} + +function getValues(enumType: T): T[keyof T][] { + return this.getKeys(enumType).map((key) => enumType[key]); } + +export const Enum = { + findKey: findKey, + getKey: getKey, + getKeys: getKeys, + getValues: getValues, + getValue: getValue, +}; diff --git a/src/utils/string-utils.ts b/src/utils/string-utils.ts index 2346090d..8a7a3d9e 100644 --- a/src/utils/string-utils.ts +++ b/src/utils/string-utils.ts @@ -6,7 +6,7 @@ export function getStringUpperUnaccent(str: string): string { } export function getStringNoSpecials(str: string) { - return str.replace(/[^a-zA-Z ]/g, ''); + return str.replace(/[^a-zA-Z0-9 ]/g, ''); } /**