# Test Scenario Guide: Offer-Request State Synchronization (Event-Driven)

### 1. Scenario Introduction 🚀
In the Maintenance module, **Price Offers** and **Maintenance Requests** were previously decoupled. When a customer approved an offer, the parent request would remain in a stale status (e.g., `AWAITING_CUSTOMER_APPROVAL`), requiring manual updates. 

This feature introduces a reactive **Event-Driven Synchronization** layer. When an offer reaches a terminal state (Accepted, Rejected, or Contract Created), the parent `MaintenanceRequest` status is automatically updated to reflect the next logical step in the ERP workflow. This ensures data consistency and triggers immediate notifications for **Contract Officers**.

---

### 2. Technical Schema Changes (Detailed) 🔍

Analyze the structural updates across the domain:

*   **Enum Updates:**
    *   `RequestStatusNew` now explicitly includes `APPROVED_TECHNICAL` (to handle re-revisions) and `CLOSED`.
*   **Model Enhancements:**
    *   **MaintenanceRequest:** Added `priceOffers()` relationship to evaluate the global state of all offers for a specific request during rejection events.
*   **Domain Events:**
    *   `PriceOfferAcceptedByClient`: Fired when `status` moves to `approved_by_customer`.
    *   `PriceOfferContractCreated`: Fired when a contract is successfully saved for a price offer.
    *   `PriceOfferRejectedByClient`: Fired when `status` moves to `rejected_by_customer`.
*   **Listener Logic:**
    *   `SyncRequestStatusOnOfferChange`: Centralized hub for executing the status mapping and notifying staff.

---

### 3. Why the Update? (Change Log) 🔄

| Metric | Previous Behavior | New Behavior |
| :--- | :--- | :--- |
| **Sync Logic** | Manual/Decoupled. | **Automatic & Event-Driven**. |
| **Request Status** | Stayed stuck in `AWAITING_APPROVAL`. | Moves to `AWAITING_CONTRACT` or `CLOSED`. |
| **Staff Awareness** | Contract Officers had to check lists manually. | **Real-time Push/Email Notifications** on approval. |
| **Data Reversion** | Rejections left requests in limbo. | Reverts to `APPROVED_TECHNICAL` for new revisions. |

**Benefits:**
*   **Data Integrity:** Prevents status mismatch between financial offers and operational requests.
*   **Operational Speed:** Contract creation can begin the second an offer is approved.

---

### 4. API Endpoints Table 📊

| Process | Endpoint | Method | Description |
| :--- | :--- | :--- | :--- |
| **Offer Approval** | `/api/v1/price-offers/{offer}/customer-approve` | `POST` | Triggers request sync to `AWAITING_CONTRACT`. |
| **Offer Rejection** | `/api/v1/price-offers/{offer}/customer-reject` | `POST` | Reverts request to `APPROVED_TECHNICAL` (if no other offers). |
| **Contract Save** | `/api/v1/contracts` | `POST` | Triggers request sync to `CLOSED` if `price_offer_id` is set. |
| **Legacy Sync** | `php artisan maintenance:sync-request-statuses` | `CLI` | Backfills and fixes mismatched statuses in existing data. |

---

### 5. Test Cases 🧪

#### [Case 1] The Happy Path: Approval & Notification
*   **Input:** Execute `customer-approve` endpoint for a pending offer.
*   **Expected:**
    1. Offer status is `approved_by_customer`.
    2. Parent Request status is `awaiting_contract`.
    3. `ContractReadyToCreateNotification` is dispatched to users with role `contract_officer`.

#### [Case 2] Backward Compatibility: Artisan Sync
*   **Input:** Run the `maintenance:sync-request-statuses` command.
*   **Expected:**
    *   Identifies requests where status doesn't match the latest offer.
    *   Updates legacy requests with accepted offers to `awaiting_contract`.
    *   Audit logs show status changes performed by the system.

#### [Case 3] Edge Case: Multi-Offer Rejection
*   **Input:** Request has Offer A (Rejected) and Offer B (Pending).
*   **Expected:** 
    *   Request status remains unchanged while Offer B is pending.
    *   Once Offer B is also rejected, Request status reverts to `approved_technical`.

#### [Case 4] Terminal State Guard
*   **Input:** Trigger an approval for an offer whose parent request is already `CLOSED`.
*   **Expected:** Request status **REMAINS** `CLOSED`. The sync logic must respect terminal states to prevent overwriting completed records.

---

> [!NOTE]
> This sync is **One-Way** (Offer -> Request). Manually changing a Request status will not affect the Price Offer to prevent unintended financial state changes.
