Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion lib/secretariat/invoice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ module Secretariat
:direct_debit_creditor_id, # BT-90
:direct_debit_iban, # BT-91,
:subject_code, # BT-21
:type_code, # BT-3, defaults to 380 (commercial invoice)
:preceding_invoice_id, # BT-25
:preceding_invoice_issue_date, # BT-26
keyword_init: true
) do

Expand Down Expand Up @@ -212,7 +215,7 @@ def to_xml(version: 1, validate: true)
if version == 1
xml['ram'].Name "RECHNUNG"
end
xml['ram'].TypeCode '380' # TODO: make configurable
xml['ram'].TypeCode type_code || '380'
xml['ram'].IssueDateTime do
xml['udt'].DateTimeString(format: '102') do
xml.text(issue_date.strftime("%Y%m%d"))
Expand Down Expand Up @@ -351,6 +354,18 @@ def to_xml(version: 1, validate: true)
Helpers.currency_element(xml, 'ram', 'TotalPrepaidAmount', paid_amount, currency_code, add_currency: version == 1)
Helpers.currency_element(xml, 'ram', 'DuePayableAmount', due_amount, currency_code, add_currency: version == 1)
end
if version == 2 && preceding_invoice_id.present?
xml['ram'].InvoiceReferencedDocument do
xml['ram'].IssuerAssignedID preceding_invoice_id
if preceding_invoice_issue_date
xml['ram'].FormattedIssueDateTime do
xml['qdt'].DateTimeString(format: '102') do
xml.text(preceding_invoice_issue_date.strftime("%Y%m%d"))
end
end
end
end
end
end
if version == 1
line_items.each_with_index do |item, i|
Expand Down
3 changes: 2 additions & 1 deletion lib/secretariat/trade_party.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ def to_xml(xml, exclude_tax: false, version: 2)
xml['ram'].Name name
if legal_organization.present?
xml['ram'].SpecifiedLegalOrganization do
xml['ram'].ID(schemeID: legal_organization[:scheme_id] || "0002") do
scheme_id = legal_organization.fetch(:scheme_id, "0002") # scheme_id: nil omits the scheme (BT-30-1)
xml['ram'].ID({ schemeID: scheme_id }.compact) do
xml.text(legal_organization[:id])
end
end
Expand Down
44 changes: 44 additions & 0 deletions test/invoice_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,50 @@ def test_fr_invoice
assert_match(%r{<ram:SpecifiedLegalOrganization>\s*<ram:ID schemeID="0002">304755032</ram:ID>\s*</ram:SpecifiedLegalOrganization>}, xml)
end

def test_type_code_defaults_to_commercial_invoice
xml = make_de_invoice.to_xml(version: 2)
assert_match(%r{<ram:TypeCode>380</ram:TypeCode>}, xml)
end

def test_credit_note_with_preceding_invoice
invoice = make_eu_invoice
invoice.type_code = '381'
invoice.preceding_invoice_id = 'R-2026-0042'
invoice.preceding_invoice_issue_date = Date.new(2026, 10, 1)
xml = invoice.to_xml(version: 2)

assert_match(%r{<ram:TypeCode>381</ram:TypeCode>}, xml)
assert_match(%r{</ram:SpecifiedTradeSettlementHeaderMonetarySummation>\s*<ram:InvoiceReferencedDocument>\s*<ram:IssuerAssignedID>R-2026-0042</ram:IssuerAssignedID>\s*<ram:FormattedIssueDateTime>\s*<qdt:DateTimeString format="102">20261001</qdt:DateTimeString>\s*</ram:FormattedIssueDateTime>\s*</ram:InvoiceReferencedDocument>}, xml)
assert_equal [], Validator.new(xml, version: 2).validate_against_schematron
end

def test_preceding_invoice_without_issue_date
invoice = make_de_invoice
invoice.preceding_invoice_id = 'R-2026-0042'
xml = invoice.to_xml(version: 2)

assert_match(%r{<ram:InvoiceReferencedDocument>\s*<ram:IssuerAssignedID>R-2026-0042</ram:IssuerAssignedID>\s*</ram:InvoiceReferencedDocument>}, xml)
end

def test_no_preceding_invoice_by_default
xml = make_de_invoice.to_xml(version: 2)
refute_match(/InvoiceReferencedDocument/, xml)
end

def test_legal_organization_without_scheme
invoice = make_fr_invoice
invoice.seller.legal_organization = { id: 'HRB 12345', scheme_id: nil }
xml = invoice.to_xml(version: 2)
assert_match(%r{<ram:SpecifiedLegalOrganization>\s*<ram:ID>HRB 12345</ram:ID>\s*</ram:SpecifiedLegalOrganization>}, xml)
end

def test_legal_organization_scheme_defaults_to_sirene
invoice = make_fr_invoice
invoice.seller.legal_organization = { id: '304755032' }
xml = invoice.to_xml(version: 2)
assert_match(%r{<ram:ID schemeID="0002">304755032</ram:ID>}, xml)
end

def test_invoice_with_quantity_causing_sub_cent_amounts
errors = []

Expand Down
Loading