sefaz 0.2.0 → 1.4.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/CHANGELOG.md +121 -0
  4. data/Gemfile.lock +77 -20
  5. data/README.md +449 -17
  6. data/Rakefile +1 -0
  7. data/docs/CFe-SAT/Especificacao_SAT_v_ER_2_30_03.pdf +0 -0
  8. data/docs/CFe-SAT/Manual_Orientacao_SAT_v_MO_2_19_04.pdf +0 -0
  9. data/docs/CFe-SAT/Manual_do_Emulador_SAT-CF-e_Offline_2015_09_10.pdf +0 -0
  10. data/docs/CFe-SAT/_CANCEL_dataset.md +14 -0
  11. data/docs/CFe-SAT/_SALE_dataset.md +171 -0
  12. data/docs/CFe-SAT/emulador_off_line_v2_9_4.zip +0 -0
  13. data/docs/NFe-NFCe/ANEXO I - Leiaute e Regra de Valida/303/247/303/243o - NF-e e NFC-e.pdf +0 -0
  14. data/docs/NFe-NFCe/ANEXO II -Manual Especifica/303/247/303/265esT/303/251cnicas - Danfe-C/303/263digo-Barras.pdf +0 -0
  15. data/docs/NFe-NFCe/Anexo III - Manual de Conting/303/252ncia - NF-e.pdf +0 -0
  16. data/docs/NFe-NFCe/Anexo IV - Manual de Conting/303/252ncia - NFC-e.pdf +0 -0
  17. data/docs/NFe-NFCe/Manual de Orienta/303/247/303/243o ao Contribuinte - MOC - vers/303/243o 7.0 - NF-e e NFC-e.pdf +0 -0
  18. data/docs/NFe-NFCe/_dataset.md +819 -0
  19. data/lib/sefaz/assets/NFe_logo.png +0 -0
  20. data/lib/sefaz/base.rb +11 -0
  21. data/lib/sefaz/configuration.rb +66 -0
  22. data/lib/sefaz/exception.rb +14 -0
  23. data/lib/sefaz/refinement.rb +91 -0
  24. data/lib/sefaz/utils/connection.rb +35 -0
  25. data/lib/sefaz/utils/prawn_helper.rb +49 -0
  26. data/lib/sefaz/utils/signer.rb +122 -0
  27. data/lib/sefaz/version.rb +1 -1
  28. data/lib/sefaz/webservice/base.rb +13 -0
  29. data/lib/sefaz/webservice/nfe/auditor.rb +35 -0
  30. data/lib/sefaz/webservice/nfe/client.rb +471 -0
  31. data/lib/sefaz/webservice/nfe/connection.rb +17 -0
  32. data/lib/sefaz/webservice/nfe/dataset.rb +451 -0
  33. data/lib/sefaz/webservice/nfe/templates/base.rb +32 -0
  34. data/lib/sefaz/webservice/nfe/templates/evento_cancelamento.rb +48 -0
  35. data/lib/sefaz/webservice/nfe/templates/evento_carta_correcao.rb +54 -0
  36. data/lib/sefaz/webservice/nfe/templates/evento_inutilizacao.rb +22 -0
  37. data/lib/sefaz/webservice/nfe/validator.rb +63 -0
  38. data/lib/sefaz/webservice/nfe/wsdl.rb +117 -0
  39. data/lib/sefaz/webservice/sat/client.rb +44 -0
  40. data/lib/sefaz/webservice/sat/dataset/cancel.rb +34 -0
  41. data/lib/sefaz/webservice/sat/dataset/sale.rb +176 -0
  42. data/lib/sefaz/webservice/sat/templates/base.rb +54 -0
  43. data/lib/sefaz/webservice/sat/templates/cupom_fiscal_55mm.rb +307 -0
  44. data/lib/sefaz/webservice/sat/templates/cupom_fiscal_80mm.rb +307 -0
  45. data/lib/sefaz.rb +51 -3
  46. data/sefaz.gemspec +6 -3
  47. metadata +103 -9
@@ -0,0 +1,451 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ module Webservice
5
+ module NFE
6
+ # Principal classe de elaboração do XML para o módulo NF-e/NFC-e
7
+ class Dataset
8
+
9
+ attr_accessor :ide, :NFref, :emit, :avulsa, :dest, :retirada, :entrega, :autXML, :det, :DI, :adi, :detExport, :rastro, :arma, :total, :transp, :reboque, :vol, :lacres, :cobr, :dup, :detPag, :infIntermed, :infAdic, :obscont, :obsfisco, :procref, :exporta, :compra, :cana, :forDia, :deduc, :infRespTec, :infNFeSupl
10
+
11
+ IDE = Struct.new(:cUF, :cNF, :natOp, :mod, :serie, :nNF, :dhEmi, :dhSaiEnt, :tpNF, :idDest, :cMunFG, :tpImp, :tpEmis, :cDV, :tpAmb, :finNFe, :indFinal, :indPres, :indIntermed, :procEmi, :verProc, :dhCont, :xJust, :NFref)
12
+ NFREF = Struct.new(:refNFe, :cUF, :AAMM, :CNPJ, :CPF, :IE, :mod, :serie, :nNF, :refCTe, :nECF, :nCOO)
13
+ EMIT = Struct.new(:CNPJ, :CPF, :xNome, :xFant, :enderEmit, :IE, :IEST, :IM, :CNAE, :CRT)
14
+ ENDEREMIT = Struct.new(:xLgr, :nro, :xCpl, :xBairro, :cMun, :xMun, :UF, :CEP, :cPais, :xPais, :fone)
15
+ AVULSA = Struct.new(:CNPJ, :xOrgao, :matr, :xAgente, :fone, :UF, :nDAR, :dEmi, :vDAR, :repEmi, :dPag)
16
+ DEST = Struct.new(:CNPJ, :CPF, :idEstrangeiro, :xNome, :enderDest, :indIEDest, :IE, :ISUF, :IM, :email)
17
+ ENDERDEST = Struct.new(:xLgr, :nro, :xCpl, :xBairro, :cMun, :xMun, :UF, :CEP, :cPais, :xPais, :fone)
18
+ RETIRADA = Struct.new(:CNPJ, :CPF, :xNome, :xLgr, :nro, :xCpl, :xBairro, :cMun, :xMun, :UF, :CEP, :cPais, :xPais, :fone, :email, :IE)
19
+ ENTREGA = Struct.new(:CNPJ, :CPF, :xNome, :xLgr, :nro, :xCpl, :xBairro, :cMun, :xMun, :UF, :CEP, :cPais, :xPais, :fone, :email, :IE)
20
+ AUTXML = Struct.new(:CNPJ, :CPF)
21
+ DET = Struct.new(:@nItem, :prod, :imposto, :impostoDevol, :infAdProd)
22
+ PROD = Struct.new(:cProd, :cEAN, :xProd, :NCM, :NVE, :CEST, :indEscala, :CNPJFab, :cBenef, :EXTIPI, :CFOP, :uCom, :qCom, :vUnCom, :vProd, :cEANTrib, :uTrib, :qTrib, :vUnTrib, :vFrete, :vSeg, :vDesc, :vOutro, :indTot, :DI, :detExport, :xPed, :nItemPed, :nFCI, :rastro, :veicProd, :med, :arma, :comb, :nRECOPI)
23
+ DI = Struct.new(:nDI, :dDI, :xLocDesemb, :UFDesemb, :dDesemb, :tpViaTransp, :vAFRMM, :tpIntermedio, :CNPJ, :UFTerceiro, :cExportador, :adi)
24
+ ADI = Struct.new(:nAdicao, :nSeqAdic, :cFabricante, :vDescDI, :nDraw)
25
+ DETEXPORT = Struct.new(:nDraw, :exportInd)
26
+ EXPORTIND = Struct.new(:nRE, :chNFe, :qExport)
27
+ RASTRO = Struct.new(:nLote, :qLote, :dFab, :dVal, :cAgreg)
28
+ VEICPROD = Struct.new(:tpOp, :chassi, :cCor, :xCor, :pot, :cilin, :pesoL, :pesoB, :nSerie, :tpComb, :nMotor, :CMT, :dist, :anoMod, :anoFab, :tpPint, :tpVeic, :espVeic, :VIN, :condVeic, :cMod, :cCorDENATRAN, :lota, :tpRest)
29
+ MED = Struct.new(:cProdANVISA, :xMotivoIsencao, :vPMC)
30
+ ARMA = Struct.new(:tpArma, :nSerie, :nCano, :descr)
31
+ COMB = Struct.new(:cProdANP, :descANP, :pGLP, :pGNn, :pGNi, :vPart, :CODIF, :qTemp, :UFCons, :CIDE, :encerrante)
32
+ CIDE = Struct.new(:qBCProd, :vAliqProd, :vCIDE)
33
+ ENCERRANTE = Struct.new(:nBico, :nBomba, :nTanque, :vEncIni, :vEncFin)
34
+ IMPOSTO = Struct.new(:vTotTrib, :ICMS, :ICMSUFDest, :IPI, :II, :PIS, :PISST, :COFINS, :COFINSST, :ISSQN)
35
+ ICMS = Struct.new(:ICMS00, :ICMS10, :ICMS20, :ICMS30, :ICMS40, :ICMS51, :ICMS60, :ICMS70, :ICMS90, :ICMSPart, :ICMSST, :ICMSSN101, :ICMSSN102, :ICMSSN201, :ICMSSN202, :ICMSSN500, :ICMSSN900)
36
+ ICMS00 = Struct.new(:orig, :CST, :modBC, :vBC, :pICMS, :vICMS, :pFCP, :vFCP)
37
+ ICMS10 = Struct.new(:orig, :CST, :modBC, :vBC, :pICMS, :vICMS, :vBCFCP, :pFCP, :vFCP, :modBCST, :pMVAST, :pRedBCST, :vBCST, :pICMSST, :vICMSST, :vBCFCPST, :pFCPST, :vFCPST)
38
+ ICMS20 = Struct.new(:orig, :CST, :modBC, :pRedBC, :vBC, :pICMS, :vICMS, :vBCFCP, :pFCP, :vFCP, :vICMSDeson, :motDesICMS)
39
+ ICMS30 = Struct.new(:orig, :CST, :modBCST, :pMVAST, :pRedBCST, :vBCST, :pICMSST, :vICMSST, :vBCFCPST, :pFCPST, :vFCPST, :vICMSDeson, :motDesICMS)
40
+ ICMS40 = Struct.new(:orig, :CST, :vICMSDeson, :motDesICMS)
41
+ ICMS51 = Struct.new(:orig, :CST, :modBC, :pRedBC, :vBC, :pICMS, :vICMSOp, :pDif, :vICMSDif, :vICMS, :vBCFCP, :pFCP, :vFCP)
42
+ ICMS60 = Struct.new(:orig, :CST, :vBCSTRet, :pST, :vICMSSubstituto, :vICMSSTRet, :vBCFCPSTRet, :pFCPSTRet, :vFCPSTRet, :pRedBCEfet, :vBCEfet, :pICMSEfet, :vICMSEfet)
43
+ ICMS70 = Struct.new(:orig, :CST, :modBC, :pRedBC, :vBC, :pICMS, :vICMS, :vBCFCP, :pFCP, :vFCP, :modBCST, :pMVAST, :pRedBCST, :vBCST, :pICMSST, :vICMSST, :vBCFCPST, :pFCPST, :vFCPST, :vICMSDeson, :motDesICMS)
44
+ ICMS90 = Struct.new(:orig, :CST, :modBC, :vBC, :pRedBC, :pICMS, :vICMS, :vBCFCP, :pFCP, :vFCP, :modBCST, :pMVAST, :pRedBCST, :vBCST, :pICMSST, :vICMSST, :vBCFCPST, :pFCPST, :vFCPST, :vICMSDeson, :motDesICMS)
45
+ ICMSPart = Struct.new(:orig, :CST, :modBC, :vBC, :pRedBC, :pICMS, :vICMS, :modBCST, :pMVAST, :pRedBCST, :vBCST, :pICMSST, :vICMSST, :pBCOp, :UFST)
46
+ ICMSST = Struct.new(:orig, :CST, :vBCSTRet, :pST, :vICMSSubstituto, :vICMSSTRet, :vBCFCPSTRet, :pFCPSTRet, :vFCPSTRet, :vBCSTDest, :vICMSSTDest, :pRedBCEfet, :vBCEfet, :pICMSEfet, :vICMSEfet)
47
+ ICMSSN101 = Struct.new(:orig, :CSOSN, :pCredSN, :vCredICMSSN)
48
+ ICMSSN102 = Struct.new(:orig, :CSOSN)
49
+ ICMSSN201 = Struct.new(:orig, :CSOSN, :modBCST, :pMVAST, :pRedBCST, :vBCST, :pICMSST, :vICMSST, :vBCFCPST, :pFCPST, :vFCPST, :pCredSN, :vCredICMSSN)
50
+ ICMSSN202 = Struct.new(:orig, :CSOSN, :modBCST, :pMVAST, :pRedBCST, :vBCST, :pICMSST, :vICMSST, :vBCFCPST, :pFCPST, :vFCPST)
51
+ ICMSSN500 = Struct.new(:orig, :CSOSN, :vBCSTRet, :pST, :vICMSSubstituto, :vICMSSTRet, :vBCFCPSTRet, :pFCPSTRet, :vFCPSTRet, :pRedBCEfet, :vBCEfet, :pICMSEfet, :vICMSEfet)
52
+ ICMSSN900 = Struct.new(:orig, :CSOSN, :modBC, :vBC, :pRedBC, :pICMS, :vICMS, :modBCST, :pMVAST, :pRedBCST, :vBCST, :pICMSST, :vICMSST, :vBCFCPST, :pFCPST, :vFCPST, :pCredSN, :vCredICMSSN)
53
+ ICMSUFDest = Struct.new(:vBCUFDest, :vBCFCPUFDest, :pFCPUFDest, :pICMSUFDest, :pICMSInter, :pICMSInterPart, :vFCPUFDest, :vICMSUFDest, :vICMSUFRemet)
54
+ IPI = Struct.new(:CNPJProd, :cSelo, :qSelo, :cEnq, :IPITrib, :IPINT)
55
+ IPITrib = Struct.new(:CST, :vBC, :qUnid, :vUnid, :vIPI)
56
+ IPINT = Struct.new(:CST)
57
+ II = Struct.new(:vBC, :vDespAdu, :vII, :vIOF)
58
+ PIS = Struct.new(:PISAliq, :PISQtde, :PISNT, :PISOutr)
59
+ PISAliq = Struct.new(:CST, :vBC, :pPIS, :vPIS)
60
+ PISQtde = Struct.new(:CST, :qBCProd, :vAliqProd, :vPIS)
61
+ PISNT = Struct.new(:CST)
62
+ PISOutr = Struct.new(:CST, :vBC, :pPIS, :qBCProd, :vAliqProd, :vPIS)
63
+ PISST = Struct.new(:vBC, :pPIS, :qBCProd, :vAliqProd, :vPIS)
64
+ COFINS = Struct.new(:COFINSAliq, :COFINSQtde, :COFINSNT, :COFINSOutr)
65
+ COFINSAliq = Struct.new(:CST, :vBC, :pCOFINS, :vCOFINS)
66
+ COFINSQtde = Struct.new(:CST, :qBCProd, :vAliqProd, :vCOFINS)
67
+ COFINSNT = Struct.new(:CST)
68
+ COFINSOutr = Struct.new(:CST, :vBC, :pCOFINS, :qBCProd, :vAliqProd, :vCOFINS)
69
+ COFINSST = Struct.new(:vBC, :pCOFINS, :qBCProd, :vAliqProd, :vCOFINS)
70
+ ISSQN = Struct.new(:vBC, :vAliq, :vISSQN, :cMunFG, :cListServ, :vDeducao, :vOutro, :vDescIncond, :vDescCond, :vISSRet, :indISS, :cServico, :cMun, :cPais, :nProcesso, :indIncentivo)
71
+ IMPOSTODEVOL = Struct.new(:pDevol, :IPI)
72
+ IPIDEVOL = Struct.new(:vIPIDevol)
73
+ TOTAL = Struct.new(:ICMSTot, :ISSQNtot, :retTrib)
74
+ ICMSTot = Struct.new(:vBC, :vICMS, :vICMSDeson, :vFCPUFDest, :vICMSUFDest, :vICMSUFRemet, :vFCP, :vBCST, :vST, :vFCPST, :vFCPSTRet, :vProd, :vFrete, :vSeg, :vDesc, :vII, :vIPI, :vIPIDevol, :vPIS, :vCOFINS, :vOutro, :vNF, :vTotTrib)
75
+ ISSQNtot = Struct.new(:vServ, :vBC, :vISS, :vPIS, :vCOFINS, :dCompet, :vDeducao, :vOutro, :vDescIncond, :vDescCond, :vISSRet, :cRegTrib)
76
+ RETTrib = Struct.new(:vRetPIS, :vRetCOFINS, :vRetCSLL, :vBCIRRF, :vIRRF, :vBCRetPrev, :vRetPrev)
77
+ TRANSP = Struct.new(:modFrete, :transporta, :retTransp, :veicTransp, :reboque, :vagao, :balsa, :vol)
78
+ TRANSPORTA = Struct.new(:CNPJ, :CPF, :xNome, :IE, :xEnder, :xMun, :UF)
79
+ RETTRANSP = Struct.new(:vServ, :vBCRet, :pICMSRet, :vICMSRet, :CFOP, :cMunFG)
80
+ VEICTRANSP = Struct.new(:placa, :UF, :RNTC)
81
+ REBOQUE = Struct.new(:placa, :UF, :RNTC)
82
+ VOL = Struct.new(:qVol, :esp, :marca, :nVol, :pesoL, :pesoB, :lacres)
83
+ LACRES = Struct.new(:nLacre)
84
+ COBR = Struct.new(:fat, :dup)
85
+ FAT = Struct.new(:nFat, :vOrig, :vDesc, :vLiq)
86
+ DUP = Struct.new(:nDup, :dVenc, :vDup)
87
+ PAG = Struct.new(:detPag)
88
+ DETPAG = Struct.new(:indPag, :tPag, :vPag, :card, :vTroco)
89
+ CARD = Struct.new(:tpIntegra, :CNPJ, :tBand, :cAut)
90
+ INFINTERMED = Struct.new(:CNPJ, :idCadIntTran)
91
+ INFADIC = Struct.new(:infAdFisco, :infCpl, :obsCont, :obsFisco, :procRef)
92
+ OBSCONT = Struct.new(:xCampo, :xTexto)
93
+ OBSFISCO = Struct.new(:xCampo, :xTexto)
94
+ PROCREF = Struct.new(:nProc, :indProc)
95
+ EXPORTA = Struct.new(:UFSaidaPais, :xLocExporta, :xLocDespacho)
96
+ COMPRA = Struct.new(:xNEmp, :xPed, :xCont)
97
+ CANA = Struct.new(:safra, :ref, :forDia, :qTotMes, :qTotAnt, :qTotGer, :deduc, :vFor, :vTotDed, :vLiqFor)
98
+ FORDIA = Struct.new(:dia, :qtde)
99
+ DEDUC = Struct.new(:xDed, :vDed)
100
+ INFRESPTEC = Struct.new(:CNPJ, :xContato, :email, :fone, :idCSRT, :hashCSRT)
101
+ INFNFESUPL = Struct.new(:qrCode, :urlChave)
102
+
103
+ def initialize(chaveNF)
104
+ @versao = "4.00"
105
+ @chaveNF = chaveNF
106
+
107
+ @ide = IDE.new
108
+ @ide.NFref = []
109
+ @emit = EMIT.new
110
+ @emit.enderEmit = ENDEREMIT.new
111
+ @avulsa = AVULSA.new
112
+ @dest = DEST.new
113
+ @dest.enderDest = ENDERDEST.new
114
+ @retirada = RETIRADA.new
115
+ @entrega = ENTREGA.new
116
+ @total = TOTAL.new
117
+ @total.ICMSTot = ICMSTot.new
118
+ @total.ISSQNtot = ISSQNtot.new
119
+ @total.retTrib = RETTrib.new
120
+ @transp = TRANSP.new
121
+ @transp.transporta = TRANSPORTA.new
122
+ @transp.retTransp = RETTRANSP.new
123
+ @transp.veicTransp = VEICTRANSP.new
124
+ @transp.reboque = []
125
+ @transp.vol = []
126
+ @cobr = COBR.new
127
+ @cobr.fat = FAT.new
128
+ @cobr.dup = []
129
+ @pag = PAG.new
130
+ @pag.detPag = []
131
+ @infIntermed = INFINTERMED.new
132
+ @infAdic = INFADIC.new
133
+ @infAdic.obsCont = []
134
+ @infAdic.obsFisco = []
135
+ @infAdic.procRef = []
136
+ @exporta = EXPORTA.new
137
+ @compra = COMPRA.new
138
+ @cana = CANA.new
139
+ @cana.forDia = []
140
+ @cana.deduc = []
141
+ @infRespTec = INFRESPTEC.new
142
+ @infNFeSupl = INFNFESUPL.new
143
+
144
+ @listas = {}
145
+ @listas[:autXML] = []
146
+ @listas[:det] = []
147
+ end
148
+
149
+ def gerarNF
150
+ # Raiz = NFe
151
+ # A01 = infNFe
152
+ # H01 = det
153
+ # I01 = prod
154
+ # M01 = imposto
155
+ # N01 = ICMS
156
+ hash = { NFe: { :@xmlns => "http://www.portalfiscal.inf.br/nfe", infNFe: { :@Id => ("NFe" + @chaveNF.to_s), :@versao => @versao } } }
157
+ hash[:NFe][:infNFe][:ide] = @ide.to_h
158
+ hash[:NFe][:infNFe][:emit] = @emit.to_h
159
+ hash[:NFe][:infNFe][:emit][:enderEmit] = @emit.enderEmit.to_h
160
+ hash[:NFe][:infNFe][:avulsa] = @avulsa.to_h
161
+ hash[:NFe][:infNFe][:dest] = @dest.to_h
162
+ hash[:NFe][:infNFe][:dest][:enderDest] = @dest.enderDest.to_h
163
+ hash[:NFe][:infNFe][:retirada] = @retirada.to_h
164
+ hash[:NFe][:infNFe][:entrega] = @entrega.to_h
165
+ hash[:NFe][:infNFe][:autXML] = @listas[:autXML]
166
+ hash[:NFe][:infNFe][:det] = @listas[:det]
167
+ hash[:NFe][:infNFe][:total] = @total.to_h
168
+ hash[:NFe][:infNFe][:total][:ICMSTot] = @total.ICMSTot.to_h
169
+ hash[:NFe][:infNFe][:total][:ISSQNtot] = @total.ISSQNtot.to_h
170
+ hash[:NFe][:infNFe][:total][:retTrib] = @total.retTrib.to_h
171
+ hash[:NFe][:infNFe][:transp] = @transp.to_h
172
+ hash[:NFe][:infNFe][:transp][:transporta] = @transp.transporta.to_h
173
+ hash[:NFe][:infNFe][:transp][:retTransp] = @transp.retTransp.to_h
174
+ hash[:NFe][:infNFe][:transp][:veicTransp] = @transp.veicTransp.to_h
175
+ hash[:NFe][:infNFe][:cobr] = @cobr.to_h
176
+ hash[:NFe][:infNFe][:cobr][:fat] = @cobr.fat.to_h
177
+ hash[:NFe][:infNFe][:pag] = @pag.to_h
178
+ hash[:NFe][:infNFe][:infIntermed] = @infIntermed.to_h
179
+ hash[:NFe][:infNFe][:infAdic] = @infAdic.to_h
180
+ hash[:NFe][:infNFe][:exporta] = @exporta.to_h
181
+ hash[:NFe][:infNFe][:compra] = @compra.to_h
182
+ hash[:NFe][:infNFe][:cana] = @cana.to_h
183
+ hash[:NFe][:infNFe][:infRespTec] = @infRespTec.to_h
184
+ hash[:NFe][:infNFeSupl] = @infNFeSupl.to_h
185
+ compressed = hash.compress!
186
+
187
+ return [compressed.to_xml!, compressed]
188
+ end
189
+
190
+ def add(part_name)
191
+ part_object = case part_name
192
+ when "NFREF"
193
+ @NFref = NFREF.new
194
+ @NFref
195
+ when "AUTXML"
196
+ @autXML = AUTXML.new
197
+ @autXML
198
+ when "DET"
199
+ @det = DET.new
200
+ @det.prod = PROD.new
201
+ @det.prod.veicProd = VEICPROD.new
202
+ @det.prod.med = MED.new
203
+ @det.prod.comb = COMB.new
204
+ @det.prod.comb.CIDE = CIDE.new
205
+ @det.prod.comb.encerrante = ENCERRANTE.new
206
+ @det.prod.DI = []
207
+ @det.prod.detExport = []
208
+ @det.prod.rastro = []
209
+ @det.prod.arma = []
210
+ @det.imposto = IMPOSTO.new
211
+ @det.imposto.ICMS = ICMS.new
212
+ @det.imposto.ICMS.ICMS00 = ICMS00.new
213
+ @det.imposto.ICMS.ICMS10 = ICMS10.new
214
+ @det.imposto.ICMS.ICMS20 = ICMS20.new
215
+ @det.imposto.ICMS.ICMS30 = ICMS30.new
216
+ @det.imposto.ICMS.ICMS40 = ICMS40.new
217
+ @det.imposto.ICMS.ICMS51 = ICMS51.new
218
+ @det.imposto.ICMS.ICMS60 = ICMS60.new
219
+ @det.imposto.ICMS.ICMS70 = ICMS70.new
220
+ @det.imposto.ICMS.ICMS90 = ICMS90.new
221
+ @det.imposto.ICMS.ICMSPart = ICMSPart.new
222
+ @det.imposto.ICMS.ICMSST = ICMSST.new
223
+ @det.imposto.ICMS.ICMSSN101 = ICMSSN101.new
224
+ @det.imposto.ICMS.ICMSSN102 = ICMSSN102.new
225
+ @det.imposto.ICMS.ICMSSN201 = ICMSSN201.new
226
+ @det.imposto.ICMS.ICMSSN202 = ICMSSN202.new
227
+ @det.imposto.ICMS.ICMSSN500 = ICMSSN500.new
228
+ @det.imposto.ICMS.ICMSSN900 = ICMSSN900.new
229
+ @det.imposto.ICMSUFDest = ICMSUFDest.new
230
+ @det.imposto.IPI = IPI.new
231
+ @det.imposto.IPI.IPITrib = IPITrib.new
232
+ @det.imposto.IPI.IPINT = IPINT.new
233
+ @det.imposto.II = II.new
234
+ @det.imposto.PIS = PIS.new
235
+ @det.imposto.PIS.PISAliq = PISAliq.new
236
+ @det.imposto.PIS.PISQtde = PISQtde.new
237
+ @det.imposto.PIS.PISNT = PISNT.new
238
+ @det.imposto.PIS.PISOutr = PISOutr.new
239
+ @det.imposto.PISST = PISST.new
240
+ @det.imposto.COFINS = COFINS.new
241
+ @det.imposto.COFINS.COFINSAliq = COFINSAliq.new
242
+ @det.imposto.COFINS.COFINSQtde = COFINSQtde.new
243
+ @det.imposto.COFINS.COFINSNT = COFINSNT.new
244
+ @det.imposto.COFINS.COFINSOutr = COFINSOutr.new
245
+ @det.imposto.COFINSST = COFINSST.new
246
+ @det.imposto.ISSQN = ISSQN.new
247
+ @det.impostoDevol = IMPOSTODEVOL.new
248
+ @det.impostoDevol.IPI = IPIDEVOL.new
249
+ @det
250
+ when "DI"
251
+ @DI = DI.new
252
+ @DI.adi = []
253
+ @DI
254
+ when "ADI"
255
+ @adi = ADI.new
256
+ @adi
257
+ when "DETEXPORT"
258
+ @detExport = DETEXPORT.new
259
+ @detExport.exportInd = EXPORTIND.new
260
+ @detExport
261
+ when "RASTRO"
262
+ @rastro = RASTRO.new
263
+ @rastro
264
+ when "ARMA"
265
+ @arma = ARMA.new
266
+ @arma
267
+ when "REBOQUE"
268
+ @reboque = REBOQUE.new
269
+ @reboque
270
+ when "VOL"
271
+ @vol = VOL.new
272
+ @vol.lacres = []
273
+ @vol
274
+ when "LACRES"
275
+ @lacres = LACRES.new
276
+ @lacres
277
+ when "DUP"
278
+ @dup = DUP.new
279
+ @dup
280
+ when "DETPAG"
281
+ @detPag = DETPAG.new
282
+ @detPag.card = CARD.new
283
+ @detPag
284
+ when "OBSCONT"
285
+ @obscont = OBSCONT.new
286
+ @obscont
287
+ when "OBSFISCO"
288
+ @obsfisco = OBSFISCO.new
289
+ @obsfisco
290
+ when "PROCREF"
291
+ @procref = PROCREF.new
292
+ @procref
293
+ when "FORDIA"
294
+ @forDia = FORDIA.new
295
+ @forDia
296
+ when "DEDUC"
297
+ @deduc = DEDUC.new
298
+ @deduc
299
+ end
300
+
301
+ if block_given?
302
+ yield(part_object)
303
+ save(part_name)
304
+ end
305
+
306
+ nil
307
+ end
308
+
309
+ def save(part_name)
310
+ case part_name
311
+ when "NFREF"
312
+ if @ide.is_a?(IDE) && @NFref.is_a?(NFREF)
313
+ case @NFref.mod
314
+ when "01", "02"
315
+ @ide.NFref.push({ refNF: { cUF: @NFref.cUF, AAMM: @NFref.AAMM, CNPJ: @NFref.CNPJ, mod: @NFref.mod, serie: @NFref.serie, nNF: @NFref.nNF } })
316
+ when "04"
317
+ @ide.NFref.push({ refNFP: { cUF: @NFref.cUF, AAMM: @NFref.AAMM, CNPJ: @NFref.CNPJ, CPF: @NFref.CPF, IE: @NFref.IE, mod: @NFref.mod, serie: @NFref.serie, nNF: @NFref.nNF, refCTe: @NFref.refCTe } })
318
+ when "2B", "2C", "2D"
319
+ @ide.NFref.push({ refECF: { mod: @NFref.mod, nECF: @NFref.nECF, nCOO: @NFref.nCOO } })
320
+ else
321
+ @ide.NFref.push({ refNFe: @NFref.refNFe })
322
+ end
323
+ end
324
+ when "AUTXML"
325
+ if @autXML.is_a?(AUTXML)
326
+ @listas[:autXML].push(@autXML.to_h)
327
+ end
328
+ when "DET"
329
+ if @det.is_a?(DET)
330
+ item = @det
331
+ item.prod.veicProd = item.prod.veicProd.to_h
332
+ item.prod.med = item.prod.med.to_h
333
+ item.prod.comb.encerrante = item.prod.comb.encerrante.to_h
334
+ item.prod.comb.CIDE = item.prod.comb.CIDE.to_h
335
+ item.prod.comb = item.prod.comb.to_h
336
+ item.prod = item.prod.to_h
337
+ item.imposto.ICMS.ICMS00 = item.imposto.ICMS.ICMS00.to_h
338
+ item.imposto.ICMS.ICMS10 = item.imposto.ICMS.ICMS10.to_h
339
+ item.imposto.ICMS.ICMS20 = item.imposto.ICMS.ICMS20.to_h
340
+ item.imposto.ICMS.ICMS30 = item.imposto.ICMS.ICMS30.to_h
341
+ item.imposto.ICMS.ICMS40 = item.imposto.ICMS.ICMS40.to_h
342
+ item.imposto.ICMS.ICMS51 = item.imposto.ICMS.ICMS51.to_h
343
+ item.imposto.ICMS.ICMS60 = item.imposto.ICMS.ICMS60.to_h
344
+ item.imposto.ICMS.ICMS70 = item.imposto.ICMS.ICMS70.to_h
345
+ item.imposto.ICMS.ICMS90 = item.imposto.ICMS.ICMS90.to_h
346
+ item.imposto.ICMS.ICMSPart = item.imposto.ICMS.ICMSPart.to_h
347
+ item.imposto.ICMS.ICMSST = item.imposto.ICMS.ICMSST.to_h
348
+ item.imposto.ICMS.ICMSSN101 = item.imposto.ICMS.ICMSSN101.to_h
349
+ item.imposto.ICMS.ICMSSN102 = item.imposto.ICMS.ICMSSN102.to_h
350
+ item.imposto.ICMS.ICMSSN201 = item.imposto.ICMS.ICMSSN201.to_h
351
+ item.imposto.ICMS.ICMSSN202 = item.imposto.ICMS.ICMSSN202.to_h
352
+ item.imposto.ICMS.ICMSSN500 = item.imposto.ICMS.ICMSSN500.to_h
353
+ item.imposto.ICMS.ICMSSN900 = item.imposto.ICMS.ICMSSN900.to_h
354
+ item.imposto.ICMS = item.imposto.ICMS.to_h
355
+ item.imposto.ICMSUFDest = item.imposto.ICMSUFDest.to_h
356
+ item.imposto.IPI.IPITrib = item.imposto.IPI.IPITrib.to_h
357
+ item.imposto.IPI.IPINT = item.imposto.IPI.IPINT.to_h
358
+ item.imposto.IPI = item.imposto.IPI.to_h
359
+ item.imposto.II = item.imposto.II.to_h
360
+ item.imposto.PIS.PISAliq = item.imposto.PIS.PISAliq.to_h
361
+ item.imposto.PIS.PISQtde = item.imposto.PIS.PISQtde.to_h
362
+ item.imposto.PIS.PISNT = item.imposto.PIS.PISNT.to_h
363
+ item.imposto.PIS.PISOutr = item.imposto.PIS.PISOutr.to_h
364
+ item.imposto.PIS = item.imposto.PIS.to_h
365
+ item.imposto.PISST = item.imposto.PISST.to_h
366
+ item.imposto.COFINS.COFINSAliq = item.imposto.COFINS.COFINSAliq.to_h
367
+ item.imposto.COFINS.COFINSQtde = item.imposto.COFINS.COFINSQtde.to_h
368
+ item.imposto.COFINS.COFINSNT = item.imposto.COFINS.COFINSNT.to_h
369
+ item.imposto.COFINS.COFINSOutr = item.imposto.COFINS.COFINSOutr.to_h
370
+ item.imposto.COFINS = item.imposto.COFINS.to_h
371
+ item.imposto.COFINSST = item.imposto.COFINSST.to_h
372
+ item.imposto.ISSQN = item.imposto.ISSQN.to_h
373
+ item.imposto = item.imposto.to_h
374
+ item.impostoDevol.IPI = item.impostoDevol.IPI.to_h
375
+ item.impostoDevol = item.impostoDevol.to_h
376
+ item[:@nItem] = (@listas[:det].length + 1)
377
+ @listas[:det].push(item.to_h)
378
+ end
379
+ when "DI"
380
+ if @det.is_a?(DET) && @DI.is_a?(DI)
381
+ @det.prod.DI.push(@DI.to_h)
382
+ end
383
+ when "ADI"
384
+ if @DI.is_a?(DI) && @adi.is_a?(ADI)
385
+ @DI.adi.push(@adi.to_h)
386
+ end
387
+ when "DETEXPORT"
388
+ if @det.is_a?(DET) && @detExport.is_a?(DETEXPORT)
389
+ item = @detExport
390
+ item.exportInd = item.exportInd.to_h
391
+ @det.prod.detExport.push(item.to_h)
392
+ end
393
+ when "RASTRO"
394
+ if @det.is_a?(DET) && @rastro.is_a?(RASTRO)
395
+ @det.prod.rastro.push(@rastro.to_h)
396
+ end
397
+ when "ARMA"
398
+ if @det.is_a?(DET) && @arma.is_a?(ARMA)
399
+ @det.prod.arma.push(@arma.to_h)
400
+ end
401
+ when "REBOQUE"
402
+ if @transp.is_a?(TRANSP) && @reboque.is_a?(REBOQUE)
403
+ @transp.reboque.push(@reboque.to_h)
404
+ end
405
+ when "VOL"
406
+ if @transp.is_a?(TRANSP) && @vol.is_a?(VOL)
407
+ @transp.vol.push(@vol.to_h)
408
+ end
409
+ when "LACRES"
410
+ if @vol.is_a?(VOL) && @lacres.is_a?(LACRES)
411
+ @vol.lacres.push(@lacres.to_h)
412
+ end
413
+ when "DUP"
414
+ if @cobr.is_a?(COBR) && @dup.is_a?(DUP)
415
+ @cobr.dup.push(@dup.to_h)
416
+ end
417
+ when "DETPAG"
418
+ if @pag.is_a?(PAG) && @detPag.is_a?(DETPAG)
419
+ item = @detPag
420
+ item.card = item.card.to_h
421
+ @pag.detPag.push(item.to_h)
422
+ end
423
+ when "OBSCONT"
424
+ if @infAdic.is_a?(INFADIC) && @obscont.is_a?(OBSCONT)
425
+ @infAdic.obsCont.push(@obscont.to_h)
426
+ end
427
+ when "OBSFISCO"
428
+ if @infAdic.is_a?(INFADIC) && @obsfisco.is_a?(OBSFISCO)
429
+ @infAdic.obsFisco.push(@obsfisco.to_h)
430
+ end
431
+ when "PROCREF"
432
+ if @infAdic.is_a?(INFADIC) && @procref.is_a?(PROCREF)
433
+ @infAdic.procRef.push(@procref.to_h)
434
+ end
435
+ when "FORDIA"
436
+ if @cana.is_a?(CANA) && @forDia.is_a?(FORDIA)
437
+ @cana.forDia.push(@forDia.to_h)
438
+ end
439
+ when "DEDUC"
440
+ if @cana.is_a?(CANA) && @deduc.is_a?(DEDUC)
441
+ @cana.deduc.push(@deduc.to_h)
442
+ end
443
+ end
444
+
445
+ nil
446
+ end
447
+
448
+ end
449
+ end
450
+ end
451
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ module Webservice
5
+ module NFE
6
+ module Templates
7
+ # Classe base dos templates para NFe
8
+ class Base
9
+
10
+ include SEFAZ::Utils::PrawnHelper
11
+
12
+ def initialize
13
+ @margin = 7.mm
14
+ @page_size = 'A4'
15
+ @page_layout = :portrait
16
+ end
17
+
18
+ def build(doc, hash)
19
+ raise SEFAZ::NotImplemented, "Você deve implementar o método 'build' em uma subclasse."
20
+ end
21
+
22
+ def render(hash)
23
+ Prawn::Document.new(page_size: @page_size, margin: @margin, page_layout: @page_layout) do |doc|
24
+ build(doc, hash)
25
+ end.render
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ module Webservice
5
+ module NFE
6
+ module Templates
7
+ # Template para Evento de Cancelamento em PDF
8
+ class EventoCancelamento < SEFAZ::Webservice::NFE::Templates::Base
9
+
10
+ def build(doc, hash)
11
+ doc.font_size 10
12
+
13
+ chNFe = hash[:procEventoNFe][:evento][:infEvento][:chNFe]
14
+ id = hash[:procEventoNFe][:evento][:infEvento][:@Id].delete('^0-9')
15
+ nProt = hash[:procEventoNFe][:evento][:infEvento][:detEvento][:nProt]
16
+ nProtCancelamento = hash[:procEventoNFe][:retEvento][:infEvento][:nProt]
17
+ dhEvento = hash[:procEventoNFe][:evento][:infEvento][:dhEvento].to_time.strftime("%d/%m/%Y %H:%M:%S")
18
+ dhRegEvento = hash[:procEventoNFe][:retEvento][:infEvento][:dhRegEvento].to_time.strftime("%d/%m/%Y %H:%M:%S")
19
+ xJust = hash[:procEventoNFe][:evento][:infEvento][:detEvento][:xJust]
20
+ xMotivo = hash[:procEventoNFe][:retEvento][:infEvento][:xMotivo]
21
+ nSeqEvento = hash[:procEventoNFe][:evento][:infEvento][:nSeqEvento]
22
+ cOrgao = hash[:procEventoNFe][:retEvento][:infEvento][:cOrgao]
23
+ chNFeBlob = Barby::PngOutputter.new(Barby::Code128C.new(chNFe)).to_png(xdim: 1, height: 40, margin: 3)
24
+ idBlob = Barby::PngOutputter.new(Barby::Code128C.new(id)).to_png(xdim: 1, height: 40, margin: 3)
25
+
26
+ header = [[{ content: "Cancelamento de NF-e", align: :center, font_style: :bold, size: 18, padding: [15, 0] }]]
27
+ body = [
28
+ [{ content: "Chave de Acesso - NF-e", align: :center, size: 12, borders: [:top, :left, :right], padding: [5, 0, 0, 0], width: doc.bounds.width / 2 }, { content: "Chave de Acesso Cancelamento - NF-e", align: :center, size: 12, borders: [:top, :left, :right], padding: [5, 0, 0, 0], width: doc.bounds.width / 2 }],
29
+ [{ content: chNFe, align: :center, borders: [:bottom, :left, :right], padding: [0, 0, 5, 0] }, { content: id, align: :center, borders: [:bottom, :left, :right], padding: [0, 0, 5, 0], size: 9 }],
30
+ [{ image: StringIO.new(chNFeBlob), scale: 0.7, position: :center, vposition: :center, width: doc.bounds.width / 2 }, { image: StringIO.new(idBlob), scale: 0.7, position: :center, vposition: :center, width: doc.bounds.width / 2 }],
31
+ [{ content: "Protocolo de Autorização NF-e\n#{nProt}", align: :center }, { content: "Protocolo de Cancelamento\n#{nProtCancelamento}", align: :center }],
32
+ [{ content: "Data e Hora do Pedido de Cancelamento\n#{dhEvento}", align: :center }, { content: "Data e Hora do Registro de Cancelamento\n#{dhRegEvento}", align: :center }],
33
+ [{ content: "Justificativa", colspan: 2, align: :center, borders: [:top, :left, :right], padding: [5, 0] }],
34
+ [{ content: xJust, colspan: 2, align: :left, borders: [:bottom, :left, :right], padding: [5, 5], height: 100 }]
35
+ ]
36
+
37
+ footer = [
38
+ [{ content: "Motivo", align: :center, borders: [:top, :left, :right], padding: [5, 0] }, { content: "Sequência", align: :center, borders: [:top, :left, :right], padding: [5, 0] }, { content: "Orgão", align: :center, borders: [:top, :left, :right], padding: [5, 0] }],
39
+ [{ content: xMotivo, align: :center, borders: [:bottom, :left, :right], padding: [5, 0] }, { content: nSeqEvento, align: :center, borders: [:bottom, :left, :right], padding: [5, 0] }, { content: cOrgao, align: :center, borders: [:bottom, :left, :right], padding: [5, 0] }]
40
+ ]
41
+
42
+ [header, body, footer].each { |section| doc.table(section, width: doc.bounds.width) }
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ module Webservice
5
+ module NFE
6
+ module Templates
7
+ # Template para Evento de Carta de Correção em PDF
8
+ class EventoCartaCorrecao < SEFAZ::Webservice::NFE::Templates::Base
9
+
10
+ def build(doc, hash)
11
+ doc.font_size 9
12
+
13
+ cnpj = hash[:procEventoNFe][:evento][:infEvento][:CNPJ].mask!("##.###.###/####-##")
14
+ chNFe = hash[:procEventoNFe][:evento][:infEvento][:chNFe]
15
+ nrNFe = chNFe[25..33].to_i
16
+ serie = chNFe[22..24]
17
+ modelo = chNFe[20..21]
18
+ anomes = hash[:procEventoNFe][:evento][:infEvento][:dhEvento].to_date.strftime("%m/%y")
19
+ nProt = hash[:procEventoNFe][:retEvento][:infEvento][:nProt]
20
+ dhRegEvento = hash[:procEventoNFe][:retEvento][:infEvento][:dhRegEvento].to_time.strftime("%d/%m/%Y %H:%M:%S")
21
+ nSeqEvento = hash[:procEventoNFe][:retEvento][:infEvento][:nSeqEvento]
22
+ cOrgao = hash[:procEventoNFe][:retEvento][:infEvento][:cOrgao]
23
+ xCorrecao = hash[:procEventoNFe][:evento][:infEvento][:detEvento][:xCorrecao]
24
+ xCondUso = hash[:procEventoNFe][:evento][:infEvento][:detEvento][:xCondUso]
25
+ chNFeBlob = Barby::PngOutputter.new(Barby::Code128C.new(chNFe)).to_png(xdim: 1, height: 40, margin: 3)
26
+
27
+ header = [
28
+ [{ content: "CNPJ: #{cnpj}", size: 10, align: :center, valign: :center, width: doc.bounds.width / 2 }, { content: "CCe", align: :center, font_style: :bold, size: 18, borders: [:top, :left, :right], padding: [15, 0, 0, 0], width: doc.bounds.width / 2 }],
29
+ [{ content: nil, borders: [:top, :left] }, { content: "CARTA DE CORREÇÃO ELETRÔNICA", size: 10, align: :center, borders: [:bottom, :left, :right], padding: [0, 0, 15, 0] }],
30
+ [{ content: nil, borders: [:left] }, { content: "Chave de Acesso da NFe", borders: [:top, :left, :right], padding: [5, 0, 0, 5] }],
31
+ [{ content: nil, borders: [:left] }, { content: chNFe, size: 10, borders: [:bottom, :left, :right], padding: [0, 0, 5, 5] }],
32
+ [{ content: nil, borders: [:bottom, :left] }, { image: StringIO.new(chNFeBlob), scale: 0.7, position: :center, vposition: :center }],
33
+ ]
34
+
35
+ body = [
36
+ [{ content: "Número da Nota Fiscal", padding: [5, 0, 0, 0], align: :center, borders: [:top, :left, :right] }, { content: "Série", padding: [5, 0, 0, 0], align: :center, borders: [:top, :left, :right] }, { content: "Modelo", padding: [5, 0, 0, 0], align: :center, borders: [:top, :left, :right] }, { content: "Mês / Ano Emissão", padding: [5, 0, 0, 0], align: :center, borders: [:top, :left, :right] }],
37
+ [{ content: nrNFe.to_s, padding: [0, 0, 5, 0], align: :center, borders: [:bottom, :left, :right] }, { content: serie, padding: [0, 0, 5, 0], align: :center, borders: [:bottom, :left, :right] }, { content: modelo, padding: [0, 0, 5, 0], align: :center, borders: [:bottom, :left, :right] }, { content: anomes, padding: [0, 0, 5, 0], align: :center, borders: [:bottom, :left, :right] }],
38
+ [{ content: "Protocolo de Autorização - CCe", padding: [5, 0, 0, 0], align: :center, borders: [:top, :left, :right] }, { content: "Data de Autorização", padding: [5, 0, 0, 0], align: :center, borders: [:top, :left, :right] }, { content: "Sequência", padding: [5, 0, 0, 0], align: :center, borders: [:top, :left, :right] }, { content: "Orgão", padding: [5, 0, 0, 0], align: :center, borders: [:top, :left, :right] }],
39
+ [{ content: nProt, padding: [0, 0, 5, 0], align: :center, borders: [:bottom, :left, :right] }, { content: dhRegEvento, padding: [0, 0, 5, 0], align: :center, borders: [:bottom, :left, :right] }, { content: nSeqEvento, padding: [0, 0, 5, 0], align: :center, borders: [:bottom, :left, :right] }, { content: cOrgao, padding: [0, 0, 5, 0], align: :center, borders: [:bottom, :left, :right] }],
40
+ [{ content: "Correção:\n#{xCorrecao}", colspan: 4, padding: 5, height: 350 }],
41
+ [{ content: xCondUso, colspan: 4, padding: 5, size: 8, align: :justify }],
42
+ ]
43
+
44
+ [header, body].each do |section|
45
+ doc.table(section, width: doc.bounds.width)
46
+ doc.move_down 5
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ module Webservice
5
+ module NFE
6
+ module Templates
7
+ # Template para Evento de Inutilização em PDF
8
+ class EventoInutilizacao < SEFAZ::Webservice::NFE::Templates::Base
9
+
10
+ def build(doc, hash)
11
+ doc.font "Courier", style: :normal
12
+ doc.font_size 12
13
+
14
+ doc.text "Documento emitido por meio do software livre ruby-sefaz"
15
+ doc.text hash.inspect
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end