## 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>
This update enhances the filtering capabilities by including 'corporateIdentificationNumber' in the list of supported properties for search. It improves the flexibility of customer queries and ensures better alignment with user needs.
Previously, the absence of a discountPercentage caused issues. The code now uses a default value of 0 to ensure stability and prevent potential errors when the discount is not set.
Implemented endpoints to list and import customers from the Economic API, including query filtering, pagination, and validation. Added supporting trait methods, database functions, and error handling. Expanded the user object for Economic integration and introduced utilities for type checking and parameter extraction.
Introduced a `setSearchableFields` method to restrict searchable fields in database queries, enhancing security by preventing unintended access to sensitive data. Updated user and department routes to leverage this feature. Default behavior remains unchanged when no searchable fields are specified.