zugpferd 0.6.0 → 0.8.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 +3 -0
- data/lib/zugpferd/cii/reader.rb +11 -3
- data/lib/zugpferd/cii/writer.rb +15 -3
- data/lib/zugpferd/model/billing_document.rb +2 -1
- data/lib/zugpferd/model/postal_address.rb +6 -6
- data/lib/zugpferd/model/trade_party.rb +3 -1
- data/lib/zugpferd/ubl/mapping.rb +3 -0
- data/lib/zugpferd/ubl/reader.rb +11 -3
- data/lib/zugpferd/ubl/writer.rb +32 -11
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 05fc84848e61ccfc901d5a22ab7d35ff8032531d543dcd85883073a7d0bd2c43
|
|
4
|
+
data.tar.gz: cd37bf998f94dd2be0f9adac19761976145b49f7aace4d22d5af2812df173e1a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 245cb66ea6b7b151145130747873780113acd36790a66420e23b210ddd1920082e22bd50661cadde218bf15bc1713687ddbc0b5a802bfd0245aa6b72b569fe7c
|
|
7
|
+
data.tar.gz: 72af5d37db91aaa59deee1cc9b9ec7aa70347d1dce1f87decc6f5347f5714a077d869533f4bcb23d9bb42b4b52b6db73157904c987c98144c5a888616d7f5f24
|
data/lib/zugpferd/cii/mapping.rb
CHANGED
|
@@ -26,6 +26,8 @@ module Zugpferd
|
|
|
26
26
|
# Delivery (BG-13)
|
|
27
27
|
DELIVERY = "#{TRANSACTION}/ram:ApplicableHeaderTradeDelivery"
|
|
28
28
|
DELIVERY_DATE = "ram:ActualDeliverySupplyChainEvent/ram:OccurrenceDateTime/udt:DateTimeString"
|
|
29
|
+
# Deliver to address (BG-15), fields as in ADDRESS
|
|
30
|
+
DELIVER_TO_ADDRESS = "ram:ShipToTradeParty/ram:PostalTradeAddress"
|
|
29
31
|
|
|
30
32
|
# Settlement (contains currency, payment, tax, totals)
|
|
31
33
|
SETTLEMENT = "#{TRANSACTION}/ram:ApplicableHeaderTradeSettlement"
|
|
@@ -64,6 +66,7 @@ module Zugpferd
|
|
|
64
66
|
legal_registration_id: "ram:SpecifiedLegalOrganization/ram:ID",
|
|
65
67
|
legal_form: "ram:Description",
|
|
66
68
|
vat_identifier: "ram:SpecifiedTaxRegistration/ram:ID[@schemeID='VA']",
|
|
69
|
+
tax_registration_identifier: "ram:SpecifiedTaxRegistration/ram:ID[@schemeID='FC']",
|
|
67
70
|
electronic_address: "ram:URIUniversalCommunication/ram:URIID",
|
|
68
71
|
}.freeze
|
|
69
72
|
|
data/lib/zugpferd/cii/reader.rb
CHANGED
|
@@ -49,6 +49,7 @@ module Zugpferd
|
|
|
49
49
|
issue_date: parse_cii_date(text(root, INVOICE[:issue_date])),
|
|
50
50
|
due_date: parse_cii_date(settlement ? text(settlement, PAYMENT_TERMS_DUE_DATE) : nil),
|
|
51
51
|
delivery_date: parse_cii_date(delivery ? text(delivery, DELIVERY_DATE) : nil),
|
|
52
|
+
deliver_to_address: build_deliver_to_address(delivery),
|
|
52
53
|
invoicing_period_start_date: parse_cii_date(period ? text(period, BILLING_PERIOD_FIELDS[:start_date]) : nil),
|
|
53
54
|
invoicing_period_end_date: parse_cii_date(period ? text(period, BILLING_PERIOD_FIELDS[:end_date]) : nil),
|
|
54
55
|
type_code: text(root, INVOICE[:type_code]),
|
|
@@ -58,7 +59,7 @@ module Zugpferd
|
|
|
58
59
|
customization_id: text(root, INVOICE[:customization_id]),
|
|
59
60
|
profile_id: text(root, INVOICE[:profile_id]),
|
|
60
61
|
note: text(root, INVOICE[:note]),
|
|
61
|
-
seller: build_party(root.at_xpath(SELLER, NS)),
|
|
62
|
+
seller: build_party(root.at_xpath(SELLER, NS), seller: true),
|
|
62
63
|
buyer: build_party(root.at_xpath(BUYER, NS)),
|
|
63
64
|
line_items: root.xpath(INVOICE_LINE, NS).map { |n| build_line_item(n) },
|
|
64
65
|
allowance_charges: settlement ? build_allowance_charges(settlement) : [],
|
|
@@ -69,7 +70,8 @@ module Zugpferd
|
|
|
69
70
|
)
|
|
70
71
|
end
|
|
71
72
|
|
|
72
|
-
|
|
73
|
+
# Seller-only terms are read only for the seller
|
|
74
|
+
def build_party(node, seller: false)
|
|
73
75
|
return nil unless node
|
|
74
76
|
|
|
75
77
|
party = Model::TradeParty.new(
|
|
@@ -77,8 +79,9 @@ module Zugpferd
|
|
|
77
79
|
trading_name: text(node, PARTY[:trading_name]),
|
|
78
80
|
identifier: text(node, PARTY[:identifier]),
|
|
79
81
|
legal_registration_id: text(node, PARTY[:legal_registration_id]),
|
|
80
|
-
legal_form: text(node, PARTY[:legal_form]),
|
|
82
|
+
legal_form: (text(node, PARTY[:legal_form]) if seller),
|
|
81
83
|
vat_identifier: text(node, PARTY[:vat_identifier]),
|
|
84
|
+
tax_registration_identifier: (text(node, PARTY[:tax_registration_identifier]) if seller),
|
|
82
85
|
electronic_address: text(node, PARTY[:electronic_address]),
|
|
83
86
|
)
|
|
84
87
|
|
|
@@ -103,6 +106,11 @@ module Zugpferd
|
|
|
103
106
|
)
|
|
104
107
|
end
|
|
105
108
|
|
|
109
|
+
def build_deliver_to_address(delivery_node)
|
|
110
|
+
addr_node = delivery_node&.at_xpath(DELIVER_TO_ADDRESS, NS)
|
|
111
|
+
build_postal_address(addr_node) if addr_node
|
|
112
|
+
end
|
|
113
|
+
|
|
106
114
|
def build_contact(node)
|
|
107
115
|
Model::Contact.new(
|
|
108
116
|
name: text(node, CONTACT_FIELDS[:name]),
|
data/lib/zugpferd/cii/writer.rb
CHANGED
|
@@ -74,7 +74,7 @@ module Zugpferd
|
|
|
74
74
|
def build_agreement(xml, doc)
|
|
75
75
|
xml["ram"].ApplicableHeaderTradeAgreement do
|
|
76
76
|
xml["ram"].BuyerReference doc.buyer_reference if doc.buyer_reference
|
|
77
|
-
build_party(xml, "SellerTradeParty", doc.seller) if doc.seller
|
|
77
|
+
build_party(xml, "SellerTradeParty", doc.seller, seller: true) if doc.seller
|
|
78
78
|
build_party(xml, "BuyerTradeParty", doc.buyer) if doc.buyer
|
|
79
79
|
build_buyer_order_reference(xml, doc) if doc.purchase_order_reference
|
|
80
80
|
end
|
|
@@ -86,7 +86,8 @@ module Zugpferd
|
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
# Seller-only terms are written only for the seller
|
|
90
|
+
def build_party(xml, element_name, party, seller: false)
|
|
90
91
|
xml["ram"].send(element_name) do
|
|
91
92
|
if party.identifier
|
|
92
93
|
xml["ram"].ID party.identifier
|
|
@@ -94,7 +95,7 @@ module Zugpferd
|
|
|
94
95
|
|
|
95
96
|
xml["ram"].Name party.name
|
|
96
97
|
|
|
97
|
-
xml["ram"].Description party.legal_form if party.legal_form
|
|
98
|
+
xml["ram"].Description party.legal_form if seller && party.legal_form
|
|
98
99
|
|
|
99
100
|
if party.legal_registration_id || party.trading_name
|
|
100
101
|
xml["ram"].SpecifiedLegalOrganization do
|
|
@@ -120,6 +121,12 @@ module Zugpferd
|
|
|
120
121
|
xml["ram"].ID(party.vat_identifier, schemeID: "VA")
|
|
121
122
|
end
|
|
122
123
|
end
|
|
124
|
+
|
|
125
|
+
if seller && party.tax_registration_identifier
|
|
126
|
+
xml["ram"].SpecifiedTaxRegistration do
|
|
127
|
+
xml["ram"].ID(party.tax_registration_identifier, schemeID: "FC")
|
|
128
|
+
end
|
|
129
|
+
end
|
|
123
130
|
end
|
|
124
131
|
end
|
|
125
132
|
|
|
@@ -150,6 +157,11 @@ module Zugpferd
|
|
|
150
157
|
|
|
151
158
|
def build_delivery(xml, doc)
|
|
152
159
|
xml["ram"].ApplicableHeaderTradeDelivery do
|
|
160
|
+
if doc.deliver_to_address
|
|
161
|
+
xml["ram"].ShipToTradeParty do
|
|
162
|
+
build_postal_address(xml, doc.deliver_to_address)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
153
165
|
if doc.delivery_date
|
|
154
166
|
xml["ram"].ActualDeliverySupplyChainEvent do
|
|
155
167
|
xml["ram"].OccurrenceDateTime do
|
|
@@ -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 [PostalAddress, nil] BG-15 Deliver to address
|
|
22
23
|
# @return [Array<PrecedingInvoice>] BG-3 Preceding invoice references
|
|
23
24
|
# @return [Date, nil] BT-73 Invoicing period start date
|
|
24
25
|
# @return [Date, nil] BT-74 Invoicing period end date
|
|
@@ -35,7 +36,7 @@ module Zugpferd
|
|
|
35
36
|
# @return [PaymentInstructions, nil] BG-16 Payment information
|
|
36
37
|
# @return [Array<AllowanceCharge>] BG-20/BG-21 Document-level allowances and charges
|
|
37
38
|
attr_accessor :number, :issue_date, :due_date, :type_code,
|
|
38
|
-
:currency_code, :delivery_date,
|
|
39
|
+
:currency_code, :delivery_date, :deliver_to_address,
|
|
39
40
|
:invoicing_period_start_date, :invoicing_period_end_date,
|
|
40
41
|
:buyer_reference, :purchase_order_reference,
|
|
41
42
|
:customization_id, :profile_id, :note, :seller, :buyer,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
module Zugpferd
|
|
2
2
|
module Model
|
|
3
|
-
# Postal address (BG-5 / BG-8).
|
|
3
|
+
# Postal address (BG-5 / BG-8 / BG-15).
|
|
4
4
|
class PostalAddress
|
|
5
|
-
# @return [String, nil] BT-35/BT-50 Street name
|
|
6
|
-
# @return [String, nil] BT-37/BT-52 City name
|
|
7
|
-
# @return [String, nil] BT-38/BT-53 Postal zone
|
|
8
|
-
# @return [String] BT-40/BT-55 Country code
|
|
5
|
+
# @return [String, nil] BT-35/BT-50/BT-75 Street name
|
|
6
|
+
# @return [String, nil] BT-37/BT-52/BT-77 City name
|
|
7
|
+
# @return [String, nil] BT-38/BT-53/BT-78 Postal zone
|
|
8
|
+
# @return [String] BT-40/BT-55/BT-80 Country code
|
|
9
9
|
attr_accessor :street_name, :city_name, :postal_zone, :country_code
|
|
10
10
|
|
|
11
|
-
# @param country_code [String] BT-40/BT-55 Country code (ISO 3166-1 alpha-2)
|
|
11
|
+
# @param country_code [String] BT-40/BT-55/BT-80 Country code (ISO 3166-1 alpha-2)
|
|
12
12
|
# @param rest [Hash] additional attributes set via accessors
|
|
13
13
|
def initialize(country_code:, **rest)
|
|
14
14
|
@country_code = country_code
|
|
@@ -10,14 +10,16 @@ module Zugpferd
|
|
|
10
10
|
# @return [String, nil] BT-28/BT-45 Trading name
|
|
11
11
|
# @return [String, nil] BT-29/BT-46 Party identifier
|
|
12
12
|
# @return [String, nil] BT-30/BT-47 Legal registration identifier
|
|
13
|
-
# @return [String, nil] BT-33 Company legal form
|
|
13
|
+
# @return [String, nil] BT-33 Company legal form (seller only)
|
|
14
14
|
# @return [String, nil] BT-31/BT-48 VAT identifier
|
|
15
|
+
# @return [String, nil] BT-32 Seller tax registration identifier (seller only)
|
|
15
16
|
# @return [String, nil] BT-34/BT-49 Electronic address
|
|
16
17
|
# @return [String, nil] BT-34-1/BT-49-1 Electronic address scheme
|
|
17
18
|
# @return [PostalAddress, nil] BG-5/BG-8 Postal address
|
|
18
19
|
# @return [Contact, nil] BG-6/BG-9 Contact information
|
|
19
20
|
attr_accessor :name, :trading_name, :identifier,
|
|
20
21
|
:legal_registration_id, :legal_form, :vat_identifier,
|
|
22
|
+
:tax_registration_identifier,
|
|
21
23
|
:electronic_address, :electronic_address_scheme,
|
|
22
24
|
:postal_address, :contact
|
|
23
25
|
|
data/lib/zugpferd/ubl/mapping.rb
CHANGED
|
@@ -32,6 +32,8 @@ module Zugpferd
|
|
|
32
32
|
# Delivery (BG-13)
|
|
33
33
|
DELIVERY = "cac:Delivery"
|
|
34
34
|
DELIVERY_DATE = "cbc:ActualDeliveryDate"
|
|
35
|
+
# Deliver to address (BG-15), fields as in ADDRESS
|
|
36
|
+
DELIVER_TO_ADDRESS = "cac:DeliveryLocation/cac:Address"
|
|
35
37
|
|
|
36
38
|
# Invoicing period (BG-14)
|
|
37
39
|
INVOICE_PERIOD = "cac:InvoicePeriod"
|
|
@@ -63,6 +65,7 @@ module Zugpferd
|
|
|
63
65
|
legal_registration_id: "cac:PartyLegalEntity/cbc:CompanyID",
|
|
64
66
|
legal_form: "cac:PartyLegalEntity/cbc:CompanyLegalForm",
|
|
65
67
|
vat_identifier: "cac:PartyTaxScheme[cac:TaxScheme/cbc:ID='VAT']/cbc:CompanyID",
|
|
68
|
+
tax_registration_identifier: "cac:PartyTaxScheme[cac:TaxScheme/cbc:ID!='VAT']/cbc:CompanyID",
|
|
66
69
|
electronic_address: "cbc:EndpointID",
|
|
67
70
|
}.freeze
|
|
68
71
|
|
data/lib/zugpferd/ubl/reader.rb
CHANGED
|
@@ -42,6 +42,7 @@ module Zugpferd
|
|
|
42
42
|
issue_date: parse_date(text(root, INVOICE[:issue_date])),
|
|
43
43
|
due_date: parse_date(text(root, due_date_element)),
|
|
44
44
|
delivery_date: delivery_node ? parse_date(text(delivery_node, DELIVERY_DATE)) : nil,
|
|
45
|
+
deliver_to_address: build_deliver_to_address(delivery_node),
|
|
45
46
|
invoicing_period_start_date: period_node ? parse_date(text(period_node, INVOICE_PERIOD_FIELDS[:start_date])) : nil,
|
|
46
47
|
invoicing_period_end_date: period_node ? parse_date(text(period_node, INVOICE_PERIOD_FIELDS[:end_date])) : nil,
|
|
47
48
|
type_code: text(root, type_code_element),
|
|
@@ -51,7 +52,7 @@ module Zugpferd
|
|
|
51
52
|
customization_id: text(root, INVOICE[:customization_id]),
|
|
52
53
|
profile_id: text(root, INVOICE[:profile_id]),
|
|
53
54
|
note: text(root, INVOICE[:note]),
|
|
54
|
-
seller: build_party(root.at_xpath(SELLER, @ns)),
|
|
55
|
+
seller: build_party(root.at_xpath(SELLER, @ns), seller: true),
|
|
55
56
|
buyer: build_party(root.at_xpath(BUYER, @ns)),
|
|
56
57
|
line_items: root.xpath(line_element, @ns).map { |n| build_line_item(n) },
|
|
57
58
|
allowance_charges: root.xpath(ALLOWANCE_CHARGE, @ns).map { |n| build_allowance_charge(n) },
|
|
@@ -62,7 +63,8 @@ module Zugpferd
|
|
|
62
63
|
)
|
|
63
64
|
end
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
# Seller-only terms are read only for the seller
|
|
67
|
+
def build_party(node, seller: false)
|
|
66
68
|
return nil unless node
|
|
67
69
|
|
|
68
70
|
party = Model::TradeParty.new(
|
|
@@ -70,8 +72,9 @@ module Zugpferd
|
|
|
70
72
|
trading_name: text(node, PARTY[:trading_name]),
|
|
71
73
|
identifier: text(node, PARTY[:identifier]),
|
|
72
74
|
legal_registration_id: text(node, PARTY[:legal_registration_id]),
|
|
73
|
-
legal_form: text(node, PARTY[:legal_form]),
|
|
75
|
+
legal_form: (text(node, PARTY[:legal_form]) if seller),
|
|
74
76
|
vat_identifier: text(node, PARTY[:vat_identifier]),
|
|
77
|
+
tax_registration_identifier: (text(node, PARTY[:tax_registration_identifier]) if seller),
|
|
75
78
|
electronic_address: text(node, PARTY[:electronic_address]),
|
|
76
79
|
)
|
|
77
80
|
|
|
@@ -96,6 +99,11 @@ module Zugpferd
|
|
|
96
99
|
)
|
|
97
100
|
end
|
|
98
101
|
|
|
102
|
+
def build_deliver_to_address(delivery_node)
|
|
103
|
+
addr_node = delivery_node&.at_xpath(DELIVER_TO_ADDRESS, @ns)
|
|
104
|
+
build_postal_address(addr_node) if addr_node
|
|
105
|
+
end
|
|
106
|
+
|
|
99
107
|
def build_contact(node)
|
|
100
108
|
Model::Contact.new(
|
|
101
109
|
name: text(node, CONTACT_FIELDS[:name]),
|
data/lib/zugpferd/ubl/writer.rb
CHANGED
|
@@ -56,7 +56,7 @@ module Zugpferd
|
|
|
56
56
|
|
|
57
57
|
build_supplier(xml, doc.seller, doc.payment_instructions) if doc.seller
|
|
58
58
|
build_customer(xml, doc.buyer) if doc.buyer
|
|
59
|
-
build_delivery(xml, doc) if doc.delivery_date
|
|
59
|
+
build_delivery(xml, doc) if doc.delivery_date || doc.deliver_to_address
|
|
60
60
|
build_payment_means(xml, doc.payment_instructions, doc.due_date) if doc.payment_instructions
|
|
61
61
|
build_payment_terms(xml, doc.payment_instructions) if doc.payment_instructions&.note
|
|
62
62
|
doc.allowance_charges.each { |ac| build_allowance_charge(xml, ac, doc.currency_code) }
|
|
@@ -68,7 +68,7 @@ module Zugpferd
|
|
|
68
68
|
def build_supplier(xml, party, payment_instructions = nil)
|
|
69
69
|
xml["cac"].AccountingSupplierParty do
|
|
70
70
|
build_party(xml, party,
|
|
71
|
-
creditor_reference_id: payment_instructions&.creditor_reference_id)
|
|
71
|
+
creditor_reference_id: payment_instructions&.creditor_reference_id, seller: true)
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
|
|
@@ -78,7 +78,8 @@ module Zugpferd
|
|
|
78
78
|
end
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
# Seller-only terms are written only for the seller
|
|
82
|
+
def build_party(xml, party, creditor_reference_id: nil, seller: false)
|
|
82
83
|
xml["cac"].Party do
|
|
83
84
|
if party.electronic_address
|
|
84
85
|
attrs = {}
|
|
@@ -115,10 +116,19 @@ module Zugpferd
|
|
|
115
116
|
end
|
|
116
117
|
end
|
|
117
118
|
|
|
119
|
+
if seller && party.tax_registration_identifier
|
|
120
|
+
xml["cac"].PartyTaxScheme do
|
|
121
|
+
xml["cbc"].CompanyID party.tax_registration_identifier
|
|
122
|
+
xml["cac"].TaxScheme do
|
|
123
|
+
xml["cbc"].ID "FC"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
118
128
|
xml["cac"].PartyLegalEntity do
|
|
119
129
|
xml["cbc"].RegistrationName party.name
|
|
120
130
|
xml["cbc"].CompanyID party.legal_registration_id if party.legal_registration_id
|
|
121
|
-
xml["cbc"].CompanyLegalForm party.legal_form if party.legal_form
|
|
131
|
+
xml["cbc"].CompanyLegalForm party.legal_form if seller && party.legal_form
|
|
122
132
|
end
|
|
123
133
|
|
|
124
134
|
build_contact(xml, party.contact) if party.contact
|
|
@@ -127,12 +137,16 @@ module Zugpferd
|
|
|
127
137
|
|
|
128
138
|
def build_postal_address(xml, addr)
|
|
129
139
|
xml["cac"].PostalAddress do
|
|
130
|
-
xml
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
140
|
+
build_address_fields(xml, addr)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def build_address_fields(xml, addr)
|
|
145
|
+
xml["cbc"].StreetName addr.street_name if addr.street_name
|
|
146
|
+
xml["cbc"].CityName addr.city_name if addr.city_name
|
|
147
|
+
xml["cbc"].PostalZone addr.postal_zone if addr.postal_zone
|
|
148
|
+
xml["cac"].Country do
|
|
149
|
+
xml["cbc"].IdentificationCode addr.country_code
|
|
136
150
|
end
|
|
137
151
|
end
|
|
138
152
|
|
|
@@ -168,7 +182,14 @@ module Zugpferd
|
|
|
168
182
|
|
|
169
183
|
def build_delivery(xml, doc)
|
|
170
184
|
xml["cac"].Delivery do
|
|
171
|
-
xml["cbc"].ActualDeliveryDate doc.delivery_date.to_s
|
|
185
|
+
xml["cbc"].ActualDeliveryDate doc.delivery_date.to_s if doc.delivery_date
|
|
186
|
+
if doc.deliver_to_address
|
|
187
|
+
xml["cac"].DeliveryLocation do
|
|
188
|
+
xml["cac"].Address do
|
|
189
|
+
build_address_fields(xml, doc.deliver_to_address)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
172
193
|
end
|
|
173
194
|
end
|
|
174
195
|
|