Skip to content

Commit

Permalink
wip: stringify/parse cnab
Browse files Browse the repository at this point in the history
  • Loading branch information
yxuo committed Feb 22, 2024
1 parent 08fe640 commit e4c3f12
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 28 deletions.
12 changes: 12 additions & 0 deletions src/cnab/cnab-field-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,4 +476,16 @@ describe('cnab-utils.ts', () => {
expect(result).toThrowError();
});
});

// describe('parseField()', () => {
// it('should parse text from index 0', () => {
// // Arrange
// const text = '123 1234567890' + ' '.repeat(220);
// const registro: CnabRegistro = {
// a: { picture: '9(2)V9', pos: [1, 3], value: '' },
// };

// // Act
// });
// });
});
21 changes: 20 additions & 1 deletion src/cnab/cnab-field-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,27 @@ export function validateCnabFieldPositionSize(item: CnabField) {
}
}

function getPictureTotalSize(item: CnabField) {
export function getPictureTotalSize(item: CnabField) {
return getCnabFieldType(item) === CnabFieldType.Text
? getPictureTextSize(item.picture)
: ((i = getPictureNumberSize(item.picture)) => i.decimal + i.integer)();
}

/**
* Remember:
* - CnabField position start starts counting from 1, not zero.
* - To represent size = 1 the position must be [1,1], [8,8] etc.
* - To represent size = 2 the position must be [1,2], [8,9] etc.
*/
export function parseField(
cnab: string,
field: CnabField,
textStart = 0,
): CnabField {
const start = textStart + field.pos[0] - 1;
const end = textStart + field.pos[0] + field.pos[1];
return {
...field,
value: cnab.slice(start, end),
};
}
6 changes: 3 additions & 3 deletions src/cnab/cnab-remessa.service.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { Injectable } from '@nestjs/common';
import { CnabFile } from './types/cnab-file.type';
import { getPlainRegistros, getRegistroLine } from './cnab-utils';
import { getCnabRegistros, stringifyRegistro } from './cnab-utils';

@Injectable()
export class CnabRemessaService {
/**
* Generate CNAB Remessa text content from CnabFile
*/
generateRemessaCnab(cnab: CnabFile): string {
const plainCnab = getPlainRegistros(cnab);
const plainCnab = getCnabRegistros(cnab);
const cnabTextList: string[] = [];
for (const registro of plainCnab) {
cnabTextList.push(getRegistroLine(registro));
cnabTextList.push(stringifyRegistro(registro));
}
const CNAB_EOL = '\r\n';
return cnabTextList.join(CNAB_EOL);
Expand Down
27 changes: 17 additions & 10 deletions src/cnab/cnab-utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
getPlainRegistros,
getRegistroLine,
getCnabRegistros,
stringifyRegistro,
validateRegistroPosition,
} from './cnab-utils';
import { ICnabRegistroFieldMap } from './interfaces/cnab-registro-field-map.interface';
Expand All @@ -15,7 +15,14 @@ import { CnabRegistro } from './types/cnab-registro.type';
process.env.TZ = 'UTC';

describe('cnab-utils.ts', () => {
describe('getRegistroLine()', () => {
// describe('stringifyCnabFile()', () => {
// it('should return text version of CnabFile accordingly', () => {
// // Arrange
// const cnab: CnabFile
// });
// });

describe('stringifyRegistro()', () => {
it('should return text version of Registro accordingly', () => {
// Arrange
const registro: CnabRegistro = {
Expand All @@ -26,7 +33,7 @@ describe('cnab-utils.ts', () => {
};

// Act
const result = getRegistroLine(registro);
const result = stringifyRegistro(registro);

// Assert
expect(result).toEqual('10400013A' + ' '.repeat(231));
Expand All @@ -42,7 +49,7 @@ describe('cnab-utils.ts', () => {
};

// Act
const result = () => getRegistroLine(registro);
const result = () => stringifyRegistro(registro);

// Assert
expect(result).toThrowError();
Expand Down Expand Up @@ -195,7 +202,7 @@ describe('cnab-utils.ts', () => {
});
});

describe('getPlainRegistros()', () => {
describe('getCnabRegistros()', () => {
const fields: Record<string, CnabField>[] = [
{ a: { picture: 'X(1)', pos: [1, 1], value: ' ' } },
{ b: { picture: 'X(2)', pos: [1, 2], value: ' ' } },
Expand Down Expand Up @@ -242,7 +249,7 @@ describe('cnab-utils.ts', () => {
};

// Act
const result = getPlainRegistros(lote);
const result = getCnabRegistros(lote);

// Assert
expect(result).toEqual(registros);
Expand Down Expand Up @@ -275,7 +282,7 @@ describe('cnab-utils.ts', () => {
};

// Act
const result = getPlainRegistros(lote);
const result = getCnabRegistros(lote);

// Assert
expect(result).toEqual([
Expand Down Expand Up @@ -319,7 +326,7 @@ describe('cnab-utils.ts', () => {
};

// Act
const result = getPlainRegistros(file);
const result = getCnabRegistros(file);

// Assert
expect(result).toEqual(registros);
Expand Down Expand Up @@ -359,7 +366,7 @@ describe('cnab-utils.ts', () => {
};

// Act
const result = getPlainRegistros(file);
const result = getCnabRegistros(file);

// Assert
expect(result).toEqual([
Expand Down
57 changes: 43 additions & 14 deletions src/cnab/cnab-utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Exception } from 'handlebars';
import { CNAB_SUPPORTED_FORMATS } from './cnab-consts';
import { getCnabPictureValue } from './cnab-field-utils';
import { getCnabPictureValue, parseField } from './cnab-field-utils';
import { CnabField } from './types/cnab-field.type';
import {
CnabFileMapped,
Expand All @@ -17,7 +17,7 @@ import { CnabRegistro } from './types/cnab-registro.type';
/**
* Convert CNAB Registro into CNAB file line
*/
export function getRegistroLine(registro: CnabRegistro) {
export function stringifyRegistro(registro: CnabRegistro) {
let line = '';
const registros = Object.values(registro);
for (const i in registros) {
Expand All @@ -32,6 +32,25 @@ export function getRegistroLine(registro: CnabRegistro) {
return line;
}

export function parseRegistro(
cnab: string,
registro: CnabRegistro,
textStart = 0,
): CnabRegistro {
const regEntries = Object.entries(registro);
const newRegistro: CnabRegistro = {};
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.
*/
Expand All @@ -42,7 +61,7 @@ export function validateRegistroPosition(
) {
if (!previous && current.pos[0] !== 1) {
throw new Error(
`First CnabField position start should be 0 but is ${current.pos[0]}`,
`First CnabField position start should be 1 but is ${current.pos[0]}`,
);
}
if (!hasNext && !CNAB_SUPPORTED_FORMATS.includes(current.pos[1])) {
Expand All @@ -59,58 +78,68 @@ export function validateRegistroPosition(
}
}

export function getPlainRegistros(
export function getCnabRegistros(
cnab: CnabFile | CnabFileMapped | CnabLote | CnabLoteMapped,
): CnabRegistro[] {
const plainRegistros: CnabRegistro[] = [];

if (isCnabLote(cnab)) {
plainRegistros.push(...getPlainRegistrosFromLote(cnab as CnabLote));
plainRegistros.push(...getCnabRegistrosFromLote(cnab as CnabLote));
} else if (isCnabLoteMapped(cnab)) {
plainRegistros.push(
...getPlainRegistrosFromLoteMapped(cnab as CnabLoteMapped),
...getCnabRegistrosFromLoteMapped(cnab as CnabLoteMapped),
);
} else if (isCnabFile(cnab)) {
plainRegistros.push(...getPlainRegistrosFromCnabFile(cnab as CnabFile));
plainRegistros.push(...getCnabRegistrosFromCnabFile(cnab as CnabFile));
} else if (isCnabFileMapped(cnab)) {
plainRegistros.push(
...getPlainRegistrosFromCnabFileMapped(cnab as CnabFileMapped),
...getCnabRegistrosFromCnabFileMapped(cnab as CnabFileMapped),
);
} else {
throw new Exception('Unsupported object type.');
}
return plainRegistros;
}

function getPlainRegistrosFromCnabFile(file: CnabFile): CnabRegistro[] {
function getCnabRegistrosFromCnabFile(file: CnabFile): CnabRegistro[] {
return [
file.headerArquivo,
...file.lotes.reduce((l, i) => [...l, ...getPlainRegistrosFromLote(i)], []),
...file.lotes.reduce((l, i) => [...l, ...getCnabRegistrosFromLote(i)], []),
file.trailerArquivo,
];
}

function getPlainRegistrosFromCnabFileMapped(
function getCnabRegistrosFromCnabFileMapped(
file: CnabFileMapped,
): CnabRegistro[] {
return [
file.headerArquivo.registro,
...file.lotes.reduce(
(l, i) => [...l, ...getPlainRegistrosFromLoteMapped(i)],
(l, i) => [...l, ...getCnabRegistrosFromLoteMapped(i)],
[],
),
file.trailerArquivo.registro,
];
}

function getPlainRegistrosFromLote(lote: CnabLote): CnabRegistro[] {
function getCnabRegistrosFromLote(lote: CnabLote): CnabRegistro[] {
return [lote.headerLote, ...lote.registros, lote.trailerLote];
}

function getPlainRegistrosFromLoteMapped(lote: CnabLoteMapped): CnabRegistro[] {
function getCnabRegistrosFromLoteMapped(lote: CnabLoteMapped): CnabRegistro[] {
return [
lote.headerLote.registro,
...lote.registros.reduce((l, i) => [...l, i.registro], []),
lote.trailerLote.registro,
];
}

export function stringifyCnab(cnab: CnabFile | CnabFileMapped): string {
return getCnabRegistros(cnab)
.reduce((l, i) => [...l, stringifyRegistro(i)], [])
.join('\r\n');
}

// export function parseCnab(str: string): CnabFile {

// }

0 comments on commit e4c3f12

Please sign in to comment.