From f0a206f4d6f1fc433635271039915279c0b477ba Mon Sep 17 00:00:00 2001 From: Lucas Carrias Date: Thu, 10 Jun 2021 16:01:58 -0300 Subject: [PATCH 1/7] Get boleto value in cents --- src/utilities/boleto/index.test.ts | 24 +++++++++++++++++++++++- src/utilities/boleto/index.ts | 14 ++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/utilities/boleto/index.test.ts b/src/utilities/boleto/index.test.ts index af611854..d19f0838 100644 --- a/src/utilities/boleto/index.test.ts +++ b/src/utilities/boleto/index.test.ts @@ -1,4 +1,4 @@ -import { isValid, format, LENGTH } from '.'; +import { isValid, format, getValueInCents, LENGTH } from '.'; describe('isValid', () => { describe('should return false', () => { @@ -144,3 +144,25 @@ describe('format', () => { expect(format('')).toBe(''); }); }); + +describe('getValueInCents', () => { + describe('should return zero', () => { + test('should return zero value when boleto is empty string', () => { + expect(getValueInCents("")).toBe(0); + }); + + test('should return zero value when boleto is invalid', () => { + expect(getValueInCents("00190000090114971860168524522114775860000102656")).toBe(0); + }); + }); + + describe('should return boleto value', () => { + test('should return the value in cents', () => { + expect(getValueInCents("00190000090114971860168524522114675860000102656")).toBe(102656); + }); + + test('should return value in cents when boleto is with mask' ,() => { + expect(getValueInCents("0019000009 01149.718601 68524.522114 6 75860000102656")).toBe(102656); + }); + }) +}); diff --git a/src/utilities/boleto/index.ts b/src/utilities/boleto/index.ts index 54b04053..a5d528c9 100644 --- a/src/utilities/boleto/index.ts +++ b/src/utilities/boleto/index.ts @@ -41,6 +41,10 @@ export const DIGITABLE_LINE_TO_BOLETO_CONVERT_POSITIONS = [ { end: 31, start: 21 }, ]; +export interface Boleto { + value: number; +} + function isValidLength(digitableLine: string): boolean { return digitableLine.length === LENGTH; } @@ -134,3 +138,13 @@ export function format(boleto: string) { return result; }, ''); } + +export function getValueInCents(digitableLine: string): number { + if (!digitableLine || !isValid(digitableLine)) return 0; + + const digits = onlyNumbers(digitableLine); + + const valueStartIndex = digits.length - 10; + + return Number(digits.substr(valueStartIndex)); +} From 8590446a5f7c51024433217364853286f7a0d911 Mon Sep 17 00:00:00 2001 From: Lucas Carrias Date: Thu, 10 Jun 2021 18:00:07 -0300 Subject: [PATCH 2/7] Get boleto expiration date --- src/utilities/boleto/index.test.ts | 36 ++++++++++++++++++++++++------ src/utilities/boleto/index.ts | 12 ++++++++++ 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/utilities/boleto/index.test.ts b/src/utilities/boleto/index.test.ts index d19f0838..5c655e8d 100644 --- a/src/utilities/boleto/index.test.ts +++ b/src/utilities/boleto/index.test.ts @@ -1,4 +1,4 @@ -import { isValid, format, getValueInCents, LENGTH } from '.'; +import { isValid, format, getValueInCents, getExpirationDate, LENGTH } from '.'; describe('isValid', () => { describe('should return false', () => { @@ -148,21 +148,43 @@ describe('format', () => { describe('getValueInCents', () => { describe('should return zero', () => { test('should return zero value when boleto is empty string', () => { - expect(getValueInCents("")).toBe(0); + expect(getValueInCents('')).toBe(0); }); test('should return zero value when boleto is invalid', () => { - expect(getValueInCents("00190000090114971860168524522114775860000102656")).toBe(0); + expect(getValueInCents('00190000090114971860168524522114775860000102656')).toBe(0); }); }); describe('should return boleto value', () => { test('should return the value in cents', () => { - expect(getValueInCents("00190000090114971860168524522114675860000102656")).toBe(102656); + expect(getValueInCents('00190000090114971860168524522114675860000102656')).toBe(102656); }); - test('should return value in cents when boleto is with mask' ,() => { - expect(getValueInCents("0019000009 01149.718601 68524.522114 6 75860000102656")).toBe(102656); + test('should return value in cents when boleto is with mask', () => { + expect(getValueInCents('0019000009 01149.718601 68524.522114 6 75860000102656')).toBe(102656); }); - }) + }); +}); + +describe('getExpirationDate', () => { + describe('should return zero', () => { + test('should return null when boleto is empty string', () => { + expect(getExpirationDate('')).toBe(null); + }); + + test('should return null when boleto is invalid', () => { + expect(getExpirationDate('00190000090114971860168524522114775860000102656')).toBe(null); + }); + }); + + describe('should return boleto value', () => { + test('should return the expiration date', () => { + expect(getExpirationDate('00190000090114971860168524522114675860000102656')).toEqual(new Date(2018, 6, 15)); + }); + + test('should return the expiration date when boleto is with mask', () => { + expect(getExpirationDate('0019000009 01149.718601 68524.522114 6 75860000102656')).toEqual(new Date(2018, 6, 15)); + }); + }); }); diff --git a/src/utilities/boleto/index.ts b/src/utilities/boleto/index.ts index a5d528c9..6796d116 100644 --- a/src/utilities/boleto/index.ts +++ b/src/utilities/boleto/index.ts @@ -43,6 +43,7 @@ export const DIGITABLE_LINE_TO_BOLETO_CONVERT_POSITIONS = [ export interface Boleto { value: number; + expirationDate: Date; } function isValidLength(digitableLine: string): boolean { @@ -148,3 +149,14 @@ export function getValueInCents(digitableLine: string): number { return Number(digits.substr(valueStartIndex)); } + +export function getExpirationDate(digitableLine: string): Date | null { + if (!digitableLine || !isValid(digitableLine)) return null; + + const firstDay = new Date(1997, 9, 7); + + const daysSinceFirstDay = digitableLine.substr(digitableLine.length - 14, 4); + const dateSinceFirstDay = new Date(Number(daysSinceFirstDay) * 24 * 60 * 60 * 1000); + + return new Date(dateSinceFirstDay.getTime() + firstDay.getTime()); +} From 4ce2d3745ecea302358de361b969613a6e31a230 Mon Sep 17 00:00:00 2001 From: Lucas Carrias Date: Thu, 10 Jun 2021 18:15:00 -0300 Subject: [PATCH 3/7] Get boleto bank code --- src/utilities/boleto/index.test.ts | 24 +++++++++++++++++++++++- src/utilities/boleto/index.ts | 6 ++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/utilities/boleto/index.test.ts b/src/utilities/boleto/index.test.ts index 5c655e8d..32ee8368 100644 --- a/src/utilities/boleto/index.test.ts +++ b/src/utilities/boleto/index.test.ts @@ -1,4 +1,4 @@ -import { isValid, format, getValueInCents, getExpirationDate, LENGTH } from '.'; +import { isValid, format, getValueInCents, getExpirationDate, getBankCode, LENGTH } from '.'; describe('isValid', () => { describe('should return false', () => { @@ -188,3 +188,25 @@ describe('getExpirationDate', () => { }); }); }); + +describe('getBankCode', () => { + describe('should return empty string', () => { + test('should return empty string when boleto is empty string', () => { + expect(getBankCode('')).toBe(''); + }); + + test('should return empty string when boleto is invalid', () => { + expect(getBankCode('00190000090114971860168524522114775860000102656')).toBe(''); + }); + }); + + describe('should return bank code value', () => { + test('should return the bank code', () => { + expect(getBankCode('00190000090114971860168524522114675860000102656')).toEqual('001'); + }); + + test('should return the bank code when boleto is with mask', () => { + expect(getBankCode('0019000009 01149.718601 68524.522114 6 75860000102656')).toEqual('001'); + }); + }); +}); diff --git a/src/utilities/boleto/index.ts b/src/utilities/boleto/index.ts index 6796d116..f9278f14 100644 --- a/src/utilities/boleto/index.ts +++ b/src/utilities/boleto/index.ts @@ -160,3 +160,9 @@ export function getExpirationDate(digitableLine: string): Date | null { return new Date(dateSinceFirstDay.getTime() + firstDay.getTime()); } + +export function getBankCode(digitableLine: string): string { + if (!digitableLine || !isValid(digitableLine)) return ''; + + return digitableLine.substr(0, 3); +} \ No newline at end of file From 932eb041af2ca70c3d5a1e5395d7104b9b371799 Mon Sep 17 00:00:00 2001 From: Lucas Carrias Date: Thu, 10 Jun 2021 20:44:13 -0300 Subject: [PATCH 4/7] Get boleto information --- src/index.test.ts | 1 + src/utilities/boleto/index.test.ts | 32 +++++++++++++++++++++++++++++- src/utilities/boleto/index.ts | 17 +++++++++++++--- src/utilities/index.ts | 2 +- 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/index.test.ts b/src/index.test.ts index f8d4baa0..26abe451 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -24,6 +24,7 @@ describe('Public API', () => { 'generateCNPJ', 'formatBoleto', 'isValidBoleto', + 'getBoletoInfo', 'generateChecksum', 'generateRandomNumber', 'getCities', diff --git a/src/utilities/boleto/index.test.ts b/src/utilities/boleto/index.test.ts index 32ee8368..0f75dc15 100644 --- a/src/utilities/boleto/index.test.ts +++ b/src/utilities/boleto/index.test.ts @@ -1,4 +1,4 @@ -import { isValid, format, getValueInCents, getExpirationDate, getBankCode, LENGTH } from '.'; +import { isValid, format, getValueInCents, getExpirationDate, getBankCode, getInfo, LENGTH } from '.'; describe('isValid', () => { describe('should return false', () => { @@ -210,3 +210,33 @@ describe('getBankCode', () => { }); }); }); + +describe('getInfo', () => { + describe('should throw error', () => { + test('should throw error when boleto is empty string', () => { + expect(() => getInfo('')).toThrow('Invalid boleto'); + }); + + test('should throw error when boleto is invalid', () => { + expect(() => getInfo('00190000090114971860168524522114775860000102656')).toThrow('Invalid boleto'); + }); + }); + + describe('should return boleto info', () => { + test('should return the bank code', () => { + expect(getInfo('00190000090114971860168524522114675860000102656')).toStrictEqual({ + valueInCents: 102656, + expirationDate: new Date(2018, 6, 15), + bankCode: '001', + }); + }); + + test('should return the bank code when boleto is with mask', () => { + expect(getInfo('0019000009 01149.718601 68524.522114 6 75860000102656')).toStrictEqual({ + valueInCents: 102656, + expirationDate: new Date(2018, 6, 15), + bankCode: '001', + }); + }); + }); +}); diff --git a/src/utilities/boleto/index.ts b/src/utilities/boleto/index.ts index f9278f14..f53c3182 100644 --- a/src/utilities/boleto/index.ts +++ b/src/utilities/boleto/index.ts @@ -42,8 +42,9 @@ export const DIGITABLE_LINE_TO_BOLETO_CONVERT_POSITIONS = [ ]; export interface Boleto { - value: number; - expirationDate: Date; + valueInCents: number; + expirationDate: Date | null; + bankCode: string; } function isValidLength(digitableLine: string): boolean { @@ -165,4 +166,14 @@ export function getBankCode(digitableLine: string): string { if (!digitableLine || !isValid(digitableLine)) return ''; return digitableLine.substr(0, 3); -} \ No newline at end of file +} + +export function getInfo(digitableLine: string): Boleto { + if (!digitableLine || !isValid(digitableLine)) throw new Error('Invalid boleto'); + + return { + valueInCents: getValueInCents(digitableLine), + expirationDate: getExpirationDate(digitableLine), + bankCode: getBankCode(digitableLine), + }; +} diff --git a/src/utilities/index.ts b/src/utilities/index.ts index 48fdf9e9..fa0faa39 100644 --- a/src/utilities/index.ts +++ b/src/utilities/index.ts @@ -4,7 +4,7 @@ export { isValid as isValidPhone, isValidMobilePhone, isValidLandlinePhone } fro export { isValid as isValidEmail } from './email'; export { format as formatProcessoJuridico, isValid as isValidProcessoJuridico } from './processo-juridico'; export { format as formatCEP, isValid as isValidCEP } from './cep'; -export { format as formatBoleto, isValid as isValidBoleto } from './boleto'; +export { format as formatBoleto, isValid as isValidBoleto, getInfo as getBoletoInfo } from './boleto'; export { format as formatCurrency, parse as parseCurrency } from './currency'; export { format as formatCPF, generate as generateCPF, isValid as isValidCPF } from './cpf'; export { format as formatCNPJ, generate as generateCNPJ, isValid as isValidCNPJ } from './cnpj'; From a54c5d27af5f24b41b1c141a9150b4945a2a4882 Mon Sep 17 00:00:00 2001 From: Lucas Carrias Date: Thu, 10 Jun 2021 21:31:53 -0300 Subject: [PATCH 5/7] Add getBoletoInfo to docs page --- docs/pt-br/utilities.md | 15 +++++++++++++++ docs/utilities.md | 19 +++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/docs/pt-br/utilities.md b/docs/pt-br/utilities.md index b375f313..cf566730 100644 --- a/docs/pt-br/utilities.md +++ b/docs/pt-br/utilities.md @@ -84,6 +84,21 @@ import { isValidBoleto } from '@brazilian-utils/brazilian-utils'; isValidBoleto('00190000090114971860168524522114675860000102656'); // true ``` +## getBoletoInfo + +Retorna informações sobre um boleto válido. + +```javascript +import { getBoletoInfo } from '@brazilian-utils/brazilian-utils'; + +getBoletoInfo('00190000090114971860168524522114675860000102656'); +// { +// valueInCents: 102656, +// expirationDate: 2018-07-15T03:00:00.000Z, +// bankCode: '001' +// } +``` + ## isValidEmail Valida se email é valido. diff --git a/docs/utilities.md b/docs/utilities.md index 09a40031..6b2ad41d 100644 --- a/docs/utilities.md +++ b/docs/utilities.md @@ -28,7 +28,7 @@ formatCPF('746506880', { pad: true }); // 007.465.068-80 Generate a valid random CPF. ```javascript -import { generateCPF } from '@brazilian-utils/brazilian-utils' +import { generateCPF } from '@brazilian-utils/brazilian-utils'; generateCPF(); ``` @@ -69,7 +69,7 @@ isValidCEP('92500000'); // true Generate a valid random CNPJ. ```javascript -import { generateCNPJ } from '@brazilian-utils/brazilian-utils' +import { generateCNPJ } from '@brazilian-utils/brazilian-utils'; generateCNPJ(); ``` @@ -84,6 +84,21 @@ import { isValidBoleto } from '@brazilian-utils/brazilian-utils'; isValidBoleto('00190000090114971860168524522114675860000102656'); // true ``` +## getBoletoInfo + +Get information about a valid boleto ([brazilian payment method](https://en.wikipedia.org/wiki/Boleto)). + +```javascript +import { getBoletoInfo } from '@brazilian-utils/brazilian-utils'; + +getBoletoInfo('00190000090114971860168524522114675860000102656'); +// { +// valueInCents: 102656, +// expirationDate: 2018-07-15T03:00:00.000Z, +// bankCode: '001' +// } +``` + ## isValidEmail Check if email is valid. From b5b38537d3dbd6a6d55ef476f9c5ee5ec6355b0d Mon Sep 17 00:00:00 2001 From: Lucas Carrias Date: Fri, 11 Jun 2021 15:22:37 -0300 Subject: [PATCH 6/7] Refactor code related to getBoletoInfo * Create BANCO_CENTRAL_BASE_DATE constant * Create variables to helper values * Replace .substr() by .slice() method --- src/utilities/boleto/index.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/utilities/boleto/index.ts b/src/utilities/boleto/index.ts index f53c3182..4707fee9 100644 --- a/src/utilities/boleto/index.ts +++ b/src/utilities/boleto/index.ts @@ -41,6 +41,8 @@ export const DIGITABLE_LINE_TO_BOLETO_CONVERT_POSITIONS = [ { end: 31, start: 21 }, ]; +export const BANCO_CENTRAL_BASE_DATE = new Date(1997, 9, 7); + export interface Boleto { valueInCents: number; expirationDate: Date | null; @@ -146,20 +148,24 @@ export function getValueInCents(digitableLine: string): number { const digits = onlyNumbers(digitableLine); - const valueStartIndex = digits.length - 10; + const valueStartIndex = -10; - return Number(digits.substr(valueStartIndex)); + return Number(digits.slice(valueStartIndex)); } export function getExpirationDate(digitableLine: string): Date | null { if (!digitableLine || !isValid(digitableLine)) return null; - const firstDay = new Date(1997, 9, 7); + const daysSinceBaseDayStartIndex = -14; + const daysSinceBaseDayEndIndex = -10; + const daysSinceBaseDay = digitableLine.slice(daysSinceBaseDayStartIndex, daysSinceBaseDayEndIndex); + + const oneDayMiliseconds = 24 * 60 * 60 * 1000; + const milisecondsSinceBaseDay = Number(daysSinceBaseDay) * oneDayMiliseconds; - const daysSinceFirstDay = digitableLine.substr(digitableLine.length - 14, 4); - const dateSinceFirstDay = new Date(Number(daysSinceFirstDay) * 24 * 60 * 60 * 1000); + const dateSinceBaseDay = new Date(milisecondsSinceBaseDay); - return new Date(dateSinceFirstDay.getTime() + firstDay.getTime()); + return new Date(dateSinceBaseDay.getTime() + BANCO_CENTRAL_BASE_DATE.getTime()); } export function getBankCode(digitableLine: string): string { From e8b673b1015bbe9587ff128034fffbb473bd8621 Mon Sep 17 00:00:00 2001 From: Lucas Carrias Date: Fri, 11 Jun 2021 15:32:42 -0300 Subject: [PATCH 7/7] Fix typo in 'milliseconds' variables names --- src/utilities/boleto/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utilities/boleto/index.ts b/src/utilities/boleto/index.ts index 4707fee9..aa3a6e63 100644 --- a/src/utilities/boleto/index.ts +++ b/src/utilities/boleto/index.ts @@ -160,10 +160,10 @@ export function getExpirationDate(digitableLine: string): Date | null { const daysSinceBaseDayEndIndex = -10; const daysSinceBaseDay = digitableLine.slice(daysSinceBaseDayStartIndex, daysSinceBaseDayEndIndex); - const oneDayMiliseconds = 24 * 60 * 60 * 1000; - const milisecondsSinceBaseDay = Number(daysSinceBaseDay) * oneDayMiliseconds; + const oneDayMilliseconds = 24 * 60 * 60 * 1000; + const millisecondsSinceBaseDay = Number(daysSinceBaseDay) * oneDayMilliseconds; - const dateSinceBaseDay = new Date(milisecondsSinceBaseDay); + const dateSinceBaseDay = new Date(millisecondsSinceBaseDay); return new Date(dateSinceBaseDay.getTime() + BANCO_CENTRAL_BASE_DATE.getTime()); }