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
@@ -0,0 +1,30 @@
|
|
1
|
+
module FE
|
2
|
+
class Document
|
3
|
+
class OtherContent < Element
|
4
|
+
include ActiveModel::Validations
|
5
|
+
attr_accessor :implementation
|
6
|
+
|
7
|
+
validates :implementation, presence: true
|
8
|
+
|
9
|
+
|
10
|
+
def initialize(args={})
|
11
|
+
@implementation = args[:implementation]
|
12
|
+
end
|
13
|
+
|
14
|
+
def build_xml(node, document)
|
15
|
+
raise FE::Error.new("other content",class: self.class, messages: errors.messages) unless valid?
|
16
|
+
node = Nokogiri::XML::Builder.new if node.nil?
|
17
|
+
node.OtroContenido do |xml|
|
18
|
+
@implementation.build_xml(xml, document)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_xml(builder,document)
|
23
|
+
build_xml(builder,document).to_xml
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
require 'facturacr/document/other_content/price_smart'
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module FE
|
2
|
+
class Document
|
3
|
+
class OtherContent
|
4
|
+
class PriceSmart
|
5
|
+
include ActiveModel::Validations
|
6
|
+
attr_accessor :transaction_type, :order_number, :order_date, :supplier_number, :store_code
|
7
|
+
|
8
|
+
TYPES = ['purchase', 'expense']
|
9
|
+
TYPES.each do |t|
|
10
|
+
define_method "#{t}?" do
|
11
|
+
transaction_type.eql?(t)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
NAMESPACES = {
|
16
|
+
"xsi:schemaLocation" => "https://invoicer.ekomercio.com/esquemas https://invoices/ekomercio.com/esquemas/ComplementoPricesmartCR_V1_0.xsd",
|
17
|
+
"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
|
18
|
+
"xmlns:retail" => "https://invoicer.ekomercio.com/esquemas"
|
19
|
+
}
|
20
|
+
|
21
|
+
validates :transaction_type, presence: true, inclusion: TYPES
|
22
|
+
validates :supplier_number, presence: true, length: {maximum: 12}
|
23
|
+
validates :store_code, presence: true
|
24
|
+
validates :order_number, presence: true, if: ->{ purchase? }
|
25
|
+
validates :order_date, presence: true, if: ->{ purchase? }
|
26
|
+
|
27
|
+
def initialize(args={})
|
28
|
+
@transaction_type = args[:transaction_type]
|
29
|
+
@supplier_number = args[:supplier_number]
|
30
|
+
@store_code = args[:store_code]
|
31
|
+
@order_number = args[:order_number]
|
32
|
+
@order_date = args[:order_date]
|
33
|
+
end
|
34
|
+
|
35
|
+
def build_xml(node)
|
36
|
+
raise "Invalid Record: #{errors.messages}" unless valid?
|
37
|
+
node = Nokogiri::XML::Builder.new if node.nil?
|
38
|
+
node['retail'].Complemento(NAMESPACES) do |xml|
|
39
|
+
xml['retail'].NumeroVendedor @supplier_number
|
40
|
+
if purchase?
|
41
|
+
xml['retail'].OrdenDeCompra do |xml2|
|
42
|
+
xml2['retail'].NumeroOrden @order_number
|
43
|
+
xml2['retail'].FechaOrden @order_date.xmlschema
|
44
|
+
end
|
45
|
+
end
|
46
|
+
xml['retail'].LugarDeEntrega do |xml2|
|
47
|
+
xml2['retail'].GLNLugarDeEntrega @store_code
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_xml(builder)
|
53
|
+
build_xml(builder)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module FE
|
2
2
|
class Document
|
3
|
-
class OtherText
|
3
|
+
class OtherText < Element
|
4
4
|
attr_accessor :xml_attributes, :content
|
5
5
|
|
6
6
|
|
@@ -10,18 +10,14 @@ module FE
|
|
10
10
|
@content = args[:content]
|
11
11
|
end
|
12
12
|
|
13
|
-
def build_xml(node)
|
14
|
-
raise "
|
13
|
+
def build_xml(node, document)
|
14
|
+
raise FE::Error.new("xml_attribues is not a hash",class: self.class) unless @xml_attributes.is_a?(Hash)
|
15
15
|
|
16
16
|
node = Nokogiri::XML::Builder.new if node.nil?
|
17
17
|
node.OtroTexto(@xml_attributes) do |xml|
|
18
18
|
xml.text(@content)
|
19
19
|
end
|
20
|
-
end
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
end
|
25
21
|
end
|
26
22
|
end
|
27
23
|
end
|
@@ -1,10 +1,6 @@
|
|
1
|
-
require "facturacr/document"
|
2
|
-
require 'active_model'
|
3
|
-
require 'nokogiri'
|
4
|
-
|
5
1
|
module FE
|
6
2
|
class Document
|
7
|
-
class PhoneType
|
3
|
+
class PhoneType < Element
|
8
4
|
include ActiveModel::Validations
|
9
5
|
|
10
6
|
attr_accessor :tag_name, :country_code, :number
|
@@ -20,8 +16,9 @@ module FE
|
|
20
16
|
@number = number
|
21
17
|
end
|
22
18
|
|
23
|
-
def build_xml(node)
|
24
|
-
raise "
|
19
|
+
def build_xml(node, document)
|
20
|
+
raise FE::Error.new("phone type invalid",class: self.class, messages: errors.messages) unless valid?
|
21
|
+
|
25
22
|
node = Nokogiri::XML::Builder.new if node.nil?
|
26
23
|
node.send(tag_name) do |xml|
|
27
24
|
xml.CodigoPais country_code
|
@@ -29,8 +26,8 @@ module FE
|
|
29
26
|
end
|
30
27
|
end
|
31
28
|
|
32
|
-
def to_xml(builder)
|
33
|
-
build_xml(builder).to_xml
|
29
|
+
def to_xml(builder,document)
|
30
|
+
build_xml(builder, document).to_xml
|
34
31
|
end
|
35
32
|
end
|
36
33
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require "facturacr/document"
|
2
1
|
require 'active_model'
|
3
2
|
require 'nokogiri'
|
4
3
|
|
@@ -6,15 +5,25 @@ module FE
|
|
6
5
|
class Document
|
7
6
|
|
8
7
|
|
9
|
-
class Receiver
|
8
|
+
class Receiver < Element
|
10
9
|
include ActiveModel::Validations
|
11
10
|
|
12
|
-
attr_accessor :name, :identification_document,:foreign_id_number, :comercial_name, :location, :phone, :fax, :email
|
11
|
+
attr_accessor :name, :identification_document,:foreign_id_number, :comercial_name, :location, :phone, :fax, :email,:other_foreign_signs, :document_type
|
13
12
|
|
14
|
-
validates :name, presence: true
|
15
|
-
|
16
|
-
validates :
|
13
|
+
validates :name, presence: true
|
14
|
+
|
15
|
+
validates :identification_document, presence: true, if: -> {document_type.eql?("01") || document_type.eql?("08")}
|
16
|
+
validates :foreign_id_number, length: { maximum: 20 }, if: -> {document_type.eql?("01") || document_type.eql?("08")}
|
17
|
+
validates :other_foreign_signs,length: { maximum: 300 }
|
18
|
+
validates :email, length: {maximum: 160}, format:{with: /\s*\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*\s*/}, if: ->{ email.present? }
|
19
|
+
|
17
20
|
|
21
|
+
validates :name, length: { maximum: 80}, if: ->{ document.version_42? }
|
22
|
+
validates :comercial_name, length: { maximum: 80 }, if: ->{ document.version_42? }
|
23
|
+
|
24
|
+
|
25
|
+
validates :name, length: { maximum: 100}, if: ->{ document.version_43? }
|
26
|
+
validates :comercial_name, length: { maximum: 100 }, if: ->{ document.version_43? }
|
18
27
|
|
19
28
|
|
20
29
|
def initialize(args={})
|
@@ -27,31 +36,31 @@ module FE
|
|
27
36
|
@fax = args[:fax]
|
28
37
|
@email = args[:email]
|
29
38
|
@foreign_id_number = args[:foreign_id_number]
|
39
|
+
@other_foreign_signs= args[:other_foreign_signs]
|
30
40
|
|
31
41
|
end
|
32
42
|
|
33
|
-
def build_xml(node)
|
34
|
-
|
35
|
-
|
36
|
-
raise "
|
37
|
-
|
38
|
-
raise "Reciever is invalid: #{errors.messages}" unless valid?
|
39
|
-
|
43
|
+
def build_xml(node, document)
|
44
|
+
@document = document
|
45
|
+
@document_type = document.document_type
|
46
|
+
raise FE::Error.new("receiver invalid",class: self.class, messages: errors.messages) unless valid?
|
47
|
+
|
40
48
|
node = Nokogiri::XML::Builder.new if node.nil?
|
41
49
|
node.Receptor do |xml|
|
42
50
|
xml.Nombre @name
|
43
|
-
@identification_document.build_xml(xml) if @identification_document.present?
|
51
|
+
@identification_document.build_xml(xml,@document) if @identification_document.present?
|
44
52
|
xml.IdentificacionExtranjero foreign_id_number if @foreign_id_number.present?
|
45
53
|
xml.NombreComercial @comercial_name if @comercial_name.present?
|
46
|
-
@location.build_xml(xml) if @location.present?
|
47
|
-
@phone.build_xml(xml) if @phone.present?
|
48
|
-
@fax.build_xml(xml) if @fax.present?
|
54
|
+
@location.build_xml(xml,@document) if @location.present?
|
55
|
+
@phone.build_xml(xml, @document) if @phone.present?
|
56
|
+
@fax.build_xml(xml, @document) if @fax.present?
|
49
57
|
xml.CorreoElectronico @email if @email.present?
|
58
|
+
xml.OtrasSenasExtranjero @other_foreign_signs if @other_foreign_signs.present? && @document.version_43?
|
50
59
|
end
|
51
60
|
end
|
52
61
|
|
53
|
-
def to_xml(builder)
|
54
|
-
build_xml(builder).to_xml
|
62
|
+
def to_xml(builder, document)
|
63
|
+
build_xml(builder, document).to_xml
|
55
64
|
end
|
56
65
|
end
|
57
66
|
|
@@ -1,12 +1,10 @@
|
|
1
|
-
require 'facturacr/document'
|
2
|
-
|
3
1
|
module FE
|
4
2
|
class Document
|
5
|
-
class Reference
|
3
|
+
class Reference < Element
|
6
4
|
include ActiveModel::Validations
|
7
|
-
|
5
|
+
|
8
6
|
attr_accessor :document_type, :number, :date, :code, :reason
|
9
|
-
|
7
|
+
|
10
8
|
REFERENCE_CODES = {
|
11
9
|
"01" => "Anula Documento de referencia",
|
12
10
|
"02" => "Corrige texto documento de referencia",
|
@@ -14,14 +12,34 @@ module FE
|
|
14
12
|
"04" => "Referencia a otro documento",
|
15
13
|
"05" => "Sustituye comprobante provisional por contingencia",
|
16
14
|
"99" => "Otros"
|
17
|
-
}
|
15
|
+
}.freeze
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
DOCUMENT_TYPES = {
|
18
|
+
"01"=> "Factura Electronica",
|
19
|
+
"02"=> "Nota de débito",
|
20
|
+
"03"=> "Nota de crédito",
|
21
|
+
"04"=> "Tiquete Electrónico",
|
22
|
+
"05"=> "Nota de despacho",
|
23
|
+
"06"=> "Contrato",
|
24
|
+
"07"=> "Procedimiento",
|
25
|
+
"08"=> "Factura Electrónica de compra",
|
26
|
+
"09"=> "Factura Electronica de exportación",
|
27
|
+
"10"=> "Sustituye factura rechazada por el Ministerio de Hacienda",
|
28
|
+
"11"=> "Sustituye factura rechazada por el Receptor del comprobante",
|
29
|
+
"12"=> "Sustituye Factura de exportación",
|
30
|
+
"13"=> "Facturación mes vencido",
|
31
|
+
"99"=> "Otros"
|
32
|
+
|
33
|
+
}.freeze
|
24
34
|
|
35
|
+
|
36
|
+
validates :document_type, presence: true, inclusion: DOCUMENT_TYPES.keys
|
37
|
+
validates :date, presence: true
|
38
|
+
|
39
|
+
validates :number, presence: true, length: {maximum: 50}, if: ->{ document_type.present? && document_type != "13"}
|
40
|
+
validates :code, presence: true, length: {is: 2}, inclusion: REFERENCE_CODES.keys, if: ->{ document_type.present? && document_type != "13" }
|
41
|
+
validates :reason, presence: true, length: {maximum: 180}, if: ->{ document_type.present? && document_type != "13" }
|
42
|
+
|
25
43
|
def initialize(args={})
|
26
44
|
@document_type = args[:document_type]
|
27
45
|
@number = args[:number]
|
@@ -29,18 +47,18 @@ module FE
|
|
29
47
|
@code = args[:code]
|
30
48
|
@reason = args[:reason]
|
31
49
|
end
|
32
|
-
|
33
|
-
def build_xml(node)
|
34
|
-
raise "
|
50
|
+
|
51
|
+
def build_xml(node, document)
|
52
|
+
raise FE::Error.new("reference invalid",class: self.class, messages: errors.messages) unless valid?
|
35
53
|
node = Nokogiri::XML::Builder.new if node.nil?
|
36
54
|
node.InformacionReferencia do |xml|
|
37
55
|
xml.TipoDoc @document_type
|
38
|
-
xml.Numero @number
|
56
|
+
xml.Numero @number if @number.present?
|
39
57
|
xml.FechaEmision @date.xmlschema
|
40
|
-
xml.Codigo @code
|
41
|
-
xml.Razon @reason
|
58
|
+
xml.Codigo @code if @code.present?
|
59
|
+
xml.Razon @reason if @reason.present?
|
42
60
|
end
|
43
61
|
end
|
44
62
|
end
|
45
63
|
end
|
46
|
-
end
|
64
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module FE
|
2
2
|
class Document
|
3
|
-
class Regulation
|
3
|
+
class Regulation < Element
|
4
4
|
include ActiveModel::Validations
|
5
5
|
|
6
6
|
attr_accessor :number, :date
|
@@ -13,8 +13,8 @@ module FE
|
|
13
13
|
@date = args[:date] ||= "20-02-2017 13:22:22"
|
14
14
|
end
|
15
15
|
|
16
|
-
def build_xml(node)
|
17
|
-
raise "
|
16
|
+
def build_xml(node, document)
|
17
|
+
raise FE::Error.new("regulation invalid",class: self.class, messages: errors.messages) unless valid?
|
18
18
|
node = Nokogiri::XML::Builder.new if node.nil?
|
19
19
|
node.Normativa do |xml|
|
20
20
|
xml.NumeroResolucion @number
|
@@ -1,64 +1,96 @@
|
|
1
1
|
module FE
|
2
2
|
class Document
|
3
|
-
class Summary
|
3
|
+
class Summary < Element
|
4
4
|
include ActiveModel::Validations
|
5
|
-
|
6
|
-
attr_accessor :currency, :exchange_rate, :services_taxable_total, :services_exent_total,
|
7
|
-
:goods_taxable_total,:goods_exent_total, :taxable_total, :exent_total,
|
8
|
-
:subtotal, :discount_total, :gross_total, :tax_total, :net_total
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
|
6
|
+
attr_accessor :currency, :exchange_rate, :services_taxable_total, :services_exent_total, :services_exonerate_total,
|
7
|
+
:goods_taxable_total,:goods_exent_total,:goods_exonerate_total, :taxable_total, :exent_total,:exonerate_total,
|
8
|
+
:subtotal, :discount_total, :gross_total, :tax_total,:total_iva_returned,:total_other_charges, :net_total,
|
9
|
+
:with_credit_card, :document_type, :has_exoneration, :medical_services_condition
|
10
|
+
|
11
|
+
validates :currency, presence: true
|
12
|
+
validates :exchange_rate, presence: true, if: -> { currency.present? && currency != "CRC" }
|
13
|
+
|
14
|
+
validates :services_exonerate_total, presence: true, if: -> { document.version_43? && !document_type.eql?(FE::ExportInvoice::DOCUMENT_TYPE) && has_exoneration}
|
15
|
+
validates :goods_exonerate_total, presence: true, if: -> { document.version_43? && !document_type.eql?(FE::ExportInvoice::DOCUMENT_TYPE) && has_exoneration}
|
16
|
+
validates :exonerate_total, presence: true, if: -> { document.version_43? && !document_type.eql?(FE::ExportInvoice::DOCUMENT_TYPE) && has_exoneration}
|
17
|
+
|
18
|
+
validates :total_iva_returned, presence: true, if: -> { document.version_43? && medical_services_condition }
|
12
19
|
validate :totals_ok?
|
13
|
-
|
20
|
+
|
14
21
|
def initialize(args={})
|
15
22
|
@currency = args[:currency]
|
16
23
|
@exchange_rate = args[:exchange_rate]
|
17
24
|
@services_taxable_total = args[:services_taxable_total].to_f
|
18
25
|
@services_exent_total = args[:services_exent_total].to_f
|
26
|
+
@services_exonerate_total = args[:services_exonerate_total].to_f
|
19
27
|
@goods_taxable_total = args[:goods_taxable_total].to_f
|
20
28
|
@goods_exent_total = args[:goods_exent_total].to_f
|
29
|
+
@goods_exonerate_total = args[:goods_exonerate_total].to_f
|
21
30
|
@taxable_total = args[:taxable_total].to_f
|
22
31
|
@exent_total = args[:exent_total].to_f
|
32
|
+
@exonerate_total = args[:exonerate_total].to_f
|
23
33
|
@subtotal = args[:subtotal].to_f
|
24
34
|
@discount_total = args[:discount_total].to_f
|
25
35
|
@gross_total = args[:gross_total].to_f
|
26
36
|
@tax_total = args[:tax_total].to_f
|
37
|
+
@total_iva_returned = args[:total_iva_returned].to_f
|
38
|
+
@total_other_charges = args[:total_other_charges].to_f
|
27
39
|
@net_total = args[:net_total].to_f
|
40
|
+
@has_exoneration = args[:has_exoneration] || false
|
41
|
+
@medical_services_condition = args[:medical_services_condition] || false
|
28
42
|
end
|
29
|
-
|
30
|
-
def build_xml(node)
|
31
|
-
|
32
|
-
|
33
|
-
|
43
|
+
|
44
|
+
def build_xml(node, document)
|
45
|
+
@document = document
|
46
|
+
@document_type = document.document_type
|
47
|
+
raise FE::Error.new("summary invalid: #{ errors.messages.map{|k,v| "#{k}=#{v.join(". ")}"}.join("; ")}",class: self.class, messages: errors.messages) unless valid?
|
34
48
|
node = Nokogiri::XML::Builder.new if node.nil?
|
35
|
-
|
49
|
+
|
36
50
|
node.ResumenFactura do |xml|
|
37
|
-
|
38
|
-
|
51
|
+
if document.version_42?
|
52
|
+
xml.CodigoMoneda @currency if @currency.present?
|
53
|
+
xml.TipoCambio @exchange_rate if @exchange_rate.present?
|
54
|
+
elsif document.version_43? && @currency.present? #&& @currency != "CRC"
|
55
|
+
xml.CodigoTipoMoneda do |x|
|
56
|
+
x.CodigoMoneda @currency
|
57
|
+
x.TipoCambio @exchange_rate || 1
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
39
61
|
xml.TotalServGravados @services_taxable_total
|
40
62
|
xml.TotalServExentos @services_exent_total
|
63
|
+
xml.TotalServExonerado @services_exonerate_total if @services_exonerate_total && document.version_43? && !document_type.eql?(FE::ExportInvoice::DOCUMENT_TYPE)
|
41
64
|
xml.TotalMercanciasGravadas @goods_taxable_total
|
42
65
|
xml.TotalMercanciasExentas @goods_exent_total
|
66
|
+
xml.TotalMercExonerada @goods_exonerate_total if @goods_exonerate_total.present? && document.version_43? && !document_type.eql?(FE::ExportInvoice::DOCUMENT_TYPE)
|
43
67
|
xml.TotalGravado @taxable_total
|
44
68
|
xml.TotalExento @exent_total
|
69
|
+
xml.TotalExonerado @exonerate_total if @exonerate_total.present? && document.version_43? && !document_type.eql?(FE::ExportInvoice::DOCUMENT_TYPE)
|
45
70
|
xml.TotalVenta @subtotal
|
46
71
|
xml.TotalDescuentos @discount_total
|
47
72
|
xml.TotalVentaNeta @gross_total
|
48
73
|
xml.TotalImpuesto @tax_total
|
74
|
+
if document.version_43?
|
75
|
+
xml.TotalIVADevuelto @total_iva_returned if @medical_services_condition && !document_type.eql?(FE::ExportInvoice::DOCUMENT_TYPE) && !document_type.eql?(FE::PurchaseInvoice::DOCUMENT_TYPE)
|
76
|
+
xml.TotalOtrosCargos @total_other_charges if @total_other_charges > 0
|
77
|
+
end
|
49
78
|
xml.TotalComprobante @net_total
|
50
79
|
end
|
51
80
|
end
|
52
|
-
|
81
|
+
|
53
82
|
private
|
54
|
-
|
83
|
+
|
55
84
|
def totals_ok?
|
56
85
|
errors.add :taxable_total, :invalid_amount, message: 'invalid amount' if (@taxable_total - (@services_taxable_total + @goods_taxable_total).round(5)).abs > 0.0005
|
57
86
|
errors.add :exent_total, :invalid_amount, message: 'invalid amount' if (@exent_total - (@services_exent_total + @goods_exent_total).round(5)).abs > 0.0005
|
58
|
-
|
87
|
+
if document.version_43?
|
88
|
+
errors.add :exonerate_total, :invalid_amount, message: 'invalid amount' if (@exonerate_total - (@services_exonerate_total + @goods_exonerate_total).round(5)).abs > 0.0005
|
89
|
+
end
|
90
|
+
errors.add :subtotal, :invalid_amount, message: 'invalid amount' if (@subtotal - (@taxable_total + @exent_total + @exonerate_total ).round(5)).abs > 0.0005
|
59
91
|
errors.add :gross_total, :invalid_amount, message: 'invalid amount' if (@gross_total - (@subtotal - @discount_total).round(5)).abs > 0.0005
|
60
|
-
errors.add :net_total, :invalid_amount, message:
|
92
|
+
errors.add :net_total, :invalid_amount, message: "invalid amount" if (@net_total - (@gross_total + @tax_total + @total_other_charges - @total_iva_returned).round(5)).abs > 0.0005
|
61
93
|
end
|
62
94
|
end
|
63
95
|
end
|
64
|
-
end
|
96
|
+
end
|