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.
Files changed (43) hide show
  1. data/.gitignore +7 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +4 -0
  4. data/README.md +122 -0
  5. data/Rakefile +28 -0
  6. data/lib/ruby_danfe.rb +1 -325
  7. data/lib/ruby_danfe/cst.rb +28 -0
  8. data/lib/ruby_danfe/dacte_generator.rb +511 -0
  9. data/lib/ruby_danfe/danfe_generator.rb +287 -0
  10. data/lib/ruby_danfe/danfe_nfce_generator.rb +237 -0
  11. data/lib/ruby_danfe/descricao.rb +44 -0
  12. data/lib/ruby_danfe/document.rb +80 -0
  13. data/lib/ruby_danfe/helper.rb +68 -0
  14. data/lib/ruby_danfe/options.rb +24 -0
  15. data/lib/ruby_danfe/railtie.rb +20 -0
  16. data/lib/ruby_danfe/ruby_danfe.rb +49 -0
  17. data/lib/ruby_danfe/version.rb +3 -0
  18. data/lib/ruby_danfe/xml.rb +58 -0
  19. data/ruby_danfe.gemspec +26 -11
  20. data/spec/features/ruby_danfe_spec.rb +59 -0
  21. data/spec/fixtures/4_decimals_nfe_simples_nacional.xml +1 -0
  22. data/spec/fixtures/cte.xml +1 -0
  23. data/spec/fixtures/nfe_date_format_infoadprod_infoadfisco_issues.xml +42 -0
  24. data/spec/fixtures/nfe_simples_nacional.xml +1 -0
  25. data/spec/fixtures/nfe_with_fci.xml +1 -0
  26. data/spec/fixtures/nfe_with_ns.xml +4 -0
  27. data/spec/fixtures/nfe_without_ns.xml +2 -0
  28. data/spec/lib/cst_spec.rb +51 -0
  29. data/spec/lib/descricao_spec.rb +129 -0
  30. data/spec/lib/helper_spec.rb +88 -0
  31. data/spec/lib/options_spec.rb +13 -0
  32. data/spec/lib/ruby_danfe_spec.rb +43 -0
  33. data/spec/spec_helper.rb +21 -0
  34. data/spec/support/be_same_file_as.rb +9 -0
  35. data/test/danfe.xml +42 -0
  36. data/test/generate.rb +8 -0
  37. data/test/generate_nfce.rb +8 -0
  38. data/test/nfce.xml +147 -0
  39. data/test/nfe_simples_nacional.xml +1 -0
  40. data/test/nfe_with_fci.xml +1 -0
  41. data/test/nfe_with_ns.xml +4 -0
  42. data/test/nfe_without_ns.xml +2 -0
  43. 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