diff --git a/lib/secretariat/invoice.rb b/lib/secretariat/invoice.rb
index 140627b..84b2734 100644
--- a/lib/secretariat/invoice.rb
+++ b/lib/secretariat/invoice.rb
@@ -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
@@ -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"))
@@ -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|
diff --git a/lib/secretariat/trade_party.rb b/lib/secretariat/trade_party.rb
index 8ad0125..d0f6b5e 100644
--- a/lib/secretariat/trade_party.rb
+++ b/lib/secretariat/trade_party.rb
@@ -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
diff --git a/test/invoice_test.rb b/test/invoice_test.rb
index 8af2c76..cdd3739 100644
--- a/test/invoice_test.rb
+++ b/test/invoice_test.rb
@@ -861,6 +861,50 @@ def test_fr_invoice
assert_match(%r{\s*304755032\s*}, xml)
end
+ def test_type_code_defaults_to_commercial_invoice
+ xml = make_de_invoice.to_xml(version: 2)
+ assert_match(%r{380}, 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{381}, xml)
+ assert_match(%r{\s*\s*R-2026-0042\s*\s*20261001\s*\s*}, 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{\s*R-2026-0042\s*}, 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{\s*HRB 12345\s*}, 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{304755032}, xml)
+ end
+
def test_invoice_with_quantity_causing_sub_cent_amounts
errors = []