-
-
Notifications
You must be signed in to change notification settings - Fork 209
Allow custom TransactionCalculator injection to properly support BR-FXEXT-CO-15 tolerance use cases #1041
Description
Context
In Factur-X EXTENDED, rule BR-FXEXT-CO-15 introduces a tolerance of ±0.01 EUR per invoice line between:
BT-112 (GrandTotalAmount)
and
BT-109 + BT-110
This tolerance exists to absorb rounding strategy differences (line-level vs document-level rounding).
However, in Mustang, TransactionCalculator is directly instantiated inside ZUGFeRD2PullProvider:
TransactionCalculator calc = new TransactionCalculator(trans);
This makes it impossible to provide an alternative calculation strategy without modifying core code.
Why this is a problem
BR-FXEXT-CO-15 explicitly acknowledges that small discrepancies may exist due to rounding strategies.
In real ERP systems:
Line amounts may be rounded early
VAT may be computed globally
Totals may be derived from upstream certified engines
Payment totals may legally differ by 0.01 or 0.02
Even when remaining within the tolerance defined by BR-FXEXT-CO-15.
Currently, Mustang:
Applies a fixed “round-early, aggregate-later” strategy
Does not allow substituting the calculation model
Prevents leveraging the tolerance provided by BR-FXEXT-CO-15
unless the core library is forked
This limits advanced but legitimate use cases in Factur-X EXTENDED.
Important Clarification
This proposal does not aim to:
Break EN 16931 compliance
Bypass BR-CO-15
Modify default behavior
It simply allows advanced users to:
Implement alternative compliant calculation strategies
Explicitly rely on BR-FXEXT-CO-15 tolerance where appropriate
Preserve ERP-certified totals when legally acceptable
without modifying Mustang core.
Proposed Solution (Minimal & Backward Compatible)
Introduce a protected factory method in ZUGFeRD2PullProvider:
protected TransactionCalculator createCalculator(Invoice trans) {
return new TransactionCalculator(trans);
}
Replace:
TransactionCalculator calc = new TransactionCalculator(trans);
with:
TransactionCalculator calc = createCalculator(trans);
Benefits
100% backward compatible
No behavioral change for existing users
Enables legitimate BR-FXEXT-CO-15 tolerance scenarios
Avoids forcing users to fork Mustang
Improves extensibility and enterprise adoption
Keeps normative compliance fully under user responsibility
Example Usage
public class CustomPullProvider extends ZUGFeRD2PullProvider {
@Override
protected TransactionCalculator createCalculator(Invoice trans) {
return new CustomTransactionCalculator(trans);
}
}
Why This Matters
BR-FXEXT-CO-15 exists specifically to tolerate controlled rounding discrepancies.
Without an extension mechanism in Mustang, it is not possible to:
Align calculation strategy with external ERP engines
Fully leverage the tolerance defined in the Factur-X EXTENDED profile
Implement controlled, documented rounding policies
Adding this factory method would make Mustang more extensible,
while keeping default behavior fully unchanged.