Commit Graph
60 Commits
Author SHA1 Message Date
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
Jeppe B 0b304a2203 Gate invoice tree activation on audit schema (#339)
## Summary
- gate object-tree v2 on exact, schema-backed supersession audit columns
- serialize checked additive DDL and fail closed without disrupting
legacy invoicing
- preserve pre-schema supersession markers when structured columns are
still null
- add a superuser-only, self-scoped canary endpoint with locked
legacy-to-canonical allowlist migration
- verify effective activation, roll back failed readiness, and audit
enable/disable/failure

## Verification
- focused invoicing safety: 16 tests passed (99 assertions)
- full unit suite: 1,237 passed (9,003 assertions), 2 skipped, existing
warnings only
- PHP syntax and `git diff --check` clean
- independent architecture, security, and reviewer gates: GO

## Activation
Deploy with global database/environment enablement off. POST the
self-canary endpoint for one authenticated superuser, require
`configured_enabled=true` and `effective_enabled=true`, then verify the
exact period and tree GET routes. Roll back with the same endpoint using
`enabled=false`.
2026-08-03 13:03:55 +02:00
Jeppe B 068f9e254f Complete selected-customer invoice period tree (#338)
Add the authoritative revision-bound invoice collection tree and guarded cleanup, merge, price-reset, and transfer operations.
2026-08-03 12:02:34 +02:00
Jeppe BandJeppe Bundgaard 42ddce84bc Serialize VAT collection mutations with payment operations (#326)
## Summary

- Makes Stripe Terminal card payment intents always use 25% moms in the
API, independent of any client-supplied `tax_percentage`.
- Updates amount calculation, metadata persistence, stored-intent reuse
matching, the authoritative OpenAPI contracts, and operation-specific
Writerside outputs.
- Prevents double charging and false order closure across stale,
concurrently succeeded, partially recorded, or mismatched intents.
- Serializes payment create/capture/closure with order-item changes and
every order-to-invoice-collection reassignment through shared database
locks.
- Converts expected lock contention and reconciliation cases into
deliberate 409 responses.

## Exact-head evidence

Current head: `3a0f70d315a94d2efe586a2188d2c54f8ff11cd4`

- PHP syntax passed for all changed runtime files.
- Focused Orders suite: **42 tests / 293 assertions passed**.
- `git diff --check` passed.
- Fresh exact-head Tests and Qodana are running.
- Every Codex finding has a concrete reply; a fresh exact-head review is
requested below.

## Safety behavior

- Caller-controlled VAT is absent from request contracts; fixed 25% moms
is server-owned.
- A succeeded payment is preserved, requires the full expected
`amount_received`, and cannot close a changed/mismatched or
already-claimed collection.
- A compatible partially recorded Stripe closure is completed
idempotently; conflicting partial state fails closed for manual
reconciliation.
- Every cancellation/delete caller honors a concurrent-success result
and never falsely reports a completed payment as cleared.
- Price changes and invoice-collection reassignment share the payment
lock through validation, capture, post-capture reload, and closure.
- Reader changes are persisted only for reusable matching intents, so
stale intent cancellation targets the original terminal.
- Accepted legacy succeeded intents normalize stored tax to 25% before
response construction.

---------

Co-authored-by: Jeppe Bundgaard <jb@truckwash.dk>
2026-07-28 22:00:59 +02:00
Jeppe B 2a6a86c9c3 Resolve backend Qodana critical and high findings (#314)
Resolve recommended-profile Critical and High findings, retain narrow analyzer exceptions, and update the edge-broker WebSocket dependency to a non-vulnerable release.
2026-07-17 05:44:16 +02:00
Jeppe Bundgaard 582edd3e6c Implement subuser verification and invoice/self-serve API fixes 2026-07-13 15:11:49 +02:00
Jeppe Bundgaard 38814545c4 Optimize collected e-conomic invoice transfers 2026-07-06 11:31:22 +02:00
Jeppe Bundgaard aca8be51dc Implement move collected invoice to customer functionality with API endpoint and associated tests 2026-06-09 13:12:55 +02:00
Jeppe Bundgaard 6d4066be1c Add unit tests for InvoicingPeriodDraftOverlay and reference suggestion logic, including fake DB integration and aggregation methods
- Implemented `InvoicingPeriodDraftOverlayTest` with coverage for blocking and permitting invoicing actions based on draft states, transactions, and metadata.
- Created `ReferenceSuggestionsApiTest` to validate ranked and filtered suggestions across bookings, orders, and vehicles with varied match relevance, context, and frequency.
- Added `order_reference_suggestions_service` class, including query methods, normalization utilities, and aggregation logic for reference suggestions.
- Enhanced query handling in `InvoicingPeriodDraftOverlayFakeDb` to validate SQL constraints and column cache resets in overlapping invoicing contexts.
2026-05-11 18:18:08 +02:00
Jeppe Bundgaard a71bde3211 Remove legacy booking completion forms and related logic
- Deleted `complete_booking_f` and `generate_booking_wash_certificate_f` classes.
- Updated tests to ensure legacy booking completion routes are disabled.
- Introduced tests for POST `/order-bookings/complete` to enforce POS-based booking completion management.
- Added `/collected-invoices/split-by-month` route with API and unit tests for splitting collections into monthly periods.
- Refactored impacted files to exclude legacy references and ensure continued compatibility with POS processes.
2026-05-06 14:02:48 +02:00
Jeppe Bundgaard 0b18433fdf Add unit tests for EconomicCustomerModel parsing and validation 2026-04-21 15:07:41 +02:00
Jeppe Bundgaard 7d450e285e Remove outdated edge gateway object classes, add new agent implementation
Transitioned from obsolete gateway object classes (`edge_gateway_shell_action_jobs_o`, `edge_gateway_shell_events_o`, `edge_gateway_shell_sessions_o`, `edge_gateway_update_jobs_o`) to the new agent implementation (`edge-gateway-agent/agent.php`).
2026-04-21 14:13:17 +02:00
Jeppe Bundgaard ba23ad6e8f Add economic_transfer_executor and economic_transfer_queue classes for handling e-conomic invoice transfer logic, queue management, and processing. Include unit tests for Redis cache validation. 2026-04-08 11:20:08 +02:00
Jeppe Bundgaard ed1751ec2c Comment out administration fee enforcement in collected_order_invoices_o for debugging purposes. 2026-02-10 12:36:53 +01:00
Jeppe Bundgaard ab93866295 Add Redis connection checks and optimize caching for collected order invoices
- Enhance Redis methods (`exists`, `setEx`, `delete`, `get`, `set`) to ensure connection before execution.
- Introduce short-lived caching for collected order invoices to minimize redundant processing and improve performance.
- Add `pagination_helper` for dynamic WHERE clause construction in queries.
- Refactor net amount calculation in `collected_order_invoices_o` for efficiency with batch processing.
- Extend `listObjectsWithPaginationIfSet` to support additional WHERE clauses.
2026-02-03 11:43:56 +01:00
Jeppe Bundgaard ecd40e0b4f Update date handling logic and add isEmpty method in collected_order_invoices_o
- Refactor date calculation to use `closed_at` for determining monthly ranges.
- Fix SQL query to use `closed_at` instead of `created_at` for filtering orders.
- Add `isEmpty` method to check if an invoice collection has any orders.
2026-02-03 09:22:40 +01:00
Jeppe Bundgaard 49589de98e Update getUserByCustomerNumber references to getCustomerByIdOrCustomerNumber and enhance null-checking in requireSelected. 2026-01-06 15:40:05 +01:00
Jeppe Bundgaard 19c13977ca Ensure administration fee exemption for users with the relevant attribute and enhance null-checking in requireSelected. 2026-01-06 15:02:46 +01:00
Jeppe Bundgaard 71261c3933 Add administration fee handling to invoice collections, ensuring fees are applied monthly or per order if unpaid. 2026-01-06 14:52:25 +01:00
Jeppe Bundgaard ecd44a455a - Add Redis mget method and cache management improvements
- Update cache expiration times for `economicCustomerName` and `isBooked` objects
- Introduce `getCachedForMultipleObjects` for batch cache retrieval
- Optimize `isBooked` with optional caching and update to store results
- Implement `getCustomerNames` in `users_o` with caching for bulk name retrieval
- Refactor customer transaction handling in `InvoicingPeriodRoute` for efficiency
- Filter orders excluded from invoicing in `collected_order_invoices_o`
2025-11-26 10:01:24 +01:00
Jeppe Bundgaard 3dba2dedac Add isIncludedInInvoicing method and implement invoicing exclusions
- Introduced `isIncludedInInvoicing` in `orders_o` to check department-based invoicing exclusions.
- Updated routes and methods to skip orders excluded from invoicing.
- Refined transaction and order handling to respect invoicing settings, ensuring correct filtering.
2025-11-25 14:39:49 +01:00
Jeppe Bundgaard bfed2f231a Add new free subscription addon for "Undervognsskyld pr. enhed" in invoice collection logic 2025-11-04 13:53:01 +01:00
Jeppe Bundgaard dbc96fd0b4 Remove attribute for all associated customers if customer number exists; prevent re-adding exception in invoice collection logic. 2025-11-04 10:29:34 +01:00
Jeppe Bundgaard d06f0cedc3 Add new properties and routes for product and booking enhancements
- Added `virtual_cart` property in `bookings_o` and enhanced its structure method.
- Introduced `display_in_booking_form` and `order_priority` properties in `products_o` with updates to object structure, parsing, and routes.
- Enabled handling of product attributes `display_in_booking_form` and `order_priority` in `productsRoute`.
- Added `booked_invoice_id` reset logic in `collected_order_invoices_o`.
- Introduced `machineButtonPressRoute` to log button press incidents and send Slack notifications.
2025-10-28 09:58:29 +01:00
Jeppe Bundgaard 13ee541d57 Prevent environmental and oil fees for customer 999 with onlyTankCleaning attribute 2025-10-01 16:38:27 +02:00
Jeppe Bundgaard 8e6ad68253 Add environmental and oil fee calculation to invoice drafts
- Introduced `add_environmental_and_oil_fees` in `economic_invoices_draft_endpoint` to compute and add fees to drafts.
- Added `addEnvironmentalAndOilFeesToDraft` in `collected_order_invoices_o` to conditionally apply fees for customers with the `onlyTankCleaning` attribute.
2025-10-01 16:04:01 +02:00
Jeppe Bundgaard c2a5bad0a8 Improve error handling for draft invoice lines and refine invoice collection logic
- Added detailed error handling in `economic_invoices_draft_endpoint` to throw exceptions with line-specific error messages when adding draft invoice lines fails.
- Removed unnecessary `echo` statement from `orderInvoicesRoute`.
- Updated `collected_order_invoices_o` to allow empty invoice collections for customers with fixed price agreements.
2025-09-02 15:49:39 +02:00
Jeppe Bundgaard 5f400e1dd0 Add advanced invoice handling, cached result lookups, and customer-specific pricing
- Enhanced `orderInvoicesRoute` with `reset`, `unlink`, and `remove-special-arrangements` handlers for invoice actions, improving E-Conomic integration.
- Added `resetPricesOfItemsNotIncludedInInvoice`, `setAllItemsToBeIncludedInInvoice`, and `unlinkFromEconomic` methods in `collected_order_invoices_o` for robust invoice control.
- Introduced `getCustomerProductPrice` in `orders_o` to calculate customer-specific product pricing with discounts.
- Added `getCachedResultsBySubstring` in `motorapi_lookups_o` for efficient cached lookup based on result substrings.
2025-08-25 15:59:03 +02:00
Jepp9350 f503a5379e Enhance orders_o, order_items_o, and InvoicingPeriodRoute: add transaction and calculation methods, implement debug execution timing, refine invoicing period handling, optimize order retrieval, improve caching, and expand database query logic. 2025-07-01 13:01:01 +02:00
Jepp9350 5b88ef9dc3 Refactor order and order item management: add cache invalidation, improve object change tracking, and enhance asArray conversion with caching and expiration support. 2025-06-26 08:55:58 +02:00
Jepp9350 dcc6a56009 Add check for empty vehicle subscriptions in collected order invoices processing 2025-06-01 20:33:09 +02:00
Jepp9350 b37499e0f0 Add PO number handling and user invoices route
Introduced a new `po_number` property in `collected_order_invoices_o` and updated related methods to handle it. Added `userInvoicesRoute` to manage user invoice APIs with GET and PUT endpoints for listing and updating invoices. Updated `microsoft/microsoft-graph` dependency to version `^2.8`.
2025-05-20 12:15:35 +02:00
Jepp9350 30ff7d385e Add support for fixed pricing in collected order invoices
Introduced functionality to handle fixed prices for collected order invoices, allowing customer-specific pricing overrides. Added a new route and methods to integrate fixed pricing logic, modify invoice items, and ensure proper data management in E-Conomic. Adjusted discount calculations to accommodate cases where final price is zero.
2025-05-05 16:21:31 +02:00
Jepp9350 8d2fe8d75d Add support for closed_at field in order invoices
Introduce the closed_at field to track closure dates for order invoices. Updated validation, processing logic, and database integration to ensure correct handling of the new field. Adjusted related routes to pass and store the closed_at value where applicable.
2025-05-01 15:45:59 +02:00
Jepp9350 c56955ee28 Add logic to remove vehicle subscription transactions
Introduced a method to handle the removal of vehicle subscription transactions from invoice collections. Refactored references to a hardcoded cashier ID by using a class property for better maintainability. This ensures a cleaner and more dynamic transaction-handling process.
2025-04-28 08:26:44 +02:00
Jepp9350 28dd7d39ce Fix invoice processing logic and improve null safety checks
Updated default values for department IDs to prevent null issues and ensure proper handling of optional fields. Adjusted logic to skip non-invoiceable items and corrected department validation to avoid invalid entries. Improved overall robustness and consistency in invoice-related operations.
2025-04-23 15:47:34 +02:00
Jepp9350 a92781cceb Add user email and phone support with security routes
Introduced support for user email and phone management, including phone country code and email validation. Added API endpoints for email change and password validation to enhance account security features. Updated Stripe processor logic for better external ID handling.
2025-04-23 10:52:13 +02:00
Jepp9350 9025ad79b7 Set specific subscription addons to zero-priced where applicable.
Introduced logic to handle free subscription addons by setting their price to zero based on a predefined list. Updated affected areas to apply this change consistently when adding or modifying order items. This ensures correct pricing and aligns with business rules for these products.
2025-04-22 13:01:23 +02:00
Jepp9350 26ccab3d3c Add endpoint for booking collected invoices to Stripe
Introduce a new POST endpoint to handle adding collected order invoices to Stripe, with necessary validations and logging. Extend `collected_order_invoices_o` to include Stripe integration, fetching details of Stripe payment intents when applicable.
2025-04-22 12:01:55 +02:00
Jepp9350 60de6ae998 Add Stripe payment capture functionality
Introduced methods to handle Stripe payment capture and updated related classes and endpoints. Refactored constants for payment processors and integrated order collections to reflect Stripe payments. Ensured robust error handling and session validation for payment operations.
2025-04-22 10:17:06 +02:00
Jepp9350 627e4d87c2 Update text constants and add fallback values for customer data
Revised a string constant for transaction purposes to improve clarity. Added fallback values for address, zip code, and city in customer data methods to ensure defaults are returned when data is missing. These changes enhance robustness and readability.
2025-04-15 11:29:24 +02:00
Jepp9350 7b82be6c57 Implement vehicle subscription handling and department SMS feature
Added functionality to handle vehicle subscriptions in invoices, including validation and item visibility. Introduced department notification SMS capability with endpoints for creating, retrieving, and deleting SMS records. Enhanced invoice drafting logic to exclude items not flagged for inclusion in invoices.
2025-04-14 16:03:29 +02:00
Jepp9350 a3f158a920 Refactor invoice collection creation logic in orders
Simplified the loop by removing the special-case handling for the first order. Adjusted variable usage to improve clarity and ensure proper assignment. This streamlines the creation of invoice collections for orders.
2025-04-11 12:49:37 +02:00
Jepp9350 b6f2629bed Add invoice splitting, booking notifications, and minor fixes
Implemented functionality to split collected order invoices, ensuring proper validation and handling processor constraints. Added a notification system to inform departments about new bookings via Slack or SMS. Also, included minor enhancements such as a corrected Gateway API URL and improved form handling for wash certificate emails.
2025-04-11 09:39:49 +02:00
Jepp9350 60bcbb6e75 Enhance invoice handling and filtering mechanisms
Refactored invoice draft handling to improve error checks, added support for optional fetch skipping, and enhanced currency management. Expanded filtering capabilities with date range and attribute-based filters. Adjusted Nginx config to increase FastCGI read timeout for long-running processes.
2025-04-07 07:43:47 +02:00
Jepp9350 8bc4252089 Add Economic invoice overview and draft check functionalities
Introduce new endpoints for viewing Economic invoice summaries and running draft checks. Implement `economic_tasks` helper for managing draft validations, and enhance `collected_order_invoices_o` and SQL clauses to improve query flexibility, including handling "NOT NULL" filters.
2025-04-02 15:08:57 +02:00
Jepp9350 02b91b4c77 Update invoice handling to support custom dates and validations
Modified functionalities for creating invoice drafts by adding support for custom dates and enhanced validations. Updated methods now check and validate date formats, handle booked invoice collections, and ensure proper invoice creation workflows.
2025-04-01 15:38:27 +02:00
Jepp9350 5f65c5ea65 Add new routes and enhance invoice handling in backend
Introduced new superuser-only routes for handling collected invoices, including viewing invoices per order/month, invoice totals, and transactions. Enhanced validation for invoice closure with processors and added support for database views in multiple classes and objects. These updates improve backend functionality and data granularity while maintaining strict permission control.
2025-04-01 11:53:54 +02:00
Jepp9350 68ab9bc84c Add support for dynamic currency conversion in invoices
Introduced dynamic currency handling in invoice generation by adding methods to set currency and retrieve conversion rates. Adjusted logic to ensure accurate currency conversions when processing orders, draft invoices, and customer data. Default behavior falls back to DKK if no currency is specified.
2025-03-31 14:42:19 +02:00
Jepp9350 82a6349218 Add booking confirmation email functionality
Implemented a new booking confirmation email template and its integration with email sending functionality. Updated form handling to trigger confirmation email after submission and enhanced error handling on department validation.
2025-03-24 14:40:22 +01:00