feat: let other apps route e-invoices per business unit through hooks

Problem

Some companies invoice on behalf of several business units. A cooperative of activity and employment (CAE, served by the Ruche app) issues the invoices of each entrepreneur's activity, called an "enseigne". It registers one routing code per unit in the directory (SIREN_CODE).

  • Outbound: eTransactions always sends from the company's own electronic address (BT-34).
  • Inbound: nothing tells which unit a received invoice is addressed to. The buyer's electronic address (BT-49) is parsed but not used.

Root cause

The seller's identity is read only from the Company. The data passed from a received eInvoice to the Supplier Invoice has no extension point. The app declares no custom hooks (frappe.get_hooks isn't used anywhere).

Fix

Two generic hooks, documented in the new etransactions/utils/hooks.py. The module also has two helpers, first_hook_result and merged_hook_values.

  • etransactions_seller_electronic_address: fn(sales_invoice) -> str | None returns the directory identifier the invoice is sent from, e.g. "123456789_ATELIER" or "0225:123456789_ATELIER".
    • The first non-empty answer replaces the company's electronic address in EInvoiceMapper.map_electronic_addresses.
    • The CII and UBL writers read it from the eInvoice, so both formats follow.
    • Without an answer, nothing changes.
  • etransactions_incoming_invoice_values: fn(einvoice) -> dict | None returns extra header values merged into IncomingInvoiceDataTransformer.get_data. These are the Supplier Invoice's values.
    • SupplierInvoice.get_purchase_invoice already copies header fields by fieldname, so a field that exists on both DocTypes (e.g. an accounting dimension) reaches the Purchase Invoice.

Ruche uses both hooks to send each enseigne's invoices from its own routing code, and to put received invoices on the addressed enseigne's accounting dimension.

Tests

  • New etransactions/tests/test_extension_hooks.py (unit tests, no database):
    • hook helper order and merging;
    • the seller address comes from the hook, or falls back to the company's;
    • hook values end up in the Supplier Invoice data.
  • test_incoming_flow, test_routing and test_ubl_generator still pass.

Merge request reports

Loading
Loading