secretariat 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|