ruby_danfe 0.9.0 → 1.11.5
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.
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/README.md +122 -0
- data/Rakefile +28 -0
- data/lib/ruby_danfe.rb +1 -325
- data/lib/ruby_danfe/cst.rb +28 -0
- data/lib/ruby_danfe/dacte_generator.rb +511 -0
- data/lib/ruby_danfe/danfe_generator.rb +287 -0
- data/lib/ruby_danfe/danfe_nfce_generator.rb +237 -0
- data/lib/ruby_danfe/descricao.rb +44 -0
- data/lib/ruby_danfe/document.rb +80 -0
- data/lib/ruby_danfe/helper.rb +68 -0
- data/lib/ruby_danfe/options.rb +24 -0
- data/lib/ruby_danfe/railtie.rb +20 -0
- data/lib/ruby_danfe/ruby_danfe.rb +49 -0
- data/lib/ruby_danfe/version.rb +3 -0
- data/lib/ruby_danfe/xml.rb +58 -0
- data/ruby_danfe.gemspec +26 -11
- data/spec/features/ruby_danfe_spec.rb +59 -0
- data/spec/fixtures/4_decimals_nfe_simples_nacional.xml +1 -0
- data/spec/fixtures/cte.xml +1 -0
- data/spec/fixtures/nfe_date_format_infoadprod_infoadfisco_issues.xml +42 -0
- data/spec/fixtures/nfe_simples_nacional.xml +1 -0
- data/spec/fixtures/nfe_with_fci.xml +1 -0
- data/spec/fixtures/nfe_with_ns.xml +4 -0
- data/spec/fixtures/nfe_without_ns.xml +2 -0
- data/spec/lib/cst_spec.rb +51 -0
- data/spec/lib/descricao_spec.rb +129 -0
- data/spec/lib/helper_spec.rb +88 -0
- data/spec/lib/options_spec.rb +13 -0
- data/spec/lib/ruby_danfe_spec.rb +43 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/support/be_same_file_as.rb +9 -0
- data/test/danfe.xml +42 -0
- data/test/generate.rb +8 -0
- data/test/generate_nfce.rb +8 -0
- data/test/nfce.xml +147 -0
- data/test/nfe_simples_nacional.xml +1 -0
- data/test/nfe_with_fci.xml +1 -0
- data/test/nfe_with_ns.xml +4 -0
- data/test/nfe_without_ns.xml +2 -0
- metadata +167 -75
@@ -0,0 +1,287 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module RubyDanfe
|
3
|
+
class DanfeGenerator
|
4
|
+
def initialize(xml)
|
5
|
+
@xml = xml
|
6
|
+
@pdf = Document.new
|
7
|
+
@vol = 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def generatePDF
|
11
|
+
@pdf.repeat :all do
|
12
|
+
render_canhoto
|
13
|
+
render_emitente
|
14
|
+
render_titulo
|
15
|
+
render_faturas
|
16
|
+
render_calculo_do_imposto
|
17
|
+
render_transportadora_e_volumes
|
18
|
+
render_cabecalho_dos_produtos
|
19
|
+
render_calculo_do_issqn
|
20
|
+
render_dados_adicionais
|
21
|
+
end
|
22
|
+
|
23
|
+
render_produtos
|
24
|
+
|
25
|
+
@pdf.page_count.times do |i|
|
26
|
+
@pdf.go_to_page(i + 1)
|
27
|
+
@pdf.ibox 1.00, 3.08, 7.71, 5.54, '',
|
28
|
+
"FOLHA #{i + 1} de #{@pdf.page_count}", {:size => 8, :align => :center, :valign => :center, :border => 0, :style => :bold}
|
29
|
+
end
|
30
|
+
|
31
|
+
@pdf
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def render_canhoto
|
36
|
+
@pdf.ibox 0.85, 16.10, 0.25, 0.42, "RECEBEMOS DE " + @xml['emit/xNome'] + " OS PRODUTOS CONSTANTES DA NOTA FISCAL INDICADA ABAIXO"
|
37
|
+
@pdf.ibox 0.85, 4.10, 0.25, 1.27, "DATA DE RECEBIMENTO"
|
38
|
+
@pdf.ibox 0.85, 12.00, 4.35, 1.27, "IDENTIFICAÇÃO E ASSINATURA DO RECEBEDOR"
|
39
|
+
|
40
|
+
@pdf.ibox 1.70, 4.50, 16.35, 0.42, '',
|
41
|
+
"NF-e\n" +
|
42
|
+
"N°. " + @xml['ide/nNF'] + "\n" +
|
43
|
+
"SÉRIE " + @xml['ide/serie'], {:align => :center, :valign => :center}
|
44
|
+
end
|
45
|
+
|
46
|
+
def render_emitente
|
47
|
+
@pdf.ibox 3.92, 7.46, 0.25, 2.54, '',
|
48
|
+
@xml['emit/xNome'] + "\n" +
|
49
|
+
@xml['enderEmit/xLgr'] + ", " + @xml['enderEmit/nro'] + "\n" +
|
50
|
+
@xml['enderEmit/xBairro'] + " - " + @xml['enderEmit/CEP'] + "\n" +
|
51
|
+
@xml['enderEmit/xMun'] + "/" + @xml['enderEmit/UF'] + "\n" +
|
52
|
+
@xml['enderEmit/fone'] + " " + @xml['enderEmit/email'], {:align => :center, :valign => :center}
|
53
|
+
|
54
|
+
@pdf.ibox 3.92, 3.08, 7.71, 2.54
|
55
|
+
|
56
|
+
@pdf.ibox 0.60, 3.08, 7.71, 2.54, '', "DANFE", {:size => 12, :align => :center, :border => 0, :style => :bold}
|
57
|
+
@pdf.ibox 1.20, 3.08, 7.71, 3.14, '', "DOCUMENTO AUXILIAR DA NOTA FISCAL ELETRÔNICA", {:size => 8, :align => :center, :border => 0}
|
58
|
+
@pdf.ibox 0.60, 3.08, 7.71, 4.34, '', "#{@xml['ide/tpNF']} - " + (@xml['ide/tpNF'] == '0' ? 'ENTRADA' : 'SAÍDA'), {:size => 8, :align => :center, :border => 0}
|
59
|
+
|
60
|
+
@pdf.ibox 1.00, 3.08, 7.71, 4.94, '',
|
61
|
+
"N°. " + @xml['ide/nNF'] + "\n" +
|
62
|
+
"SÉRIE " + @xml['ide/serie'], {:size => 8, :align => :center, :valign => :center, :border => 0, :style => :bold}
|
63
|
+
|
64
|
+
@pdf.ibox 2.20, 10.02, 10.79, 2.54
|
65
|
+
@pdf.ibarcode 1.50, 8.00, 10.9010, 4.44, @xml['chNFe']
|
66
|
+
@pdf.ibox 0.85, 10.02, 10.79, 4.74, "CHAVE DE ACESSO", @xml['chNFe'].gsub(/(\d)(?=(\d\d\d\d)+(?!\d))/, "\\1 "), {:style => :bold, :align => :center}
|
67
|
+
@pdf.ibox 0.85, 10.02, 10.79, 5.60 , '', "Consulta de autenticidade no portal nacional da NF-e www.nfe.fazenda.gov.br/portal ou no site da Sefaz Autorizadora", {:align => :center, :size => 8}
|
68
|
+
@pdf.ibox 0.85, 10.54, 0.25, 6.46, "NATUREZA DA OPERAÇÃO", @xml['ide/natOp']
|
69
|
+
@pdf.ibox 0.85, 10.02, 10.79, 6.46, "PROTOCOLO DE AUTORIZAÇÃO DE USO", @xml['infProt/nProt'] + ' ' + Helper.format_datetime(@xml['infProt/dhRecbto']) , {:align => :center}
|
70
|
+
@pdf.ibox 0.85, 6.86, 0.25, 7.31, "INSCRIÇÃO ESTADUAL", @xml['emit/IE']
|
71
|
+
@pdf.ibox 0.85, 6.86, 7.11, 7.31, "INSC.ESTADUAL DO SUBST. TRIBUTÁRIO", @xml['emit/IE_ST']
|
72
|
+
@pdf.ibox 0.85, 6.84, 13.97, 7.31, "CNPJ", @xml['emit/CNPJ']
|
73
|
+
end
|
74
|
+
|
75
|
+
def render_titulo
|
76
|
+
@pdf.ititle 0.42, 10.00, 0.25, 8.16, "DESTINATÁRIO / REMETENTE"
|
77
|
+
|
78
|
+
@pdf.ibox 0.85, 12.32, 0.25, 8.58, "NOME/RAZÃO SOCIAL", @xml['dest/xNome']
|
79
|
+
@pdf.ibox 0.85, 5.33, 12.57, 8.58, "CNPJ/CPF", @xml['dest/CNPJ'] if @xml['dest/CNPJ'] != ''
|
80
|
+
@pdf.ibox 0.85, 5.33, 12.57, 8.58, "CNPJ/CPF", @xml['dest/CPF'] if @xml['dest/CPF'] != ''
|
81
|
+
@pdf.ibox 0.85, 2.92, 17.90, 8.58, "DATA DA EMISSÃO", (not @xml['ide/dEmi'].empty?) ? Helper.format_date(@xml['ide/dEmi']) : Helper.format_date(@xml['ide/dhEmi']) , {:align => :right}
|
82
|
+
@pdf.ibox 0.85, 10.16, 0.25, 9.43, "ENDEREÇO", @xml['enderDest/xLgr'] + " " + @xml['enderDest/nro']
|
83
|
+
@pdf.ibox 0.85, 4.83, 10.41, 9.43, "BAIRRO", @xml['enderDest/xBairro']
|
84
|
+
@pdf.ibox 0.85, 2.67, 15.24, 9.43, "CEP", @xml['enderDest/CEP']
|
85
|
+
@pdf.ibox 0.85, 2.92, 17.90, 9.43, "DATA DA SAÍDA/ENTRADA", (not @xml['ide/dSaiEnt'].empty?) ? Helper.format_date(@xml['ide/dSaiEnt']) : Helper.format_date(@xml['ide/dhSaiEnt']), {:align => :right}
|
86
|
+
@pdf.ibox 0.85, 7.11, 0.25, 10.28, "MUNICÍPIO", @xml['enderDest/xMun']
|
87
|
+
@pdf.ibox 0.85, 4.06, 7.36, 10.28, "FONE/FAX", @xml['enderDest/fone']
|
88
|
+
@pdf.ibox 0.85, 1.14, 11.42, 10.28, "UF", @xml['enderDest/UF']
|
89
|
+
@pdf.ibox 0.85, 5.33, 12.56, 10.28, "INSCRIÇÃO ESTADUAL", @xml['dest/IE']
|
90
|
+
@pdf.ibox 0.85, 2.92, 17.90, 10.28, "HORA DE SAÍDA", Helper.format_time(@xml['ide/hSaiEnt']), {:align => :right}
|
91
|
+
@pdf.ibox 0.85, 2.92, 17.90, 10.28, "HORA DE SAÍDA", (not @xml['ide/hSaiEnt'].empty?) ? Helper.format_time(@xml['ide/hSaiEnt']) : Helper.extract_time_from_date(@xml['ide/dhSaiEnt']) , {:align => :right}
|
92
|
+
end
|
93
|
+
|
94
|
+
def render_faturas
|
95
|
+
@pdf.ititle 0.42, 10.00, 0.25, 11.12, "FATURA / DUPLICATAS"
|
96
|
+
@pdf.ibox 0.85, 20.57, 0.25, 11.51
|
97
|
+
|
98
|
+
x = 0.25
|
99
|
+
y = 11.51
|
100
|
+
@xml.collect('xmlns', 'dup') do |det|
|
101
|
+
@pdf.ibox 0.85, 2.12, x, y, '', 'Núm.:', { :size => 6, :border => 0, :style => :italic }
|
102
|
+
@pdf.ibox 0.85, 2.12, x + 0.70, y, '', det.css('nDup').text, { :size => 6, :border => 0 }
|
103
|
+
@pdf.ibox 0.85, 2.12, x, y + 0.20, '', 'Venc.:', { :size => 6, :border => 0, :style => :italic }
|
104
|
+
dtduplicata = det.css('dVenc').text
|
105
|
+
dtduplicata = dtduplicata[8,2] + '/' + dtduplicata[5, 2] + '/' + dtduplicata[0, 4]
|
106
|
+
@pdf.ibox 0.85, 2.12, x + 0.70, y + 0.20, '', dtduplicata, { :size => 6, :border => 0 }
|
107
|
+
@pdf.ibox 0.85, 2.12, x, y + 0.40, '', 'Valor: R$', { :size => 6, :border => 0, :style => :italic }
|
108
|
+
@pdf.inumeric 0.85, 1.25, x + 0.70, y + 0.40, '', det.css('vDup').text, { :size => 6, :border => 0 }
|
109
|
+
x = x + 2.30
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def render_calculo_do_imposto
|
114
|
+
@pdf.ititle 0.42, 5.60, 0.25, 12.36, "CÁLCULO DO IMPOSTO"
|
115
|
+
|
116
|
+
@pdf.inumeric 0.85, 4.06, 0.25, 12.78, "BASE DE CÁLCULO DO ICMS", @xml['ICMSTot/vBC']
|
117
|
+
@pdf.inumeric 0.85, 4.06, 4.31, 12.78, "VALOR DO ICMS", @xml['ICMSTot/vICMS']
|
118
|
+
@pdf.inumeric 0.85, 4.06, 8.37, 12.78, "BASE DE CÁLCULO DO ICMS ST", @xml['ICMSTot/vBCST']
|
119
|
+
@pdf.inumeric 0.85, 4.06, 12.43, 12.78, "VALOR DO ICMS ST", @xml['ICMSTot/vST']
|
120
|
+
@pdf.inumeric 0.85, 4.32, 16.49, 12.78, "VALOR TOTAL DOS PRODUTOS", @xml['ICMSTot/vProd']
|
121
|
+
@pdf.inumeric 0.85, 3.46, 0.25, 13.63, "VALOR DO FRETE", @xml['ICMSTot/vFrete']
|
122
|
+
@pdf.inumeric 0.85, 3.46, 3.71, 13.63, "VALOR DO SEGURO", @xml['ICMSTot/vSeg']
|
123
|
+
@pdf.inumeric 0.85, 3.46, 7.17, 13.63, "DESCONTO", @xml['ICMSTot/vDesc']
|
124
|
+
@pdf.inumeric 0.85, 3.46, 10.63, 13.63, "OUTRAS DESPESAS ACESSORIAS", @xml['ICMSTot/vOutro']
|
125
|
+
@pdf.inumeric 0.85, 3.46, 14.09, 13.63, "VALOR DO IPI", @xml['ICMSTot/vIPI']
|
126
|
+
@pdf.inumeric 0.85, 3.27, 17.55, 13.63, "VALOR TOTAL DA NOTA", @xml['ICMSTot/vNF'], :style => :bold
|
127
|
+
end
|
128
|
+
|
129
|
+
def render_transportadora_e_volumes
|
130
|
+
@pdf.ititle 0.42, 10.00, 0.25, 14.48, "TRANSPORTADOR / VOLUMES TRANSPORTADOS"
|
131
|
+
|
132
|
+
@pdf.ibox 0.85, 9.02, 0.25, 14.90, "RAZÃO SOCIAL", @xml['transporta/xNome']
|
133
|
+
@pdf.ibox 0.85, 2.79, 9.27, 14.90, "FRETE POR CONTA", @xml['transp/modFrete'] == '0' ? ' 0 - EMITENTE' : '1 - DEST.'
|
134
|
+
@pdf.ibox 0.85, 1.78, 12.06, 14.90, "CODIGO ANTT", @xml['veicTransp/RNTC']
|
135
|
+
@pdf.ibox 0.85, 2.29, 13.84, 14.90, "PLACA DO VEÍCULO", @xml['veicTransp/placa']
|
136
|
+
@pdf.ibox 0.85, 0.76, 16.13, 14.90, "UF", @xml['veicTransp/UF']
|
137
|
+
@pdf.ibox 0.85, 3.94, 16.89, 14.90, "CNPJ/CPF", @xml['transporta/CNPJ']
|
138
|
+
@pdf.ibox 0.85, 9.02, 0.25, 15.75, "ENDEREÇO", @xml['transporta/xEnder']
|
139
|
+
@pdf.ibox 0.85, 6.86, 9.27, 15.75, "MUNICÍPIO", @xml['transporta/xMun']
|
140
|
+
@pdf.ibox 0.85, 0.76, 16.13, 15.75, "UF", @xml['transporta/UF']
|
141
|
+
@pdf.ibox 0.85, 3.94, 16.89, 15.75, "INSCRIÇÂO ESTADUAL", @xml['transporta/IE']
|
142
|
+
|
143
|
+
@vol = 0
|
144
|
+
@xml.collect('xmlns', 'vol') do |det|
|
145
|
+
@vol += 1
|
146
|
+
if @vol < 2
|
147
|
+
@pdf.ibox 0.85, 2.92, 0.25, 16.60, "QUANTIDADE", det.css('qVol').text
|
148
|
+
@pdf.ibox 0.85, 3.05, 3.17, 16.60, "ESPÉCIE", det.css('esp').text
|
149
|
+
@pdf.ibox 0.85, 3.05, 6.22, 16.60, "MARCA", det.css('marca').text
|
150
|
+
@pdf.ibox 0.85, 4.83, 9.27, 16.60, "NUMERAÇÃO"
|
151
|
+
@pdf.inumeric 0.85, 3.43, 14.10, 16.60, "PESO BRUTO", det.css('pesoB').text, {:decimals => 3}
|
152
|
+
@pdf.inumeric 0.85, 3.30, 17.53, 16.60, "PESO LÍQUIDO", det.css('pesoL').text, {:decimals => 3}
|
153
|
+
else
|
154
|
+
break
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def render_cabecalho_dos_produtos
|
160
|
+
@pdf.ititle 0.42, 10.00, 0.25, 17.45, "DADOS DO PRODUTO / SERVIÇO"
|
161
|
+
|
162
|
+
@pdf.ibox 6.70, 2.00, 0.25, 17.87, "CÓDIGO"
|
163
|
+
@pdf.ibox 6.70, 4.90, 2.25, 17.87, "DESCRIÇÃO"
|
164
|
+
@pdf.ibox 6.70, 1.30, 7.15, 17.87, "NCM"
|
165
|
+
@pdf.ibox 6.70, 0.80, 8.45, 17.87, "CST"
|
166
|
+
@pdf.ibox 6.70, 1.00, 9.25, 17.87, "CFOP"
|
167
|
+
@pdf.ibox 6.70, 1.00, 10.25, 17.87, "UNID"
|
168
|
+
@pdf.ibox 6.70, 1.30, 11.25, 17.87, "QUANT"
|
169
|
+
@pdf.ibox 6.70, 1.50, 12.55, 17.87, "VALOR UNIT"
|
170
|
+
@pdf.ibox 6.70, 1.50, 14.05, 17.87, "VALOR TOT"
|
171
|
+
@pdf.ibox 6.70, 1.50, 15.55, 17.87, "BASE CÁLC"
|
172
|
+
@pdf.ibox 6.70, 1.00, 17.05, 17.87, "VL ICMS"
|
173
|
+
@pdf.ibox 6.70, 1.00, 18.05, 17.87, "VL IPI"
|
174
|
+
@pdf.ibox 6.70, 0.90, 19.05, 17.87, "% ICMS"
|
175
|
+
@pdf.ibox 6.70, 0.86, 19.95, 17.87, "% IPI"
|
176
|
+
|
177
|
+
@pdf.horizontal_line 0.25.cm, 20.83.cm, :at => Helper.invert(18.17.cm)
|
178
|
+
end
|
179
|
+
|
180
|
+
def render_calculo_do_issqn
|
181
|
+
@pdf.ititle 0.42, 10.00, 0.25, 24.64, "CÁLCULO DO ISSQN"
|
182
|
+
|
183
|
+
@pdf.ibox 0.85, 5.08, 0.25, 25.06, "INSCRIÇÃO MUNICIPAL", @xml['emit/IM']
|
184
|
+
@pdf.ibox 0.85, 5.08, 5.33, 25.06, "VALOR TOTAL DOS SERVIÇOS", @xml['total/vServ']
|
185
|
+
@pdf.ibox 0.85, 5.08, 10.41, 25.06, "BASE DE CÁLCULO DO ISSQN", @xml['total/vBCISS']
|
186
|
+
@pdf.ibox 0.85, 5.28, 15.49, 25.06, "VALOR DO ISSQN", @xml['total/ISSTot']
|
187
|
+
end
|
188
|
+
|
189
|
+
def render_dados_adicionais
|
190
|
+
@pdf.ititle 0.42, 10.00, 0.25, 25.91, "DADOS ADICIONAIS"
|
191
|
+
inf_ad_fisco_y = 0
|
192
|
+
|
193
|
+
if @vol > 1
|
194
|
+
@pdf.ibox 3.07, 12.93, 0.25, 26.33, "INFORMAÇÕES COMPLEMENTARES", '', {:size => 8, :valign => :top}
|
195
|
+
@pdf.ibox 3.07, 12.93, 0.25, 26.60, '', 'CONTINUAÇÃO TRANSPORTADOR/VOLUMES TRANSPORTADOS', {:size => 5, :valign => :top, :border => 0}
|
196
|
+
v = 0
|
197
|
+
y = 26.67
|
198
|
+
@xml.collect('xmlns', 'vol') do |det|
|
199
|
+
v += 1
|
200
|
+
if v > 1
|
201
|
+
@pdf.ibox 0.35, 0.70, 0.25, y + 0.10, '', 'QUANT.:', { :size => 4, :border => 0 }
|
202
|
+
@pdf.ibox 0.35, 0.70, 0.90, y + 0.10, '', det.css('qVol').text, { :size => 4, :border => 0, :style => :italic }
|
203
|
+
@pdf.ibox 0.35, 0.50, 1.35, y + 0.10, '', 'ESP.:', { :size => 4, :border => 0 }
|
204
|
+
@pdf.ibox 0.35, 3.00, 1.75, y + 0.10, '', det.css('esp').text, { :size => 4, :border => 0, :style => :italic }
|
205
|
+
@pdf.ibox 0.35, 0.70, 4.15, y + 0.10, '', 'MARCA:', { :size => 4, :border => 0 }
|
206
|
+
@pdf.ibox 0.35, 2.00, 4.75, y + 0.10, '', det.css('marca').text, { :size => 4, :border => 0, :style => :italic }
|
207
|
+
@pdf.ibox 0.35, 1.00, 6.10, y + 0.10, '', 'NUM.:', { :size => 4, :border => 0 }
|
208
|
+
@pdf.ibox 0.35, 1.30, 7.00, y + 0.10, '', 'PESO B.:', { :size => 4, :border => 0 }
|
209
|
+
@pdf.inumeric 0.35, 1.30, 7.00, y + 0.10, '', det.css('pesoB').text, {:decimals => 3, :size => 4, :border => 0, :style => :italic }
|
210
|
+
@pdf.ibox 0.35, 0.90, 8.50, y + 0.10, '', 'PESO LÍQ.:', { :size => 4, :border => 0 }
|
211
|
+
@pdf.inumeric 0.35, 1.50, 8.50, y + 0.10, '', det.css('pesoL').text, {:decimals => 3, :size => 4, :border => 0, :style => :italic }
|
212
|
+
y = y + 0.15
|
213
|
+
end
|
214
|
+
end
|
215
|
+
@pdf.ibox 2.07, 12.93, 0.25, y + 0.30, '', 'OUTRAS INFORMAÇÕES', {:size => 6, :valign => :top, :border => 0}
|
216
|
+
@pdf.ibox 2.07, 12.93, 0.25, y + 0.50, '', @xml['infAdic/infCpl'], {:size => 5, :valign => :top, :border => 0}
|
217
|
+
|
218
|
+
if @xml['infAdic/infCpl'] == ""
|
219
|
+
inf_ad_fisco_y = y + 0.50
|
220
|
+
else
|
221
|
+
inf_ad_fisco_y = y + 0.100
|
222
|
+
end
|
223
|
+
|
224
|
+
@pdf.ibox 2.07, 12.93, 0.25, inf_ad_fisco_y, '', @xml['infAdic/infAdFisco'], {:size => 5, :valign => :top, :border => 0}
|
225
|
+
|
226
|
+
else
|
227
|
+
if @xml['infAdic/infCpl'] == ""
|
228
|
+
inf_ad_fisco_y = 26.60
|
229
|
+
else
|
230
|
+
inf_ad_fisco_y = 27.33
|
231
|
+
end
|
232
|
+
|
233
|
+
@pdf.ibox 3.07, 12.93, 0.25, 26.33, "INFORMAÇÕES COMPLEMENTARES", @xml['infAdic/infCpl'], {:size => 6, :valign => :top}
|
234
|
+
@pdf.ibox 3.07, 12.93, 0.25, inf_ad_fisco_y, "", @xml['infAdic/infAdFisco'], {:size => 6, :valign => :top, :border => 0}
|
235
|
+
end
|
236
|
+
|
237
|
+
@pdf.ibox 3.07, 7.62, 13.17, 26.33, "RESERVADO AO FISCO"
|
238
|
+
end
|
239
|
+
|
240
|
+
def render_produtos
|
241
|
+
@pdf.font_size(6) do
|
242
|
+
@pdf.itable 6.37, 21.50, 0.25, 18.17,
|
243
|
+
@xml.collect('xmlns', 'det') { |det|
|
244
|
+
[
|
245
|
+
det.css('prod/cProd').text, #I02
|
246
|
+
Descricao.generate(det), #I04
|
247
|
+
#{}" ",
|
248
|
+
det.css('prod/NCM').text, #I05
|
249
|
+
Cst.to_danfe(det), #N11
|
250
|
+
det.css('prod/CFOP').text, #I08
|
251
|
+
det.css('prod/uCom').text, #I09
|
252
|
+
Helper.format_quantity(det.css('prod/qCom').text),
|
253
|
+
Helper.numerify(det.css('prod/vUnCom').text), #I10a
|
254
|
+
Helper.numerify(det.css('prod/vProd').text), #I11
|
255
|
+
Helper.numerify(det.css('ICMS/*/vBC').text), #N15
|
256
|
+
Helper.numerify(det.css('ICMS/*/vICMS').text), #N17
|
257
|
+
Helper.numerify(det.css('IPI/*/vIPI').text), #O14
|
258
|
+
Helper.numerify(det.css('ICMS/*/pICMS').text), #N16
|
259
|
+
Helper.numerify(det.css('IPI/*/pIPI').text) #O13
|
260
|
+
]
|
261
|
+
},
|
262
|
+
:column_widths => {
|
263
|
+
0 => 2.00.cm,
|
264
|
+
1 => 4.90.cm,
|
265
|
+
2 => 1.30.cm,
|
266
|
+
3 => 0.80.cm,
|
267
|
+
4 => 1.00.cm,
|
268
|
+
5 => 1.00.cm,
|
269
|
+
6 => 1.30.cm,
|
270
|
+
7 => 1.50.cm,
|
271
|
+
8 => 1.50.cm,
|
272
|
+
9 => 1.50.cm,
|
273
|
+
10 => 1.00.cm,
|
274
|
+
11 => 1.00.cm,
|
275
|
+
12 => 0.90.cm,
|
276
|
+
13 => 0.86.cm
|
277
|
+
},
|
278
|
+
:cell_style => {:padding => 2, :border_width => 0} do |table|
|
279
|
+
@pdf.dash(5);
|
280
|
+
table.column(6..13).style(:align => :right)
|
281
|
+
table.column(0..13).border_width = 1
|
282
|
+
table.column(0..13).borders = [:bottom]
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
# encoding:utf-8
|
2
|
+
|
3
|
+
module RubyDanfe
|
4
|
+
class DanfeNfceGenerator
|
5
|
+
def initialize(xml)
|
6
|
+
@xml = xml
|
7
|
+
@pdf = Document.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def generatePDF
|
11
|
+
@pdf.repeat :all do
|
12
|
+
render_cabecalho
|
13
|
+
render_info_fixas
|
14
|
+
render_detalhes_venda
|
15
|
+
render_totais
|
16
|
+
render_tributos
|
17
|
+
render_mensagem_fiscal
|
18
|
+
render_consumidor
|
19
|
+
render_qrcode
|
20
|
+
end
|
21
|
+
|
22
|
+
render_produtos
|
23
|
+
|
24
|
+
@pdf
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def render_cabecalho
|
29
|
+
|
30
|
+
# ibox(h, w, x, y, title = '', info = '', options = {})
|
31
|
+
|
32
|
+
@pdf.ibox 3, 12, 0.9, 1
|
33
|
+
|
34
|
+
@pdf.ibox 2.85, 3, 1.5, 2, "", "NFC-e", {:size => 12, :align => :center, :border => 0, :style => :bold}
|
35
|
+
|
36
|
+
@pdf.ibox 4.92, 7, 4, 0, '',
|
37
|
+
@xml['emit/xNome'] + "\n" +
|
38
|
+
"CNPJ: " + @xml['emit/CNPJ'] + "\n" +
|
39
|
+
@xml['enderEmit/xLgr'] + ", " + @xml['enderEmit/nro'] + "\n" +
|
40
|
+
@xml['enderEmit/xBairro']+ " " + "-" + " " + @xml['enderEmit/xMun'] + "/" + @xml['enderEmit/UF'] + "\n" +
|
41
|
+
"Fone: " + @xml['enderEmit/fone'] + "\n" +
|
42
|
+
"CEP: " + @xml['enderEmit/CEP'] + " - " + "IE: " + @xml['emit/IE'], {:align => :center, :valign => :center, size: 8, border: 0}
|
43
|
+
end
|
44
|
+
|
45
|
+
def render_info_fixas
|
46
|
+
@pdf.ibox 2, 12, 0.9, 4, '',
|
47
|
+
"DANFE NFC-e - Documento Auxiliar da Nota Fiscal Eletrônica" + "\n" + "para Consumidor Final" + "\n \n" +
|
48
|
+
"Não permite aproveitamento de crédito de ICMS", {align: :center, :valign => :center, size: 8}
|
49
|
+
end
|
50
|
+
|
51
|
+
def render_detalhes_venda
|
52
|
+
render_cabecalho_dos_produtos
|
53
|
+
|
54
|
+
totais = @xml.css('total')
|
55
|
+
|
56
|
+
@pdf.inumeric 0.70, 4, 0.9, 15.8, "Subtotal", totais.css('vProd').text, {:size => 6}
|
57
|
+
@pdf.inumeric 0.70, 4, 4.9, 15.8, "Desconto", totais.css('vDesc').text, {:size => 6}
|
58
|
+
@pdf.inumeric 0.70, 4, 8.9, 15.8, "Troco", totais.css('vTroco').text, {:size => 6}
|
59
|
+
end
|
60
|
+
|
61
|
+
def render_cabecalho_dos_produtos
|
62
|
+
@pdf.ibox 9.55, 1.3, 0.9, 6.1, "CÓDIGO", "",{:size => 8, :align => :center, :style => :bold}
|
63
|
+
@pdf.ibox 9.55, 1.3, 2.2, 6.1, "UNIDADE"
|
64
|
+
@pdf.ibox 9.55, 5.1, 3.5, 6.1, "DESCRIÇÃO"
|
65
|
+
@pdf.ibox 9.55, 1.3, 8.6, 6.1, "QUANT"
|
66
|
+
@pdf.ibox 9.55, 1.5, 9.9, 6.1, "VALOR UNIT"
|
67
|
+
@pdf.ibox 9.55, 1.5, 11.4, 6.1, "VALOR TOTAL"
|
68
|
+
|
69
|
+
@pdf.horizontal_line 26, 365, at: 630
|
70
|
+
end
|
71
|
+
|
72
|
+
def render_produtos
|
73
|
+
@pdf.font_size(6) do
|
74
|
+
@pdf.itable 9.37, 21.50, 0.9, 6.6,
|
75
|
+
@xml.collect('xmlns', 'det') { |det|
|
76
|
+
[
|
77
|
+
det.css('prod/cProd').text, # CÓDIGO
|
78
|
+
det.css('prod/uCom').text, # UNIDADE
|
79
|
+
det.css('prod/xProd').text, # DESCRICAO
|
80
|
+
Helper.numerify(det.css('prod/qCom').text), # QUANTIDADE
|
81
|
+
Helper.numerify(det.css('prod/vUnCom').text), # VALOR UNIT
|
82
|
+
Helper.numerify(det.css('prod/vProd').text), # VALOR TOTAL
|
83
|
+
]
|
84
|
+
},
|
85
|
+
:column_widths => {
|
86
|
+
0 => 1.30.cm,
|
87
|
+
1 => 1.30.cm,
|
88
|
+
2 => 5.10.cm,
|
89
|
+
3 => 1.30.cm,
|
90
|
+
4 => 1.50.cm,
|
91
|
+
5 => 1.50.cm
|
92
|
+
},
|
93
|
+
:cell_style => {:padding => 2, :border_width => 0} do |table|
|
94
|
+
table.column(6..13).style(:align => :right)
|
95
|
+
table.column(0..13).border_width = 1
|
96
|
+
table.column(0..13).borders = [:bottom]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_produtos(produto, row = [])
|
102
|
+
row << produto.css('cProd').text
|
103
|
+
row << produto.css('uCom').text
|
104
|
+
row << produto.css('xProd').text
|
105
|
+
row << produto.css('qCom').text
|
106
|
+
row << produto.css('vUnCom').text
|
107
|
+
row << produto.css('vProd').text
|
108
|
+
return row
|
109
|
+
end
|
110
|
+
|
111
|
+
def render_totais
|
112
|
+
qtde_produtos = @xml.css('det').count
|
113
|
+
forma_pgto = get_forma_pgto
|
114
|
+
valor_total = Helper.numerify(@xml.css('total').css('vProd').text)
|
115
|
+
vlr_pago = Helper.numerify(@xml.css('vPag').text)
|
116
|
+
|
117
|
+
@pdf.ibox 2, 12, 0.9, 16.7, '',
|
118
|
+
"QTD. TOTAL DE ITENS: #{qtde_produtos}" + "\n" + "FORMA DE PAGAMENTO: #{forma_pgto}" + "\n" + "VALOR TOTAL (R$): #{valor_total}" + "\n" + "VALOR PAGO (R$): #{vlr_pago}", {align: :right, valign: :right, size: 6, border: 0, style: :bold}
|
119
|
+
end
|
120
|
+
|
121
|
+
def get_forma_pgto
|
122
|
+
cod_forma_pgto = @xml.css('tPag').text
|
123
|
+
case cod_forma_pgto
|
124
|
+
when "01" then "Dinheiro"
|
125
|
+
when "02" then "Cheque"
|
126
|
+
when "03" then "Cartão de Crédito"
|
127
|
+
when "04" then "Cartão de Débito"
|
128
|
+
when "05" then "Crédito Loja"
|
129
|
+
when "10" then "Vale Alimentação"
|
130
|
+
when "11" then "Vale Refeição"
|
131
|
+
when "12" then "Vale Presente"
|
132
|
+
when "13" then "Vale Combustível"
|
133
|
+
when "99" then "Outros"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def render_tributos
|
138
|
+
totais = @xml.css('total')
|
139
|
+
soma_tributos = totais.css('vII').text.to_f + totais.css('vIPI').text.to_f + totais.css('vIPI').text.to_f + totais.css('vPIS').text.to_f
|
140
|
+
+ totais.css('vCOFINS').text.to_f + totais.css('vOutro').text.to_f
|
141
|
+
|
142
|
+
@pdf.ibox 0.9, 12, 0.9, 18, 'Tributos',
|
143
|
+
"Informação dos Tributos Totais Incidentes (Lei Federal 12.741 /2012): #{soma_tributos}", {align: :center, :valign => :center, size: 7}
|
144
|
+
end
|
145
|
+
|
146
|
+
def render_mensagem_fiscal
|
147
|
+
numero_nota = @xml.css('nNF').text
|
148
|
+
serie = @xml.css('serie').text
|
149
|
+
data = @xml.css('dhEmi').text
|
150
|
+
data_emissao = Date.parse(data).strftime('%d/%m/%Y %I:%M:%S')
|
151
|
+
|
152
|
+
chave_acesso = get_chave
|
153
|
+
cabecalho = ""
|
154
|
+
|
155
|
+
tipo_emissao = @xml.css('tpEmis')
|
156
|
+
if tipo_emissao != nil && tipo_emissao.text != "1"
|
157
|
+
cabecalho = "EMITIDA EM CONTINGENCIA" + "\n \n"
|
158
|
+
end
|
159
|
+
|
160
|
+
@pdf.ibox 3, 12, 0.9, 18.9, 'Mensagem Fiscal',
|
161
|
+
"#{cabecalho}" +
|
162
|
+
"Número #{numero_nota} | Série #{serie} | Emissão #{data_emissao} - Via Consumidor" +
|
163
|
+
"\n \n" + "Consulte pela Chave de Acesso em sistemas.sefaz.am.gov.br/nfceweb/formConsulta.do" +
|
164
|
+
"\n \n" + "CHAVE DE ACESSO:" +
|
165
|
+
"\n \n" + chave_acesso + "\n", {align: :center, :valign => :center, size: 7}
|
166
|
+
end
|
167
|
+
|
168
|
+
def get_chave
|
169
|
+
chave = @xml.css('infNFe').attr("Id").value.gsub(/^(NFe|CTe)/, "")
|
170
|
+
return "%s %s %s %s %s %s %s %s %s %s %s" %[chave[0..3], chave[4..7], chave[8..11], chave[12..15], chave[16..19], chave[20..23], chave[24..27], chave[28..31], chave[32..35], chave[36..39], chave[40..43]]
|
171
|
+
end
|
172
|
+
|
173
|
+
def render_consumidor
|
174
|
+
consumidor = @xml.xpath("//dest")
|
175
|
+
cpf = @xml.regex_string(consumidor.to_s.downcase, "//cpf").text
|
176
|
+
nome = @xml.regex_string(consumidor.to_s.downcase, "//xnome").text.split.map(&:capitalize).join(' ')
|
177
|
+
|
178
|
+
endereco = @xml.regex_string(consumidor.to_s.downcase, "//xlgr").text + " - " + @xml.regex_string(consumidor.to_s.downcase, "//xbairro").text
|
179
|
+
endereco += " - " + @xml.regex_string(consumidor.to_s.downcase, "//xmun").text + " - " + @xml.regex_string(consumidor.to_s.downcase, "//uf").text
|
180
|
+
endereco = endereco.split.map(&:capitalize).join(' ')
|
181
|
+
|
182
|
+
if consumidor.any?
|
183
|
+
consumidor_msg = cpf.empty? ? "" : "CNPJ/CPF/ID Estrangeiro - #{cpf} - "
|
184
|
+
consumidor_msg += nome
|
185
|
+
consumidor_msg += "\n" + endereco
|
186
|
+
else
|
187
|
+
consumidor_msg = "CONSUMIDOR NÃO IDENTIFICADO"
|
188
|
+
end
|
189
|
+
|
190
|
+
@pdf.ibox 1.3, 12, 0.9, 21.9, 'Consumidor',
|
191
|
+
consumidor_msg, {align: :center, :valign => :top, size: 7}
|
192
|
+
end
|
193
|
+
|
194
|
+
def render_qrcode
|
195
|
+
@pdf.ibox 0.7, 12, 0.9, 23.3, '', ''
|
196
|
+
#@pdf.iqrcode 1.7, 8.2, 6.5, 25, get_qrcode_url
|
197
|
+
|
198
|
+
data = @xml.css('dhRecbto').text
|
199
|
+
data_receb = Date.parse(data).strftime('%d/%m/%Y %I:%M:%S')
|
200
|
+
|
201
|
+
protocolo = @xml.css('nProt').text
|
202
|
+
@pdf.draw_text "\n" + "Protocolo de Autorização: #{protocolo} - Data: #{data_receb}", at: [100, 140], :size => 6
|
203
|
+
end
|
204
|
+
|
205
|
+
def get_qrcode_url
|
206
|
+
ender_consulta = get_ender_consulta
|
207
|
+
end
|
208
|
+
|
209
|
+
def get_ender_consulta
|
210
|
+
tipo_ambiente = @xml.css('tpAmb')
|
211
|
+
uf = @xml.css('emit').css('UF').text.upcase
|
212
|
+
url = ""
|
213
|
+
|
214
|
+
if tipo_ambiente == "2" # HOMOLOGAÇÃO
|
215
|
+
case uf
|
216
|
+
when "AC" then return "http://www.sefaznet.ac.gov.br/nfe/NFe.jsp?opc=3"
|
217
|
+
when "AM" then return "http://sistemas.sefaz.am.gov.br/nfceweb/consultarNFCe.jsp?"
|
218
|
+
when "MA" then return "http://www.nfce.sefaz.ma.gov.br/portal/consultarNFCe.jsp"
|
219
|
+
when "MT" then return "http://www.sefaz.mt.gov.br/nfe/portal/consultanfce"
|
220
|
+
when "RN" then return "http://www.nfe.rn.gov.br/portal/consultarNFCe.jsp?"
|
221
|
+
when "RS" then return "https://www.sefaz.rs.gov.br/NFCE/NFCE-COM.aspx"
|
222
|
+
when "SE" then return "http://www.nfe.se.gov.br/portal/consultarNFCe.jsp?"
|
223
|
+
end
|
224
|
+
else # PRODUÇÃO
|
225
|
+
case uf
|
226
|
+
when "AC" then return "http://hml.sefaznet.ac.gov.br"
|
227
|
+
when "AM" then return "http://homnfe.sefaz.am.gov.br/nfceweb/consultarNFCe.jsp?"
|
228
|
+
when "MA" then return "http://www.hom.nfce.sefaz.ma.gov.br/portal/consultarNFCe.jsp"
|
229
|
+
when "MT" then return "http://www.hom.nfe.sefaz.mt.gov.br/portal/consultarNFCe.jsp"
|
230
|
+
when "RN" then return "http://www.hom.nfe.rn.gov.br/portal/consultarNFCe.jsp?"
|
231
|
+
when "RS" then return "https://www.sefaz.rs.gov.br/NFCE/NFCE-COM.aspx"
|
232
|
+
when "SE" then return "http://www.hom.nfe.se.gov.br/portal/consultarNFCe.jsp?"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|