# Orders Note Specification

## Purpose

The Orders Note capability exposes a single write endpoint (`PUT /orders/{order}/note`) that updates the free-text annotation (`orders.notes`) of an existing order. It is the only surface that edits an order without triggering any financial recomputation, touching exactly one column. The annotation controls whether an order appears in the customer statistics "annotated orders" panel.

## Requirements

### Requirement: Admin Authentication

The system SHALL require an authenticated admin session for all requests to `PUT /orders/{order}/note`; unauthenticated requests SHALL be redirected to `auth/login` with HTTP 302. (Implemented in `routes/web.php:24-28,74`)

#### Scenario: Unauthenticated request is rejected

- **GIVEN** a request with no active admin session
- **WHEN** `PUT /orders/{order}/note` is called
- **THEN** the system responds with `302` redirecting to `auth/login`

### Requirement: CSRF Validation

The system SHALL enforce CSRF token validation on `PUT /orders/{order}/note` via Laravel's `web` middleware; a missing or expired token SHALL result in HTTP 419. (Implemented in `routes/web.php:74`, `resources/views/pages/customer-statis.blade.php:183`)

#### Scenario: Missing CSRF token is rejected

- **GIVEN** an authenticated admin session
- **WHEN** `PUT /orders/{order}/note` is submitted without a valid `_token` field
- **THEN** the system responds with HTTP 419

### Requirement: Note Update

The system SHALL update `orders.notes` to the submitted value and redirect back to the referring page with a success flash when a valid request is received for an existing order. (Implemented in `app/Http/Controllers/OrderController.php:342-356`)

#### Scenario: Note is saved and user is redirected

- **GIVEN** an authenticated admin and an existing order with id `42`
- **WHEN** `PUT /orders/42/note` is submitted with `notes="Repack separately"`
- **THEN** `orders.notes` is set to `"Repack separately"`, the response is HTTP 302 redirecting back, and an `admin_toastr` success flash (`Cập nhật thành công`) is visible on the referring page

### Requirement: Note Clearing

The system SHALL accept an absent or empty `notes` field and persist it as null/empty, clearing the annotation without a validation error. (Implemented in `app/Http/Controllers/OrderController.php:344-346`)

#### Scenario: Empty note clears the annotation

- **GIVEN** an authenticated admin and an existing order whose `notes` column is non-null
- **WHEN** `PUT /orders/{order}/note` is submitted with `notes` absent or empty
- **THEN** `orders.notes` is set to null/empty, the response is HTTP 302 redirecting back with a success flash, and no validation error is raised

### Requirement: Non-String Note Rejection

The system SHALL reject a `notes` value that is not a string (e.g. an array), redirect back with a validation error bag, and perform no write. (Implemented in `app/Http/Controllers/OrderController.php:344-346`)

#### Scenario: Non-string value triggers validation failure

- **GIVEN** an authenticated admin and an existing order
- **WHEN** `PUT /orders/{order}/note` is submitted with `notes` set to a non-string value
- **THEN** the `nullable|string` validation fails, `orders.notes` is not changed, and the response is a redirect back carrying the validation error bag

### Requirement: Unknown Order Returns 404

The system SHALL return HTTP 404 when the `order` path parameter does not correspond to an existing order. (Implemented in `app/Http/Controllers/OrderController.php:348`)

#### Scenario: Non-existent order id yields 404

- **GIVEN** an authenticated admin
- **WHEN** `PUT /orders/99999/note` is submitted for an id that does not exist in the `orders` table
- **THEN** the system responds with HTTP 404

### Requirement: Save Failure Redirect

The system SHALL redirect back with the old input and an error message (`Cập nhật thất bại`) when `save()` returns false, without updating `orders.notes`. (Implemented in `app/Http/Controllers/OrderController.php:355`)

#### Scenario: Failed save returns error redirect

- **GIVEN** an authenticated admin, an existing order, and a condition that causes `save()` to return false
- **WHEN** `PUT /orders/{order}/note` is submitted with a valid `notes` value
- **THEN** `orders.notes` is not changed, the response is a redirect back carrying old input, and the `Cập nhật thất bại` error is present

### Requirement: Column Isolation

The system SHALL mutate only the `orders.notes` column; no other column (totals, status, debt, points, pivots) SHALL be modified by this endpoint, enforced by `Order::$fillable`. (Implemented in `app/Models/Order.php:11`, `app/Http/Controllers/OrderController.php:349`)

#### Scenario: Extra submitted fields are not persisted

- **GIVEN** an authenticated admin and an existing order
- **WHEN** `PUT /orders/{order}/note` is submitted with `notes` plus additional fields such as `total` or `status`
- **THEN** only `orders.notes` changes; all other columns retain their original values

### Requirement: No Order Status Guard

The system SHALL allow note edits on any order regardless of its status, age, or editability flag; no `is_editable`, draft, or 24-hour check SHALL be applied. (Implemented in `app/Http/Controllers/OrderController.php:342-356`)

#### Scenario: Note is editable on a finalized order

- **GIVEN** an authenticated admin and an order whose status would block edits in the full order-update flow
- **WHEN** `PUT /orders/{order}/note` is submitted with a valid `notes` value
- **THEN** `orders.notes` is updated and the response is a redirect back with a success flash

### Requirement: Redirect-Back Contract

The system SHALL always respond with an HTTP 302 redirect back to the referring page (success or failure); it SHALL NOT return a JSON body for any outcome. (Implemented in `app/Http/Controllers/OrderController.php:353,355`)

#### Scenario: Success response is a redirect, not JSON

- **GIVEN** an authenticated admin and an existing order
- **WHEN** `PUT /orders/{order}/note` is submitted successfully
- **THEN** the response is HTTP 302 with a `Location` header pointing back to the referring page, and no JSON body is returned

#### Scenario: Validation failure response is a redirect, not JSON

- **GIVEN** an authenticated admin and an existing order
- **WHEN** `PUT /orders/{order}/note` is submitted with a non-string `notes` value
- **THEN** the response is HTTP 302 redirecting back with errors, and no JSON body is returned
