zugpferd 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/zugpferd/cii/mapping.rb +10 -1
- data/lib/zugpferd/cii/reader.rb +12 -0
- data/lib/zugpferd/cii/writer.rb +19 -0
- data/lib/zugpferd/model/billing_document.rb +3 -1
- data/lib/zugpferd/model/payment_instructions.rb +1 -1
- data/lib/zugpferd/model/preceding_invoice.rb +17 -0
- data/lib/zugpferd/model/price.rb +2 -1
- data/lib/zugpferd/ubl/mapping.rb +13 -1
- data/lib/zugpferd/ubl/reader.rb +12 -1
- data/lib/zugpferd/ubl/writer.rb +20 -3
- data/lib/zugpferd.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: eb023a7256c9cf26f6688283b6204bbccc0f46f2a6c8f0bb8082c2b1db277151
|
|
4
|
+
data.tar.gz: 00d5dc92b2d38a3744af4388017629d83b74b28241014448c75b684fb8de7c5c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0b6313dfce9be63204e9c7317be9abfbd38c0a53c97e5a7960c4b4fab98421f7f5ec892af59457c4babcdc0ec811de4159f926ae8f443df5f1d417055eb3847f
|
|
7
|
+
data.tar.gz: 449b38ee768cea1a0a5167f498c5b80a6bc3604bfe92967cabed4e51d230fe56b307dd88c5313886cb2b67d6b053932bf5f8e575b18385b781fd323f74d10fdf
|
data/lib/zugpferd/cii/mapping.rb
CHANGED
|
@@ -38,6 +38,13 @@ module Zugpferd
|
|
|
38
38
|
end_date: "ram:EndDateTime/udt:DateTimeString",
|
|
39
39
|
}.freeze
|
|
40
40
|
|
|
41
|
+
# Preceding invoice reference (BG-3), relative to the settlement node
|
|
42
|
+
PRECEDING_INVOICE = "ram:InvoiceReferencedDocument"
|
|
43
|
+
PRECEDING_INVOICE_FIELDS = {
|
|
44
|
+
number: "ram:IssuerAssignedID",
|
|
45
|
+
issue_date: "ram:FormattedIssueDateTime/qdt:DateTimeString",
|
|
46
|
+
}.freeze
|
|
47
|
+
|
|
41
48
|
INVOICE_SETTLEMENT = {
|
|
42
49
|
currency_code: "#{SETTLEMENT}/ram:InvoiceCurrencyCode",
|
|
43
50
|
buyer_reference: "#{AGREEMENT}/ram:BuyerReference",
|
|
@@ -166,7 +173,9 @@ module Zugpferd
|
|
|
166
173
|
# Price (BG-29)
|
|
167
174
|
PRICE = "ram:SpecifiedLineTradeAgreement/ram:NetPriceProductTradePrice"
|
|
168
175
|
PRICE_FIELDS = {
|
|
169
|
-
amount:
|
|
176
|
+
amount: "ram:ChargeAmount",
|
|
177
|
+
base_quantity: "ram:BasisQuantity",
|
|
178
|
+
base_quantity_unit_code: "ram:BasisQuantity/@unitCode",
|
|
170
179
|
}.freeze
|
|
171
180
|
end
|
|
172
181
|
end
|
data/lib/zugpferd/cii/reader.rb
CHANGED
|
@@ -62,6 +62,7 @@ module Zugpferd
|
|
|
62
62
|
buyer: build_party(root.at_xpath(BUYER, NS)),
|
|
63
63
|
line_items: root.xpath(INVOICE_LINE, NS).map { |n| build_line_item(n) },
|
|
64
64
|
allowance_charges: settlement ? build_allowance_charges(settlement) : [],
|
|
65
|
+
preceding_invoices: settlement ? build_preceding_invoices(settlement) : [],
|
|
65
66
|
tax_breakdown: build_tax_breakdown(settlement),
|
|
66
67
|
monetary_totals: build_monetary_totals(settlement&.at_xpath(MONETARY_TOTAL, NS)),
|
|
67
68
|
payment_instructions: build_payment_instructions(settlement),
|
|
@@ -218,9 +219,20 @@ module Zugpferd
|
|
|
218
219
|
|
|
219
220
|
Model::Price.new(
|
|
220
221
|
amount: text(node, PRICE_FIELDS[:amount]),
|
|
222
|
+
base_quantity: parse_decimal(text(node, PRICE_FIELDS[:base_quantity])),
|
|
223
|
+
base_quantity_unit_code: node.at_xpath(PRICE_FIELDS[:base_quantity_unit_code], NS)&.text,
|
|
221
224
|
)
|
|
222
225
|
end
|
|
223
226
|
|
|
227
|
+
def build_preceding_invoices(settlement_node)
|
|
228
|
+
settlement_node.xpath(PRECEDING_INVOICE, NS).map do |node|
|
|
229
|
+
Model::PrecedingInvoice.new(
|
|
230
|
+
number: text(node, PRECEDING_INVOICE_FIELDS[:number]),
|
|
231
|
+
issue_date: parse_cii_date(text(node, PRECEDING_INVOICE_FIELDS[:issue_date])),
|
|
232
|
+
)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
224
236
|
def build_allowance_charges(settlement_node)
|
|
225
237
|
settlement_node.xpath(ALLOWANCE_CHARGE, NS).map do |node|
|
|
226
238
|
Model::AllowanceCharge.new(
|
data/lib/zugpferd/cii/writer.rb
CHANGED
|
@@ -197,6 +197,20 @@ module Zugpferd
|
|
|
197
197
|
end
|
|
198
198
|
|
|
199
199
|
build_monetary_total(xml, doc.monetary_totals, doc.tax_breakdown) if doc.monetary_totals
|
|
200
|
+
|
|
201
|
+
# CII allows a single InvoiceReferencedDocument, so only the first BG-3 is written
|
|
202
|
+
build_preceding_invoice(xml, doc.preceding_invoices.first) if doc.preceding_invoices.any?
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def build_preceding_invoice(xml, preceding)
|
|
207
|
+
xml["ram"].InvoiceReferencedDocument do
|
|
208
|
+
xml["ram"].IssuerAssignedID preceding.number
|
|
209
|
+
if preceding.issue_date
|
|
210
|
+
xml["ram"].FormattedIssueDateTime do
|
|
211
|
+
xml["qdt"].DateTimeString(format_cii_date(preceding.issue_date), format: "102")
|
|
212
|
+
end
|
|
213
|
+
end
|
|
200
214
|
end
|
|
201
215
|
end
|
|
202
216
|
|
|
@@ -303,6 +317,11 @@ module Zugpferd
|
|
|
303
317
|
if line.price
|
|
304
318
|
xml["ram"].NetPriceProductTradePrice do
|
|
305
319
|
xml["ram"].ChargeAmount format_decimal(line.price.amount)
|
|
320
|
+
if line.price.base_quantity
|
|
321
|
+
attrs = {}
|
|
322
|
+
attrs[:unitCode] = line.price.base_quantity_unit_code if line.price.base_quantity_unit_code
|
|
323
|
+
xml["ram"].BasisQuantity(format_decimal(line.price.base_quantity), attrs)
|
|
324
|
+
end
|
|
306
325
|
end
|
|
307
326
|
end
|
|
308
327
|
end
|
|
@@ -19,6 +19,7 @@ module Zugpferd
|
|
|
19
19
|
# @return [String] BT-3 Invoice type code
|
|
20
20
|
# @return [String] BT-5 Document currency code (default: "EUR")
|
|
21
21
|
# @return [Date, nil] BT-72 Actual delivery date
|
|
22
|
+
# @return [Array<PrecedingInvoice>] BG-3 Preceding invoice references
|
|
22
23
|
# @return [Date, nil] BT-73 Invoicing period start date
|
|
23
24
|
# @return [Date, nil] BT-74 Invoicing period end date
|
|
24
25
|
# @return [String, nil] BT-10 Buyer reference
|
|
@@ -39,7 +40,7 @@ module Zugpferd
|
|
|
39
40
|
:buyer_reference, :purchase_order_reference,
|
|
40
41
|
:customization_id, :profile_id, :note, :seller, :buyer,
|
|
41
42
|
:line_items, :tax_breakdown, :monetary_totals,
|
|
42
|
-
:payment_instructions, :allowance_charges
|
|
43
|
+
:payment_instructions, :allowance_charges, :preceding_invoices
|
|
43
44
|
|
|
44
45
|
# @param number [String] BT-1 Invoice number
|
|
45
46
|
# @param issue_date [Date] BT-2 Issue date
|
|
@@ -54,6 +55,7 @@ module Zugpferd
|
|
|
54
55
|
@currency_code = currency_code
|
|
55
56
|
@line_items = []
|
|
56
57
|
@allowance_charges = []
|
|
58
|
+
@preceding_invoices = []
|
|
57
59
|
@tax_breakdown = nil
|
|
58
60
|
rest.each { |k, v| public_send(:"#{k}=", v) }
|
|
59
61
|
end
|
|
@@ -6,7 +6,7 @@ module Zugpferd
|
|
|
6
6
|
# @return [String] BT-81 Payment means type code
|
|
7
7
|
# @return [String, nil] BT-83 Remittance information
|
|
8
8
|
# @return [String, nil] BT-84 Payment account identifier (IBAN)
|
|
9
|
-
# @return [String, nil] BT-
|
|
9
|
+
# @return [String, nil] BT-20 Payment terms
|
|
10
10
|
# @return [String, nil] BT-87 Payment card primary account number
|
|
11
11
|
# @return [String, nil] BT-88 Payment card holder name
|
|
12
12
|
# @return [String, nil] Card network ID (UBL-only, required in CardAccount)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Zugpferd
|
|
2
|
+
module Model
|
|
3
|
+
# Reference to a preceding invoice (BG-3).
|
|
4
|
+
class PrecedingInvoice
|
|
5
|
+
# @return [String] BT-25 Preceding invoice number
|
|
6
|
+
# @return [Date, nil] BT-26 Preceding invoice issue date
|
|
7
|
+
attr_accessor :number, :issue_date
|
|
8
|
+
|
|
9
|
+
# @param number [String] BT-25 Preceding invoice number
|
|
10
|
+
# @param rest [Hash] additional attributes set via accessors
|
|
11
|
+
def initialize(number:, **rest)
|
|
12
|
+
@number = number
|
|
13
|
+
rest.each { |k, v| public_send(:"#{k}=", v) }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/zugpferd/model/price.rb
CHANGED
|
@@ -6,7 +6,8 @@ module Zugpferd
|
|
|
6
6
|
class Price
|
|
7
7
|
# @return [BigDecimal] BT-146 Item net price
|
|
8
8
|
# @return [BigDecimal, nil] BT-149 Item price base quantity
|
|
9
|
-
|
|
9
|
+
# @return [String, nil] BT-150 Item price base quantity unit of measure code
|
|
10
|
+
attr_accessor :amount, :base_quantity, :base_quantity_unit_code
|
|
10
11
|
|
|
11
12
|
# @param amount [String, BigDecimal] BT-146 Item net price
|
|
12
13
|
# @param rest [Hash] additional attributes set via accessors
|
data/lib/zugpferd/ubl/mapping.rb
CHANGED
|
@@ -26,6 +26,9 @@ module Zugpferd
|
|
|
26
26
|
note: "cbc:Note",
|
|
27
27
|
}.freeze
|
|
28
28
|
|
|
29
|
+
# BT-9 in a credit note (it has no cbc:DueDate)
|
|
30
|
+
CREDIT_NOTE_DUE_DATE = "cac:PaymentMeans/cbc:PaymentDueDate"
|
|
31
|
+
|
|
29
32
|
# Delivery (BG-13)
|
|
30
33
|
DELIVERY = "cac:Delivery"
|
|
31
34
|
DELIVERY_DATE = "cbc:ActualDeliveryDate"
|
|
@@ -40,6 +43,13 @@ module Zugpferd
|
|
|
40
43
|
# Purchase order reference (BT-13)
|
|
41
44
|
ORDER_REFERENCE = "cac:OrderReference/cbc:ID"
|
|
42
45
|
|
|
46
|
+
# Preceding invoice reference (BG-3)
|
|
47
|
+
PRECEDING_INVOICE = "cac:BillingReference/cac:InvoiceDocumentReference"
|
|
48
|
+
PRECEDING_INVOICE_FIELDS = {
|
|
49
|
+
number: "cbc:ID",
|
|
50
|
+
issue_date: "cbc:IssueDate",
|
|
51
|
+
}.freeze
|
|
52
|
+
|
|
43
53
|
# Seller (BG-4)
|
|
44
54
|
SELLER = "cac:AccountingSupplierParty/cac:Party"
|
|
45
55
|
# Buyer (BG-7)
|
|
@@ -155,7 +165,9 @@ module Zugpferd
|
|
|
155
165
|
# Price (BG-29)
|
|
156
166
|
PRICE = "cac:Price"
|
|
157
167
|
PRICE_FIELDS = {
|
|
158
|
-
amount:
|
|
168
|
+
amount: "cbc:PriceAmount",
|
|
169
|
+
base_quantity: "cbc:BaseQuantity",
|
|
170
|
+
base_quantity_unit_code: "cbc:BaseQuantity/@unitCode",
|
|
159
171
|
}.freeze
|
|
160
172
|
end
|
|
161
173
|
end
|
data/lib/zugpferd/ubl/reader.rb
CHANGED
|
@@ -30,6 +30,7 @@ module Zugpferd
|
|
|
30
30
|
def build_invoice(root)
|
|
31
31
|
type_code_element = @credit_note ? "cbc:CreditNoteTypeCode" : INVOICE[:type_code]
|
|
32
32
|
line_element = @credit_note ? "cac:CreditNoteLine" : INVOICE_LINE
|
|
33
|
+
due_date_element = @credit_note ? CREDIT_NOTE_DUE_DATE : INVOICE[:due_date]
|
|
33
34
|
|
|
34
35
|
model_class = @credit_note ? Model::CreditNote : Model::Invoice
|
|
35
36
|
|
|
@@ -39,7 +40,7 @@ module Zugpferd
|
|
|
39
40
|
model_class.new(
|
|
40
41
|
number: text(root, INVOICE[:number]),
|
|
41
42
|
issue_date: parse_date(text(root, INVOICE[:issue_date])),
|
|
42
|
-
due_date: parse_date(text(root,
|
|
43
|
+
due_date: parse_date(text(root, due_date_element)),
|
|
43
44
|
delivery_date: delivery_node ? parse_date(text(delivery_node, DELIVERY_DATE)) : nil,
|
|
44
45
|
invoicing_period_start_date: period_node ? parse_date(text(period_node, INVOICE_PERIOD_FIELDS[:start_date])) : nil,
|
|
45
46
|
invoicing_period_end_date: period_node ? parse_date(text(period_node, INVOICE_PERIOD_FIELDS[:end_date])) : nil,
|
|
@@ -54,6 +55,7 @@ module Zugpferd
|
|
|
54
55
|
buyer: build_party(root.at_xpath(BUYER, @ns)),
|
|
55
56
|
line_items: root.xpath(line_element, @ns).map { |n| build_line_item(n) },
|
|
56
57
|
allowance_charges: root.xpath(ALLOWANCE_CHARGE, @ns).map { |n| build_allowance_charge(n) },
|
|
58
|
+
preceding_invoices: root.xpath(PRECEDING_INVOICE, @ns).map { |n| build_preceding_invoice(n) },
|
|
57
59
|
tax_breakdown: build_tax_breakdown(root.at_xpath(TAX_TOTAL, @ns)),
|
|
58
60
|
monetary_totals: build_monetary_totals(root.at_xpath(MONETARY_TOTAL, @ns)),
|
|
59
61
|
payment_instructions: build_payment_instructions(root),
|
|
@@ -204,6 +206,15 @@ module Zugpferd
|
|
|
204
206
|
|
|
205
207
|
Model::Price.new(
|
|
206
208
|
amount: text(node, PRICE_FIELDS[:amount]),
|
|
209
|
+
base_quantity: parse_decimal(text(node, PRICE_FIELDS[:base_quantity])),
|
|
210
|
+
base_quantity_unit_code: node.at_xpath(PRICE_FIELDS[:base_quantity_unit_code], @ns)&.text,
|
|
211
|
+
)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def build_preceding_invoice(node)
|
|
215
|
+
Model::PrecedingInvoice.new(
|
|
216
|
+
number: text(node, PRECEDING_INVOICE_FIELDS[:number]),
|
|
217
|
+
issue_date: parse_date(text(node, PRECEDING_INVOICE_FIELDS[:issue_date])),
|
|
207
218
|
)
|
|
208
219
|
end
|
|
209
220
|
|
data/lib/zugpferd/ubl/writer.rb
CHANGED
|
@@ -41,7 +41,7 @@ module Zugpferd
|
|
|
41
41
|
xml["cbc"].ProfileID doc.profile_id if doc.profile_id
|
|
42
42
|
xml["cbc"].ID doc.number
|
|
43
43
|
xml["cbc"].IssueDate doc.issue_date.to_s
|
|
44
|
-
xml["cbc"].DueDate doc.due_date.to_s if doc.due_date
|
|
44
|
+
xml["cbc"].DueDate doc.due_date.to_s if doc.due_date && !@credit_note
|
|
45
45
|
if @credit_note
|
|
46
46
|
xml["cbc"].CreditNoteTypeCode doc.type_code
|
|
47
47
|
else
|
|
@@ -52,11 +52,12 @@ module Zugpferd
|
|
|
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
54
|
build_order_reference(xml, doc) if doc.purchase_order_reference
|
|
55
|
+
doc.preceding_invoices.each { |pi| build_preceding_invoice(xml, pi) }
|
|
55
56
|
|
|
56
57
|
build_supplier(xml, doc.seller, doc.payment_instructions) if doc.seller
|
|
57
58
|
build_customer(xml, doc.buyer) if doc.buyer
|
|
58
59
|
build_delivery(xml, doc) if doc.delivery_date
|
|
59
|
-
build_payment_means(xml, doc.payment_instructions) if doc.payment_instructions
|
|
60
|
+
build_payment_means(xml, doc.payment_instructions, doc.due_date) if doc.payment_instructions
|
|
60
61
|
build_payment_terms(xml, doc.payment_instructions) if doc.payment_instructions&.note
|
|
61
62
|
doc.allowance_charges.each { |ac| build_allowance_charge(xml, ac, doc.currency_code) }
|
|
62
63
|
build_tax_total(xml, doc.tax_breakdown) if doc.tax_breakdown
|
|
@@ -156,15 +157,26 @@ module Zugpferd
|
|
|
156
157
|
end
|
|
157
158
|
end
|
|
158
159
|
|
|
160
|
+
def build_preceding_invoice(xml, preceding)
|
|
161
|
+
xml["cac"].BillingReference do
|
|
162
|
+
xml["cac"].InvoiceDocumentReference do
|
|
163
|
+
xml["cbc"].ID preceding.number
|
|
164
|
+
xml["cbc"].IssueDate preceding.issue_date.to_s if preceding.issue_date
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
159
169
|
def build_delivery(xml, doc)
|
|
160
170
|
xml["cac"].Delivery do
|
|
161
171
|
xml["cbc"].ActualDeliveryDate doc.delivery_date.to_s
|
|
162
172
|
end
|
|
163
173
|
end
|
|
164
174
|
|
|
165
|
-
|
|
175
|
+
# A credit note has no cbc:DueDate, BT-9 is written as PaymentDueDate instead.
|
|
176
|
+
def build_payment_means(xml, payment, due_date = nil)
|
|
166
177
|
xml["cac"].PaymentMeans do
|
|
167
178
|
xml["cbc"].PaymentMeansCode payment.payment_means_code
|
|
179
|
+
xml["cbc"].PaymentDueDate due_date.to_s if @credit_note && due_date
|
|
168
180
|
xml["cbc"].PaymentID payment.payment_id if payment.payment_id
|
|
169
181
|
if payment.card_account_id
|
|
170
182
|
xml["cac"].CardAccount do
|
|
@@ -318,6 +330,11 @@ module Zugpferd
|
|
|
318
330
|
def build_price(xml, price, currency_code)
|
|
319
331
|
xml["cac"].Price do
|
|
320
332
|
xml["cbc"].PriceAmount(format_decimal(price.amount), currencyID: currency_code)
|
|
333
|
+
if price.base_quantity
|
|
334
|
+
attrs = {}
|
|
335
|
+
attrs[:unitCode] = price.base_quantity_unit_code if price.base_quantity_unit_code
|
|
336
|
+
xml["cbc"].BaseQuantity(format_decimal(price.base_quantity), attrs)
|
|
337
|
+
end
|
|
321
338
|
end
|
|
322
339
|
end
|
|
323
340
|
|
data/lib/zugpferd.rb
CHANGED
|
@@ -20,6 +20,7 @@ require_relative "zugpferd/model/tax_breakdown"
|
|
|
20
20
|
require_relative "zugpferd/model/tax_subtotal"
|
|
21
21
|
require_relative "zugpferd/model/payment_instructions"
|
|
22
22
|
require_relative "zugpferd/model/allowance_charge"
|
|
23
|
+
require_relative "zugpferd/model/preceding_invoice"
|
|
23
24
|
require_relative "zugpferd/ubl/reader"
|
|
24
25
|
require_relative "zugpferd/ubl/writer"
|
|
25
26
|
require_relative "zugpferd/cii/reader"
|
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.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexander Zeitler
|
|
@@ -90,6 +90,7 @@ files:
|
|
|
90
90
|
- lib/zugpferd/model/partial_invoice.rb
|
|
91
91
|
- lib/zugpferd/model/payment_instructions.rb
|
|
92
92
|
- lib/zugpferd/model/postal_address.rb
|
|
93
|
+
- lib/zugpferd/model/preceding_invoice.rb
|
|
93
94
|
- lib/zugpferd/model/prepayment_invoice.rb
|
|
94
95
|
- lib/zugpferd/model/price.rb
|
|
95
96
|
- lib/zugpferd/model/self_billed_invoice.rb
|