saft 0.1.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.
@@ -0,0 +1,364 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SAFT::V2
4
+ class Scribe
5
+ def self.write_xml(audit_file)
6
+ new.write_xml(audit_file)
7
+ end
8
+
9
+ def write_xml(audit_file)
10
+ builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
11
+ build_the_xml(xml, audit_file)
12
+ end
13
+
14
+ builder.to_xml(save_with: SAFT.nokogiri_save_setting)
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader(:xml)
20
+
21
+ def build_the_xml(xml, audit_file)
22
+ # avoid passing the xml builder instance
23
+ @xml = xml
24
+ namespaces = {"xmlns" => "urn:StandardAuditFile-Taxation-Financial:NO"}
25
+ xml.AuditFile(namespaces) do
26
+ build(audit_file)
27
+ end
28
+
29
+ @xml = nil
30
+ end
31
+
32
+ def build_company_structure(struct)
33
+ xml.RegistrationNumber(struct.registration_number) if struct.registration_number
34
+ xml.Name(struct.name) if struct.name
35
+ struct.addresses&.each { |address| xml.Address { build(address) } }
36
+ struct.contacts&.each { |contact| xml.Contact { build(contact) } }
37
+ struct.tax_registrations&.each { |tax_registration| xml.TaxRegistration { build(tax_registration) } }
38
+ struct.bank_accounts&.each { |bank_account| xml.BankAccount { build(bank_account) } }
39
+ end
40
+
41
+ def build(struct)
42
+ return unless struct
43
+
44
+ klass = struct.class.ancestors.detect { _1.name&.start_with?("SAFT::V2") }
45
+ # We do .name.split("::").last because this has to support all three types
46
+ case klass.name.split("::").last
47
+ when Types::AuditFile.name.split("::").last
48
+ xml.Header { build(struct.header) }
49
+ if struct.master_files
50
+ xml.MasterFiles { build(struct.master_files) }
51
+ end
52
+ if struct.general_ledger_entries
53
+ xml.GeneralLedgerEntries { build(struct.general_ledger_entries) }
54
+ end
55
+
56
+ when Types::Header.name.split("::").last
57
+ xml.AuditFileVersion(struct.audit_file_version)
58
+ xml.AuditFileCountry(struct.audit_file_country)
59
+ xml.AuditFileDateCreated(struct.audit_file_date_created)
60
+ xml.SoftwareCompanyName(struct.software_company_name)
61
+ xml.SoftwareID(struct.software_id)
62
+ xml.SoftwareVersion(struct.software_version)
63
+ xml.Company { build(struct.company) }
64
+ xml.DefaultCurrencyCode(struct.default_currency_code)
65
+ xml.SelectionCriteria { build(struct.selection_criteria) } if struct.selection_criteria
66
+ xml.HeaderComment(struct.header_comment) if struct.header_comment
67
+ xml.TaxAccountingBasis(struct.tax_accounting_basis)
68
+ xml.TaxEntity(struct.tax_entity) if struct.tax_entity
69
+ xml.UserID(struct.user_id) if struct.user_id
70
+ xml.AuditFileSender { build(struct.audit_file_sender) } if struct.audit_file_sender
71
+
72
+ when Types::Customer.name.split("::").last
73
+ build_company_structure(struct)
74
+ xml.CustomerID(struct.customer_id)
75
+ xml.SelfBillingIndicator(struct.self_billing_indicator) if struct.self_billing_indicator
76
+ xml.AccountID(struct.account_id) if struct.account_id
77
+ xml.OpeningDebitBalance(struct.opening_debit_balance.to_s("F")) if struct.opening_debit_balance
78
+ xml.OpeningCreditBalance(struct.opening_credit_balance.to_s("F")) if struct.opening_credit_balance
79
+ xml.ClosingDebitBalance(struct.closing_debit_balance.to_s("F")) if struct.closing_debit_balance
80
+ xml.ClosingCreditBalance(struct.closing_credit_balance.to_s("F")) if struct.closing_credit_balance
81
+ xml.PartyInfo { build(struct.party_info) } if struct.party_info
82
+
83
+ when Types::Supplier.name.split("::").last
84
+ build_company_structure(struct)
85
+ xml.SupplierID(struct.supplier_id)
86
+ xml.SelfBillingIndicator(struct.self_billing_indicator) if struct.self_billing_indicator
87
+ xml.AccountID(struct.account_id) if struct.account_id
88
+ xml.OpeningDebitBalance(struct.opening_debit_balance.to_s("F")) if struct.opening_debit_balance
89
+ xml.OpeningCreditBalance(struct.opening_credit_balance.to_s("F")) if struct.opening_credit_balance
90
+ xml.ClosingDebitBalance(struct.closing_debit_balance.to_s("F")) if struct.closing_debit_balance
91
+ xml.ClosingCreditBalance(struct.closing_credit_balance.to_s("F")) if struct.closing_credit_balance
92
+ xml.PartyInfo { build(struct.party_info) } if struct.party_info
93
+
94
+ when Types::Owner.name.split("::").last
95
+ build_company_structure(struct)
96
+ xml.OwnerID(struct.owner_id) if struct.owner_id
97
+ xml.AccountID(struct.account_id) if struct.account_id
98
+
99
+ when Types::CompanyHeaderStructure.name.split("::").last
100
+ build_company_structure(struct)
101
+
102
+ when Types::CompanyStructure.name.split("::").last
103
+ build_company_structure(struct)
104
+
105
+ when Types::AddressStructure.name.split("::").last
106
+ xml.StreetName(struct.street_name) if struct.street_name
107
+ xml.Number(struct.number) if struct.number
108
+ xml.AdditionalAddressDetail(struct.additional_address_detail) if struct.additional_address_detail
109
+ xml.Building(struct.building) if struct.building
110
+ xml.City(struct.city) if struct.city
111
+ xml.PostalCode(struct.postal_code) if struct.postal_code
112
+ xml.Region(struct.region) if struct.region
113
+ xml.Country(struct.country) if struct.country
114
+ xml.AddressType(struct.address_type) if struct.address_type
115
+
116
+ when Types::ContactInformationStructure.name.split("::").last
117
+ xml.ContactPerson { build(struct.contact_person) }
118
+ xml.Telephone(struct.telephone) if struct.telephone
119
+ xml.Fax(struct.fax) if struct.fax
120
+ xml.Email(struct.email) if struct.email
121
+ xml.Website(struct.website) if struct.website
122
+ xml.MobilePhone(struct.mobile_phone) if struct.mobile_phone
123
+
124
+ when Types::TaxIDStructure.name.split("::").last
125
+ xml.TaxRegistrationNumber(struct.tax_registration_number)
126
+ xml.TaxAuthority(struct.tax_authority) if struct.tax_authority
127
+ xml.TaxVerificationDate(struct.tax_verification_date) if struct.tax_verification_date
128
+
129
+ when Types::BankAccountStructure.name.split("::").last
130
+ xml.IBANNumber(struct.iban_number) if struct.iban_number
131
+ xml.BankAccountNumber(struct.bank_account_number) if struct.bank_account_number
132
+ xml.BankAccountName(struct.bank_account_name) if struct.bank_account_name
133
+ xml.SortCode(struct.sort_code) if struct.sort_code
134
+ xml.BIC(struct.bic) if struct.bic
135
+ xml.CurrencyCode(struct.currency_code) if struct.currency_code
136
+ xml.GeneralLedgerAccountID(struct.general_ledger_account_id) if struct.general_ledger_account_id
137
+
138
+ when Types::PersonNameStructure.name.split("::").last
139
+ xml.Title(struct.title) if struct.title
140
+ xml.FirstName(struct.first_name)
141
+ xml.Initials(struct.initials) if struct.initials
142
+ xml.LastNamePrefix(struct.last_name_prefix) if struct.last_name_prefix
143
+ xml.LastName(struct.last_name)
144
+ xml.BirthName(struct.birth_name) if struct.birth_name
145
+ xml.Salutation(struct.salutation) if struct.salutation
146
+ struct.other_titles&.each { xml.OtherTitles(_1) }
147
+
148
+ when Types::SelectionCriteriaStructure.name.split("::").last
149
+ xml.TaxReportingJurisdiction(struct.tax_reporting_jurisdiction) if struct.tax_reporting_jurisdiction
150
+ xml.CompanyEntity(struct.company_entity) if struct.company_entity
151
+ xml.SelectionStartDate(struct.selection_start_date) if struct.selection_start_date
152
+ xml.SelectionEndDate(struct.selection_end_date) if struct.selection_end_date
153
+ xml.PeriodStart(struct.period_start) if struct.period_start
154
+ xml.PeriodStartYear(struct.period_start_year) if struct.period_start_year
155
+ xml.PeriodEnd(struct.period_end) if struct.period_end
156
+ xml.PeriodEndYear(struct.period_end_year) if struct.period_end_year
157
+ xml.DocumentType(struct.document_type) if struct.document_type
158
+ struct.other_criterias&.each { |criteria| xml.OtherCriteria(criteria) }
159
+
160
+ when Types::AmountStructure.name.split("::").last
161
+ xml.Amount(struct.amount.to_s("F"))
162
+ xml.CurrencyCode(struct.currency_code) if struct.currency_code
163
+ xml.CurrencyAmount(struct.currency_amount.to_s("F")) if struct.currency_amount
164
+ xml.ExchangeRate(struct.exchange_rate.to_s("F")) if struct.exchange_rate
165
+
166
+ when Types::AnalysisStructure.name.split("::").last
167
+ xml.AnalysisType(struct.analysis_type) if struct.analysis_type
168
+ xml.AnalysisID(struct.analysis_id) if struct.analysis_id
169
+ xml.AnalysisAmount { build(struct.analysis_amount) } if struct.analysis_amount
170
+
171
+ when Types::AnalysisPartyInfoStructure.name.split("::").last
172
+ xml.AnalysisType(struct.analysis_type)
173
+ xml.AnalysisID(struct.analysis_id)
174
+
175
+ when Types::TaxInformationStructure.name.split("::").last
176
+ xml.TaxType(struct.tax_type) if struct.tax_type
177
+ xml.TaxCode(struct.tax_code) if struct.tax_code
178
+ xml.TaxPercentage(struct.tax_percentage.to_s("F")) if struct.tax_percentage
179
+ xml.Country(struct.country) if struct.country
180
+ xml.TaxBase(struct.tax_base.to_s("F")) if struct.tax_base
181
+ xml.TaxBaseDescription(struct.tax_base_description) if struct.tax_base_description
182
+ xml.TaxAmount { build(struct.tax_amount) }
183
+ xml.TaxExemptionReason(struct.tax_exemption_reason) if struct.tax_exemption_reason
184
+ xml.TaxDeclarationPeriod(struct.tax_declaration_period) if struct.tax_declaration_period
185
+
186
+ when Types::PaymentTerms.name.split("::").last
187
+ xml.Days(struct.days) if struct.days
188
+ xml.Months(struct.months) if struct.months
189
+ xml.CashDiscountDays(struct.cash_discount_days) if struct.cash_discount_days
190
+ xml.CashDiscountRate(struct.cash_discount_rate.to_s("F")) if struct.cash_discount_rate
191
+ xml.FreeBillingMonth(struct.free_billing_month) if struct.free_billing_month
192
+
193
+ when Types::PartyInfoStructure.name.split("::").last
194
+ xml.PaymentTerms { build(struct.payment_terms) } if struct.payment_terms
195
+ xml.NaceCode(struct.nace_code) if struct.nace_code
196
+ xml.CurrencyCode(struct.currency_code) if struct.currency_code
197
+ xml.Type(struct.type) if struct.type
198
+ xml.Status(struct.status) if struct.status
199
+ struct.analyses&.each { |analysis| xml.Analysis { build(analysis) } }
200
+ xml.Notes(struct.notes) if struct.notes
201
+
202
+ when Types::ShippingPointStructure.name.split("::").last
203
+ xml.DeliveryID(struct.delivery_id) if struct.delivery_id
204
+ xml.DeliveryDate(struct.delivery_date) if struct.delivery_date
205
+ xml.WarehouseID(struct.warehouse_id) if struct.warehouse_id
206
+ xml.LocationID(struct.location_id) if struct.location_id
207
+ xml.UCR(struct.ucr) if struct.ucr
208
+ xml.Address(struct.address) if struct.address
209
+
210
+ when Types::HeaderStructure.name.split("::").last
211
+ xml.AuditFileVersion(struct.audit_file_version)
212
+ xml.AuditFileCountry(struct.audit_file_country)
213
+ xml.AuditFileDateCreated(struct.audit_file_date_created)
214
+ xml.SoftwareCompanyName(struct.software_company_name)
215
+ xml.SoftwareID(struct.software_id)
216
+ xml.SoftwareVersion(struct.software_version)
217
+ xml.Company { build(struct.company) }
218
+ xml.DefaultCurrencyCode(struct.default_currency_code)
219
+ xml.SelectionCriteria { build(struct.selection_criteria) } if struct.selection_criteria
220
+ xml.HeaderComment(struct.header_comment) if struct.header_comment
221
+
222
+ when Types::Account.name.split("::").last
223
+ xml.AccountID(struct.account_id)
224
+ xml.AccountDescription(struct.account_description)
225
+ xml.StandardAccountID(struct.standard_account_id) if struct.standard_account_id
226
+ xml.GroupingCategory(struct.grouping_category) if struct.grouping_category
227
+ xml.GroupingCode(struct.grouping_code) if struct.grouping_code
228
+ xml.AccountType(struct.account_type)
229
+ xml.AccountCreationDate(struct.account_creation_date) if struct.account_creation_date
230
+ xml.OpeningDebitBalance(struct.opening_debit_balance.to_s("F")) if struct.opening_debit_balance
231
+ xml.OpeningCreditBalance(struct.opening_credit_balance.to_s("F")) if struct.opening_credit_balance
232
+ xml.ClosingDebitBalance(struct.closing_debit_balance.to_s("F")) if struct.closing_debit_balance
233
+ xml.ClosingCreditBalance(struct.closing_credit_balance.to_s("F")) if struct.closing_credit_balance
234
+
235
+ when Types::TaxCodeDetails.name.split("::").last
236
+ xml.TaxCode(struct.tax_code)
237
+ xml.EffectiveDate(struct.effective_date) if struct.effective_date
238
+ xml.ExpirationDate(struct.expiration_date) if struct.expiration_date
239
+ xml.Description(struct.description) if struct.description
240
+ xml.TaxPercentage(struct.tax_percentage.to_s("F")) if struct.tax_percentage
241
+ xml.Country(struct.country)
242
+ xml.StandardTaxCode(struct.standard_tax_code)
243
+ xml.Compensation(struct.compensation) if struct.compensation
244
+ struct.base_rates&.each { xml.BaseRate(_1.to_s("F")) }
245
+
246
+ when Types::TaxTableEntry.name.split("::").last
247
+ xml.TaxType(struct.tax_type) if struct.tax_type
248
+ xml.Description(struct.description) if struct.description
249
+ struct.tax_code_details&.each { |tax_code_detail| xml.TaxCodeDetails { build(tax_code_detail) } }
250
+
251
+ when Types::AnalysisTypeTableEntry.name.split("::").last
252
+ xml.AnalysisType(struct.analysis_type)
253
+ xml.AnalysisTypeDescription(struct.analysis_type_description)
254
+ xml.AnalysisID(struct.analysis_id)
255
+ xml.AnalysisIDDescription(struct.analysis_id_description)
256
+ xml.StartDate(struct.start_date) if struct.start_date
257
+ xml.EndDate(struct.end_date) if struct.end_date
258
+ xml.Status(struct.status) if struct.status
259
+ struct.analyses&.each { |analysis| xml.Analysis { build(analysis) } }
260
+
261
+ when Types::MasterFiles.name.split("::").last
262
+ if struct.general_ledger_accounts
263
+ xml.GeneralLedgerAccounts {
264
+ struct.general_ledger_accounts.each do |account|
265
+ xml.Account { build(account) }
266
+ end
267
+ }
268
+ end
269
+
270
+ if struct.customers
271
+ xml.Customers {
272
+ struct.customers.each do |customer|
273
+ xml.Customer { build(customer) }
274
+ end
275
+ }
276
+ end
277
+
278
+ if struct.suppliers
279
+ xml.Suppliers {
280
+ struct.suppliers.each do |supplier|
281
+ xml.Supplier { build(supplier) }
282
+ end
283
+ }
284
+ end
285
+
286
+ if struct.tax_table
287
+ xml.TaxTable {
288
+ struct.tax_table.each do |tax_table_entry|
289
+ xml.TaxTableEntry { build(tax_table_entry) }
290
+ end
291
+ }
292
+ end
293
+
294
+ if struct.analysis_type_table
295
+ xml.AnalysisTypeTable {
296
+ struct.analysis_type_table.each do |analysis_type_table_entry|
297
+ xml.AnalysisTypeTableEntry { build(analysis_type_table_entry) }
298
+ end
299
+ }
300
+ end
301
+
302
+ if struct.owners
303
+ xml.Owners {
304
+ struct.owners.each do |owner|
305
+ xml.Owner { build(owner) }
306
+ end
307
+ }
308
+ end
309
+
310
+ when Types::Line.name.split("::").last
311
+ xml.RecordID(struct.record_id)
312
+ xml.AccountID(struct.account_id)
313
+ struct.analyses&.each { |analysis| xml.Analysis { build(analysis) } }
314
+ xml.ValueDate(struct.value_date) if struct.value_date
315
+ xml.SourceDocumentID(struct.source_document_id) if struct.source_document_id
316
+ xml.CustomerID(struct.customer_id) if struct.customer_id
317
+ xml.SupplierID(struct.supplier_id) if struct.supplier_id
318
+ xml.Description(struct.description)
319
+ xml.DebitAmount { build(struct.debit_amount) } if struct.debit_amount
320
+ xml.CreditAmount { build(struct.credit_amount) } if struct.credit_amount
321
+ struct.tax_information&.each { |tax_information| xml.TaxInformation { build(tax_information) } }
322
+ xml.ReferenceNumber(struct.reference_number) if struct.reference_number
323
+ xml.CID(struct.cid) if struct.cid
324
+ xml.DueDate(struct.due_date) if struct.due_date
325
+ xml.Quantity(struct.quantity.to_s("F")) if struct.quantity
326
+ xml.CrossReference(struct.cross_reference) if struct.cross_reference
327
+ xml.SystemEntryTime(struct.system_entry_time.strftime("%FT%T")) if struct.system_entry_time
328
+ xml.OwnerID(struct.owner_id) if struct.owner_id
329
+
330
+ when Types::Transaction.name.split("::").last
331
+ xml.TransactionID(struct.transaction_id) if struct.transaction_id
332
+ xml.Period(struct.period) if struct.period
333
+ xml.PeriodYear(struct.period_year) if struct.period_year
334
+ xml.TransactionDate(struct.transaction_date) if struct.transaction_date
335
+ xml.SourceID(struct.source_id) if struct.source_id
336
+ xml.TransactionType(struct.transaction_type) if struct.transaction_type
337
+ xml.Description(struct.description) if struct.description
338
+ xml.BatchID(struct.batch_id) if struct.batch_id
339
+ xml.SystemEntryDate(struct.system_entry_date) if struct.system_entry_date
340
+ xml.GLPostingDate(struct.gl_posting_date) if struct.gl_posting_date
341
+ xml.SystemID(struct.system_id) if struct.system_id
342
+ struct.lines&.each do |line|
343
+ xml.Line { build(line) }
344
+ end
345
+
346
+ when Types::Journal.name.split("::").last
347
+ xml.JournalID(struct.journal_id) if struct.journal_id
348
+ xml.Description(struct.description) if struct.description
349
+ xml.Type(struct.type) if struct.type
350
+ struct.transactions&.each do |transaction|
351
+ xml.Transaction { build(transaction) }
352
+ end
353
+
354
+ when Types::GeneralLedgerEntries.name.split("::").last
355
+ xml.NumberOfEntries(struct.number_of_entries) if struct.number_of_entries
356
+ xml.TotalDebit(struct.total_debit.to_s("F")) if struct.total_debit
357
+ xml.TotalCredit(struct.total_credit.to_s("F")) if struct.total_credit
358
+ struct.journals&.each do |journal|
359
+ xml.Journal { build(journal) }
360
+ end
361
+ end
362
+ end
363
+ end
364
+ end