# TANRAIL ONE — Phase 3.2.3 Pre-Implementation Review

## Architecture Compatibility Assessment

### A. Is the proposed Sales architecture compatible with Inventory?
**Yes.** The Inventory Core's pessimistic locking and strictly enforced Business Unit isolation boundaries perfectly support the synchronous deduction model required by Sales. The `InventoryService::issue()` method natively handles the mathematical integrity required by the Order confirmation transaction.

### B. How will an Order determine its Business Unit?
An `Order` inherently belongs to a Business Unit through its `branch_id`. A Branch belongs to a Business Unit. To optimize querying, `business_unit_id` will be denormalized onto the `orders` table and automatically populated upon creation via `$branch->business_unit_id`.

### C. How will an Order determine its Branch?
The `branch_id` will be explicitly required when creating an `Order`. It will be derived from the User's Active Context or explicitly provided by the business module (e.g., POS terminal configuration).

### D. How will an Order determine its inventory deduction location?
**Analysis**: Currently, `Branch` does not specify a default location, and `InventoryService::issue()` requires an explicit `InventoryLocation`.
**Decision**: We MUST add `default_sales_location_id` (foreign key to `inventory_locations`) to the `branches` table. 
**Justification**: This allows the Core `OrderService` to autonomously determine where to deduct generic stock without requiring business-specific routing logic. If a specific extension needs advanced routing later (e.g., Kitchen vs Bar), the extension will override this at the `OrderLine` level, but the Core needs a solid baseline default.

### E. How will cross-BU Item insertion be prevented?
Inside `OrderService::addItem()`, a strict application-boundary assertion will run:
`if ($item->business_unit_id !== $order->branch->business_unit_id) { throw new Exception(); }`

### F. How will negative stock rejection rollback Order confirmation?
`OrderService::confirmOrder()` wraps its state change and Event dispatch inside `DB::transaction()`. The `OrderConfirmed` event triggers the `DeductInventoryListener` synchronously. If `InventoryService::issue()` encounters negative stock, it throws an `Exception`. The Exception bubbles up, terminating the database transaction and rolling the Order back to `DRAFT`.

### G. How will duplicate confirmation be prevented?
`OrderService::confirmOrder()` will apply a pessimistic read lock (`lockForUpdate()`) to the `Order` row. It will then check `if ($order->status !== 'DRAFT') { return; }`. This prevents race conditions where two simultaneous API calls attempt to confirm the same order.

### H. How will Payments remain append-only?
The `Payment` model will leverage an Eloquent Observer (via the `booted()` method) mapping to `updating` and `deleting` events. Any attempt to update or delete a payment will immediately throw a `\RuntimeException`.

### I. How will OrderLine immutability be enforced?
The `OrderLine` model will leverage similar `updating` and `deleting` observers. These observers will inspect `$model->order->status`. If the status is NOT `DRAFT`, the observer throws a `\RuntimeException`, cementing the historical price and tax values.

### J. How will Restaurant/Catering attach themselves to an Order later without modifying Core?
Business extensions will create mapping tables (e.g., `RestaurantTableOrder`) containing a `table_id` and an `order_id`. The Core `Order` remains oblivious to the extension, fulfilling the TANRAIL ONE business-agnostic doctrine.

---
## Conclusion
No blocking architectural contradictions exist. The addition of `default_sales_location_id` to `Branch` provides the necessary glue for the inventory integration while keeping Core Sales completely agnostic of industry logic. The architecture is ready for implementation.
