facturacr 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 442248d98ebb602ee4d8f647bf9a24939b07e87a
4
- data.tar.gz: d6786825ba580d22c565b0714a744fadf34f5347
3
+ metadata.gz: 5fe54ad4526251387084b74247d3897b87781a56
4
+ data.tar.gz: 549cdc504c1ee37a4cac7c15cc424031fe043c0f
5
5
  SHA512:
6
- metadata.gz: 68d71ab7ae6715f6e61fbc92e09ca4da4d062e2ef9bc1c215ebea38c6bf4f865f9214a2344e48463f6ec3b3bda71fd1855de64b6b58e4a994fa7b65a0daf90df
7
- data.tar.gz: cc15f59583e0d342fd11148a948e48137abf52ae27a2886e7e151d2add273d69628f97754142ea6c9d0f70a3d406686eaa1f7e81093b2ae3c9df8a2b9a0be72c
6
+ metadata.gz: 0dcf0d1781a0be675f4a33053dd834b6c60a1e6e0d6e8a2a4d7b82bdbe3ae63aa8549664b6e4f281104175daa50969eb520c8447051ab827359dd9700e14a343
7
+ data.tar.gz: 8ca8978495e86e774cdb566fb6162d6ea112c369e84b70ce46f7c54100b05dfd31757a4e473c4eec48813e267c823f42d5050b845886f73c6fac8a21eb0a58b0
data/README.md CHANGED
@@ -30,45 +30,45 @@ O instale el gem
30
30
  Para generar documentos:
31
31
 
32
32
  ```ruby
33
- require 'facturacr'
33
+ require 'facturacr'
34
34
 
35
- id_document = FE::Document::IdentificationDocument.new type: "01", number: "112345678"
36
- phone = FE::Document::Phone.new country_code: "506", "22222222"
37
- location = FE::Document::Location.new province: "1",county: "01", district: "01", others: "Otras señas"
38
- issuer = FE::Document::Issuer.new name: "EMISON EJEMPLO", identification_document: id_document, location: location, phone: phone, email: "emisor@ejemplo.com"
35
+ id_document = FE::Document::IdentificationDocument.new type: "01", number: "112345678"
36
+ phone = FE::Document::Phone.new country_code: "506", "22222222"
37
+ location = FE::Document::Location.new province: "1",county: "01", district: "01", others: "Otras señas"
38
+ issuer = FE::Document::Issuer.new name: "EMISON EJEMPLO", identification_document: id_document, location: location, phone: phone, email: "emisor@ejemplo.com"
39
39
 
40
- reciever_id_document = FE::Document::IdentificationDocument.new type: "02", number: "3102123456"
41
- receiver = FE::Document::Receiver.new name: "RECEPTOR EJEMPLO", identification_document: id_document
40
+ reciever_id_document = FE::Document::IdentificationDocument.new type: "02", number: "3102123456"
41
+ receiver = FE::Document::Receiver.new name: "RECEPTOR EJEMPLO", identification_document: id_document
42
42
 
43
- items = []
44
- items << FE::Document::Item.new(code: "001", line_number: 1, quantity: 1, unit: "Sp", description: "Desarrollo de Software y Mantenimiento", unit_price: 300, subtotal: 300, net_total: 300, total: 300)
45
- taxes = [FE::Document::Tax.new(code: "01", rate: 13, total: (100 * 0.13))]
46
- items << FE::Document::Item.new(code: "002", line_number: 2, quantity: 2, unit: "Unid", description: "Impresora de POS", unit_price: 50, total: 100, taxes: taxes, net_total: 113, subtotal: 100)
47
- summary = FE::Document::Summary.new currency: "USD", exchange_rate: 575, services_exent_total: 300, goods_taxable_total: 100, exent_total: 300, taxable_total: 100, subtotal: 400, gross_total: 400, tax_total: 13, net_total: 413
43
+ items = []
44
+ items << FE::Document::Item.new(code: "001", line_number: 1, quantity: 1, unit: "Sp", description: "Desarrollo de Software y Mantenimiento", unit_price: 300, subtotal: 300, net_total: 300, total: 300)
45
+ taxes = [FE::Document::Tax.new(code: "01", rate: 13, total: (100 * 0.13))]
46
+ items << FE::Document::Item.new(code: "002", line_number: 2, quantity: 2, unit: "Unid", description: "Impresora de POS", unit_price: 50, total: 100, taxes: taxes, net_total: 113, subtotal: 100)
47
+ summary = FE::Document::Summary.new currency: "USD", exchange_rate: 575, services_exent_total: 300, goods_taxable_total: 100, exent_total: 300, taxable_total: 100, subtotal: 400, gross_total: 400, tax_total: 13, net_total: 413
48
48
 
49
49
 
50
- invoice = FE::Invoice.new date: date, issuer: issuer, receiver: receiver, number: number, items: items, condition: condition, credit_term: credit_term, summary: summary, security_code: "12345678", document_situation: "1"
50
+ invoice = FE::Invoice.new date: date, issuer: issuer, receiver: receiver, number: number, items: items, condition: condition, credit_term: credit_term, summary: summary, security_code: "12345678", document_situation: "1"
51
51
 
52
- # Para generar el XML como string
53
- xml = invoice.generate
54
-
55
- # Escribir el archivo
56
- File.open("/path/to/file.xml","w"){|f| f.write(xml)}
52
+ # Para generar el XML como string
53
+ xml = invoice.generate
54
+
55
+ # Escribir el archivo
56
+ File.open("/path/to/file.xml","w"){|f| f.write(xml)}
57
57
  ```
58
58
 
59
59
  Para configurar el API / Firmador:
60
60
  ```ruby
61
61
 
62
- FE.configure do |config|
63
- config.api_username "su_usuario_api_atv"
64
- config.api_password = "su_password_api_atv"
65
- config.key_path = "tmp/llave_criptografica.p12"
66
- config.key_password = "99999999999999"
67
- # api hacienda: valores default
68
- config.api_client_id = 'api-stag'
69
- config.documents_endpoint = "https://api.comprobanteselectronicos.go.cr/recepcion-sandbox/v1"
70
- config.authentication_endpoint = "https://idp.comprobanteselectronicos.go.cr/auth/realms/rut-stag/protocol/openid-connect/token"s
71
- end
62
+ FE.configure do |config|
63
+ config.api_username "su_usuario_api_atv"
64
+ config.api_password = "su_password_api_atv"
65
+ config.key_path = "tmp/llave_criptografica.p12"
66
+ config.key_password = "99999999999999"
67
+ # api hacienda: valores default
68
+ config.api_client_id = 'api-stag'
69
+ config.documents_endpoint = "https://api.comprobanteselectronicos.go.cr/recepcion-sandbox/v1"
70
+ config.authentication_endpoint = "https://idp.comprobanteselectronicos.go.cr/auth/realms/rut-stag/protocol/openid-connect/token"s
71
+ end
72
72
  ```
73
73
 
74
74
  Para firmar documentos. (Debe tener java instalado)
@@ -81,27 +81,27 @@ Para firmar documentos. (Debe tener java instalado)
81
81
 
82
82
  Para enviar documentos al API
83
83
  ```ruby
84
-
85
- api = FE::API.new
86
- # document is FE::Document
87
- signed_document = FE::SignedDocument.new(document,path)
88
- api = FE::Api.new
89
- if api.send_document(signed_document.payload)
90
- puts "Document sent!"
91
- else
92
- puts "Error: #{api.errors}"
93
- end
84
+
85
+ api = FE::API.new
86
+ # document is FE::Document
87
+ signed_document = FE::SignedDocument.new(document,path)
88
+ api = FE::Api.new
89
+ if api.send_document(signed_document.payload)
90
+ puts "Document sent!"
91
+ else
92
+ puts "Error: #{api.errors}"
93
+ end
94
94
  ```
95
95
 
96
96
  Para chequear el estatus del documento
97
97
  ```ruby
98
98
 
99
- api = FE::API.new
100
- FE::Utils.configure(options[:config_file])
101
- api = FE::Api.new
102
- document_status = api.get_document_status(key)
103
- puts document_status.to_h
104
- #=> {key: "50601011600310112345600100010100000000011999999999", date: "2016-01-01T00:00:00-0600", status: "aceptado", datails: ""}
99
+ api = FE::API.new
100
+ FE::Utils.configure(options[:config_file])
101
+ api = FE::Api.new
102
+ document_status = api.get_document_status(key)
103
+ puts document_status.to_h
104
+ #=> {key: "50601011600310112345600100010100000000011999999999", date: "2016-01-01T00:00:00-0600", status: "aceptado", datails: ""}
105
105
  ```
106
106
 
107
107
  ## Lína de comando
@@ -112,15 +112,22 @@ Para utilziar la línea de comando y generar documentos de prueba, debe generar
112
112
 
113
113
  Modifique los archivos config.yml y data.yml para utilziar la línea de comando
114
114
 
115
- Para generar documentos:
115
+ Resumen de la funcionalidad de la línea de comando
116
116
 
117
- $ facturacr generate help
118
-
117
+ $ facturacr help
119
118
  Commands:
120
- facturacr generate credit_note # generates an XML credit note
121
- facturacr generate debit_note # generates an XML debit note
122
- facturacr generate help [COMMAND] # Describe subcommands or one specific subcommand
123
- facturacr generate invoice # generates an XML invoice
119
+ facturacr check KEY # checks a sent document in the api
120
+ facturacr generate DOCUMENT ARGS # generate xml documents
121
+ facturacr generate credit_note # generates an XML credit note
122
+ facturacr generate debit_note # generates an XML debit note
123
+ facturacr generate help [COMMAND] # Describe subcommands or one specific subcommand
124
+ facturacr generate invoice # generates an XML invoice
125
+ facturacr generate reception_message # generate an XML reception message
126
+ facturacr generate ticket # generates an XML ticket
127
+ facturacr help [COMMAND] # Describe available commands or one specific command
128
+ facturacr send_document SIGNED_XML # sends the SIGNED_XML file to the API
129
+ facturacr setup PATH # will create a tmp directory with a sample config file and a sample data file at the specified path.
130
+ facturacr sign XML_IN XML_OUT # signs the xml document and stores the signed document in the output path
124
131
 
125
132
  Por ejemplo, para generar una factura
126
133
 
@@ -156,7 +163,7 @@ Adicionalmente se pueden especificar las opciones para firma y enviar a hacienda
156
163
 
157
164
  Para firmar documentos
158
165
 
159
- $ facturacr sign_document /path/to/unsigned.xml /path/to/signed.xml
166
+ $ facturacr sign /path/to/unsigned.xml /path/to/signed.xml
160
167
 
161
168
  Para enviar documentos
162
169
 
data/lib/facturacr/api.rb CHANGED
@@ -24,7 +24,8 @@ module FE
24
24
 
25
25
  @token
26
26
  rescue => e
27
- raise "AUTH ERROR"
27
+ puts "AUTH ERROR: #{e.message}".red
28
+ raise e
28
29
  end
29
30
 
30
31
 
@@ -45,7 +46,13 @@ module FE
45
46
 
46
47
  def get_document(key)
47
48
  authenticate
48
- response = RestClient.get "#{@document_endpoint}/comprogantes/#{key}", {:Authorization=> "bearer #{@token}", content_type: :json}
49
+ response = RestClient.get "#{@document_endpoint}/comprobantes/#{key}", {:Authorization=> "bearer #{@token}", content_type: :json}
50
+ JSON.parse(response)
51
+ end
52
+
53
+ def get_documents
54
+ authenticate
55
+ response = RescClient.get "#{@document_endpoint}/comprobantes", {:Authorization => "bearer #{@token}", content_type: :json }
49
56
  JSON.parse(response)
50
57
  end
51
58
 
@@ -132,6 +132,38 @@ module FE
132
132
  FE::Invoice.new date: args[:date], issuer: issuer, receiver: receiver, number: args[:number], items: items, condition: args[:condition], credit_term: args[:credit_term], summary: summary, security_code: args[:security_code], document_situation: args[:document_situation]
133
133
  end
134
134
 
135
+ def ticket(args = {})
136
+ if args[:issuer].is_a?(Hash)
137
+ issuer = self.issuer(args[:issuer])
138
+ else
139
+ issuer = args[:issuer]
140
+ end
141
+
142
+ if args[:receiver].is_a?(Hash)
143
+ receiver = self.receiver(args[:receiver])
144
+ else
145
+ receiver = args[:receiver]
146
+ end
147
+
148
+ if args[:items].is_a?(Array) && args[:items].first.is_a?(Hash)
149
+ tmp_items = []
150
+ args[:items].each do |i|
151
+ tmp_items << self.item(i)
152
+ end
153
+ items = tmp_items
154
+ else
155
+ items = args[:items]
156
+ end
157
+
158
+ if args[:summary].is_a?(Hash)
159
+ summary = self.summary(args[:summary])
160
+ else
161
+ summary = args[:summary]
162
+ end
163
+ FE::Ticket.new date: args[:date], issuer: issuer, receiver: receiver, number: args[:number], items: items, condition: args[:condition], credit_term: args[:credit_term], summary: summary, security_code: args[:security_code], document_situation: args[:document_situation]
164
+ end
165
+
166
+
135
167
  def credit_note(args = {})
136
168
  if args[:issuer].is_a?(Hash)
137
169
  issuer = self.issuer(args[:issuer])
@@ -214,6 +246,13 @@ module FE
214
246
  FE::DebitNote.new date: args[:date], issuer: issuer, receiver: receiver, number: args[:number], items: items, condition: args[:condition], credit_term: args[:credit_term], summary: summary, security_code: args[:security_code], document_situation: args[:document_situation], references: references
215
247
  end
216
248
 
249
+ def reception_message(args={})
250
+ FE::ReceptionMessage.new number: args[:number], date: args[:date], key: args[:key],
251
+ issuer_id_number: args[:issuer_id_number], issuer_id_type: args[:issuer_id_type],
252
+ receiver_id_number: args[:receiver_id_number], receiver_id_type: args[:receiver_id_type],
253
+ message: args[:message], details: args[:details], tax: args[:tax], total: args[:total], security_code: args[:security_code], document_situation: args[:document_situation]
254
+ end
255
+
217
256
 
218
257
  def reference(args={})
219
258
  FE::Document::Reference.new args
@@ -19,7 +19,7 @@ module FE
19
19
  invoice.number = options[:number].to_i if options[:number].present?
20
20
 
21
21
  if options[:output_path]
22
- output_path = output_path
22
+ output_path = options[:output_path]
23
23
  else
24
24
  output_path = "tmp/#{invoice.key}.xml"
25
25
  end
@@ -55,7 +55,7 @@ module FE
55
55
  credit_note.number = options[:number].to_i if options[:number].present?
56
56
 
57
57
  if options[:output_path]
58
- output_path = output_path
58
+ output_path = options[:output_path]
59
59
  else
60
60
  output_path = "tmp/#{credit_note.key}.xml"
61
61
  end
@@ -90,7 +90,7 @@ module FE
90
90
  debit_note.number = options[:number].to_i if options[:number].present?
91
91
 
92
92
  if options[:output_path]
93
- output_path = output_path
93
+ output_path = options[:output_path]
94
94
  else
95
95
  output_path = "tmp/#{debit_note.key}.xml"
96
96
  end
@@ -102,6 +102,82 @@ module FE
102
102
 
103
103
  end
104
104
 
105
+ desc "ticket", "generates an XML ticket"
106
+ method_option :config_file, aliases: '-c', desc: "default configuration file", default: "tmp/config.yml"
107
+ method_option :number, aliases: '-n', desc: "set the number of the document"
108
+ method_option :sign, type: :boolean, default: false
109
+ method_option :send, type: :boolean, default: false
110
+ method_option :data_path, default: "tmp/data.yml"
111
+ method_option :output_path, desc: "path to save the output"
112
+ def ticket
113
+ data = YAML.load_file(options[:data_path]).with_indifferent_access
114
+ builder = FE::Builder.new
115
+
116
+ ticket = builder.ticket(data[:document])
117
+ ticket.date = Time.now
118
+ ticket.number = options[:number].to_i if options[:number].present?
119
+
120
+ if options[:output_path]
121
+ output_path = options[:output_path]
122
+ else
123
+ output_path = "tmp/#{ticket.key}.xml"
124
+ end
125
+
126
+ write(ticket, output_path)
127
+ print_details(ticket)
128
+ sign(output_path, options) if options[:sign]
129
+ send_document("#{output_path}.signed.xml") if options[:sign] && options[:send]
130
+
131
+ end
132
+ desc "reception_message", "generate an XML reception message"
133
+ method_option :xml_in, aliases: '-i', desc: "path to the xml invoice to accept"
134
+ method_option :number, aliases: '-n', desc: "the number of the document"
135
+ method_option :output_path, desc: "path to save the output"
136
+ method_option :sign, type: :boolean, default: false
137
+ method_option :send, type: :boolean, default: false
138
+ method_option :action, aliases: '-a', desc: "action 1=total 2=partial 3=reject", limited_to: [1,2,3]
139
+ method_option :details, desc: "details to include"
140
+ method_option :document_situation, desc: "the situation of the document", default: "1"
141
+ method_option :config_file, aliases: '-c', desc: "default configuration file", default: "tmp/config.yml"
142
+ def reception_message
143
+ doc = XmlDocument.new(options[:xml_in])
144
+
145
+ builder = FE::Builder.new
146
+
147
+ # Roles of receiver and issuer are inverted because they are extracted from the document.
148
+ # The ISSUER of the reception message is the RECEIVER of the document
149
+ message = builder.reception_message({
150
+ key: doc.document.key,
151
+ date: doc.document.date,
152
+ number: options[:number],
153
+ issuer_id_number: doc.document.receiver.identification_document.id_number,
154
+ issuer_id_type: doc.document.receiver.identification_document.document_type,
155
+ receiver_id_number: doc.document.issuer.identification_document.id_number,
156
+ receiver_id_type: doc.document.issuer.identification_document.document_type,
157
+ message: options[:action],
158
+ tax: doc.document.summary.tax_total,
159
+ total: doc.document.summary.net_total,
160
+ document_situation: options[:document_situation]
161
+ })
162
+
163
+ message.security_code = (SecureRandom.random_number * (10**8)).round.to_s
164
+ if options[:output_path]
165
+ output_path = options[:output_path]
166
+ else
167
+ output_path = "tmp/msj-receptor-#{message.key}.xml"
168
+ end
169
+ write(message, output_path)
170
+ puts "Mensaje Receptor"
171
+ puts "Accion: #{FE::ReceptionMessage::MESSAGE_TYPES[message.message]}"
172
+ puts "Factura: #{doc.document.key}"
173
+ puts "Ced. Receptor: #{message.receiver_id_number}"
174
+ puts "Ced. Emisor: #{message.issuer_id_number}"
175
+
176
+ sign(output_path, options) if options[:sign]
177
+ send_document("#{output_path}.signed.xml") if options[:sign] && options[:send]
178
+
179
+ end
180
+
105
181
  no_commands{
106
182
  def write(document, output_path)
107
183
  File.open(output_path, 'w'){|f| f.write(document.generate.gsub("\n",""))}
@@ -115,10 +191,10 @@ module FE
115
191
  end
116
192
 
117
193
  def sign(path, options)
118
- puts " => SIGN ..............."
194
+ puts "=> SIGN ................."
119
195
  cli = FE::CLI.new
120
196
  cli.options = {config_file: options[:config_file]}
121
- cli.sign_document("#{path}", "#{path}.signed.xml")
197
+ cli.sign("#{path}", "#{path}.signed.xml")
122
198
  end
123
199
 
124
200
  def send_document(path)
data/lib/facturacr/cli.rb CHANGED
@@ -53,9 +53,9 @@ module FE
53
53
  desc "generate DOCUMENT ARGS", "generate xml documents"
54
54
  subcommand "generate", Generate
55
55
 
56
- desc "sign_document XML_IN XML_OUT", "signs the xml document and stores the signed document in the output path"
56
+ desc "sign XML_IN XML_OUT", "signs the xml document and stores the signed document in the output path"
57
57
  method_option :config_file, aliases: '-c', desc: "default configuration file", default: "tmp/config.yml"
58
- def sign_document(xml_in, xml_out)
58
+ def sign(xml_in, xml_out)
59
59
  FE::Utils.configure(options[:config_file])
60
60
  signer = FE::JavaSigner.new FE.configuration.key_path, FE.configuration.key_password, xml_in, xml_out
61
61
  signer.sign
@@ -66,15 +66,18 @@ module FE
66
66
  def send_document(path)
67
67
  FE::Utils.configure(options[:config_file])
68
68
  xml_document = FE::XmlDocument.new(path)
69
- invoice = xml_document.document
70
- signed_document = FE::SignedDocument.new(invoice,path)
69
+ document = xml_document.document
70
+ if document.is_a?(FE::ReceptionMessage)
71
+ document.receiver_id_type = "02"
72
+ end
73
+ signed_document = FE::SignedDocument.new(document,path)
71
74
  api = FE::Api.new
72
75
  if api.send_document(signed_document.payload)
73
76
  puts "Document Sent".green
74
- puts "KEY: #{invoice.key}"
77
+ puts "KEY: #{document.key}"
75
78
  puts "Wait 5 seconds before check..."
76
79
  sleep 5
77
- invoke :check, [invoice.key], :config_file=>options[:config_file]
80
+ invoke :check, [document.key], :config_file=>options[:config_file]
78
81
  else
79
82
  puts "ERROR".red
80
83
  ap api.errors
@@ -82,18 +85,7 @@ module FE
82
85
  end
83
86
  end
84
87
 
85
- desc "test_invoice NUMBER DATA_PATH", "generates a test invoice and sends it to the api"
86
- method_option :config_file, aliases: '-c', desc: "default configuration file", default: "tmp/config.yml"
87
- def test_invoice(number, data_path)
88
- FE::Utils.configure(options[:config_file])
89
- puts "Generating document ..."
90
- invoke :generate_invoice, [data_path,"tmp/unsigned_#{number}.xml"], number: number
91
- puts "Signing document ..."
92
- invoke :sign_document, ["tmp/unsigned_#{number}.xml","tmp/#{number}.xml"]
93
- puts "Sending ..."
94
- invoke :send_document, ["tmp/#{number}.xml"]
95
- end
96
-
88
+
97
89
  desc "setup PATH", "will create a tmp directory with a sample config file and a sample data file at the specified path."
98
90
  def setup(path)
99
91
  puts "\n\n SETUP FACTURACR \n\n"
@@ -103,8 +95,8 @@ module FE
103
95
  answer = ask("Are you sure you want to continue?", :yellow, limited_to: ["y","n"])
104
96
  if answer.downcase == "y"
105
97
  FileUtils.mkdir_p "#{path}/tmp"
106
- FileUtils.cp "resources/data.yml", "#{path}/tmp/data.yml"
107
- FileUtils.cp "config/config.yml", "#{path}/tmp/config.yml"
98
+ FileUtils.cp "#{FE.root}/resources/data.yml", "#{path}/tmp/data.yml"
99
+ FileUtils.cp "#{FE.root}/config/config.yml", "#{path}/tmp/config.yml"
108
100
  say "Done.", :green
109
101
  else
110
102
  say "Ok. Bye", :green
@@ -17,7 +17,7 @@ module FE
17
17
  }
18
18
 
19
19
  validates :document_type, presence: true, inclusion: FE::Document::DOCUMENT_TYPES.keys
20
- validates :number, presence: true, length: {is: 50}
20
+ validates :number, presence: true, length: {maximum: 50}
21
21
  validates :date, presence: true
22
22
  validates :code, presence: true, length: {is: 2}, inclusion: REFERENCE_CODES.keys
23
23
  validates :reason, presence: true, length: {maximum: 180}
@@ -0,0 +1,118 @@
1
+ require 'active_model'
2
+
3
+ module FE
4
+ class ReceptionMessage
5
+ include ActiveModel::Validations
6
+
7
+ MESSAGE_TYPES = {
8
+ "1" => "Aceptado",
9
+ "2" => "Aceptacion Parcial",
10
+ "3" => "Rechazado"
11
+ }
12
+ attr_accessor :key, :date, :issuer_id_number, :receiver_id_number, :message, :details, :tax, :total, :number, :receiver_id_type, :security_code, :document_situation
13
+
14
+ validates :date, presence: true
15
+ validates :issuer_id_number, presence: true, length: {is: 12}
16
+ validates :receiver_id_number, presence: true, length: {is: 12}
17
+ validates :message, presence: true, inclusion: MESSAGE_TYPES.keys
18
+ validates :tax, numericality: true, if: -> { tax.present? }
19
+ validates :total, presence: true, numericality: true
20
+ validates :number, presence: true
21
+ validates :security_code, presence: true, length: {is: 8}
22
+
23
+ def initialize(args = {})
24
+ @key = args[:key]
25
+ @date = args[:date]
26
+ @issuer_id_number = args[:issuer_id_number]
27
+ @receiver_id_type = args[:receiver_id_type]
28
+ @receiver_id_number = args[:receiver_id_number]
29
+ @message = args[:message].to_s
30
+ @details = args[:details]
31
+ @tax = args[:tax]
32
+ @total = args[:total]
33
+ @number = args[:number].to_i
34
+ @security_code = args[:security_code]
35
+ @document_situation = args[:document_situation]
36
+ @namespaces = {
37
+ "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
38
+ "xmlns:xsd"=>"http://www.w3.org/2001/XMLSchema",
39
+ "xmlns"=>"https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/mensajeReceptor"
40
+ }
41
+ end
42
+
43
+ def key
44
+ raise "Documento inválido: #{errors.messages}" unless valid?
45
+ country = "506"
46
+ day = "%02d" % @date.day
47
+ month = "%02d" % @date.month
48
+ year = "%02d" % (@date.year - 2000)
49
+ id_number = @receiver_id_number.rjust(12,"0")
50
+
51
+ situation = @document_situation
52
+ security_code = @security_code
53
+
54
+ result = "#{country}#{day}#{month}#{year}#{id_number}#{sequence}#{situation}#{security_code}"
55
+ raise "The key is invalid: #{result}" unless result.length.eql?(50)
56
+
57
+ result
58
+ end
59
+
60
+ def headquarters
61
+ @headquarters ||= "001"
62
+ end
63
+
64
+ def terminal
65
+ @terminal ||= "00001"
66
+ end
67
+
68
+ def sequence
69
+ if @message.eql?("1")
70
+ @document_type = "05"
71
+ elsif @message.eql?("2")
72
+ @document_type = "06"
73
+ elsif @message.eql?("3")
74
+ @document_type = "07"
75
+ end
76
+ cons = ("%010d" % @number)
77
+ "#{headquarters}#{terminal}#{@document_type}#{cons}"
78
+ end
79
+
80
+
81
+
82
+ def build_xml
83
+ raise "Documento inválido: #{errors.messages}" unless valid?
84
+ builder = Nokogiri::XML::Builder.new
85
+
86
+ builder.MensajeReceptor(@namespaces) do |xml|
87
+ xml.Clave key
88
+ xml.NumeroCedulaEmisor @issuer_id_number
89
+ xml.FechaEmisionDoc @date.xmlschema
90
+ xml.Mensaje @message
91
+ xml.DetalleMensaje @details if @details
92
+ xml.MontoTotalImpuesto @tax if @tax
93
+ xml.TotalFactura @total
94
+ xml.NumeroCedulaReceptor @receiver_id_number
95
+ xml.NumConsecutivoReceptor sequence
96
+ end
97
+
98
+ builder
99
+ end
100
+
101
+ def generate
102
+ build_xml.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML)
103
+ end
104
+
105
+ def api_payload
106
+ payload = {}
107
+ payload[:clave] = key
108
+ payload[:fecha] = @date.xmlschema
109
+ payload[:emisor] = {
110
+ tipoIdentificacion: @receiver_id_type,
111
+ numeroIdentificacion: @receiver_id_number
112
+ }
113
+ payload
114
+ end
115
+
116
+
117
+ end
118
+ end
@@ -21,8 +21,7 @@ module FE
21
21
  @namespaces = {
22
22
  "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
23
23
  "xmlns:xsd"=>"http://www.w3.org/2001/XMLSchema",
24
- "xmlns"=>"https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/tiqueteElectronico",
25
- "xsi:schemaLocation"=>"https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/tiqueteElectronico https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/tiqueteElectronico.xsd"
24
+ "xmlns"=>"https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/tiqueteElectronico"
26
25
  }
27
26
  end
28
27
 
@@ -1,3 +1,3 @@
1
1
  module FE
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
@@ -21,138 +21,158 @@ module FE
21
21
  @document = FE::CreditNote.new
22
22
  elsif root_tag.eql?("NotaDebitoElectronica")
23
23
  @document = FE::DebitNote.new
24
+ elsif root_tag.eql?("TiqueteElectronico")
25
+ @document = FE::Ticket.new
26
+ elsif root_tag.eql?("MensajeReceptor")
27
+ @document = FE::ReceptionMessage.new
24
28
  end
25
- @document.date = DateTime.parse(@doc.css("#{root_tag} FechaEmision").text)
26
- @key = @doc.css("#{root_tag} Clave").text
27
- @document.number = @key[31..40].to_i
28
- @document.document_situation = @key[41]
29
- @document.security_code = @key[42..-1]
30
- @document.condition = @doc.css("#{root_tag} CondicionVenta").text
31
- @document.credit_term = @doc.css("#{root_tag} PlazoCredito").text unless @doc.css("#{root_tag} PlazoCredito").empty?
32
- @document.payment_type = @doc.css("#{root_tag} MedioPago").first.text
33
29
 
34
- @issuer = FE::Document::Issuer.new
35
- @issuer.identification_document = FE::Document::IdentificationDocument.new type: @doc.css("#{root_tag} Emisor Identificacion Tipo").text, number: @doc.css("#{root_tag} Emisor Identificacion Numero").text.to_i
36
- @issuer.name = @doc.css("#{root_tag} Emisor Nombre").text
37
- @issuer.comercial_name = @doc.css("#{root_tag} Emisor NombreComercial").text unless @doc.css("#{root_tag} Emisor NombreComercial").empty?
38
- location = FE::Document::Location.new
39
- location.province = @doc.css("#{root_tag} Emisor Ubicacion Provincia").text
40
- location.county = @doc.css("#{root_tag} Emisor Ubicacion Canton").text
41
- location.district = @doc.css("#{root_tag} Emisor Ubicacion Distrito").text
42
- location.others = @doc.css("#{root_tag} Emisor Ubicacion OtrasSenas").text
43
- @issuer.location = location
30
+ if @document.is_a?(FE::Document)
31
+ @document.date = DateTime.parse(@doc.css("#{root_tag} FechaEmision").text)
32
+ @key = @doc.css("#{root_tag} Clave").text
33
+ @document.number = @key[31..40].to_i
34
+ @document.document_situation = @key[41]
35
+ @document.security_code = @key[42..-1]
36
+ @document.condition = @doc.css("#{root_tag} CondicionVenta").text
37
+ @document.credit_term = @doc.css("#{root_tag} PlazoCredito").text unless @doc.css("#{root_tag} PlazoCredito").empty?
38
+ @document.payment_type = @doc.css("#{root_tag} MedioPago").first.text
44
39
 
45
- if !@doc.css("#{root_tag} Emisor Telefono").empty?
46
- @issuer.phone = FE::Document::Phone.new country_code: @doc.css("#{root_tag} Emisor Telefono CodigoPais").text, number: @doc.css("#{root_tag} Emisor Telefono CodigoPais").text
47
- end
48
- if !@doc.css("#{root_tag} Emisor Fax").empty?
49
- @issuer.fax = FE::Document::Phone.new country_code: @doc.css("#{root_tag} Emisor Telefono CodigoPais").text, number: @doc.css("#{root_tag} Emisor Telefono CodigoPais").text
50
- end
51
- @issuer.email = @doc.css("#{root_tag} Emisor CorreoElectronico").text
40
+ @issuer = FE::Document::Issuer.new
41
+ @issuer.identification_document = FE::Document::IdentificationDocument.new type: @doc.css("#{root_tag} Emisor Identificacion Tipo").text, number: @doc.css("#{root_tag} Emisor Identificacion Numero").text.to_i
42
+ @issuer.name = @doc.css("#{root_tag} Emisor Nombre").text
43
+ @issuer.comercial_name = @doc.css("#{root_tag} Emisor NombreComercial").text unless @doc.css("#{root_tag} Emisor NombreComercial").empty?
44
+ location = FE::Document::Location.new
45
+ location.province = @doc.css("#{root_tag} Emisor Ubicacion Provincia").text
46
+ location.county = @doc.css("#{root_tag} Emisor Ubicacion Canton").text
47
+ location.district = @doc.css("#{root_tag} Emisor Ubicacion Distrito").text
48
+ location.others = @doc.css("#{root_tag} Emisor Ubicacion OtrasSenas").text
49
+ @issuer.location = location
52
50
 
53
- unless @doc.css("#{root_tag} Receptor").empty?
54
- @receiver = FE::Document::Receiver.new
55
- @receiver.name = @doc.css("#{root_tag} Receptor Nombre").text
56
- unless @doc.css("#{root_tag} Receptor Identificacion").empty?
57
- @receiver.identification_document = FE::Document::IdentificationDocument.new type: @doc.css("#{root_tag} Receptor Identificacion Tipo").text, number: @doc.css("#{root_tag} Receptor Identificacion Numero").text.to_i
51
+ if !@doc.css("#{root_tag} Emisor Telefono").empty?
52
+ @issuer.phone = FE::Document::Phone.new country_code: @doc.css("#{root_tag} Emisor Telefono CodigoPais").text, number: @doc.css("#{root_tag} Emisor Telefono CodigoPais").text
58
53
  end
59
-
60
- unless @doc.css("#{root_tag} Receptor IdentificacionExtranjero").empty?
61
- @receiver.foreign_id_number = @doc.css("#{root_tag} Receptor IdentificacionExtranjero").text
54
+ if !@doc.css("#{root_tag} Emisor Fax").empty?
55
+ @issuer.fax = FE::Document::Phone.new country_code: @doc.css("#{root_tag} Emisor Telefono CodigoPais").text, number: @doc.css("#{root_tag} Emisor Telefono CodigoPais").text
62
56
  end
63
- @receiver.comercial_name = @doc.css("#{root_tag} Receptor NombreComercial").text unless @doc.css("#{root_tag} Receptor NombreComercial").empty?
57
+ @issuer.email = @doc.css("#{root_tag} Emisor CorreoElectronico").text
58
+
59
+ unless @doc.css("#{root_tag} Receptor").empty?
60
+ @receiver = FE::Document::Receiver.new
61
+ @receiver.name = @doc.css("#{root_tag} Receptor Nombre").text
62
+ unless @doc.css("#{root_tag} Receptor Identificacion").empty?
63
+ @receiver.identification_document = FE::Document::IdentificationDocument.new type: @doc.css("#{root_tag} Receptor Identificacion Tipo").text, number: @doc.css("#{root_tag} Receptor Identificacion Numero").text.to_i
64
+ end
64
65
 
65
- unless @doc.css("#{root_tag} Receptor Ubicacion").empty?
66
- location = FE::Document::Location.new
67
- location.province = @doc.css("#{root_tag} Receptor Ubicacion Provincia").text
68
- location.county = @doc.css("#{root_tag} Receptor Ubicacion Canton").text
69
- location.district = @doc.css("#{root_tag} Receptor Ubicacion Distrito").text
70
- location.others = @doc.css("#{root_tag} Receptor Ubicacion OtrasSenas").text
71
- @receiver.location = location
72
- end
66
+ unless @doc.css("#{root_tag} Receptor IdentificacionExtranjero").empty?
67
+ @receiver.foreign_id_number = @doc.css("#{root_tag} Receptor IdentificacionExtranjero").text
68
+ end
69
+ @receiver.comercial_name = @doc.css("#{root_tag} Receptor NombreComercial").text unless @doc.css("#{root_tag} Receptor NombreComercial").empty?
73
70
 
74
- if !@doc.css("#{root_tag} Receptor Telefono").empty?
75
- @issuer.phone = FE::Document::Phone.new country_code: @doc.css("#{root_tag} Receptor Telefono CodigoPais").text, number: @doc.css("#{root_tag} Receptor Telefono CodigoPais").text
76
- end
77
- if !@doc.css("#{root_tag} Receptor Fax").empty?
78
- @receiver.fax = FE::Document::Phone.new country_code: @doc.css("#{root_tag} Receptor Telefono CodigoPais").text, number: @doc.css("#{root_tag} Receptor Telefono CodigoPais").text
79
- end
80
- @receiver.email = @doc.css("#{root_tag} Receptor CorreoElectronico").text unless @doc.css("#{root_tag} Receptor CorreoElectronico").empty?
81
- end
82
- @items = []
83
- @doc.css("#{root_tag} DetalleServicio LineaDetalle").each do |line|
84
- item = FE::Document::Item.new
85
- item.line_number = line.css("NumeroLinea").text.to_i
86
- item.code = line.css("Codigo Codigo").text
87
- item.quantity = line.css("Cantidad").text
88
- item.unit = line.css("UnidadMedida").text
89
- item.description = line.css("Detalle").text
90
- item.unit_price = line.css("PrecioUnitario").text.to_f
91
- item.total = line.css("MontoTotal").text.to_f
92
- item.discount = line.css("MontoDescuento").text.to_f unless line.css("MontoDescuento").empty?
93
- item.discount_reason = line.css("NaturalezaDescuento").text unless line.css("NaturalezaDescuento").empty?
94
- item.subtotal = line.css("SubTotal").text.to_f
95
- item.net_total = line.css("MontoTotalLinea").text.to_f
96
- item.taxes = []
97
- line.css("Impuesto").each do |tax|
98
- item.taxes << FE::Document::Tax.new(code: tax.css("Codigo").text, rate: tax.css("Tarifa").text.to_f, total: tax.css("Monto").text.to_f)
71
+ unless @doc.css("#{root_tag} Receptor Ubicacion").empty?
72
+ location = FE::Document::Location.new
73
+ location.province = @doc.css("#{root_tag} Receptor Ubicacion Provincia").text
74
+ location.county = @doc.css("#{root_tag} Receptor Ubicacion Canton").text
75
+ location.district = @doc.css("#{root_tag} Receptor Ubicacion Distrito").text
76
+ location.others = @doc.css("#{root_tag} Receptor Ubicacion OtrasSenas").text
77
+ @receiver.location = location
78
+ end
79
+
80
+ if !@doc.css("#{root_tag} Receptor Telefono").empty?
81
+ @issuer.phone = FE::Document::Phone.new country_code: @doc.css("#{root_tag} Receptor Telefono CodigoPais").text, number: @doc.css("#{root_tag} Receptor Telefono CodigoPais").text
82
+ end
83
+ if !@doc.css("#{root_tag} Receptor Fax").empty?
84
+ @receiver.fax = FE::Document::Phone.new country_code: @doc.css("#{root_tag} Receptor Telefono CodigoPais").text, number: @doc.css("#{root_tag} Receptor Telefono CodigoPais").text
85
+ end
86
+ @receiver.email = @doc.css("#{root_tag} Receptor CorreoElectronico").text unless @doc.css("#{root_tag} Receptor CorreoElectronico").empty?
99
87
  end
100
- unless line.css("Exoneracion").empty?
101
- exo = FE::Document::Exoneration.new
102
- exo.document_type = line.css("Exoneracion TipoDocumento").text
103
- exo.document_number = line.css("Exoneracion NumeroDocumento").text
104
- exo.institution = line.css("Exoneracion NombreInstitucion").text
105
- exo.date = DateTime.parse(line.css("Exoneracion FechaEmision").text)
106
- exo.total_tax = line.css("Exoneracion MontoImpuesto").text.to_f
107
- exo.percentage = line.css("Exoneracion PorcentajeCompra").text.to_i
108
- item.exoneration = exo
88
+ @items = []
89
+ @doc.css("#{root_tag} DetalleServicio LineaDetalle").each do |line|
90
+ item = FE::Document::Item.new
91
+ item.line_number = line.css("NumeroLinea").text.to_i
92
+ item.code = line.css("Codigo Codigo").text
93
+ item.quantity = line.css("Cantidad").text
94
+ item.unit = line.css("UnidadMedida").text
95
+ item.description = line.css("Detalle").text
96
+ item.unit_price = line.css("PrecioUnitario").text.to_f
97
+ item.total = line.css("MontoTotal").text.to_f
98
+ item.discount = line.css("MontoDescuento").text.to_f unless line.css("MontoDescuento").empty?
99
+ item.discount_reason = line.css("NaturalezaDescuento").text unless line.css("NaturalezaDescuento").empty?
100
+ item.subtotal = line.css("SubTotal").text.to_f
101
+ item.net_total = line.css("MontoTotalLinea").text.to_f
102
+ item.taxes = []
103
+ line.css("Impuesto").each do |tax|
104
+ item.taxes << FE::Document::Tax.new(code: tax.css("Codigo").text, rate: tax.css("Tarifa").text.to_f, total: tax.css("Monto").text.to_f)
105
+ end
106
+ unless line.css("Exoneracion").empty?
107
+ exo = FE::Document::Exoneration.new
108
+ exo.document_type = line.css("Exoneracion TipoDocumento").text
109
+ exo.document_number = line.css("Exoneracion NumeroDocumento").text
110
+ exo.institution = line.css("Exoneracion NombreInstitucion").text
111
+ exo.date = DateTime.parse(line.css("Exoneracion FechaEmision").text)
112
+ exo.total_tax = line.css("Exoneracion MontoImpuesto").text.to_f
113
+ exo.percentage = line.css("Exoneracion PorcentajeCompra").text.to_i
114
+ item.exoneration = exo
115
+ end
116
+ @items << item
109
117
  end
110
- @items << item
111
- end
112
118
 
113
119
 
114
- @summary = FE::Document::Summary.new
115
- sum = @doc.css("#{root_tag} ResumenFactura")
116
- @summary.currency = sum.css("CodigoMoneda").text
117
- @summary.exchange_rate = sum.css("TipoCambio").text.to_f
118
- @summary.services_taxable_total = sum.css("TotalServGravados").text.to_f
119
- @summary.services_exent_total = sum.css("TotalServExentos").text.to_f
120
- @summary.goods_taxable_total = sum.css("TotalMercanciasGravadas").text.to_f
121
- @summary.goods_exent_total = sum.css("TotalMercanciasExentas").text.to_f
122
- @summary.taxable_total = sum.css("TotalGravado").text.to_f
123
- @summary.exent_total = sum.css("TotalExento").text.to_f
124
- @summary.subtotal = sum.css("TotalVenta").text.to_f
125
- @summary.discount_total = sum.css("TotalDescuentos").text.to_f
126
- @summary.gross_total = sum.css("TotalVentaNeta").text.to_f
127
- @summary.tax_total = sum.css("TotalImpuesto").text.to_f
128
- @summary.net_total = sum.css("TotalComprobante").text.to_f
120
+ @summary = FE::Document::Summary.new
121
+ sum = @doc.css("#{root_tag} ResumenFactura")
122
+ @summary.currency = sum.css("CodigoMoneda").text
123
+ @summary.exchange_rate = sum.css("TipoCambio").text.to_f
124
+ @summary.services_taxable_total = sum.css("TotalServGravados").text.to_f
125
+ @summary.services_exent_total = sum.css("TotalServExentos").text.to_f
126
+ @summary.goods_taxable_total = sum.css("TotalMercanciasGravadas").text.to_f
127
+ @summary.goods_exent_total = sum.css("TotalMercanciasExentas").text.to_f
128
+ @summary.taxable_total = sum.css("TotalGravado").text.to_f
129
+ @summary.exent_total = sum.css("TotalExento").text.to_f
130
+ @summary.subtotal = sum.css("TotalVenta").text.to_f
131
+ @summary.discount_total = sum.css("TotalDescuentos").text.to_f
132
+ @summary.gross_total = sum.css("TotalVentaNeta").text.to_f
133
+ @summary.tax_total = sum.css("TotalImpuesto").text.to_f
134
+ @summary.net_total = sum.css("TotalComprobante").text.to_f
129
135
 
130
- refs = @doc.css("#{root_tag} InformacionReferencia")
131
- @references = []
132
- unless refs.empty?
133
- refs.each do |ref|
134
- reference = FE::Document::Reference.new
135
- reference.document_type = ref.css("TipoDoc")
136
- reference.number = ref.css("Numero")
137
- reference.date = ref.css("FechaEmision")
138
- reference.code = ref.css("Codigo")
139
- reference.reason = ref.css("Razon")
140
- @references << reference
136
+ refs = @doc.css("#{root_tag} InformacionReferencia")
137
+ @references = []
138
+ unless refs.empty?
139
+ refs.each do |ref|
140
+ reference = FE::Document::Reference.new
141
+ reference.document_type = ref.css("TipoDoc")
142
+ reference.number = ref.css("Numero")
143
+ reference.date = ref.css("FechaEmision")
144
+ reference.code = ref.css("Codigo")
145
+ reference.reason = ref.css("Razon")
146
+ @references << reference
147
+ end
141
148
  end
142
- end
143
149
 
144
- reg = @doc.css("#{root_tag} Normativa")
145
- @regulation = FE::Document::Regulation.new
146
- @regulation.number = reg.css("NumeroResolucion").text
147
- @regulation.date = reg.css("FechaResolucion").text
150
+ reg = @doc.css("#{root_tag} Normativa")
151
+ @regulation = FE::Document::Regulation.new
152
+ @regulation.number = reg.css("NumeroResolucion").text
153
+ @regulation.date = reg.css("FechaResolucion").text
148
154
 
149
155
 
150
- @document.issuer = @issuer
151
- @document.receiver = @receiver
152
- @document.items = @items
153
- @document.summary = @summary
154
- @document.references = @references
155
- @document.regulation = @regulation
156
+ @document.issuer = @issuer
157
+ @document.receiver = @receiver
158
+ @document.items = @items
159
+ @document.summary = @summary
160
+ @document.references = @references
161
+ @document.regulation = @regulation
162
+ else
163
+ @document.date = DateTime.parse(@doc.css("#{root_tag} FechaEmisionDoc").text)
164
+ @key = @doc.css("#{root_tag} Clave").text
165
+ @document.key = @key
166
+ @document.issuer_id_number = @doc.css("#{root_tag} NumeroCedulaEmisor").text
167
+ @document.receiver_id_number = @doc.css("#{root_tag} NumeroCedulaReceptor").text
168
+ @document.message = @doc.css("#{root_tag} Mensaje").text
169
+ @document.details = @doc.css("#{root_tag} DetalleMensaje").text
170
+ @document.number = @key[31..40].to_i
171
+ @document.document_situation = @key[41]
172
+ @document.security_code = @key[42..-1]
173
+ @document.total = @doc.css("#{root_tag} TotalFactura").text
174
+ @document.tax = @doc.css("#{root_tag} MontoTotalImpuesto").text
175
+ end
156
176
  else
157
177
  raise "#{xml_path} does not exist"
158
178
  end
data/lib/facturacr.rb CHANGED
@@ -12,6 +12,7 @@ require 'facturacr/api'
12
12
  require 'facturacr/builder'
13
13
  require 'facturacr/version'
14
14
  require 'facturacr/signer/signer'
15
+ require 'facturacr/reception_message'
15
16
 
16
17
  module FE
17
18
  class << self
@@ -0,0 +1,86 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <NotaCreditoElectronica xmlns="https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/notaCreditoElectronica" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3
+ <Clave>50601041800310263679500100001030000000111199999999</Clave>
4
+ <NumeroConsecutivo>00100001030000000111</NumeroConsecutivo>
5
+ <FechaEmision>2018-04-01T01:00:18-06:00</FechaEmision>
6
+ <Emisor>
7
+ <Nombre>EMISOR EJEMPLO</Nombre>
8
+ <Identificacion>
9
+ <Tipo>02</Tipo>
10
+ <Numero>3102123456</Numero>
11
+ </Identificacion>
12
+ <Ubicacion>
13
+ <Provincia>1</Provincia>
14
+ <Canton>01</Canton>
15
+ <Distrito>01</Distrito>
16
+ <OtrasSenas>Direccion</OtrasSenas>
17
+ </Ubicacion>
18
+ <Telefono>
19
+ <CodigoPais>506</CodigoPais>
20
+ <NumTelefono>22222222</NumTelefono>
21
+ </Telefono>
22
+ <CorreoElectronico>email@ejemplo.com</CorreoElectronico>
23
+ </Emisor>
24
+ <Receptor>
25
+ <Nombre>RECEPTOR EJEMPLO</Nombre>
26
+ <Identificacion>
27
+ <Tipo>01</Tipo>
28
+ <Numero>112345678</Numero>
29
+ </Identificacion>
30
+ </Receptor>
31
+ <CondicionVenta>01</CondicionVenta>
32
+ <MedioPago>01</MedioPago>
33
+ <DetalleServicio>
34
+ <LineaDetalle>
35
+ <NumeroLinea>1</NumeroLinea>
36
+ <Cantidad>1</Cantidad>
37
+ <UnidadMedida>Sp</UnidadMedida>
38
+ <Detalle>Honorarios por servicios profesionales</Detalle>
39
+ <PrecioUnitario>300</PrecioUnitario>
40
+ <MontoTotal>300</MontoTotal>
41
+ <SubTotal>300</SubTotal>
42
+ <MontoTotalLinea>300</MontoTotalLinea>
43
+ </LineaDetalle>
44
+ <LineaDetalle>
45
+ <NumeroLinea>2</NumeroLinea>
46
+ <Cantidad>2</Cantidad>
47
+ <UnidadMedida>Unid</UnidadMedida>
48
+ <Detalle>Articulo de Venta</Detalle>
49
+ <PrecioUnitario>50</PrecioUnitario>
50
+ <MontoTotal>100</MontoTotal>
51
+ <SubTotal>100</SubTotal>
52
+ <Impuesto>
53
+ <Codigo>01</Codigo>
54
+ <Tarifa>13</Tarifa>
55
+ <Monto>13</Monto>
56
+ </Impuesto>
57
+ <MontoTotalLinea>113</MontoTotalLinea>
58
+ </LineaDetalle>
59
+ </DetalleServicio>
60
+ <ResumenFactura>
61
+ <CodigoMoneda>USD</CodigoMoneda>
62
+ <TipoCambio>575</TipoCambio>
63
+ <TotalServGravados>0.0</TotalServGravados>
64
+ <TotalServExentos>300.0</TotalServExentos>
65
+ <TotalMercanciasGravadas>100.0</TotalMercanciasGravadas>
66
+ <TotalMercanciasExentas>0.0</TotalMercanciasExentas>
67
+ <TotalGravado>100.0</TotalGravado>
68
+ <TotalExento>300.0</TotalExento>
69
+ <TotalVenta>400.0</TotalVenta>
70
+ <TotalDescuentos>0.0</TotalDescuentos>
71
+ <TotalVentaNeta>400.0</TotalVentaNeta>
72
+ <TotalImpuesto>13.0</TotalImpuesto>
73
+ <TotalComprobante>413.0</TotalComprobante>
74
+ </ResumenFactura>
75
+ <InformacionReferencia>
76
+ <TipoDoc>01</TipoDoc>
77
+ <Numero>50601041800310263679500100001010000000109199999999</Numero>
78
+ <FechaEmision>2018-04-01T00:19:27-06:00</FechaEmision>
79
+ <Codigo>01</Codigo>
80
+ <Razon>Anula documento</Razon>
81
+ </InformacionReferencia>
82
+ <Normativa>
83
+ <NumeroResolucion>DGT-R-48-2016</NumeroResolucion>
84
+ <FechaResolucion>20-02-2017 13:22:22</FechaResolucion>
85
+ </Normativa>
86
+ </NotaCreditoElectronica>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: facturacr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josef Sauter
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-04-01 00:00:00.000000000 Z
11
+ date: 2018-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -196,6 +196,7 @@ files:
196
196
  - lib/facturacr/document/summary.rb
197
197
  - lib/facturacr/document/tax.rb
198
198
  - lib/facturacr/invoice.rb
199
+ - lib/facturacr/reception_message.rb
199
200
  - lib/facturacr/signed_document.rb
200
201
  - lib/facturacr/signer/signer.rb
201
202
  - lib/facturacr/ticket.rb
@@ -208,6 +209,7 @@ files:
208
209
  - resources/debit_note.xml
209
210
  - resources/invoice.xml
210
211
  - resources/pruebas.xml
212
+ - resources/reception_message.xml
211
213
  - resources/test.p12
212
214
  homepage: https://github.com/apokalipto/facturacr
213
215
  licenses: []