## 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>
5.1 KiB
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
- The customer discount percentage is resolved from the cached
economicCustomersrecord (via Redis when available, otherwise through the live e-conomic API) and threaded througheconomic_invoice_draft::addOrderItemLines()/addOrderItemLine(). - 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. - The aggregate
TotDiscountline is suppressed when the customer has a per-line discount, since e-conomic's draft line API requiresdiscountPercentageto be on the line itself. - 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.php—addOrderItemLines()andaddOrderItemLine()now accept acustomer_discount_percentageargument 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 aggregateTotDiscountline.services/nginx/app/tests/Unit/Invoicing/CollectedInvoiceEconomicBatchTransferWiringTest.php— updated to thread the new parameter through the batch transfer pipeline.