## 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>
99 lines
5.1 KiB
Markdown
99 lines
5.1 KiB
Markdown
# 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.php`
|
||
— `addOrderItemLines()` 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.
|