facturacr 1.0.6 → 1.1.1
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 +5 -5
- data/facturacr.gemspec +2 -2
- data/lib/facturacr.rb +25 -19
- data/lib/facturacr/api.rb +5 -4
- data/lib/facturacr/builder.rb +4 -4
- data/lib/facturacr/configuration.rb +18 -9
- data/lib/facturacr/credit_note.rb +24 -13
- data/lib/facturacr/data.rb +41 -0
- data/lib/facturacr/data_provider.rb +1 -1
- data/lib/facturacr/debit_note.rb +25 -13
- data/lib/facturacr/document.rb +120 -69
- data/lib/facturacr/document/exoneration.rb +17 -12
- data/lib/facturacr/document/fax.rb +1 -4
- data/lib/facturacr/document/identification_document.rb +7 -10
- data/lib/facturacr/document/issuer.rb +31 -32
- data/lib/facturacr/document/item.rb +77 -20
- data/lib/facturacr/document/location.rb +19 -23
- data/lib/facturacr/document/other_charges.rb +56 -0
- data/lib/facturacr/document/other_content.rb +30 -0
- data/lib/facturacr/document/other_content/price_smart.rb +58 -0
- data/lib/facturacr/document/other_text.rb +4 -8
- data/lib/facturacr/document/phone.rb +1 -3
- data/lib/facturacr/document/phone_type.rb +6 -9
- data/lib/facturacr/document/receiver.rb +28 -19
- data/lib/facturacr/document/reference.rb +36 -18
- data/lib/facturacr/document/regulation.rb +3 -3
- data/lib/facturacr/document/summary.rb +54 -22
- data/lib/facturacr/document/tax.rb +43 -21
- data/lib/facturacr/element.rb +9 -0
- data/lib/facturacr/error.rb +11 -0
- data/lib/facturacr/export_invoice.rb +38 -0
- data/lib/facturacr/invoice.rb +27 -15
- data/lib/facturacr/purchase_invoice.rb +39 -0
- data/lib/facturacr/reception_message.rb +73 -28
- data/lib/facturacr/signed_document.rb +4 -4
- data/lib/facturacr/signer/signer.rb +20 -8
- data/lib/facturacr/ticket.rb +27 -14
- data/lib/facturacr/version.rb +1 -1
- data/lib/facturacr/xml_document.rb +46 -29
- metadata +15 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5a8fe4de4d95d4c43eadb53200c1ce6b847554a1970fb9cb803ffdd9b3a5ea93
|
4
|
+
data.tar.gz: a4ba9d8357de2b21305f5c32577e25433d0c477c4996cfdfdc8b42e1f5665935
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c339e27c622a15a04f9d55924b40bd78529fc31c284517e6dfa6b42473f1fa99993b8667e1a3b3960872c65cef8f674951a5f820564ed3754e159013ac2d0bd6
|
7
|
+
data.tar.gz: 3640e8f8d11d531ad16e801820c9eeb1c3671988338d5cc029548839338ade8ca4b99e467864647940a2851441d1c1a8ade3711d19b92b1bbff9011cc154f4a3
|
data/facturacr.gemspec
CHANGED
@@ -18,10 +18,10 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
20
|
spec.add_development_dependency "bundler", "~> 1.10"
|
21
|
-
spec.add_development_dependency "rake", "
|
21
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
22
22
|
spec.add_development_dependency "minitest", '~> 5.11'
|
23
23
|
spec.add_development_dependency "minitest-colorize", '~> 0.0'
|
24
|
-
|
24
|
+
|
25
25
|
spec.add_dependency 'rest-client', '~> 2.0'
|
26
26
|
spec.add_dependency 'nokogiri', '~> 1.8'
|
27
27
|
spec.add_dependency 'colorize', '~> 0.8'
|
data/lib/facturacr.rb
CHANGED
@@ -1,25 +1,31 @@
|
|
1
1
|
require 'awesome_print'
|
2
|
-
|
3
|
-
require 'facturacr
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
2
|
+
|
3
|
+
#require 'facturacr'
|
4
|
+
require_relative 'facturacr/configuration'
|
5
|
+
require_relative 'facturacr/element'
|
6
|
+
require_relative 'facturacr/invoice'
|
7
|
+
require_relative 'facturacr/credit_note'
|
8
|
+
require_relative 'facturacr/export_invoice'
|
9
|
+
require_relative 'facturacr/purchase_invoice'
|
10
|
+
require_relative 'facturacr/debit_note'
|
11
|
+
require_relative 'facturacr/ticket'
|
12
|
+
require_relative 'facturacr/document'
|
13
|
+
require_relative 'facturacr/signed_document'
|
14
|
+
require_relative 'facturacr/xml_document'
|
15
|
+
require_relative 'facturacr/api'
|
16
|
+
require_relative 'facturacr/builder'
|
17
|
+
require_relative 'facturacr/version'
|
18
|
+
require_relative 'facturacr/data_provider'
|
19
|
+
require_relative 'facturacr/signer/signer'
|
20
|
+
require_relative 'facturacr/reception_message'
|
21
|
+
require_relative 'facturacr/error'
|
22
|
+
require_relative 'facturacr/data'
|
17
23
|
|
18
24
|
module FE
|
19
25
|
class << self
|
20
26
|
attr_accessor :configuration
|
21
27
|
end
|
22
|
-
|
28
|
+
|
23
29
|
def self.configure
|
24
30
|
if self.configuration.nil?
|
25
31
|
self.configuration ||= Configuration.new
|
@@ -27,13 +33,13 @@ module FE
|
|
27
33
|
yield(configuration)
|
28
34
|
configuration.read_config_file if configuration.file?
|
29
35
|
end
|
30
|
-
|
36
|
+
|
31
37
|
def self.root
|
32
38
|
File.dirname __dir__
|
33
39
|
end
|
34
|
-
|
40
|
+
|
35
41
|
def self.bin
|
36
42
|
File.join root, 'bin'
|
37
43
|
end
|
38
|
-
|
44
|
+
|
39
45
|
end
|
data/lib/facturacr/api.rb
CHANGED
@@ -32,17 +32,17 @@ module FE
|
|
32
32
|
@token
|
33
33
|
rescue => e
|
34
34
|
puts "AUTH ERROR: #{e.message}".red
|
35
|
-
raise e
|
35
|
+
raise FE::Error.new("authentication error: #{e.message}",class: self.class)
|
36
36
|
end
|
37
37
|
|
38
38
|
def logout
|
39
39
|
url = @authentication_endpoint
|
40
40
|
if @authentication_endpoint.end_with?('token')
|
41
|
-
url.gsub
|
41
|
+
url = url.gsub("token","logout")
|
42
42
|
else
|
43
43
|
url += "/logout"
|
44
44
|
end
|
45
|
-
|
45
|
+
RestClient.post url, logout_data
|
46
46
|
rescue => e
|
47
47
|
puts "LOGOUT ERROR: #{e.message}".red
|
48
48
|
end
|
@@ -57,7 +57,8 @@ module FE
|
|
57
57
|
return true
|
58
58
|
end
|
59
59
|
rescue => e
|
60
|
-
@errors[:request] = {message: e.message
|
60
|
+
@errors[:request] = {message: e.message}
|
61
|
+
@errors[:response] = e.response if e.respond_to?(:response)
|
61
62
|
return false
|
62
63
|
end
|
63
64
|
|
data/lib/facturacr/builder.rb
CHANGED
@@ -134,7 +134,7 @@ module FE
|
|
134
134
|
else
|
135
135
|
summary = args[:summary]
|
136
136
|
end
|
137
|
-
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]
|
137
|
+
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], version: args[:version], economic_activity: args[:economic_activity]
|
138
138
|
end
|
139
139
|
|
140
140
|
def ticket(args = {})
|
@@ -165,7 +165,7 @@ module FE
|
|
165
165
|
else
|
166
166
|
summary = args[:summary]
|
167
167
|
end
|
168
|
-
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]
|
168
|
+
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], version: args[:version], economic_activity: args[:economic_activity]
|
169
169
|
end
|
170
170
|
|
171
171
|
|
@@ -207,7 +207,7 @@ module FE
|
|
207
207
|
references = args[:references]
|
208
208
|
end
|
209
209
|
|
210
|
-
FE::CreditNote.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
|
210
|
+
FE::CreditNote.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, version: args[:version], economic_activity: args[:economic_activity]
|
211
211
|
end
|
212
212
|
|
213
213
|
def debit_note(args = {})
|
@@ -248,7 +248,7 @@ module FE
|
|
248
248
|
references = args[:references]
|
249
249
|
end
|
250
250
|
|
251
|
-
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
|
251
|
+
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, version: args[:version], economic_activity: args[:economic_activity]
|
252
252
|
end
|
253
253
|
|
254
254
|
def reception_message(args={})
|
@@ -2,7 +2,7 @@ require 'yaml'
|
|
2
2
|
require 'erb'
|
3
3
|
module FE
|
4
4
|
class Configuration
|
5
|
-
|
5
|
+
|
6
6
|
attr_accessor :api_username
|
7
7
|
attr_accessor :api_password
|
8
8
|
attr_accessor :key_path
|
@@ -13,8 +13,9 @@ module FE
|
|
13
13
|
attr_accessor :environment
|
14
14
|
attr_accessor :file_path
|
15
15
|
attr_accessor :mode
|
16
|
-
|
17
|
-
|
16
|
+
attr_accessor :version
|
17
|
+
|
18
|
+
|
18
19
|
def initialize
|
19
20
|
@environment = "development"
|
20
21
|
@mode = :manual
|
@@ -26,9 +27,9 @@ module FE
|
|
26
27
|
@documents_endpoint = "https://api.comprobanteselectronicos.go.cr/recepcion-sandbox/v1"
|
27
28
|
@authentication_endpoint = "https://idp.comprobanteselectronicos.go.cr/auth/realms/rut-stag/protocol/openid-connect"
|
28
29
|
end
|
29
|
-
|
30
|
+
|
30
31
|
def read_config_file
|
31
|
-
if file? && @file_path && File.
|
32
|
+
if file? && @file_path && File.exist?(@file_path)
|
32
33
|
template = ERB.new(File.read(@file_path))
|
33
34
|
result = YAML.load(template.result(binding))
|
34
35
|
result[@environment].each do |k,v|
|
@@ -38,14 +39,22 @@ module FE
|
|
38
39
|
end
|
39
40
|
end
|
40
41
|
end
|
41
|
-
|
42
|
+
|
42
43
|
def manual?
|
43
44
|
@mode.to_sym.eql?(:manual)
|
44
45
|
end
|
45
|
-
|
46
|
+
|
46
47
|
def file?
|
47
48
|
@mode.to_sym.eql?(:file)
|
48
49
|
end
|
49
|
-
|
50
|
+
|
51
|
+
def version_42?
|
52
|
+
version.eql?('4.2')
|
53
|
+
end
|
54
|
+
|
55
|
+
def version_43?
|
56
|
+
version.eql?('4.3')
|
57
|
+
end
|
58
|
+
|
50
59
|
end
|
51
|
-
end
|
60
|
+
end
|
@@ -1,34 +1,45 @@
|
|
1
1
|
require 'facturacr/document/regulation'
|
2
2
|
module FE
|
3
|
-
|
3
|
+
|
4
4
|
class CreditNote < Document
|
5
|
-
|
5
|
+
NAMESPACES ={
|
6
|
+
"4.2" => {
|
7
|
+
"xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
|
8
|
+
"xmlns:xsd"=>"http://www.w3.org/2001/XMLSchema",
|
9
|
+
"xmlns"=>"https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/notaCreditoElectronica"#,
|
10
|
+
},
|
11
|
+
"4.3" => {
|
12
|
+
"xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
|
13
|
+
"xmlns:xsd"=>"http://www.w3.org/2001/XMLSchema",
|
14
|
+
"xmlns"=>"https://cdn.comprobanteselectronicos.go.cr/xml-schemas/v4.3/notaCreditoElectronica"#,
|
15
|
+
}
|
16
|
+
}
|
17
|
+
DOCUMENT_TYPE = "03"
|
6
18
|
def initialize(args={})
|
19
|
+
@version = args[:version]
|
20
|
+
@economic_activity = args[:economic_activity]
|
7
21
|
@date = args[:date]
|
8
22
|
@issuer = args[:issuer]
|
9
23
|
@receiver = args[:receiver]
|
10
24
|
@items = args[:items]
|
11
25
|
@number = args[:number]
|
12
26
|
@condition = args[:condition]
|
13
|
-
@payment_type = args[:payment_type] || "01"
|
14
|
-
@document_type =
|
27
|
+
@payment_type = args[:payment_type] || ["01"]
|
28
|
+
@document_type = DOCUMENT_TYPE
|
15
29
|
@credit_term = args[:credit_term]
|
16
30
|
@summary = args[:summary]
|
17
31
|
@regulation = args[:regulation] ||= FE::Document::Regulation.new
|
18
32
|
@security_code = args[:security_code]
|
19
33
|
@document_situation = args[:document_situation]
|
20
34
|
@references = args[:references]
|
21
|
-
@
|
22
|
-
|
23
|
-
"xmlns:xsd"=>"http://www.w3.org/2001/XMLSchema",
|
24
|
-
"xmlns"=>"https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/notaCreditoElectronica"#,
|
25
|
-
}
|
35
|
+
@other_charges = args[:other_charges]
|
36
|
+
@namespaces = NAMESPACES[@version]
|
26
37
|
@others = args[:others] || []
|
27
38
|
end
|
28
|
-
|
39
|
+
|
29
40
|
def document_tag
|
30
41
|
"NotaCreditoElectronica"
|
31
42
|
end
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'rest-client'
|
3
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
4
|
+
|
5
|
+
module FE
|
6
|
+
class Data
|
7
|
+
|
8
|
+
ENDPOINT = "https://api.hacienda.go.cr"
|
9
|
+
|
10
|
+
def self.contributor(id_number)
|
11
|
+
response = RestClient.get "#{ENDPOINT}/fe/ae?identificacion=#{id_number}"
|
12
|
+
return JSON.parse(response.body).with_indifferent_access
|
13
|
+
rescue => e
|
14
|
+
puts "FE::Data.contributor(#{id_number}) #{e.message}"
|
15
|
+
return nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.exchange_rate(currency = "USD")
|
19
|
+
if currency.eql?("USD")
|
20
|
+
path = "tc/dolar"
|
21
|
+
elsif currency.eql?("EUR")
|
22
|
+
path = "tc/euro"
|
23
|
+
else
|
24
|
+
raise "#{currency} is not a valid argument"
|
25
|
+
end
|
26
|
+
response = RestClient.get "#{ENDPOINT}/indicadores/#{path}"
|
27
|
+
return JSON.parse(response.body).with_indifferent_access
|
28
|
+
rescue => e
|
29
|
+
puts "FE::Data.exchange_rate(#{currency}) #{e.message}"
|
30
|
+
return nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.exonerations(id_number)
|
34
|
+
response = RestClient.get "#{ENDPOINT}/fe/ex?identificacion=#{id_number}"
|
35
|
+
return JSON.parse(response.body).with_indifferent_access
|
36
|
+
rescue => e
|
37
|
+
puts "FE::Data.exonerations(#{id_number}) #{e.message}"
|
38
|
+
return nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -8,7 +8,7 @@ module FE
|
|
8
8
|
def initialize(source, data)
|
9
9
|
source = source.to_s.to_sym
|
10
10
|
raise ArgumentError, "source (#{source}) is not valid" if !SOURCES.include?(source)
|
11
|
-
raise ArgumentError, "#{data} does not exist" if source.eql?(:file) && !File.
|
11
|
+
raise ArgumentError, "#{data} does not exist" if source.eql?(:file) && !File.exist?(data)
|
12
12
|
|
13
13
|
if source.eql?(:string)
|
14
14
|
@contents = data
|
data/lib/facturacr/debit_note.rb
CHANGED
@@ -1,34 +1,46 @@
|
|
1
1
|
require 'facturacr/document/regulation'
|
2
2
|
module FE
|
3
|
-
|
3
|
+
|
4
4
|
class DebitNote < Document
|
5
|
-
|
5
|
+
|
6
|
+
NAMESPACES ={
|
7
|
+
"4.2" => {
|
8
|
+
"xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
|
9
|
+
"xmlns:xsd"=>"http://www.w3.org/2001/XMLSchema",
|
10
|
+
"xmlns"=>"https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/notaDebitoElectronica"
|
11
|
+
},
|
12
|
+
"4.3" => {
|
13
|
+
"xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
|
14
|
+
"xmlns:xsd"=>"http://www.w3.org/2001/XMLSchema",
|
15
|
+
"xmlns"=>"https://cdn.comprobanteselectronicos.go.cr/xml-schemas/v4.3/notaDebitoElectronica"#,
|
16
|
+
}
|
17
|
+
}
|
18
|
+
DOCUMENT_TYPE = "02"
|
6
19
|
def initialize(args={})
|
20
|
+
@version = args[:version]
|
21
|
+
@economic_activity = args[:economic_activity]
|
7
22
|
@date = args[:date]
|
8
23
|
@issuer = args[:issuer]
|
9
24
|
@receiver = args[:receiver]
|
10
25
|
@items = args[:items]
|
11
26
|
@number = args[:number]
|
12
27
|
@condition = args[:condition]
|
13
|
-
@payment_type = args[:payment_type] || "01"
|
14
|
-
@document_type =
|
28
|
+
@payment_type = args[:payment_type] || ["01"]
|
29
|
+
@document_type = DOCUMENT_TYPE
|
15
30
|
@credit_term = args[:credit_term]
|
16
31
|
@summary = args[:summary]
|
17
32
|
@regulation = args[:regulation] ||= FE::Document::Regulation.new
|
18
33
|
@security_code = args[:security_code]
|
19
34
|
@document_situation = args[:document_situation]
|
20
35
|
@references = args[:references]
|
21
|
-
@
|
22
|
-
|
23
|
-
"xmlns:xsd"=>"http://www.w3.org/2001/XMLSchema",
|
24
|
-
"xmlns"=>"https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/notaDebitoElectronica"
|
25
|
-
}
|
36
|
+
@other_charges = args[:other_charges]
|
37
|
+
@namespaces = NAMESPACES[@version]
|
26
38
|
@others = args[:others] || []
|
27
39
|
end
|
28
|
-
|
40
|
+
|
29
41
|
def document_tag
|
30
42
|
"NotaDebitoElectronica"
|
31
43
|
end
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
data/lib/facturacr/document.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
require 'active_model'
|
2
2
|
|
3
|
-
module FE
|
3
|
+
module FE
|
4
4
|
class Document
|
5
5
|
include ActiveModel::Validations
|
6
|
-
|
6
|
+
|
7
7
|
CONDITIONS = {
|
8
|
-
"01"=>"Contado",
|
9
|
-
"02"=>"Crédito",
|
10
|
-
"03"=>"Consignación",
|
11
|
-
"04"=>"Apartado",
|
12
|
-
"05"=>"Arrendamiento con Opción de Compra",
|
8
|
+
"01"=>"Contado",
|
9
|
+
"02"=>"Crédito",
|
10
|
+
"03"=>"Consignación",
|
11
|
+
"04"=>"Apartado",
|
12
|
+
"05"=>"Arrendamiento con Opción de Compra",
|
13
13
|
"06"=>"Arrendamiento en Función Financiera",
|
14
|
+
"07"=>"Cobro a favor de un tercero",
|
15
|
+
"08"=>"Servicios prestados al Estado a crédito ",
|
16
|
+
"09"=>"Pago del servicios prestado al Estado ",
|
14
17
|
"99"=>"Otros"
|
15
18
|
}.freeze
|
16
19
|
PAYMENT_TYPES = {
|
@@ -29,47 +32,50 @@ module FE
|
|
29
32
|
"05"=> "Nota de despacho",
|
30
33
|
"06"=> "Contrato",
|
31
34
|
"07"=> "Procedimiento",
|
32
|
-
"08"=> "
|
33
|
-
"
|
34
|
-
|
35
|
+
"08"=> "Factura Electrónica de compra",
|
36
|
+
"09"=> "Factura Electronica de exportación"
|
35
37
|
}.freeze
|
36
38
|
DOCUMENT_SITUATION = {
|
37
39
|
"1" => "Normal",
|
38
40
|
"2" => "Contingencia",
|
39
41
|
"3" => "Sin Internet"
|
40
42
|
}.freeze
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
:
|
45
|
-
:
|
46
|
-
:
|
47
|
-
|
43
|
+
|
44
|
+
attr_writer :headquarters, :terminal, :key
|
45
|
+
attr_accessor :serial, :date, :issuer, :receiver, :condition, :credit_term,
|
46
|
+
:payment_type, :service_type, :reference_information,
|
47
|
+
:regulation, :number, :document_type, :security_code,
|
48
|
+
:items, :references, :namespaces, :summary, :document_situation,
|
49
|
+
:headquarters, :terminal, :others, :key, :economic_activity, :other_charges, :version
|
50
|
+
validates :version, presence: true
|
51
|
+
validates :economic_activity, presence: true, if: ->{ version.eql?("4.3") }
|
48
52
|
validates :date, presence: true
|
49
53
|
validates :number, presence: true
|
50
54
|
validates :issuer, presence: true
|
55
|
+
validates :receiver, presence: true, if: -> {document_type.eql?("01") || document_type.eql?("08")}
|
51
56
|
validates :condition, presence: true, inclusion: CONDITIONS.keys
|
52
|
-
validates :credit_term, presence: true, if: ->{condition.eql?("02")}
|
53
|
-
validates :payment_type, presence: true, inclusion: PAYMENT_TYPES.keys
|
57
|
+
validates :credit_term, presence: true, if: ->{ condition.eql?("02") }
|
54
58
|
validates :document_type, presence: true, inclusion: DOCUMENT_TYPES.keys
|
55
59
|
validates :document_situation, presence: true, inclusion: DOCUMENT_SITUATION.keys
|
56
60
|
validates :summary, presence: true
|
57
|
-
validates :regulation, presence: true
|
61
|
+
validates :regulation, presence: true, if: ->{ version.eql?("4.2") }
|
58
62
|
validates :security_code, presence: true, length: {is: 8}
|
59
63
|
validates :references, presence: true, if: -> {document_type.eql?("02") || document_type.eql?("03")}
|
60
|
-
|
61
|
-
|
64
|
+
validates :items, presence:true
|
65
|
+
validate :payment_types_ok?
|
66
|
+
validate :other_charges_ok?, if: -> {@other_charges.present?}
|
67
|
+
|
62
68
|
def initialize
|
63
|
-
raise "Subclasses must implement this method"
|
69
|
+
raise FE::Error "Subclasses must implement this method"
|
64
70
|
end
|
65
|
-
|
71
|
+
|
66
72
|
def document_name
|
67
|
-
raise "Subclasses must implement this method"
|
73
|
+
raise FE::Error "Subclasses must implement this method"
|
68
74
|
end
|
69
|
-
|
75
|
+
|
70
76
|
def key
|
71
77
|
@key ||= begin
|
72
|
-
raise "Documento inválido: #{errors.messages}" unless valid?
|
78
|
+
raise "Documento inválido: #{errors.messages}" unless valid?
|
73
79
|
country = "506"
|
74
80
|
day = "%02d" % @date.day
|
75
81
|
month = "%02d" % @date.month
|
@@ -81,69 +87,92 @@ module FE
|
|
81
87
|
|
82
88
|
result = "#{country}#{day}#{month}#{year}#{id_number}#{sequence}#{type}#{security_code}"
|
83
89
|
raise "The key is invalid: #{result}" unless result.length.eql?(50)
|
84
|
-
|
90
|
+
|
85
91
|
result
|
86
92
|
end
|
87
93
|
end
|
88
|
-
|
94
|
+
|
89
95
|
def headquarters
|
90
96
|
@headquarters ||= "001"
|
91
97
|
end
|
92
|
-
|
98
|
+
|
93
99
|
def terminal
|
94
100
|
@terminal ||= "00001"
|
95
|
-
end
|
96
|
-
|
101
|
+
end
|
102
|
+
|
97
103
|
def sequence
|
98
104
|
cons = ("%010d" % @number)
|
99
105
|
"#{headquarters}#{terminal}#{@document_type}#{cons}"
|
100
106
|
end
|
101
|
-
|
107
|
+
|
108
|
+
def version_42?
|
109
|
+
@version.eql?("4.2")
|
110
|
+
end
|
111
|
+
|
112
|
+
def version_43?
|
113
|
+
@version.eql?("4.3")
|
114
|
+
end
|
115
|
+
|
102
116
|
def build_xml
|
103
|
-
raise "Documento inválido
|
117
|
+
raise FE::Error.new "Documento inválido #{errors.messages}", class: self.class, messages: errors.messages unless valid?
|
104
118
|
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8')
|
105
|
-
|
119
|
+
|
106
120
|
builder.send(document_tag, @namespaces) do |xml|
|
107
121
|
xml.Clave key
|
122
|
+
xml.CodigoActividad @economic_activity if version_43?
|
108
123
|
xml.NumeroConsecutivo sequence
|
109
124
|
xml.FechaEmision @date.xmlschema
|
110
|
-
issuer.build_xml(xml)
|
111
|
-
receiver.build_xml(xml) if receiver.present?
|
125
|
+
issuer.build_xml(xml, self)
|
126
|
+
receiver.build_xml(xml,self) if receiver.present?
|
112
127
|
xml.CondicionVenta @condition
|
113
128
|
xml.PlazoCredito @credit_term if @credit_term.present? && @condition.eql?("02")
|
114
|
-
|
129
|
+
|
130
|
+
@payment_type.each do |pt|
|
131
|
+
@summary.with_credit_card = true if pt.eql?("02")
|
132
|
+
xml.MedioPago pt
|
133
|
+
end
|
134
|
+
|
135
|
+
|
115
136
|
xml.DetalleServicio do |x|
|
116
137
|
@items.each do |item|
|
117
|
-
item.build_xml(x)
|
138
|
+
item.build_xml(x, self)
|
118
139
|
end
|
119
140
|
end
|
120
|
-
|
121
|
-
|
122
|
-
|
141
|
+
|
142
|
+
if other_charges.present?
|
143
|
+
@other_charges.each do |other_charge|
|
144
|
+
other_charge.build_xml(xml, self)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
#other_charges.build_xml(xml,self) if other_charges.present? && version_43? # see this
|
149
|
+
|
150
|
+
summary.build_xml(xml, self)
|
151
|
+
|
123
152
|
if references.present?
|
124
153
|
references.each do |r|
|
125
|
-
r.build_xml(xml)
|
154
|
+
r.build_xml(xml, self)
|
126
155
|
end
|
127
156
|
end
|
128
|
-
|
129
|
-
regulation.build_xml(xml)
|
130
|
-
|
157
|
+
|
158
|
+
regulation.build_xml(xml,self) if version_42?
|
159
|
+
|
131
160
|
if others.any?
|
132
161
|
xml.Otros do |x|
|
133
162
|
@others.each do |o|
|
134
|
-
o.build_xml(x)
|
163
|
+
o.build_xml(x, self)
|
135
164
|
end
|
136
165
|
end
|
137
166
|
end
|
138
167
|
end
|
139
|
-
|
168
|
+
|
140
169
|
builder
|
141
170
|
end
|
142
|
-
|
171
|
+
|
143
172
|
def generate
|
144
173
|
build_xml.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML)
|
145
174
|
end
|
146
|
-
|
175
|
+
|
147
176
|
def api_payload
|
148
177
|
payload = {}
|
149
178
|
payload[:clave] = key
|
@@ -158,27 +187,49 @@ module FE
|
|
158
187
|
numeroIdentificacion: @receiver.identification_document.id_number
|
159
188
|
}
|
160
189
|
end
|
161
|
-
|
190
|
+
|
162
191
|
payload
|
163
192
|
end
|
164
|
-
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
def other_charges_ok?
|
197
|
+
if @other_charges.is_a?(Array)
|
198
|
+
errors.add :other_charges, "invalid other_charges: the length can't be greater than 15" if @other_charges.length > 15
|
199
|
+
errors.add :other_charges, "invalid other_charges: not included" unless @other_charges.all? {|i| FE::Document::OtherCharges::OTHER_DOCUMENT_TYPES.include?(i.document_type)}
|
200
|
+
else
|
201
|
+
errors.add :other_charges, "invalid other_charges: not array"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def payment_types_ok?
|
206
|
+
errors.add :payment_type, "missing payment type" if @payment_type.nil?
|
207
|
+
if @payment_type.is_a?(Array)
|
208
|
+
errors.add :payment_type, "invalid payment types: not included" unless @payment_type.all? {|i| PAYMENT_TYPES.include?(i)}
|
209
|
+
else
|
210
|
+
errors.add :payment_type, "invalid payment type: not array"
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
|
165
215
|
end
|
166
|
-
|
167
|
-
|
168
216
|
end
|
169
217
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
218
|
+
require_relative 'document/code'
|
219
|
+
require_relative 'document/exoneration'
|
220
|
+
require_relative 'document/fax'
|
221
|
+
require_relative 'document/identification_document'
|
222
|
+
require_relative 'document/issuer'
|
223
|
+
require_relative 'document/item'
|
224
|
+
require_relative 'document/location'
|
225
|
+
require_relative 'document/phone_type'
|
226
|
+
require_relative 'document/phone'
|
227
|
+
require_relative 'document/fax'
|
228
|
+
require_relative 'document/receiver'
|
229
|
+
require_relative 'document/reference'
|
230
|
+
require_relative 'document/regulation'
|
231
|
+
require_relative 'document/summary'
|
232
|
+
require_relative 'document/tax'
|
233
|
+
require_relative 'document/other_text'
|
234
|
+
require_relative 'document/other_content'
|
235
|
+
require_relative 'document/other_charges'
|