Files
api/documentation/economic/invoice-discount-format-drift12.md
T
Jeppe BandMiniMax M3 Subagent 52d43fc16c fix(api): apply e-conomic discount percentage at line level for customer 35131752 (TRU-73 / DRIFT 12) (#400)
## Summary

Fixes **TRU-73 / DRIFT 12** — invoice format must clearly show the
discount given on all services.

For customers with a global e-conomic discount (e.g. `kd` customer
`35131752` with a 15% discount), the discount was being silently dropped
on draft invoice lines. E-conomic's draft invoice line API requires
`discountPercentage` on each line, so an aggregate `TotDiscount` line is
ignored when the customer has a per-line discount configured. The fix
applies the customer discount at the line level.

## What changed

-
`services/nginx/app/modules/economic/helpers/economic_invoice_draft.php`
— `addOrderItemLines()` and `addOrderItemLine()` now accept a
`customer_discount_percentage` argument and combine it with the per-item
discount using `max(per_item, customer)`. The aggregate `TotDiscount`
line is suppressed when a customer-level discount is in play.
- `services/nginx/app/modules/economic/customers/economicCustomers.php`
— logs swallowed missing-currency-price errors so silently-missing
discounts become visible in the application log.
-
`services/nginx/app/modules/economic/endpoints/invoices/draft/economic_invoices_draft_endpoint.php`
— forwards the customer discount percentage to the draft builder.
- `services/nginx/app/objects/collected_order_invoices_o.php` — resolves
the customer discount via Redis cache + e-conomicCustomers and passes it
to the draft builder.
-
`services/nginx/app/tests/Unit/Invoicing/EconomicInvoiceDraftCustomerDiscountTest.php`
— new test class covering the customer 35131752 15% case plus edge cases
(per-item + customer discount combined, clamping to 0..100,
zero-discount baseline).
-
`services/nginx/app/tests/Unit/Invoicing/EconomicInvoiceDraftDiscountLineModeWiringTest.php`
— updated for the new parameter and the customer-discount guard on the
aggregate `TotDiscount` line.
-
`services/nginx/app/tests/Unit/Invoicing/CollectedInvoiceEconomicBatchTransferWiringTest.php`
— updated to thread the new parameter through the batch transfer
pipeline.
- `documentation/economic/invoice-discount-format-drift12.md` — new doc
with the before/after invoice layout (the example Jimmy asked for in the
DRIFT 12 description).

## Example (for Jimmy)

Customer 35131752 ("kd") with 15% global e-conomic discount, one wash
line at 100,00 DKK.

### Before
```
Vask                                     1 ×   100,00 DKK     100,00
Subtotal                                                    100,00 DKK
Rabat (15%)                                                  0,00 DKK   ← silently dropped
Total                                                       100,00 DKK
```

### After
```
Vask (15% rabat)                        1 ×   100,00 DKK     100,00
                                                       Rabat:  -15,00 DKK (15%)
Subtotal                                                    100,00 DKK
Rabat                                                        15,00 DKK
Total                                                         85,00 DKK
```

## Test plan

- [x] New `EconomicInvoiceDraftCustomerDiscountTest` covers: 15%
customer discount applied at line level, per-item + customer discount
combined using `max`, clamping to 0..100, zero-discount baseline.
- [x] `EconomicInvoiceDraftDiscountLineModeWiringTest` updated and still
passes.
- [x] `CollectedInvoiceEconomicBatchTransferWiringTest` updated for the
new parameter.
- [ ] Run full `php-ci-test.sh unit` locally to confirm nothing else
regressed.

## Linear

Closes TRU-73 (DRIFT 12).

🤖 Generated via the TRU-73 pickup cron run.

---------

Co-authored-by: MiniMax M3 Subagent <fix@truckwash.local>
2026-08-17 13:41:10 +00:00

5.1 KiB
Raw Blame History

Invoice Discount Format — DRIFT 12 (TRU-73)

What changed

The e-conomic draft invoice now applies the customer-level discount percentage at the line level on every line item, so the discount is clearly visible on each service line on the customer's invoice.

Before this fix, a customer with a global e-conomic discount (e.g. the kd customer 35131752 with a 15% discount) would receive an invoice where the discount was only reflected via an aggregate TotDiscount line — and crucially, e-conomic's draft invoice line API requires discountPercentage on each line, so the aggregate line was being ignored entirely. The customer was getting invoiced at full price with no visible discount at all.

Invoice layout — before vs after (for Jimmy)

The example below uses customer 35131752 ("kd") with a 15% global e-conomic discount, ordering one wash line at 100.00 DKK.

Before the fix (DRIFT 12 — discount silently dropped)

─────────────────────────────────────────
  Vask                                     1 ×   100,00 DKK     100,00
─────────────────────────────────────────
                                       Subtotal                100,00 DKK
                                          Rabat (15%)            0,00 DKK   ← never applied
                                       Total                   100,00 DKK
─────────────────────────────────────────

The Rabat line was never actually created on the e-conomic side because the customer has a per-line discount configured, not an aggregate one. The customer saw 100,00 DKK with no discount displayed.

After the fix (TRU-73)

─────────────────────────────────────────
  Vask (15% rabat)                        1 ×   100,00 DKK     100,00
                                                          Rabat:  -15,00 DKK (15%)
─────────────────────────────────────────
                                       Subtotal                100,00 DKK
                                          Rabat                 15,00 DKK
                                          Total                 85,00 DKK
─────────────────────────────────────────

The 15% discount now appears on the wash line itself (via the discountPercentage field that e-conomic renders on each line), and the subtotal correctly reflects the 85,00 DKK total the customer owes.

How the fix works

  1. The customer discount percentage is resolved from the cached economicCustomers record (via Redis when available, otherwise through the live e-conomic API) and threaded through economic_invoice_draft::addOrderItemLines() / addOrderItemLine().
  2. On each line, the customer discount is combined with the per-item discount using max(per_item, customer) so the larger discount always wins — the system never accidentally double-discounts a line that already has a per-item price reduction.
  3. The aggregate TotDiscount line is suppressed when the customer has a per-line discount, since e-conomic's draft line API requires discountPercentage to be on the line itself.
  4. The customer discount is clamped to 0..100 to guard against bad data from the e-conomic API.

Code paths

  • services/nginx/app/modules/economic/helpers/economic_invoice_draft.phpaddOrderItemLines() and addOrderItemLine() now accept a customer_discount_percentage argument and combine it with the per-item discount at the line level.
  • services/nginx/app/modules/economic/customers/economicCustomers.php — logs swallowed missing-currency-price errors so silently-missing discounts become visible in the application log.
  • services/nginx/app/modules/economic/endpoints/invoices/draft/economic_invoices_draft_endpoint.php — forwards the customer discount percentage to the draft builder.
  • services/nginx/app/objects/collected_order_invoices_o.php — resolves the customer discount via the Redis cache + e-conomic customer index and passes it to the draft builder.

Tests

  • services/nginx/app/tests/Unit/Invoicing/EconomicInvoiceDraftCustomerDiscountTest.php — new tests covering the customer 35131752 case (15% global discount, applied at line level) plus edge cases: per-item + customer discount combined, clamping to 0..100, zero-discount baseline.
  • services/nginx/app/tests/Unit/Invoicing/EconomicInvoiceDraftDiscountLineModeWiringTest.php — updated to account for the new parameter and the customer-discount guard on the aggregate TotDiscount line.
  • services/nginx/app/tests/Unit/Invoicing/CollectedInvoiceEconomicBatchTransferWiringTest.php — updated to thread the new parameter through the batch transfer pipeline.