br_danfe 0.15.1 → 0.16.0
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.
- checksums.yaml +4 -4
- data/.tool-versions +1 -0
- data/Gemfile.lock +35 -22
- data/Guardfile +2 -2
- data/README.md +23 -0
- data/br_danfe.gemspec +3 -2
- data/lib/br_danfe.rb +1 -1
- data/lib/br_danfe/danfe_lib/nfce.rb +1 -1
- data/lib/br_danfe/danfe_lib/nfe_lib/dest.rb +1 -1
- data/lib/br_danfe/danfe_lib/nfe_lib/emit_header.rb +1 -1
- data/lib/br_danfe/document_builder.rb +1 -1
- data/lib/br_danfe/helper.rb +7 -9
- data/lib/br_danfe/mdfe.rb +55 -0
- data/lib/br_danfe/mdfe_lib/authorization_protocol.rb +24 -0
- data/lib/br_danfe/mdfe_lib/document.rb +26 -0
- data/lib/br_danfe/mdfe_lib/drivers.rb +70 -0
- data/lib/br_danfe/mdfe_lib/fisco_control.rb +40 -0
- data/lib/br_danfe/mdfe_lib/header.rb +78 -0
- data/lib/br_danfe/mdfe_lib/mdfe_identification.rb +69 -0
- data/lib/br_danfe/mdfe_lib/notes.rb +94 -0
- data/lib/br_danfe/mdfe_lib/totalizer.rb +57 -0
- data/lib/br_danfe/mdfe_lib/vehicles.rb +80 -0
- data/lib/br_danfe/qr_code.rb +22 -0
- data/lib/br_danfe/version.rb +1 -1
- data/spec/br_danfe/danfe_lib/nfe_lib/infadic_spec.rb +3 -3
- data/spec/br_danfe/helper_spec.rb +12 -0
- data/spec/br_danfe/mdfe_lib/authorization_protocol_spec.rb +35 -0
- data/spec/br_danfe/mdfe_lib/document_spec.rb +20 -0
- data/spec/br_danfe/mdfe_lib/drivers_spec.rb +88 -0
- data/spec/br_danfe/mdfe_lib/fisco_control_spec.rb +55 -0
- data/spec/br_danfe/mdfe_lib/header_spec.rb +126 -0
- data/spec/br_danfe/mdfe_lib/mdfe_identification_spec.rb +104 -0
- data/spec/br_danfe/mdfe_lib/notes_spec.rb +97 -0
- data/spec/br_danfe/mdfe_lib/totalizer_spec.rb +63 -0
- data/spec/br_danfe/mdfe_lib/vehicles_spec.rb +66 -0
- data/spec/br_danfe/mdfe_spec.rb +46 -0
- data/spec/br_danfe/{danfe_lib/nfce_lib/qr_code_spec.rb → qr_code_spec.rb} +10 -5
- data/spec/fixtures/mdfe/lib/document#render.pdf +0 -0
- data/spec/fixtures/mdfe/lib/document#text.align.pdf +0 -0
- data/spec/fixtures/mdfe/lib/document#text.pad.pdf +0 -0
- data/spec/fixtures/mdfe/lib/document#text.simple.pdf +0 -0
- data/spec/fixtures/mdfe/lib/document#text.size.pdf +0 -0
- data/spec/fixtures/mdfe/lib/document#text.style.pdf +0 -0
- data/spec/fixtures/mdfe/lib/fisco_control#barcode.pdf +0 -0
- data/spec/fixtures/mdfe/lib/header#render-qr-code.pdf +0 -0
- data/spec/fixtures/mdfe/lib/header#render-with_logo.pdf +0 -0
- data/spec/fixtures/mdfe/lib/header#render-without_logo.pdf +0 -0
- data/spec/fixtures/mdfe/lib/mdfe-with-multiple-pages.pdf +1945 -0
- data/spec/fixtures/mdfe/lib/mdfe.fixture.pdf +1286 -0
- data/spec/fixtures/mdfe/lib/notes#render-big-aditional-information.pdf +1943 -0
- data/spec/fixtures/mdfe/lib/xml-mdfe-multiples-pages.xml +116 -0
- data/spec/fixtures/mdfe/lib/xml-mdfe.xml +250 -0
- data/spec/fixtures/qr_code/qr_code#render.pdf +0 -0
- metadata +83 -34
- data/lib/br_danfe/danfe_lib/nfce_lib/qr_code.rb +0 -25
- data/lib/br_danfe/danfe_lib/nfe_lib/cep.rb +0 -11
- data/spec/br_danfe/danfe_lib/nfe_lib/cep_spec.rb +0 -10
@@ -0,0 +1,40 @@
|
|
1
|
+
module BrDanfe
|
2
|
+
module MdfeLib
|
3
|
+
class FiscoControl
|
4
|
+
def initialize(pdf, xml)
|
5
|
+
@pdf = pdf
|
6
|
+
@xml = xml
|
7
|
+
end
|
8
|
+
|
9
|
+
def generate
|
10
|
+
title
|
11
|
+
barcode
|
12
|
+
generate_nfe_key
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def title
|
18
|
+
title = 'CONTROLE DO FISCO'
|
19
|
+
|
20
|
+
@pdf.text_box(title, size: 9, align: :left, at: [250, 600])
|
21
|
+
end
|
22
|
+
|
23
|
+
def barcode
|
24
|
+
barcode = Barby::Code128C.new(nfe_key)
|
25
|
+
barcode.annotate_pdf(@pdf, x: 250, y: 530, height: 50)
|
26
|
+
end
|
27
|
+
|
28
|
+
def nfe_key
|
29
|
+
@xml['mdfeProc > protMDFe > infProt > chMDFe']
|
30
|
+
end
|
31
|
+
|
32
|
+
def generate_nfe_key
|
33
|
+
title = 'Chave de Acesso'
|
34
|
+
|
35
|
+
@pdf.text_box(title, size: 9, align: :left, style: :bold, at: [250, 510])
|
36
|
+
@pdf.text_box(nfe_key, size: 11, align: :left, at: [250, 500])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module BrDanfe
|
2
|
+
module MdfeLib
|
3
|
+
class Header
|
4
|
+
def initialize(pdf, xml, logo, logo_dimensions)
|
5
|
+
@pdf = pdf
|
6
|
+
@xml = xml
|
7
|
+
@logo = logo
|
8
|
+
@logo_dimensions = logo_dimensions
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate
|
12
|
+
generate_emit
|
13
|
+
generate_title
|
14
|
+
qr_code
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def generate_emit
|
20
|
+
if @logo.present?
|
21
|
+
company(x: 90)
|
22
|
+
logo
|
23
|
+
else
|
24
|
+
company(x: 0)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def company(x:)
|
29
|
+
@pdf.bounding_box([x, @pdf.cursor], width: 280, height: 80) do
|
30
|
+
@pdf.text(@xml['emit/xNome'], size: 12, style: :bold, align: :left)
|
31
|
+
@pdf.text(address, align: :left, size: 9)
|
32
|
+
@pdf.text(company_informations, size: 9, align: :left, inline_format: true)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def address
|
37
|
+
formatted = @xml['enderEmit/xLgr'] + ', nº ' + @xml['enderEmit/nro'] + "\n"
|
38
|
+
formatted += @xml['enderEmit/xMun'] + ' - ' + @xml['enderEmit/UF'] + ' ' + 'CEP ' + cep + "\n"
|
39
|
+
formatted
|
40
|
+
end
|
41
|
+
|
42
|
+
def cep
|
43
|
+
Helper.format_cep(@xml['enderEmit/CEP'])
|
44
|
+
end
|
45
|
+
|
46
|
+
def company_informations
|
47
|
+
'<b>CNPJ: </b>' + @xml['emit/CNPJ'] + ' ' + '<b>IE: </b>' + @xml['emit/IE']
|
48
|
+
end
|
49
|
+
|
50
|
+
def logo
|
51
|
+
bounding_box_size = 80
|
52
|
+
logo_options = BrDanfe::Logo::Options.new(bounding_box_size, @logo_dimensions).options
|
53
|
+
|
54
|
+
@pdf.bounding_box([0, 770], width: bounding_box_size, height: bounding_box_size) do
|
55
|
+
@pdf.image @logo, logo_options
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def generate_title
|
60
|
+
title = '<b>DAMDFE</b> - Documento Auxiliar de Manifesto Eletrônico de Documentos Fiscais'
|
61
|
+
|
62
|
+
@pdf.move_down 15
|
63
|
+
@pdf.bounding_box([0, @pdf.cursor], width: 500, height: 20) do
|
64
|
+
@pdf.text(title, size: 12, align: :left, inline_format: true)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def qr_code
|
69
|
+
box_size = 40.mm
|
70
|
+
security_margin = box_size + box_size / 10.0
|
71
|
+
|
72
|
+
@pdf.bounding_box([414, 780], width: security_margin, height: security_margin) do
|
73
|
+
BrDanfe::QrCode.new(pdf: @pdf, xml: @xml, qr_code_tag: @xml['qrCodMDFe'], box_size: box_size).render
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module BrDanfe
|
2
|
+
module MdfeLib
|
3
|
+
class MdfeIdentification
|
4
|
+
def initialize(pdf, xml)
|
5
|
+
@pdf = pdf
|
6
|
+
@xml = xml
|
7
|
+
end
|
8
|
+
|
9
|
+
def generate(page)
|
10
|
+
model
|
11
|
+
series
|
12
|
+
number
|
13
|
+
number_of_pages(page)
|
14
|
+
emitted_at
|
15
|
+
origin_uf
|
16
|
+
destination_uf
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def model
|
22
|
+
generate_box('Modelo', @xml['ide/mod'], 0)
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate_box(title, text, x_position, width = 40)
|
26
|
+
@pdf.move_cursor_to 655
|
27
|
+
|
28
|
+
@pdf.stroke do
|
29
|
+
@pdf.fill_color LIGHT_GRAY_COLOR
|
30
|
+
@pdf.fill_rectangle([x_position, @pdf.cursor], width, 35)
|
31
|
+
@pdf.fill_color BLACK_COLOR
|
32
|
+
end
|
33
|
+
|
34
|
+
@pdf.bounding_box([x_position, @pdf.cursor], width: width, height: 35) do
|
35
|
+
@pdf.move_down 5
|
36
|
+
@pdf.text_box(title, size: 10, at: [3, @pdf.cursor])
|
37
|
+
@pdf.move_down 15
|
38
|
+
@pdf.text_box(text, size: 12, at: [3, @pdf.cursor])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def series
|
43
|
+
generate_box('Série', @xml['ide/serie'], 40)
|
44
|
+
end
|
45
|
+
|
46
|
+
def number
|
47
|
+
generate_box('Número', @xml['ide/nMDF'], 80)
|
48
|
+
end
|
49
|
+
|
50
|
+
def number_of_pages(page)
|
51
|
+
text = page.to_s + '/' + @pdf.page_count.to_s
|
52
|
+
generate_box('FL', text, 125)
|
53
|
+
end
|
54
|
+
|
55
|
+
def emitted_at
|
56
|
+
date = Helper.format_datetime(@xml['dhEmi'])
|
57
|
+
generate_box('Data e hora de Emissão', date, 170, 110)
|
58
|
+
end
|
59
|
+
|
60
|
+
def origin_uf
|
61
|
+
generate_box('UF Carreg.', @xml['ide/UFIni'], 285, 70)
|
62
|
+
end
|
63
|
+
|
64
|
+
def destination_uf
|
65
|
+
generate_box('UF Descarreg.', @xml['ide/UFFim'], 345, 70)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module BrDanfe
|
2
|
+
module MdfeLib
|
3
|
+
class Notes
|
4
|
+
MAX_CHARS_ON_LINE = 120
|
5
|
+
|
6
|
+
def initialize(pdf, xml)
|
7
|
+
@pdf = pdf
|
8
|
+
@xml = xml
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate
|
12
|
+
title
|
13
|
+
aditional_information_first_page
|
14
|
+
aditional_information_taxpayer
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def title
|
20
|
+
title = 'Observações'
|
21
|
+
|
22
|
+
@pdf.move_down 20
|
23
|
+
@pdf.bounding_box [0, @pdf.cursor], width: 278, height: 20 do
|
24
|
+
@pdf.stroke_color GRAY_COLOR
|
25
|
+
@pdf.stroke_horizontal_line(0, 526, at: 6)
|
26
|
+
@pdf.text(title, size: 12, align: :left, style: :bold)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def aditional_information_first_page
|
31
|
+
fisco_information = @xml['infAdic/infAdFisco']
|
32
|
+
|
33
|
+
fisco_information_title = 'INFORMAÇÕES ADICIONAIS DE INTERESSE DO FISCO'
|
34
|
+
taxpayer_information_title = 'INFORMAÇÕES ADICIONAIS DE INTERESSE DO CONTRIBUINTE'
|
35
|
+
|
36
|
+
@pdf.bounding_box([0, @pdf.cursor], width: 526) do
|
37
|
+
if fisco_information.present?
|
38
|
+
@pdf.text(fisco_information_title, size: 10)
|
39
|
+
@pdf.move_down 5
|
40
|
+
@pdf.text(fisco_information, size: 10)
|
41
|
+
@pdf.move_down 10
|
42
|
+
end
|
43
|
+
|
44
|
+
if taxpayer_information_xml.present?
|
45
|
+
@pdf.text(taxpayer_information_title, size: 10)
|
46
|
+
@pdf.move_down 5
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def taxpayer_information_xml
|
52
|
+
@taxpayer_information_xml ||= @xml['infAdic/infCpl']
|
53
|
+
end
|
54
|
+
|
55
|
+
def aditional_information_taxpayer
|
56
|
+
first_page, next_page = fill_aditional_information_taxpayer(@pdf.cursor).values_at(:first_page, :next_page)
|
57
|
+
|
58
|
+
generate_aditional_information_taxpayer(first_page, @pdf.cursor)
|
59
|
+
|
60
|
+
if next_page.present?
|
61
|
+
@pdf.start_new_page
|
62
|
+
generate_aditional_information_taxpayer(next_page, y_position_next_pages)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def fill_aditional_information_taxpayer(height_on_first_page)
|
67
|
+
first_page = ''
|
68
|
+
next_page = ''
|
69
|
+
total_chars = 0
|
70
|
+
total_height = 0
|
71
|
+
|
72
|
+
taxpayer_information_xml.split.each do |word|
|
73
|
+
total_chars += word.split.count + 1
|
74
|
+
|
75
|
+
total_height += 10 if total_chars >= MAX_CHARS_ON_LINE
|
76
|
+
|
77
|
+
total_height <= height_on_first_page ? first_page += word + ' ' : next_page += word + ' '
|
78
|
+
end
|
79
|
+
|
80
|
+
{ first_page: first_page, next_page: next_page }
|
81
|
+
end
|
82
|
+
|
83
|
+
def generate_aditional_information_taxpayer(data, position)
|
84
|
+
@pdf.bounding_box([0, position], width: 526) do
|
85
|
+
@pdf.text(data, size: 10)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def y_position_next_pages
|
90
|
+
600
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module BrDanfe
|
2
|
+
module MdfeLib
|
3
|
+
class Totalizer
|
4
|
+
def initialize(pdf, xml)
|
5
|
+
@pdf = pdf
|
6
|
+
@xml = xml
|
7
|
+
end
|
8
|
+
|
9
|
+
def generate
|
10
|
+
generate_title
|
11
|
+
nfe_quantity
|
12
|
+
cte_quantity
|
13
|
+
total_weight
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def generate_title
|
19
|
+
title = 'Modelo Rodoviário de Carga'
|
20
|
+
|
21
|
+
@pdf.text_box(title, size: 12, align: :left, style: :bold, at: [0, 600])
|
22
|
+
end
|
23
|
+
|
24
|
+
def nfe_quantity
|
25
|
+
generate_box('QTD. NFe', @xml['qNFe'], 65)
|
26
|
+
end
|
27
|
+
|
28
|
+
def generate_box(title, text, x_position, width = 60)
|
29
|
+
@pdf.move_cursor_to 580
|
30
|
+
|
31
|
+
@pdf.stroke do
|
32
|
+
@pdf.fill_color LIGHT_GRAY_COLOR
|
33
|
+
@pdf.fill_rectangle([x_position, @pdf.cursor], width, 35)
|
34
|
+
@pdf.fill_color BLACK_COLOR
|
35
|
+
end
|
36
|
+
|
37
|
+
@pdf.bounding_box([x_position, @pdf.cursor], width: width, height: 35) do
|
38
|
+
@pdf.move_down 5
|
39
|
+
@pdf.text_box(title, size: 10, at: [3, @pdf.cursor])
|
40
|
+
@pdf.move_down 15
|
41
|
+
@pdf.text_box(text, size: 12, at: [3, @pdf.cursor])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def cte_quantity
|
46
|
+
generate_box('QTD. CTe', '', 0)
|
47
|
+
end
|
48
|
+
|
49
|
+
def total_weight
|
50
|
+
weight = ActiveSupport::NumberHelper.number_to_rounded(@xml['qCarga'], precision: 2)
|
51
|
+
weight = Helper.numerify(weight)
|
52
|
+
|
53
|
+
generate_box('Peso total (Kg)', weight, 130, 90)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module BrDanfe
|
2
|
+
module MdfeLib
|
3
|
+
class Vehicles
|
4
|
+
def initialize(pdf, xml)
|
5
|
+
@pdf = pdf
|
6
|
+
@xml = xml
|
7
|
+
end
|
8
|
+
|
9
|
+
def generate
|
10
|
+
@pdf.move_cursor_to 460
|
11
|
+
title
|
12
|
+
table_titles
|
13
|
+
generate_vehicles
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def title
|
19
|
+
title = 'Veículo'
|
20
|
+
|
21
|
+
@pdf.text_box(title, size: 12, align: :left, style: :bold, at: [0, @pdf.cursor])
|
22
|
+
end
|
23
|
+
|
24
|
+
def table_titles
|
25
|
+
plate = 'Placa'
|
26
|
+
rntrc = 'RNTRC'
|
27
|
+
|
28
|
+
@pdf.stroke_color GRAY_COLOR
|
29
|
+
@pdf.move_down 20
|
30
|
+
@pdf.text_box(plate, size: 9, align: :left, at: [0, @pdf.cursor])
|
31
|
+
@pdf.text_box(rntrc, size: 9, align: :left, at: [100, @pdf.cursor])
|
32
|
+
@pdf.move_down 10
|
33
|
+
@pdf.stroke_horizontal_line(0, 190, at: @pdf.cursor)
|
34
|
+
end
|
35
|
+
|
36
|
+
def generate_vehicles
|
37
|
+
@pdf.move_cursor_to 425
|
38
|
+
|
39
|
+
vehicles.each_with_index do |cell, index|
|
40
|
+
@pdf.bounding_box [0, @pdf.cursor], width: 190, height: 20 do
|
41
|
+
@pdf.stroke_color GRAY_COLOR
|
42
|
+
@pdf.dash([2], phase: 6)
|
43
|
+
@pdf.stroke_horizontal_line(0, 190, at: 26) unless index.zero?
|
44
|
+
@pdf.text cell[:content], cell[:options]
|
45
|
+
@pdf.undash
|
46
|
+
@pdf.move_down 20
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def vehicles
|
52
|
+
vehicle = []
|
53
|
+
vehicle += collect_vehicles('veicReboque')
|
54
|
+
vehicle += collect_vehicles('veicTracao')
|
55
|
+
|
56
|
+
vehicle
|
57
|
+
end
|
58
|
+
|
59
|
+
def collect_vehicles(tag)
|
60
|
+
vehicles = []
|
61
|
+
@xml.collect('xmlns', tag) { |rodo| vehicles += vehicle(rodo) }
|
62
|
+
|
63
|
+
vehicles
|
64
|
+
end
|
65
|
+
|
66
|
+
def vehicle(rodo)
|
67
|
+
[
|
68
|
+
cell_text(rodo.css('placa').text)
|
69
|
+
]
|
70
|
+
end
|
71
|
+
|
72
|
+
def cell_text(text, options = {})
|
73
|
+
cell = { content: text, options: { size: 12 } }
|
74
|
+
cell[:options].merge!(options)
|
75
|
+
|
76
|
+
cell
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module BrDanfe
|
2
|
+
class QrCode
|
3
|
+
require 'rqrcode'
|
4
|
+
require 'chunky_png'
|
5
|
+
require 'tempfile'
|
6
|
+
|
7
|
+
def initialize(pdf:, xml:, qr_code_tag:, box_size:)
|
8
|
+
@pdf = pdf
|
9
|
+
@xml = xml
|
10
|
+
@qr_code_tag = qr_code_tag
|
11
|
+
@box_size = box_size
|
12
|
+
end
|
13
|
+
|
14
|
+
def render
|
15
|
+
qrcode = RQRCode::QRCode.new(@qr_code_tag)
|
16
|
+
image = Tempfile.new(%w[qrcode png], binmode: true)
|
17
|
+
image.write(qrcode.as_png(module_px_size: 12).to_s)
|
18
|
+
|
19
|
+
@pdf.image(image, width: @box_size, height: @box_size, position: :center)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|