# Business Red-Flush API

## Scope

Approved internal business orders can be red-flushed through dedicated endpoints. The first version supports whole-order red flush only.

External-source data must not participate in red flush. If an order has `is_external_source=true` or a non-empty `external_source_id`, the service rejects the red-flush operation even when the API request is otherwise valid.

## Endpoints

All endpoints require authentication and reuse the existing business order review/cancel employee permission checks.

| Order type | Method | Path |
| --- | --- | --- |
| Purchase order | POST | `/api/v1/purchase-orders/{id}/red-flush/` |
| Sales order | POST | `/api/v1/sales-orders/{id}/red-flush/` |
| Purchase return order | POST | `/api/v1/purchase-return-orders/{id}/red-flush/` |
| Sales return order | POST | `/api/v1/sales-return-orders/{id}/red-flush/` |
| Payment order | POST | `/api/v1/payment-orders/{id}/red-flush/` |
| Receipt order | POST | `/api/v1/receipt-orders/{id}/red-flush/` |

## Request Body

```json
{
  "reason": "录入错误，需要红冲"
}
```

`reason` is required and cannot be blank at the API layer.

## Success Response

Returns the refreshed order serializer with HTTP 200.

Important red-flush fields included in responses:

| Field | Description |
| --- | --- |
| `is_red_flushed` | Whether the source order has been red-flushed |
| `red_flush_id` | UUID audit batch ID for this red flush |
| `red_flushed_at` | Timestamp when the source order was marked red-flushed |

Example:

```json
{
  "id": 123,
  "status": 2,
  "is_red_flushed": true,
  "red_flush_id": "1c8e4c7a-6f2a-4d6b-8f8e-674a2d6b67f4",
  "red_flushed_at": "2026-06-12T10:00:00Z"
}
```

The source order `status` remains approved after red flush.

## Error Responses

| Condition | Status | Response shape |
| --- | --- | --- |
| Missing or blank `reason` | 400 | DRF serializer error, keyed by `reason` |
| Order not found in current merchant | 404 | Existing API not-found response |
| Order is not approved | 400 | `{ "error": "..." }` |
| Order already red-flushed | 400 | `{ "error": "..." }` |
| Order is external-source data | 400 | `{ "error": "外部来源...不允许红冲" }` |
| Service validation failure | 400 | `{ "error": "..." }` |

## Merchant Safety

The API first scopes order lookup by `request.user.employee.merchant`. The service layer also requires `merchant` and verifies that the order belongs to that merchant.

## Audit Notes

`red_flush_id` is written to the source order and related `BalanceChangeRecord` rows. It is also written to related `StockChangeRecord` rows when the source order actually has inventory records. Sales orders may be red-flushed without inventory records; in that case only the balance side is reversed. Existing `offset_to`/`offset_id` relationships remain the precise reverse-link mechanism for balance and stock records.

## Test Coverage

The dedicated regression suite is:

```bash
python manage.py test business.tests.test_red_flush_services api_v1.tests.BusinessRedFlushAPITestCase --settings=flower.settings_test
```

Coverage expectations:

- Service tests cover all six order types, balance reversal, inventory reversal, duplicate blocking, merchant isolation, missing balance/stock records, transaction rollback, and external payment/receipt rejection.
- API tests cover all six endpoints, required `reason`, employee permission rejection, merchant-scoped 404, non-approved orders, duplicate red flush, external payment/receipt rejection, stock-validation error mapping, sales red flush without stock records, and sampled balance/stock side effects.
