Adds a scope-based access control layer to all 81 existing API routes.
Sits alongside existing session-cookie auth (does not replace it).
What this PR does:
- Audits every existing route and documents required scope per route
(see documentation/auth/route-scope-audit.md)
- Adds classes/auth/scope.php with 10 scope constants and role→scope defaults
- Adds classes/auth/scope_middleware.php with requireScope/requireAnyScope/requireRole
- Applies require*() calls to all 81 existing routes
- Adds ScopeMiddlewareTest (unit, 178 lines) and RouteScopeTest (integration, 212 lines)
Coexistence note:
This branch's classes/auth/scope.php is a stub that will be replaced
by classes/auth/scope_registry.php (from TRU-145 / PR #396) when that
PR merges first. The two have compatible APIs.
Refs: TRU-149
## Root cause
`route_t::hasPermission()` and `requirePermission()` are instance
methods. Route code was invoking them with `self::`; the new XL Vask
hall-scope helper made that call from a genuinely static context,
causing PHP to throw:
`Non-static method routes\\xlvaskUsageLogsRoute::hasPermission() cannot
be called statically`
## Changes
- Invoke route permission methods through `$this` across all 273
executable legacy calls in 45 route classes.
- Make `xlvaskUsageLogsRoute::allowedHallIdsForUser()` an instance
helper and update all 13 callers.
- Preserve the existing all-scope and own-scope hall selection rules.
- Add a token-aware regression test that rejects executable
`self::hasPermission()` and `self::requirePermission()` calls, while
ignoring comments.
- Add focused XL Vask tests for global scanner hall scope and
group-limited own scope.
- Update affected route contract assertions to the instance-call form.
## Verification
- PHP lint: all 53 changed PHP files
- Focused PHPStan: changed XL Vask route and both new regression tests —
clean
- Focused regression slice: 58 passed, 748 assertions
- Full local unit suite: 1,300 passed, 9,442 assertions (1 unrelated
existing warning, 1 environment skip)
- Full local API suite: 285 passed, 11,704 assertions
- Exact-SHA GitHub Tests workflow: all 7 jobs passed (unit, API,
integration, legacy, edge gateway, and supporting checks)
- Independent exact-SHA QA gate: PASS, no findings
- Independent exact-SHA security gate: PASS, no findings
- Independent exact-SHA reviewer gate: PASS, no findings
- Remote comparison: exactly one commit ahead of
`40b104abed7723a7d1b7028190ecda0e7aeef829`; all 53 remote blob hashes
matched the reviewed worktree
## Delivery state
Draft only for human review. No merge or deployment is included. Qodana
is skipped while the PR remains draft and is therefore not represented
as a passed gate.
## 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>
Resolve recommended-profile Critical and High findings, retain narrow analyzer exceptions, and update the edge-broker WebSocket dependency to a non-vulnerable release.
- 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.
- 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.
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`).
- Enhance `/collected-invoices/economic/compare` with improved HTTP status determination and response structure.
- Add handling for `draft_total` and `booked_total` comparisons against internal totals.
- Deprecate `/tmp-customer-list-overcharged` route with error response.
- Update OpenAPI documentation for `compareCollectedInvoiceEconomic` endpoint.
- Introduce `CollectedInvoiceEconomicCompareResponse` schema for consistent API responses.
- Comment out unused return data and debug code for clarity.
- Introduce `/collected-invoices/economic/compare` endpoint for superusers.
- Enable validation and comparison of draft and booked invoice totals from E-Conomic against internal data.
- Add detailed error handling and warnings for mismatches and retrieval failures.
- 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.
- 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.
Replaced `created_at` with `closed_at` to accurately set the timestamp when closing collected order invoices. This ensures the correct date is applied during the invoice update process.
Introduced a check to apply fixed pricing for customers with predefined rates. This ensures that customer-specific fixed prices override default prices before adding invoices to E-Conomic. The change improves pricing consistency and accuracy for eligible customers.
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.
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.
Set proper timestamps for collected invoices and added `getLastOrderId` for vehicles. Streamlined order fetching logic by fixing parameter usage, refining customer and order item retrieval, and improving type casting in multiple methods.
Introduced a new POST route for collected vehicle subscription invoices and enhanced responses with wash subscription transactions. Refactored order handling by adding department-based pricing logic and simplifying reusable methods. Various minor improvements include exception handling, input validation, and updated permissions.
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.
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.
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.
Introduce a new route for running error checks and implement a method to evaluate and clear specific invoice errors. Enhance draft handling with additional error checks and new helper methods to fetch and manage draft invoices.
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.
Introduced a "NOT ZERO" filter in `db_object_t` to enable stricter checks for fields with non-zero values. Applied this filter to enforce restrictions on active invoices in relevant routes to improve data consistency and validation accuracy.
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.
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.
The /collected-invoices/transactions route was removed as it was no longer in use. Removing this unused code improves maintainability and reduces potential confusion in the codebase.
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.
Refactored `orderInvoicesRoute` to use a central method for fetching invoice details, reducing code duplication. Added functionality for generating and storing material transaction PDFs using a new HTML2PDF template. Updated database handling for accommodating null filters and enhanced customer data retrieval in orders.
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.
Removed commented-out code snippets for better readability and maintainability. This streamlines the logic by eliminating unused query modifications and debug artifacts.
Introduced customer attribute-based filtering for individual invoicing and enhanced collected order invoice processing with proper associations to customers and orders. Added new endpoints, fields, and utility methods to streamline data retrieval, ensure consistency, and support new use cases like 'Ready to Invoice'. Includes minor fixes, validations, and optimizations throughout the affected modules.
Introduce logic for validating booked and draft invoices in E-conomic. Add methods to calculate the total net amount for invoice collections and improve error handling for specific invoice states. Updated related workflows to ensure consistent validation and data integrity.