secretariat 1.0.0 → 2.0.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/secretariat.rb +2 -0
- data/lib/secretariat/constants.rb +26 -2
- data/lib/secretariat/helpers.rb +19 -0
- data/lib/secretariat/invoice.rb +103 -41
- data/lib/secretariat/line_item.rb +86 -26
- data/lib/secretariat/trade_party.rb +1 -1
- data/lib/secretariat/validator.rb +20 -5
- data/lib/secretariat/version.rb +1 -1
- data/lib/secretariat/versioner.rb +13 -0
- metadata +4 -8
- data/schemas/zf_en16931.sch +0 -9581
- data/schemas/zf_en16931.xsd +0 -20
- data/schemas/zf_en16931_codedb.xml +0 -4971
- data/schemas/zf_en16931_urn_un_unece_uncefact_data_standard_QualifiedDataType_100.xsd +0 -1649
- data/schemas/zf_en16931_urn_un_unece_uncefact_data_standard_ReusableAggregateBusinessInformationEntity_100.xsd +0 -318
- data/schemas/zf_en16931_urn_un_unece_uncefact_data_standard_UnqualifiedDataType_100.xsd +0 -85
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3574ab368be0c92f96a25ad98e00f9c17a96da895d1ce3046a1c387eecf43d75
|
4
|
+
data.tar.gz: 90630718af00d0a76af1d75173d58f6c94f7eaf2485dafd9a75a773c2e2f7a97
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3d9e62d62321d142b502e32b01198256cb22e65b4f0502c071a525a96ae4dff5200d54ca2313a985bad0571c923ebb8c044f5b12b4fd3b1260a4799d2a743cc
|
7
|
+
data.tar.gz: 39ea3264258a3e058b24276caf8232d53db7516b1d10aa2cee66807ee25d601bb68413d61f18125021fcd0bad6bbced1aad14f4b7126392991984f5b8f6dc5db
|
data/lib/secretariat.rb
CHANGED
@@ -16,6 +16,8 @@ limitations under the License.
|
|
16
16
|
|
17
17
|
require_relative 'secretariat/version'
|
18
18
|
require_relative 'secretariat/constants'
|
19
|
+
require_relative 'secretariat/helpers'
|
20
|
+
require_relative 'secretariat/versioner'
|
19
21
|
require_relative 'secretariat/validation_error'
|
20
22
|
require_relative 'secretariat/invoice'
|
21
23
|
require_relative 'secretariat/trade_party'
|
@@ -22,12 +22,36 @@ module Secretariat
|
|
22
22
|
:TAXEXEMPT => "E",
|
23
23
|
:ZEROTAXPRODUCTS => "Z",
|
24
24
|
:UNTAXEDSERVICE => "O",
|
25
|
-
:INTRACOMMUNITY => "K"
|
25
|
+
:INTRACOMMUNITY => "K",
|
26
|
+
:EXPORT => 'G'
|
27
|
+
}
|
28
|
+
|
29
|
+
TAX_CATEGORY_CODES_1 = {
|
30
|
+
:STANDARDRATE => "S",
|
31
|
+
:REVERSECHARGE => "AE",
|
32
|
+
:TAXEXEMPT => "E",
|
33
|
+
:ZEROTAXPRODUCTS => "Z",
|
34
|
+
:UNTAXEDSERVICE => "O",
|
35
|
+
:INTRACOMMUNITY => "IC",
|
36
|
+
:EXPORT => 'E'
|
37
|
+
}
|
38
|
+
|
39
|
+
PAYMENT_CODES = {
|
40
|
+
:BANKACCOUNT => "42",
|
41
|
+
:NOTSPECIFIED => "1",
|
42
|
+
:AUTOMATICCLEARING => "3",
|
43
|
+
:CASH => "10",
|
44
|
+
:CHECK => "20",
|
45
|
+
:DEBITADVICE => "31",
|
46
|
+
:CREDITCARD => "48",
|
47
|
+
:DEBIT => "49",
|
48
|
+
:COMPENSATION => "97",
|
26
49
|
}
|
27
50
|
|
28
51
|
TAX_EXEMPTION_REASONS = {
|
29
52
|
:REVERSECHARGE => 'Reverse Charge',
|
30
|
-
:INTRACOMMUNITY => ''
|
53
|
+
:INTRACOMMUNITY => 'Intra-community transaction',
|
54
|
+
:EXPORT => 'Export outside the EU'
|
31
55
|
}
|
32
56
|
|
33
57
|
UNIT_CODES = {
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Secretariat
|
2
|
+
module Helpers
|
3
|
+
def self.format(something, round: nil, digits:2)
|
4
|
+
dec = BigDecimal(something, 10)
|
5
|
+
dec = dec.round(round, :down) if round
|
6
|
+
"%0.#{digits}f" % dec
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.currency_element(xml, ns, name, amount, currency, add_currency: true, digits: 2)
|
10
|
+
attrs = {}
|
11
|
+
if add_currency
|
12
|
+
attrs[:currencyID] = currency
|
13
|
+
end
|
14
|
+
xml[ns].send(name, attrs) do
|
15
|
+
xml.text(format(amount, round: 4, digits: digits))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/secretariat/invoice.rb
CHANGED
@@ -24,7 +24,7 @@ module Secretariat
|
|
24
24
|
:buyer,
|
25
25
|
:line_items,
|
26
26
|
:currency_code,
|
27
|
-
:
|
27
|
+
:payment_type,
|
28
28
|
:payment_text,
|
29
29
|
:tax_category,
|
30
30
|
:tax_percent,
|
@@ -38,6 +38,8 @@ module Secretariat
|
|
38
38
|
keyword_init: true
|
39
39
|
) do
|
40
40
|
|
41
|
+
include Versioner
|
42
|
+
|
41
43
|
def errors
|
42
44
|
@errors
|
43
45
|
end
|
@@ -46,57 +48,93 @@ module Secretariat
|
|
46
48
|
tax_reason || TAX_EXEMPTION_REASONS[tax_category]
|
47
49
|
end
|
48
50
|
|
49
|
-
def tax_category_code
|
51
|
+
def tax_category_code(version: 2)
|
52
|
+
if version == 1
|
53
|
+
return TAX_CATEGORY_CODES_1[tax_category] || 'S'
|
54
|
+
end
|
50
55
|
TAX_CATEGORY_CODES[tax_category] || 'S'
|
51
56
|
end
|
52
57
|
|
58
|
+
def payment_code
|
59
|
+
PAYMENT_CODES[payment_type] || '1'
|
60
|
+
end
|
61
|
+
|
53
62
|
def valid?
|
63
|
+
@errors = []
|
54
64
|
tax = BigDecimal(tax_amount)
|
55
65
|
basis = BigDecimal(basis_amount)
|
56
66
|
calc_tax = basis * BigDecimal(tax_percent) / BigDecimal(100)
|
67
|
+
calc_tax = calc_tax.round(2, :down)
|
57
68
|
if tax != calc_tax
|
58
|
-
@errors << "Tax amount and calculated tax amount deviate"
|
69
|
+
@errors << "Tax amount and calculated tax amount deviate: #{tax} / #{calc_tax}"
|
59
70
|
return false
|
60
71
|
end
|
61
72
|
grand_total = BigDecimal(grand_total_amount)
|
62
73
|
calc_grand_total = basis + tax
|
63
74
|
if grand_total != calc_grand_total
|
64
|
-
@errors << "Grand total amount and calculated grand total amount deviate"
|
75
|
+
@errors << "Grand total amount and calculated grand total amount deviate: #{grand_total} / #{calc_grand_total}"
|
65
76
|
return false
|
66
77
|
end
|
67
78
|
line_item_sum = line_items.inject(BigDecimal(0)) do |m, item|
|
68
79
|
m + BigDecimal(item.charge_amount)
|
69
80
|
end
|
70
81
|
if line_item_sum != basis
|
71
|
-
@errors << "Line items do not add up to basis amount"
|
82
|
+
@errors << "Line items do not add up to basis amount #{line_item_sum} / #{basis}"
|
72
83
|
return false
|
73
84
|
end
|
74
85
|
return true
|
75
86
|
end
|
76
87
|
|
77
88
|
|
78
|
-
def
|
89
|
+
def namespaces(version: 1)
|
90
|
+
by_version(version,
|
91
|
+
{
|
92
|
+
'xmlns:ram' => 'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12',
|
93
|
+
'xmlns:udt' => 'urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15',
|
94
|
+
'xmlns:rsm' => 'urn:ferd:CrossIndustryDocument:invoice:1p0',
|
95
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
|
96
|
+
},
|
97
|
+
{
|
98
|
+
'xmlns:qdt' => 'urn:un:unece:uncefact:data:standard:QualifiedDataType:100',
|
99
|
+
'xmlns:ram' => 'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100',
|
100
|
+
'xmlns:udt' => 'urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100',
|
101
|
+
'xmlns:rsm' => 'urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100',
|
102
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
|
103
|
+
}
|
104
|
+
)
|
105
|
+
end
|
106
|
+
|
107
|
+
def to_xml(version: 1)
|
108
|
+
if version < 1 || version > 2
|
109
|
+
raise 'Unsupported Document Version'
|
110
|
+
end
|
79
111
|
|
80
112
|
unless valid?
|
81
113
|
raise ValidationError.new("Invoice is invalid", errors)
|
82
114
|
end
|
83
115
|
|
84
116
|
builder = Nokogiri::XML::Builder.new do |xml|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
'
|
91
|
-
|
92
|
-
xml.
|
117
|
+
|
118
|
+
root = by_version(version, 'CrossIndustryDocument', 'CrossIndustryInvoice')
|
119
|
+
|
120
|
+
xml['rsm'].send(root, namespaces(version: version)) do
|
121
|
+
|
122
|
+
context = by_version(version, 'SpecifiedExchangedDocumentContext', 'ExchangedDocumentContext')
|
123
|
+
|
124
|
+
xml['rsm'].send(context) do
|
93
125
|
xml['ram'].GuidelineSpecifiedDocumentContextParameter do
|
94
|
-
|
126
|
+
version_id = by_version(version, 'urn:ferd:CrossIndustryDocument:invoice:1p0:comfort', 'urn:cen.eu:en16931:2017')
|
127
|
+
xml['ram'].ID version_id
|
95
128
|
end
|
96
129
|
end
|
97
130
|
|
98
|
-
|
131
|
+
header = by_version(version, 'HeaderExchangedDocument', 'ExchangedDocument')
|
132
|
+
|
133
|
+
xml['rsm'].send(header) do
|
99
134
|
xml['ram'].ID id
|
135
|
+
if version == 1
|
136
|
+
xml['ram'].Name "RECHNUNG"
|
137
|
+
end
|
100
138
|
xml['ram'].TypeCode '380' # TODO: make configurable
|
101
139
|
xml['ram'].IssueDateTime do
|
102
140
|
xml['udt'].DateTimeString(format: '102') do
|
@@ -104,21 +142,33 @@ module Secretariat
|
|
104
142
|
end
|
105
143
|
end
|
106
144
|
end
|
107
|
-
|
108
|
-
|
109
|
-
|
145
|
+
transaction = by_version(version, 'SpecifiedSupplyChainTradeTransaction', 'SupplyChainTradeTransaction')
|
146
|
+
xml['rsm'].send(transaction) do
|
147
|
+
|
148
|
+
if version == 2
|
149
|
+
line_items.each_with_index do |item, i|
|
150
|
+
item.to_xml(xml, i + 1, version: version) # one indexed
|
151
|
+
end
|
110
152
|
end
|
111
|
-
|
153
|
+
|
154
|
+
trade_agreement = by_version(version, 'ApplicableSupplyChainTradeAgreement', 'ApplicableHeaderTradeAgreement')
|
155
|
+
|
156
|
+
xml['ram'].send(trade_agreement) do
|
112
157
|
xml['ram'].SellerTradeParty do
|
113
|
-
seller.to_xml(xml)
|
158
|
+
seller.to_xml(xml, version: version)
|
114
159
|
end
|
115
160
|
xml['ram'].BuyerTradeParty do
|
116
|
-
buyer.to_xml(xml)
|
161
|
+
buyer.to_xml(xml, version: version)
|
117
162
|
end
|
118
163
|
end
|
119
|
-
|
120
|
-
|
121
|
-
|
164
|
+
|
165
|
+
delivery = by_version(version, 'ApplicableSupplyChainTradeDelivery', 'ApplicableHeaderTradeDelivery')
|
166
|
+
|
167
|
+
xml['ram'].send(delivery) do
|
168
|
+
if version == 2
|
169
|
+
xml['ram'].ShipToTradeParty do
|
170
|
+
buyer.to_xml(xml, exclude_tax: true, version: version)
|
171
|
+
end
|
122
172
|
end
|
123
173
|
xml['ram'].ActualDeliverySupplyChainEvent do
|
124
174
|
xml['ram'].OccurrenceDateTime do
|
@@ -128,34 +178,47 @@ module Secretariat
|
|
128
178
|
end
|
129
179
|
end
|
130
180
|
end
|
131
|
-
|
181
|
+
trade_settlement = by_version(version, 'ApplicableSupplyChainTradeSettlement', 'ApplicableHeaderTradeSettlement')
|
182
|
+
xml['ram'].send(trade_settlement) do
|
132
183
|
xml['ram'].InvoiceCurrencyCode currency_code
|
133
184
|
xml['ram'].SpecifiedTradeSettlementPaymentMeans do
|
134
185
|
xml['ram'].TypeCode payment_code
|
135
186
|
xml['ram'].Information payment_text
|
136
187
|
end
|
137
188
|
xml['ram'].ApplicableTradeTax do
|
138
|
-
|
189
|
+
|
190
|
+
Helpers.currency_element(xml, 'ram', 'CalculatedAmount', tax_amount, currency_code, add_currency: version == 1)
|
139
191
|
xml['ram'].TypeCode 'VAT'
|
140
192
|
if tax_reason_text && tax_reason_text != ''
|
141
|
-
xml['ram'].ExemptionReason
|
193
|
+
xml['ram'].ExemptionReason tax_reason_text
|
142
194
|
end
|
143
|
-
xml
|
144
|
-
xml['ram'].CategoryCode tax_category_code
|
145
|
-
|
195
|
+
Helpers.currency_element(xml, 'ram', 'BasisAmount', basis_amount, currency_code, add_currency: version == 1)
|
196
|
+
xml['ram'].CategoryCode tax_category_code(version: version)
|
197
|
+
|
198
|
+
percent = by_version(version, 'ApplicablePercent', 'RateApplicablePercent')
|
199
|
+
xml['ram'].send(percent, Helpers.format(tax_percent))
|
146
200
|
end
|
147
201
|
xml['ram'].SpecifiedTradePaymentTerms do
|
148
202
|
xml['ram'].Description "Paid"
|
149
203
|
end
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
xml
|
157
|
-
xml
|
158
|
-
xml
|
204
|
+
|
205
|
+
monetary_summation = by_version(version, 'SpecifiedTradeSettlementMonetarySummation', 'SpecifiedTradeSettlementHeaderMonetarySummation')
|
206
|
+
|
207
|
+
xml['ram'].send(monetary_summation) do
|
208
|
+
Helpers.currency_element(xml, 'ram', 'LineTotalAmount', basis_amount, currency_code, add_currency: version == 1)
|
209
|
+
# TODO: Fix this!
|
210
|
+
Helpers.currency_element(xml, 'ram', 'ChargeTotalAmount', BigDecimal(0), currency_code, add_currency: version == 1)
|
211
|
+
Helpers.currency_element(xml, 'ram', 'AllowanceTotalAmount', BigDecimal(0), currency_code, add_currency: version == 1)
|
212
|
+
Helpers.currency_element(xml, 'ram', 'TaxBasisTotalAmount', basis_amount, currency_code, add_currency: version == 1)
|
213
|
+
Helpers.currency_element(xml, 'ram', 'TaxTotalAmount', tax_amount, currency_code, add_currency: true)
|
214
|
+
Helpers.currency_element(xml, 'ram', 'GrandTotalAmount', grand_total_amount, currency_code, add_currency: version == 1)
|
215
|
+
Helpers.currency_element(xml, 'ram', 'TotalPrepaidAmount', paid_amount, currency_code, add_currency: version == 1)
|
216
|
+
Helpers.currency_element(xml, 'ram', 'DuePayableAmount', due_amount, currency_code, add_currency: version == 1)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
if version == 1
|
220
|
+
line_items.each_with_index do |item, i|
|
221
|
+
item.to_xml(xml, i + 1, version: version) # one indexed
|
159
222
|
end
|
160
223
|
end
|
161
224
|
end
|
@@ -164,5 +227,4 @@ module Secretariat
|
|
164
227
|
builder.to_xml
|
165
228
|
end
|
166
229
|
end
|
167
|
-
|
168
230
|
end
|
@@ -25,32 +25,49 @@ module Secretariat
|
|
25
25
|
:name,
|
26
26
|
:quantity,
|
27
27
|
:unit,
|
28
|
-
:
|
29
|
-
:
|
28
|
+
:gross_amount,
|
29
|
+
:net_amount,
|
30
30
|
:tax_category,
|
31
31
|
:tax_percent,
|
32
32
|
:tax_amount,
|
33
|
+
:discount_amount,
|
34
|
+
:discount_reason,
|
35
|
+
:charge_amount,
|
33
36
|
:origin_country_code,
|
37
|
+
:currency_code,
|
34
38
|
keyword_init: true
|
35
39
|
) do
|
36
40
|
|
41
|
+
include Versioner
|
42
|
+
|
37
43
|
def errors
|
38
44
|
@errors
|
39
45
|
end
|
40
46
|
|
41
47
|
def valid?
|
42
|
-
|
48
|
+
@errors = []
|
49
|
+
net_price = BigDecimal(net_amount)
|
50
|
+
gross_price = BigDecimal(gross_amount)
|
43
51
|
charge_price = BigDecimal(charge_amount)
|
44
52
|
tax = BigDecimal(tax_amount)
|
53
|
+
unit_price = net_price * BigDecimal(quantity)
|
45
54
|
|
46
|
-
if charge_price != unit_price
|
47
|
-
@errors << "charge price and
|
55
|
+
if charge_price != unit_price
|
56
|
+
@errors << "charge price and gross price times quantity deviate: #{charge_price} / #{unit_price}"
|
48
57
|
return false
|
49
58
|
end
|
59
|
+
if discount_amount
|
60
|
+
discount = BigDecimal(discount_amount)
|
61
|
+
calculated_net_price = (gross_price - discount).round(2, :down)
|
62
|
+
if calculated_net_price != net_price
|
63
|
+
@errors = "Calculated net price and net price deviate: #{calculated_net_price} / #{net_price}"
|
64
|
+
return false
|
65
|
+
end
|
66
|
+
end
|
50
67
|
|
51
68
|
calculated_tax = charge_price * BigDecimal(tax_percent) / BigDecimal(100)
|
52
69
|
if calculated_tax != tax
|
53
|
-
@errors << "Tax and calculated tax deviate"
|
70
|
+
@errors << "Tax and calculated tax deviate: #{tax} / #{calculated_tax}"
|
54
71
|
return false
|
55
72
|
end
|
56
73
|
return true
|
@@ -60,12 +77,16 @@ module Secretariat
|
|
60
77
|
UNIT_CODES[unit] || 'C62'
|
61
78
|
end
|
62
79
|
|
63
|
-
def tax_category_code
|
80
|
+
def tax_category_code(version: 2)
|
81
|
+
if version == 1
|
82
|
+
return TAX_CATEGORY_CODES_1[tax_category] || 'S'
|
83
|
+
end
|
64
84
|
TAX_CATEGORY_CODES[tax_category] || 'S'
|
65
85
|
end
|
66
86
|
|
67
|
-
def to_xml(xml, line_item_index)
|
87
|
+
def to_xml(xml, line_item_index, version: 2)
|
68
88
|
if !valid?
|
89
|
+
pp errors
|
69
90
|
raise ValidationError.new("LineItem #{line_item_index} is invalid", errors)
|
70
91
|
end
|
71
92
|
|
@@ -73,40 +94,79 @@ module Secretariat
|
|
73
94
|
xml['ram'].AssociatedDocumentLineDocument do
|
74
95
|
xml['ram'].LineID line_item_index
|
75
96
|
end
|
76
|
-
|
77
|
-
xml['ram'].
|
78
|
-
|
79
|
-
xml['ram'].
|
97
|
+
if (version == 2)
|
98
|
+
xml['ram'].SpecifiedTradeProduct do
|
99
|
+
xml['ram'].Name name
|
100
|
+
xml['ram'].OriginTradeCountry do
|
101
|
+
xml['ram'].ID origin_country_code
|
102
|
+
end
|
80
103
|
end
|
81
104
|
end
|
82
|
-
|
105
|
+
agreement = by_version(version, 'SpecifiedSupplyChainTradeAgreement', 'SpecifiedLineTradeAgreement')
|
106
|
+
|
107
|
+
xml['ram'].send(agreement) do
|
83
108
|
xml['ram'].GrossPriceProductTradePrice do
|
84
|
-
xml
|
85
|
-
|
86
|
-
xml.
|
109
|
+
Helpers.currency_element(xml, 'ram', 'ChargeAmount', gross_amount, currency_code, add_currency: version == 1, digits: 4)
|
110
|
+
if version == 2 && discount_amount
|
111
|
+
xml['ram'].BasisQuantity(unitCode: unit_code) do
|
112
|
+
xml.text(Helpers.format(quantity, digits: 4))
|
113
|
+
end
|
114
|
+
xml['ram'].AppliedTradeAllowanceCharge do
|
115
|
+
xml['ram'].ChargeIndicator do
|
116
|
+
xml['udt'].Indicator 'false'
|
117
|
+
end
|
118
|
+
Helpers.currency_element(xml, 'ram', 'ActualAmount', discount_amount, currency_code, add_currency: version == 1)
|
119
|
+
xml['ram'].Reason discount_reason
|
120
|
+
end
|
121
|
+
end
|
122
|
+
if version == 1 && discount_amount
|
123
|
+
xml['ram'].AppliedTradeAllowanceCharge do
|
124
|
+
xml['ram'].ChargeIndicator do
|
125
|
+
xml['udt'].Indicator 'false'
|
126
|
+
end
|
127
|
+
Helpers.currency_element(xml, 'ram', 'ActualAmount', discount_amount, currency_code, add_currency: version == 1)
|
128
|
+
xml['ram'].Reason discount_reason
|
129
|
+
end
|
87
130
|
end
|
88
131
|
end
|
89
132
|
xml['ram'].NetPriceProductTradePrice do
|
90
|
-
xml
|
91
|
-
|
92
|
-
xml.
|
133
|
+
Helpers.currency_element(xml, 'ram', 'ChargeAmount', net_amount, currency_code, add_currency: version == 1, digits: 4)
|
134
|
+
if version == 2
|
135
|
+
xml['ram'].BasisQuantity(unitCode: unit_code) do
|
136
|
+
xml.text(Helpers.format(quantity, digits: 4))
|
137
|
+
end
|
93
138
|
end
|
94
139
|
end
|
95
140
|
end
|
96
|
-
|
141
|
+
|
142
|
+
delivery = by_version(version, 'SpecifiedSupplyChainTradeDelivery', 'SpecifiedLineTradeDelivery')
|
143
|
+
|
144
|
+
xml['ram'].send(delivery) do
|
97
145
|
xml['ram'].BilledQuantity(unitCode: unit_code) do
|
98
|
-
xml.text(quantity)
|
146
|
+
xml.text(Helpers.format(quantity, digits: 4))
|
99
147
|
end
|
100
148
|
end
|
101
|
-
|
149
|
+
|
150
|
+
settlement = by_version(version, 'SpecifiedSupplyChainTradeSettlement', 'SpecifiedLineTradeSettlement')
|
151
|
+
|
152
|
+
xml['ram'].send(settlement) do
|
102
153
|
xml['ram'].ApplicableTradeTax do
|
103
154
|
xml['ram'].TypeCode 'VAT'
|
104
|
-
xml['ram'].CategoryCode tax_category_code
|
105
|
-
xml['ram'].RateApplicablePercent tax_percent
|
155
|
+
xml['ram'].CategoryCode tax_category_code(version: version)
|
106
156
|
|
157
|
+
percent = by_version(version, 'ApplicablePercent', 'RateApplicablePercent')
|
158
|
+
xml['ram'].send(percent,Helpers.format(tax_percent))
|
159
|
+
|
160
|
+
end
|
161
|
+
monetary_summation = by_version(version, 'SpecifiedTradeSettlementMonetarySummation', 'SpecifiedTradeSettlementLineMonetarySummation')
|
162
|
+
xml['ram'].send(monetary_summation) do
|
163
|
+
Helpers.currency_element(xml, 'ram', 'LineTotalAmount', charge_amount, currency_code, add_currency: version == 1)
|
107
164
|
end
|
108
|
-
|
109
|
-
|
165
|
+
end
|
166
|
+
|
167
|
+
if version == 1
|
168
|
+
xml['ram'].SpecifiedTradeProduct do
|
169
|
+
xml['ram'].Name name
|
110
170
|
end
|
111
171
|
end
|
112
172
|
end
|