qqlib-node-boleto 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +11 -0
- package/.eslintignore +1 -0
- package/.eslintrc +10 -0
- package/.idea/encodings.xml +4 -0
- package/.idea/modules.xml +8 -0
- package/.idea/node-boleto.git_master.iml +8 -0
- package/.idea/vcs.xml +7 -0
- package/LICENSE +20 -0
- package/README.md +92 -0
- package/assets/layout.ejs +433 -0
- package/banks/banco do brasil/index.js +172 -0
- package/banks/bradesco/index.js +154 -0
- package/banks/caixa/index.js +66 -0
- package/banks/santander/helper.js +3 -0
- package/banks/santander/index.js +145 -0
- package/examples/bradesco-edi.js +6 -0
- package/examples/bradesco-emission.js +35 -0
- package/examples/retorno.txt +8 -0
- package/examples/santander-edi.js +6 -0
- package/examples/santander-emission.js +32 -0
- package/index.js +12 -0
- package/lib/barcode.js +93 -0
- package/lib/boleto.js +105 -0
- package/lib/edi-helper.js +13 -0
- package/lib/edi-parser.js +7 -0
- package/lib/formatters.js +109 -0
- package/package.json +30 -0
- package/public/images/b.png +0 -0
- package/public/images/bb.png +0 -0
- package/public/images/bradesco.jpg +0 -0
- package/public/images/santander.png +0 -0
- package/public/images/w.png +0 -0
- package/readme.will.md +11 -0
- package/sonar-project.properties +9 -0
- package/test/e2e/boleto-output.js +420 -0
- package/test/e2e/boleto-render.spec.js +104 -0
- package/test/integration/bradesco/boleto.spec.js +216 -0
- package/test/integration/bradesco/edi.spec.js +113 -0
- package/test/integration/caixa/edi.spec.js +99 -0
- package/test/integration/santander/boleto.spec.js +45 -0
- package/test/integration/santander/edi.spec.js +73 -0
- package/test/mocks/banks.js +13 -0
- package/test/mocks/boleto-2018-10-31.js +25 -0
- package/test/mocks/boleto-2018-11-09.js +25 -0
- package/test/unit/boleto-object.spec.js +134 -0
- package/test/unit/boleto-render.spec.js +34 -0
- package/test/unit/formatters.spec.js +62 -0
package/lib/barcode.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
exports.binaryRepresentationForBarcodeData = function (barcodeData) {
|
|
2
|
+
const digits = {
|
|
3
|
+
0: '00110',
|
|
4
|
+
1: '10001',
|
|
5
|
+
2: '01001',
|
|
6
|
+
3: '11000',
|
|
7
|
+
4: '00101',
|
|
8
|
+
5: '10100',
|
|
9
|
+
6: '01100',
|
|
10
|
+
7: '00011',
|
|
11
|
+
8: '10010',
|
|
12
|
+
9: '01010'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (barcodeData.length % 2 !== 0) {
|
|
16
|
+
barcodeData = '0' + barcodeData
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let binaryDigits = '0000'
|
|
20
|
+
// Start of barcode
|
|
21
|
+
for (let i = 0; i < barcodeData.length; i += 2) {
|
|
22
|
+
const digit1 = digits[parseInt(barcodeData[i])]
|
|
23
|
+
const digit2 = digits[parseInt(barcodeData[i + 1])]
|
|
24
|
+
|
|
25
|
+
for (let j = 0; j < digit1.length; j++) {
|
|
26
|
+
binaryDigits += digit1[j] + digit2[j]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// End of barcode
|
|
31
|
+
binaryDigits += '1000'
|
|
32
|
+
|
|
33
|
+
return binaryDigits
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Convert a value to a little endian hexadecimal value
|
|
37
|
+
exports._getLittleEndianHex = function (value) {
|
|
38
|
+
const result = []
|
|
39
|
+
|
|
40
|
+
for (let bytes = 4; bytes > 0; bytes--) {
|
|
41
|
+
result.push(String.fromCharCode(value & 0xff))
|
|
42
|
+
value >>= 0x8
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return result.join('')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
exports._bmpHeader = function (width, height) {
|
|
49
|
+
const numFileBytes = exports._getLittleEndianHex(width * height)
|
|
50
|
+
width = exports._getLittleEndianHex(width)
|
|
51
|
+
height = exports._getLittleEndianHex(height)
|
|
52
|
+
|
|
53
|
+
return 'BM' + // Signature
|
|
54
|
+
numFileBytes + // size of the file (bytes)*
|
|
55
|
+
'\x00\x00' + // reserved
|
|
56
|
+
'\x00\x00' + // reserved
|
|
57
|
+
'\x36\x00\x00\x00' + // offset of where BMP data lives (54 bytes)
|
|
58
|
+
'\x28\x00\x00\x00' + // number of remaining bytes in header from here (40 bytes)
|
|
59
|
+
width + // the width of the bitmap in pixels*
|
|
60
|
+
height + // the height of the bitmap in pixels*
|
|
61
|
+
'\x01\x00' + // the number of color planes (1)
|
|
62
|
+
'\x20\x00' + // 32 bits / pixel
|
|
63
|
+
'\x00\x00\x00\x00' + // No compression (0)
|
|
64
|
+
'\x00\x00\x00\x00' + // size of the BMP data (bytes)*
|
|
65
|
+
'\x13\x0B\x00\x00' + // 2835 pixels/meter - horizontal resolution
|
|
66
|
+
'\x13\x0B\x00\x00' + // 2835 pixels/meter - the vertical resolution
|
|
67
|
+
'\x00\x00\x00\x00' + // Number of colors in the palette (keep 0 for 32-bit)
|
|
68
|
+
'\x00\x00\x00\x00' // 0 important colors (means all colors are important)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
exports.bmpLineForBarcodeData = function (barcodeData) {
|
|
72
|
+
const binaryRepresentation = exports.binaryRepresentationForBarcodeData(barcodeData)
|
|
73
|
+
|
|
74
|
+
let bmpData = []
|
|
75
|
+
let black = true
|
|
76
|
+
let offset = 0
|
|
77
|
+
|
|
78
|
+
for (let i = 0; i < binaryRepresentation.length; i++) {
|
|
79
|
+
const digit = binaryRepresentation[i]
|
|
80
|
+
const color = black ? String.fromCharCode(0, 0, 0, 0) : String.fromCharCode(255, 255, 255, 0)
|
|
81
|
+
let pixelsToDraw = (digit === '0') ? 1 : 3
|
|
82
|
+
|
|
83
|
+
for (let j = 0; j < pixelsToDraw; j++) {
|
|
84
|
+
bmpData[offset++] = color
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
black = !black
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const bmpHeader = exports._bmpHeader(offset - 1, 1)
|
|
91
|
+
const bmpBuffer = new Buffer(bmpHeader + bmpData.join(''), 'binary')
|
|
92
|
+
return bmpBuffer.toString('base64')
|
|
93
|
+
}
|
package/lib/boleto.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const ejs = require('ejs')
|
|
2
|
+
const formatters = require('./formatters')
|
|
3
|
+
const barcode = require('./barcode')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const moment = require('moment')
|
|
6
|
+
|
|
7
|
+
var banks = null
|
|
8
|
+
|
|
9
|
+
var hashString = function (string) {
|
|
10
|
+
var hash = 0
|
|
11
|
+
var i
|
|
12
|
+
var chr
|
|
13
|
+
var len
|
|
14
|
+
|
|
15
|
+
if (string.length == 0) return hash
|
|
16
|
+
for (i = 0, len = string.length; i < len; i++) {
|
|
17
|
+
chr = string.charCodeAt(i)
|
|
18
|
+
hash = ((hash << 5) - hash) + chr
|
|
19
|
+
hash |= 0 // Convert to 32bit integer
|
|
20
|
+
}
|
|
21
|
+
return hash
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var Boleto = function (options) {
|
|
25
|
+
if (!options) {
|
|
26
|
+
throw 'No options provided initializing Boleto.'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.bank = banks[options['banco']]
|
|
30
|
+
if (!this.bank) {
|
|
31
|
+
throw 'Invalid bank.'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!options['data_emissao']) {
|
|
35
|
+
options['data_emissao'] = moment().utc()
|
|
36
|
+
} else {
|
|
37
|
+
options['data_emissao'] = moment(moment(options['data_emissao']).utc().format('YYYY-MM-DD'))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!options['data_vencimento']) {
|
|
41
|
+
options['data_vencimento'] = moment().utc().add('5', 'days')
|
|
42
|
+
} else {
|
|
43
|
+
options['data_vencimento'] = moment(moment(options['data_vencimento']).utc().format('YYYY-MM-DD'))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for (var key in options) {
|
|
47
|
+
this[key] = options[key]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this['pagador'] = formatters.htmlString(this['pagador'])
|
|
51
|
+
this['instrucoes'] = formatters.htmlString(this['instrucoes'])
|
|
52
|
+
|
|
53
|
+
if (!this['local_de_pagamento']) {
|
|
54
|
+
this['local_de_pagamento'] = 'Até o vencimento, preferencialmente no Banco ' + formatters.capitalize(this['banco'])
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this._calculate()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
Boleto.barcodeRenderEngine = 'img'
|
|
61
|
+
|
|
62
|
+
Boleto.prototype._calculate = function () {
|
|
63
|
+
this['codigo_banco'] = this.bank.options.codigo + '-' + formatters.mod11(this.bank.options.codigo)
|
|
64
|
+
this['nosso_numero_dv'] = formatters.mod11(this['nosso_numero'].toString())
|
|
65
|
+
this['barcode_data'] = this.bank.barcodeData(this)
|
|
66
|
+
this['linha_digitavel'] = this.bank.linhaDigitavel(this['barcode_data'])
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Boleto.prototype.renderHTML = function (callback) {
|
|
70
|
+
var self = this
|
|
71
|
+
|
|
72
|
+
var renderOptions = self.bank.options
|
|
73
|
+
renderOptions.boleto = self
|
|
74
|
+
|
|
75
|
+
// Copy renderHelper's methods to renderOptions
|
|
76
|
+
for (var key in formatters) {
|
|
77
|
+
renderOptions[key] = formatters[key]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
renderOptions['barcode_render_engine'] = Boleto.barcodeRenderEngine
|
|
81
|
+
renderOptions['barcode_height'] = '50'
|
|
82
|
+
|
|
83
|
+
if (Boleto.barcodeRenderEngine == 'bmp') {
|
|
84
|
+
renderOptions['barcode_data'] = barcode.bmpLineForBarcodeData(self['barcode_data'])
|
|
85
|
+
} else if (Boleto.barcodeRenderEngine == 'img') {
|
|
86
|
+
renderOptions['barcode_data'] = barcode.binaryRepresentationForBarcodeData(self['barcode_data'])
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
renderOptions['boleto']['linha_digitavel_hash'] = hashString(renderOptions['boleto']['linha_digitavel']).toString()
|
|
90
|
+
|
|
91
|
+
ejs.renderFile(path.join(__dirname, '/../assets/layout.ejs'), renderOptions, {
|
|
92
|
+
cache: true
|
|
93
|
+
}, function (err, html) {
|
|
94
|
+
if (err) {
|
|
95
|
+
throw new Error(err)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
callback(html)
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = function (_banks) {
|
|
103
|
+
banks = _banks
|
|
104
|
+
return Boleto
|
|
105
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
var crypto = require('crypto')
|
|
2
|
+
|
|
3
|
+
exports.calculateLineChecksum = function (line) {
|
|
4
|
+
return crypto.createHash('sha1').update(line).digest('hex')
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
exports.dateFromEdiDate = function (ediDate) {
|
|
8
|
+
const year = ediDate.substring(4, 8)
|
|
9
|
+
const month = ediDate.substring(2, 4)
|
|
10
|
+
const day = ediDate.substring(0, 2)
|
|
11
|
+
|
|
12
|
+
return new Date(parseInt('20' + year), parseInt(month) - 1, parseInt(day))
|
|
13
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const escapeXML = require('ejs').escapeXML
|
|
2
|
+
const moment = require('moment')
|
|
3
|
+
|
|
4
|
+
exports.capitalize = function (string) {
|
|
5
|
+
return string.charAt(0).toUpperCase() + string.slice(1)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
exports.addTrailingZeros = function (string, length) {
|
|
9
|
+
string = string.toString()
|
|
10
|
+
|
|
11
|
+
while (string.length < length) {
|
|
12
|
+
string = '0' + string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
exports.formatAmount = function (amount) {
|
|
19
|
+
amount = amount.toString()
|
|
20
|
+
var cents = exports.addTrailingZeros(amount.substring(amount.length - 2, amount.length), 2)
|
|
21
|
+
var integers = exports.addTrailingZeros(amount.substring(0, amount.length - 2), 1)
|
|
22
|
+
|
|
23
|
+
var newIntegers = ''
|
|
24
|
+
|
|
25
|
+
for (var i = 0; i < integers.length; i++) {
|
|
26
|
+
if (i > 0 && (integers.length - i) % 3 == 0) newIntegers += '.'
|
|
27
|
+
newIntegers += integers[i]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return 'R$ ' + newIntegers + ',' + cents
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
exports.formatDate = function (date) {
|
|
34
|
+
return moment(date).format('DD/MM/YYYY')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
exports.mod11 = function (num, base, r) {
|
|
38
|
+
if (!base) base = 9
|
|
39
|
+
if (!r) r = 0
|
|
40
|
+
|
|
41
|
+
var soma = 0
|
|
42
|
+
var fator = 2
|
|
43
|
+
|
|
44
|
+
for (var i = num.length - 1; i >= 0; i--) {
|
|
45
|
+
var parcial = parseInt(num[i]) * fator
|
|
46
|
+
soma += parcial
|
|
47
|
+
|
|
48
|
+
if (fator == base) {
|
|
49
|
+
fator = 1
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fator++
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (r == 0) {
|
|
56
|
+
soma *= 10
|
|
57
|
+
var digito = soma % 11
|
|
58
|
+
return digito == 10 ? 0 : digito
|
|
59
|
+
} else if (r == 1) {
|
|
60
|
+
return soma % 11
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
exports.mod10 = function (num) {
|
|
65
|
+
var total = 0
|
|
66
|
+
var fator = 2
|
|
67
|
+
|
|
68
|
+
for (var i = num.length - 1; i >= 0; i--) {
|
|
69
|
+
var temp = (parseInt(num[i]) * fator).toString()
|
|
70
|
+
var tempSum = 0
|
|
71
|
+
for (var j = 0; j < temp.length; j++) {
|
|
72
|
+
tempSum += parseInt(temp[j])
|
|
73
|
+
}
|
|
74
|
+
total += tempSum
|
|
75
|
+
fator = (fator == 2) ? 1 : 2
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
var resto = total % 10
|
|
79
|
+
return (resto == 0) ? 0 : (10 - resto)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
exports.fatorVencimento = function (date) {
|
|
83
|
+
const parsedDate = moment(date).utc().format('YYYY-MM-DD')
|
|
84
|
+
const startDate = moment('1997-10-07').utc().format('YYYY-MM-DD')
|
|
85
|
+
|
|
86
|
+
let factor = moment(parsedDate).diff(startDate, 'days')
|
|
87
|
+
|
|
88
|
+
if (factor >= 10000) {
|
|
89
|
+
factor = (factor % 10000) + 1000
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return exports.addTrailingZeros(factor, 4)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
exports.dateFromEdiDate = function (ediDate) {
|
|
96
|
+
return new Date(parseInt(ediDate.substring(4, 8)), parseInt(ediDate.substring(2, 4)) - 1, parseInt(ediDate.substring(0, 2)))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
exports.removeTrailingZeros = function (string) {
|
|
100
|
+
while (string.charAt(0) == '0') {
|
|
101
|
+
string = string.substring(1, string.length)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
exports.htmlString = function (str) {
|
|
108
|
+
return str ? escapeXML(str).replace(/\n/g, '<br/>') : str
|
|
109
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "qqlib-node-boleto",
|
|
3
|
+
"version": "1.0.11",
|
|
4
|
+
"description": "Boleto generator in Node.js",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"lint": "eslint .",
|
|
8
|
+
"test": "nyc --silent --all mocha \"./test/unit/**/*.spec.js\" && nyc --silent --all mocha \"./test/integration/**/*.spec.js\" && nyc --silent --all mocha \"./test/e2e/**/*.spec.js\"",
|
|
9
|
+
"cover-report": "nyc report --reporter=html --reporter=lcov --report-dir=./coverage"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"ejs": "2.5.5"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"chai": "^3.5.0",
|
|
16
|
+
"chai-datetime": "^1.4.1",
|
|
17
|
+
"chai-string": "^1.3.0",
|
|
18
|
+
"chai-subset": "^1.4.0",
|
|
19
|
+
"eslint": "^3.12.2",
|
|
20
|
+
"eslint-config-standard": "^6.2.1",
|
|
21
|
+
"eslint-plugin-promise": "^3.3.0",
|
|
22
|
+
"eslint-plugin-standard": "^2.0.1",
|
|
23
|
+
"mocha": "^3.2.0",
|
|
24
|
+
"moment": "https://github.com/pagarme/moment/archive/0.0.5.tar.gz",
|
|
25
|
+
"nyc": "15.1.0",
|
|
26
|
+
"ramda": "^0.23.0"
|
|
27
|
+
},
|
|
28
|
+
"license": "MIT"
|
|
29
|
+
|
|
30
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/readme.will.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
sonar.organization=pagarme
|
|
2
|
+
sonar.projectKey=node-boleto
|
|
3
|
+
sonar.projectName=node-boleto
|
|
4
|
+
sonar.projectVersion=1.0
|
|
5
|
+
sonar.sources=.
|
|
6
|
+
sonar.sourceEncoding=UTF-8
|
|
7
|
+
sonar.javascript.lcov.reportPaths=lcov.info
|
|
8
|
+
sonar.tests=test
|
|
9
|
+
sonar.exclusions=**/node_modules/**,test/**
|