# Test Scenario Guide: Maintenance Price Workflow Optimization

The maintenance system has been upgraded with a more robust price offer lifecycle, automated validity tracking, and specialized workflows for Preventive and Corrective maintenance. This documentation outlines the technical changes and provides a comprehensive test plan to ensure the reliability of the pricing engine and offer management.

## 1. Scenario Introduction
Previously, price offers were handled through a generic workflow that didn't fully account for the differences between preventive contracts and one-off corrective repairs. The new system introduces:
*   **Specialized Workflows**: Dedicated controllers and services for **Preventive** (contract-based) and **Corrective** (incident-based) offers.
*   **Lifecycle Management**: A state machine that includes internal approval, sales-controlled sending, and automated expiration.
*   **Calculated Snapshots**: Improved in-memory calculation for PDF previews, allowing users to see the final document before saving.

## 2. Technical Schema Changes 🔍

### Validation Logic Updates
Significant changes were made to **FormRequest** validation to ensure financial data integrity.

*   **StorePreventivePriceOfferRequest**:
    *   `chiller_visit_cost`: Now **required** if the related technical offer has `has_chiller = true`.
    *   `consumables_cost`: Now **required** if `is_consumables_included` is checked.
    *   `resident_labor_cost` & `labor_includes_accommodation`: Now **required** if `resident_labor` is true.
*   **UpdatePriceOfferRequest**:
    *   Now dynamically determines if the offer is preventive to enforce the specific pricing rules mentioned above.
    *   `offer_validity_date`: Enforced to be `after_or_equal:today`.

### API Response & Status Changes
The `status` field for `MaintenancePriceOffer` has been expanded to reflect a professional sales lifecycle:
*   `pending_approval` → `pending_internal_approval`
*   `pending_customer_approval` → `waiting_to_send_to_customer`
*   Added: `waiting_customer_response` (Triggered after sales clicks "Send to Customer")
*   Added: `expired` (Managed by system command)
*   Added: `closed` (Manual closure by admin)
*   Renamed: `approved` → `approved_by_customer`, `rejected` → `rejected_by_customer`

## 3. Why the Update? (Change Log) 🔄
| Feature | Previous Behavior | New Behavior | Benefit |
| :--- | :--- | :--- | :--- |
| **Offer Expiry** | Offers remained "Pending" indefinitely. | `CheckExpiredPriceOffers` command auto-expires old offers. | Better sales tracking and accurate data. |
| **Sales Control** | Offers were notified to clients immediately upon internal approval. | Introduces `waiting_to_send_to_customer` for final sales review. | Reduced errors in communication. |
| **In-Memory Preview** | Required saving a record to generate a PDF. | Dedicated `/preview` endpoints use in-memory models. | Performance & UI/UX improvement. |
| **Data Integrity** | Chiller/Labor costs were often missing despite requirements. | Strict `required_if` validation at the API layer. | Accurate financial reporting. |

## 4. API Endpoints Table 📊
| Process | Endpoint | Method | Description |
| :--- | :--- | :--- | :--- |
| **Preventive Offer (Auto)** | `/price-offers/preventive/{technicalOffer}` | `POST` | Create offer from Technical Offer |
| **Preventive Offer (Manual)** | `/price-offers/from-breakdown/{request}` | `POST` | Create preventive offer from a request |
| **Corrective Offer** | `/price-offers/from-corrective/{request}` | `POST` | Create corrective offer from a request |
| **PDF Preview** | `/price-offers/.../{id}/preview` | `POST` | Generate PDF without database storage |
| **Send to Client** | `/price-offers/{offer}/send-to-customer` | `POST` | Moves from internal approval to client view |
| **Close Offer** | `/price-offers/{offer}/close` | `POST` | Manually close a dead deal |

## 5. Test Cases 🧪

### [Case 1] The Happy Path: Preventive Workflow
1.  **Scenario**: Create a preventive offer for a client with chillers.
2.  **Input**: Technical offer with `has_chiller = true`.
3.  **Expectation**: Payload must include `chiller_visit_cost`. The system should calculate total visits by multiplying `unit_count` × `frequency`. Status should start as `draft`.

### [Case 2] Backward Compatibility & Migration
1.  **Scenario**: Accessing an older offer with status `pending_customer_approval`.
2.  **Expectation**: Model scopes and resources must map legacy statuses correctly to the new `waiting_customer_response` labels to prevent dashboard crashes.

### [Case 3] Edge Cases & Constraints
*   **Validation Failure**: Attempt to save a preventive offer with `resident_labor = true` but no `labor_cost`. System must return `422 Unprocessable Entity`.
*   **Automated Expiration**: Create an offer with `offer_validity_date = yesterday`. Run `php artisan maintenance:check-expired-offers`. Status must change to `expired`.
*   **Unauthorized Send**: Attempt to call `send-to-customer` on an offer still in `draft`. System should block with an error message.

---

> [!TIP]
> Use the new **Preview Endpoints** during development to verify calculation logic without polluting the database with test records.

> [!IMPORTANT]
> The `chiller_visit_cost` validation is now strictly enforced by the backend and should be clearly marked in the UI to avoid user frustration.
