zugpferd 0.5.0 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a9f2f51374e01f8940bd39a69c088477348c26d77d69adca3f1737445f99c9d
4
- data.tar.gz: 8a541edb6c9b0aa78d87d715e8a04271ef0a8ea03d9d49463b4d0f45f72ce499
3
+ metadata.gz: 837410c3386f0fb24e0c903378bad0e4d797e24867b2a3b15b7fdc6d23f1edb3
4
+ data.tar.gz: e5a4808ba918693dcd393212064c3e6590038aa61406fcd0fccf37e3a91794d0
5
5
  SHA512:
6
- metadata.gz: 5f3051364d36fc4b5fddb4ff6e8369f37aca520f88aaa20784443176706bbfa688da434f4f3ba28fea8953460a092914b7fa0ca4380a9d07e16df5205258b7de
7
- data.tar.gz: 4c40141f885ee40dd9da1e67432ba2a7a80cf5d59b2847cf4b487df4682baffc224f7b61d58b5a0b5f51aeeb684b6bf8ae501b9616e124dcaa77828761e8034a
6
+ metadata.gz: 1f0fcf101222d3f841c8d1ea2601159509deafcc1c8344a04a70d4b63049d32dd78c180b4e9061f768f65b0675adfdc1393dbfbde9f40ef2efafdd37447e5478
7
+ data.tar.gz: 9bcf99a1530b14c1540551eab5534be30ffe6c6f1c1bf666f7875f2e7f442f0b929ebc08ff6351b477685520fe724dd7419292f2fce5f5a508a29b3b22cb162d
@@ -41,6 +41,7 @@ module Zugpferd
41
41
  INVOICE_SETTLEMENT = {
42
42
  currency_code: "#{SETTLEMENT}/ram:InvoiceCurrencyCode",
43
43
  buyer_reference: "#{AGREEMENT}/ram:BuyerReference",
44
+ purchase_order_reference: "#{AGREEMENT}/ram:BuyerOrderReferencedDocument/ram:IssuerAssignedID",
44
45
  }.freeze
45
46
 
46
47
  # Seller (BG-4)
@@ -93,6 +94,7 @@ module Zugpferd
93
94
 
94
95
  # TaxTotal (BG-23)
95
96
  TAX_SUBTOTAL = "ram:ApplicableTradeTax"
97
+ TAX_FALLBACK_CURRENCY = "ram:InvoiceCurrencyCode"
96
98
  TAX = {
97
99
  taxable_amount: "ram:BasisAmount",
98
100
  tax_amount: "ram:CalculatedAmount",
@@ -12,6 +12,9 @@ module Zugpferd
12
12
  class Reader
13
13
  include Mapping
14
14
 
15
+ # Raised when BT-110 is missing and the VAT breakdown (BG-23) does not sum to 0.
16
+ class MissingTaxTotalError < Zugpferd::Error; end
17
+
15
18
  TYPE_CODE_MAP = {
16
19
  "381" => Model::CreditNote,
17
20
  "384" => Model::CorrectedInvoice,
@@ -25,6 +28,7 @@ module Zugpferd
25
28
  # @param xml_string [String] valid CII D16B XML
26
29
  # @return [Model::BillingDocument]
27
30
  # @raise [Nokogiri::XML::SyntaxError] if the XML is malformed
31
+ # @raise [MissingTaxTotalError] if BT-110 is missing and the VAT breakdown does not sum to 0
28
32
  def read(xml_string)
29
33
  doc = Nokogiri::XML(xml_string) { |config| config.strict }
30
34
  root = doc.root
@@ -50,6 +54,7 @@ module Zugpferd
50
54
  type_code: text(root, INVOICE[:type_code]),
51
55
  currency_code: text(root, INVOICE_SETTLEMENT[:currency_code]),
52
56
  buyer_reference: text(root, INVOICE_SETTLEMENT[:buyer_reference]),
57
+ purchase_order_reference: text(root, INVOICE_SETTLEMENT[:purchase_order_reference]),
53
58
  customization_id: text(root, INVOICE[:customization_id]),
54
59
  profile_id: text(root, INVOICE[:profile_id]),
55
60
  note: text(root, INVOICE[:note]),
@@ -129,14 +134,9 @@ module Zugpferd
129
134
 
130
135
  totals_node = settlement_node.at_xpath(MONETARY_TOTAL, NS)
131
136
  tax_total_node = totals_node&.at_xpath(TOTALS[:tax_total_amount], NS)
132
- currency = tax_total_node&.[]("currencyID")
133
-
134
- breakdown = Model::TaxBreakdown.new(
135
- tax_amount: tax_total_node&.text,
136
- currency_code: currency,
137
- )
137
+ currency = tax_total_node ? tax_total_node["currencyID"] : text(settlement_node, TAX_FALLBACK_CURRENCY)
138
138
 
139
- breakdown.subtotals = settlement_node.xpath(TAX_SUBTOTAL, NS).map do |sub|
139
+ subtotals = settlement_node.xpath(TAX_SUBTOTAL, NS).map do |sub|
140
140
  Model::TaxSubtotal.new(
141
141
  taxable_amount: text(sub, TAX[:taxable_amount]),
142
142
  tax_amount: text(sub, TAX[:tax_amount]),
@@ -148,9 +148,25 @@ module Zugpferd
148
148
  )
149
149
  end
150
150
 
151
+ breakdown = Model::TaxBreakdown.new(
152
+ tax_amount: tax_total_node ? tax_total_node.text : zero_tax_total(subtotals),
153
+ currency_code: currency,
154
+ )
155
+ breakdown.subtotals = subtotals
151
156
  breakdown
152
157
  end
153
158
 
159
+ # BR-CO-15 lets CII omit BT-110 on invoices without VAT. A breakdown
160
+ # that shows VAT contradicts that, even where the Schematron passes it.
161
+ def zero_tax_total(subtotals)
162
+ sum = subtotals.sum(BigDecimal("0"), &:tax_amount)
163
+ return sum if subtotals.any? && sum.zero?
164
+
165
+ raise MissingTaxTotalError,
166
+ "Invoice total VAT amount (BT-110) is missing and the VAT breakdown (BG-23) " \
167
+ "#{subtotals.empty? ? "is empty" : "sums to #{sum.to_s("F")}"}"
168
+ end
169
+
154
170
  def build_monetary_totals(node)
155
171
  return nil unless node
156
172
 
@@ -76,6 +76,13 @@ module Zugpferd
76
76
  xml["ram"].BuyerReference doc.buyer_reference if doc.buyer_reference
77
77
  build_party(xml, "SellerTradeParty", doc.seller) if doc.seller
78
78
  build_party(xml, "BuyerTradeParty", doc.buyer) if doc.buyer
79
+ build_buyer_order_reference(xml, doc) if doc.purchase_order_reference
80
+ end
81
+ end
82
+
83
+ def build_buyer_order_reference(xml, doc)
84
+ xml["ram"].BuyerOrderReferencedDocument do
85
+ xml["ram"].IssuerAssignedID doc.purchase_order_reference
79
86
  end
80
87
  end
81
88
 
@@ -22,6 +22,7 @@ module Zugpferd
22
22
  # @return [Date, nil] BT-73 Invoicing period start date
23
23
  # @return [Date, nil] BT-74 Invoicing period end date
24
24
  # @return [String, nil] BT-10 Buyer reference
25
+ # @return [String, nil] BT-13 Purchase order reference
25
26
  # @return [String, nil] BT-24 Specification identifier
26
27
  # @return [String, nil] BT-23 Business process type
27
28
  # @return [String, nil] BT-22 Invoice note
@@ -35,7 +36,8 @@ module Zugpferd
35
36
  attr_accessor :number, :issue_date, :due_date, :type_code,
36
37
  :currency_code, :delivery_date,
37
38
  :invoicing_period_start_date, :invoicing_period_end_date,
38
- :buyer_reference, :customization_id, :profile_id, :note, :seller, :buyer,
39
+ :buyer_reference, :purchase_order_reference,
40
+ :customization_id, :profile_id, :note, :seller, :buyer,
39
41
  :line_items, :tax_breakdown, :monetary_totals,
40
42
  :payment_instructions, :allowance_charges
41
43
 
@@ -37,6 +37,9 @@ module Zugpferd
37
37
  end_date: "cbc:EndDate",
38
38
  }.freeze
39
39
 
40
+ # Purchase order reference (BT-13)
41
+ ORDER_REFERENCE = "cac:OrderReference/cbc:ID"
42
+
40
43
  # Seller (BG-4)
41
44
  SELLER = "cac:AccountingSupplierParty/cac:Party"
42
45
  # Buyer (BG-7)
@@ -46,6 +46,7 @@ module Zugpferd
46
46
  type_code: text(root, type_code_element),
47
47
  currency_code: text(root, INVOICE[:currency_code]),
48
48
  buyer_reference: text(root, INVOICE[:buyer_reference]),
49
+ purchase_order_reference: text(root, ORDER_REFERENCE),
49
50
  customization_id: text(root, INVOICE[:customization_id]),
50
51
  profile_id: text(root, INVOICE[:profile_id]),
51
52
  note: text(root, INVOICE[:note]),
@@ -51,6 +51,7 @@ module Zugpferd
51
51
  xml["cbc"].DocumentCurrencyCode doc.currency_code
52
52
  xml["cbc"].BuyerReference doc.buyer_reference if doc.buyer_reference
53
53
  build_invoice_period(xml, doc) if doc.invoicing_period_start_date || doc.invoicing_period_end_date
54
+ build_order_reference(xml, doc) if doc.purchase_order_reference
54
55
 
55
56
  build_supplier(xml, doc.seller, doc.payment_instructions) if doc.seller
56
57
  build_customer(xml, doc.buyer) if doc.buyer
@@ -149,6 +150,12 @@ module Zugpferd
149
150
  end
150
151
  end
151
152
 
153
+ def build_order_reference(xml, doc)
154
+ xml["cac"].OrderReference do
155
+ xml["cbc"].ID doc.purchase_order_reference
156
+ end
157
+ end
158
+
152
159
  def build_delivery(xml, doc)
153
160
  xml["cac"].Delivery do
154
161
  xml["cbc"].ActualDeliveryDate doc.delivery_date.to_s
data/lib/zugpferd.rb CHANGED
@@ -1,3 +1,7 @@
1
+ module Zugpferd
2
+ class Error < StandardError; end
3
+ end
4
+
1
5
  require_relative "zugpferd/model/billing_document"
2
6
  require_relative "zugpferd/model/invoice"
3
7
  require_relative "zugpferd/model/credit_note"
@@ -20,7 +24,3 @@ require_relative "zugpferd/ubl/reader"
20
24
  require_relative "zugpferd/ubl/writer"
21
25
  require_relative "zugpferd/cii/reader"
22
26
  require_relative "zugpferd/cii/writer"
23
-
24
- module Zugpferd
25
- class Error < StandardError; end
26
- end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zugpferd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Zeitler