From 496e369edd1a0839d32e931767aca69071f0c80d Mon Sep 17 00:00:00 2001 From: ahmedm10 Date: Mon, 19 Oct 2026 19:42:29 +0300 Subject: [PATCH] feat: support seller and buyer electronic addresses Adds TradeParty#electronic_address and #electronic_address_scheme_id (EN 16931 BT-34 / BT-49) as URIUniversalCommunication. Written only with a scheme (BR-62, BR-63) and left out of the ShipToTradeParty, where the profile does not use it. --- lib/secretariat/trade_party.rb | 10 ++++++++++ test/invoice_test.rb | 25 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/lib/secretariat/trade_party.rb b/lib/secretariat/trade_party.rb index 8ad0125..039976e 100644 --- a/lib/secretariat/trade_party.rb +++ b/lib/secretariat/trade_party.rb @@ -21,6 +21,7 @@ module Secretariat :id, :name, :street1, :street2, :city, :postal_code, :country_id, :vat_id, :global_id, :global_id_scheme_id, :tax_id, :person_name, :legal_organization, + :electronic_address, :electronic_address_scheme_id, keyword_init: true, ) do def to_xml(xml, exclude_tax: false, version: 2) @@ -54,6 +55,15 @@ def to_xml(xml, exclude_tax: false, version: 2) xml['ram'].CityName city xml['ram'].CountryID country_id end + # EN16931 BT-34 / BT-49, the scheme (BT-34-1 / BT-49-1) is mandatory (BR-62, BR-63). + # Like the ID, it is left out of the ShipToTradeParty, where it is not used. + if version == 2 && !exclude_tax && electronic_address.present? && electronic_address_scheme_id.present? + xml['ram'].URIUniversalCommunication do + xml['ram'].URIID(schemeID: electronic_address_scheme_id) do + xml.text(electronic_address) + end + end + end if !exclude_tax && vat_id.present? xml['ram'].SpecifiedTaxRegistration do xml['ram'].ID(schemeID: 'VA') do diff --git a/test/invoice_test.rb b/test/invoice_test.rb index 8af2c76..532a679 100644 --- a/test/invoice_test.rb +++ b/test/invoice_test.rb @@ -861,6 +861,31 @@ def test_fr_invoice assert_match(%r{\s*304755032\s*}, xml) end + def test_electronic_addresses_of_seller_and_buyer + invoice = make_eu_invoice + invoice.seller.electronic_address = 'invoices@depfu.com' + invoice.seller.electronic_address_scheme_id = 'EM' + invoice.buyer.electronic_address = 'accounting@example.se' + invoice.buyer.electronic_address_scheme_id = 'EM' + xml = invoice.to_xml(version: 2) + + assert_match(%r{\s*\s*invoices@depfu.com\s*\s*}, xml) + assert_equal 1, xml.scan('accounting@example.se').size # not repeated in the ShipToTradeParty + assert_equal [], Validator.new(xml, version: 2).validate_against_schematron + end + + def test_electronic_address_without_scheme_is_omitted + invoice = make_de_invoice + invoice.seller.electronic_address = 'invoices@depfu.com' + xml = invoice.to_xml(version: 2) + refute_match(//, xml) + end + + def test_no_electronic_address_by_default + xml = make_de_invoice.to_xml(version: 2) + refute_match(//, xml) + end + def test_invoice_with_quantity_causing_sub_cent_amounts errors = []