# Shipper Payments, Invoice Generation, and Favorites APIs

This document explains the enforced runtime flow for shipper invoice/payment lifecycle, shipment history, nearby drivers, and favorite transporter endpoints.

## Scope

- Shipper payment flow (`WALLET`, `CARD`, `CASH`, `CREDIT`)
- Invoice generation timing, settlement, and archive transition
- Shipment history endpoint
- Nearby drivers endpoint
- Shipper favorite transporter APIs

---

## 1) Required Payment Lifecycle (Enforced)

The backend now follows this strict sequence:

1. Trip reaches `COMPLETED`
2. Invoice is generated (`ISSUED`)
3. Payment is processed against that invoice
4. Record is archived (`is_archived=true`, `archived_at` set)

### Endpoints used

- `GET /api/shipper/wallet/`
- `POST /api/shipper/trips/{trip_id}/pay/`
- `POST /api/transporter/trips/{trip_id}/confirm-cash/` (for cash settlement completion)
- `GET /api/shipper/invoices/`
- `GET /api/shipper/invoices/{id}/`

### How amount is calculated

For the trip's accepted bid:

- use `counter_amount` when present
- otherwise use `amount`

### Preconditions

- Trip must be `COMPLETED`
- Invoice must exist for the trip (auto-created at completion if missing)

If trip is not completed, payment call is rejected.

### Method: `WALLET`

When shipper calls `POST /api/shipper/trips/{trip_id}/pay/`:

```json
{
  "method": "WALLET"
}
```

The server:

1. creates `Payment` with status `CAPTURED`
2. debits shipper wallet (`LedgerEntry: WALLET_DEBIT_PAYMENT`)
3. credits transporter wallet (`LedgerEntry: WALLET_CREDIT_EARNING`)
4. marks invoice as `PAID`
5. archives invoice (`is_archived=true`, `archived_at` timestamp)

### Method: `CARD`

When shipper calls `POST /api/shipper/trips/{trip_id}/pay/` with `CARD`:

1. payment is created with status `REQUIRES_ACTION`
2. invoice is linked to payment and remains `ISSUED` until capture
3. archive is not set until payment is captured/settled

Only the trip transporter (`trip.transporter` — bid winner) confirms via:

- `POST /api/transporter/trips/{trip_id}/confirm-card/`

Assigned fleet drivers cannot confirm. Shipper cannot call this endpoint.

### Method: `CASH`

When shipper calls `POST /api/shippe  r/trips/{trip_id}/pay/` with:

```json
{
  "method": "CASH"
}
```

The server:

1. creates `Payment` with status `PENDING_COD`
2. links existing `ISSUED` invoice to payment
3. waits for transporter confirmation

Then the trip transporter (`trip.transporter` only — not `assigned_driver`) confirms collection via:

- `POST /api/transporter/trips/{trip_id}/confirm-cash/`

On confirmation:

1. payment status becomes `CAPTURED`
2. transporter platform wallet credited (physical cash was collected in person; **shipper wallet is not debited**)
3. invoice status updated to `PAID`
4. invoice archived (`is_archived=true`, `archived_at` set)

### Method: `CREDIT`

When shipper calls pay with `CREDIT`:

1. payment becomes `CAPTURED` (credit terms)
2. transporter earning is recorded as `CREDIT_EARNING`
3. invoice becomes `PAID`
4. invoice is archived

---

## 2) Invoice Generation Timing

Invoice is generated when trip status becomes `COMPLETED` (driver/status flow or admin override to completed).

Status by method:

- On completion (before payment): `ISSUED`
- `WALLET` / `CREDIT` successful settlement: `PAID` + archived
- `CASH`: `ISSUED` until confirm-cash, then `PAID` + archived
- `CARD`: `ISSUED` while `REQUIRES_ACTION`/processing, archived only after successful capture

### Invoice retrieval endpoints

- `GET /api/shipper/invoices/`
- `GET /api/shipper/invoices/{id}/`

---

## 3) Shipment History

### Endpoint

- `GET /api/shipper/shipments/history/`

Returns shipper shipments in terminal statuses:

- `DELIVERED`
- `COMPLETED`
- `CLOSED`

---

## 4) Shipper Favorite Transporter APIs

These endpoints are shipper-authenticated.

### Add favorite transporter

- `POST /api/shipper/favorites/transporters/`

### List favorites

- `GET /api/shipper/favorites/transporters/`

### Remove favorite

- `DELETE /api/shipper/favorites/transporters/{id}/`

---

## 5) Idempotency and Safety Notes

- `POST /api/shipper/trips/{trip_id}/pay/` supports `Idempotency-Key` header.
- Server also prevents multiple active payments on the same trip.
- This avoids duplicate charges when client retries due to network issues.
- Archive fields are exposed in invoice responses: `is_archived`, `archived_at`.

---

## 6) Nearby Drivers API (Shipper)

This endpoint returns nearby **verified + active** transporters for a specific shipment using live Traccar positions.

### URL

- `GET /api/shipper/shipments/{shipment_id}/nearby-drivers/`

### Request

- Method: `GET`
- Auth: Shipper token required
- Path param: `shipment_id`
- Body: none
- Query params: none (radius is fixed on server at `5.0 km`)

Reference point used by server:

1. shipment pickup coordinates

### Response `200` (example)

```json
{
  "status_code": 200,
  "message": "Nearby verified active transporters retrieved successfully.",
  "error": null,
  "data": {
    "shipment_id": 21,
    "radius_km": 5.0,
    "reference": {
      "lat": 24.8607,
      "lon": 67.0011
    },
    "count": 1,
    "drivers": [
      {
        "transporter_id": 45,
        "email": "driver@example.com",
        "first_name": "Ali",
        "last_name": "Khan",
        "phone": "03001234567",
        "company_name": "Fast Fleet",
        "tc_id": "111",
        "distance_km": 0.234,
        "position": {
          "lat": 24.861,
          "lon": 67.002
        }
      }
    ]
  }
}
```

### Error cases

- `404`: shipment not found for this shipper
- `400`: missing reference coordinates or Traccar connection/response issue

---

## 7) Transporter Public Profile API (Shipper)

This endpoint returns transporter details for the bidding/profile sheet in mobile app, including:

- current vehicle (active + verified)
- recent ratings (latest 5)
- rating summary (`review_count`, `rating_sum`, `average_rating`)

`experience` is intentionally **not** returned.

### URL

- `GET /api/shipper/transporters/{transporter_id}/profile/`

### Request

- Method: `GET`
- Auth: Any authenticated user
- Path param: `transporter_id`
- Body: none

### Response `200` (example)

```json
{
  "status_code": 200,
  "message": "Transporter profile retrieved successfully.",
  "error": null,
  "data": {
    "transporter": {
      "id": 45,
      "email": "driver@example.com",
      "first_name": "Ali",
      "last_name": "Khan",
      "phone": "03001234567",
      "company_name": "Fast Fleet",
      "documents_verified": true
    },
    "current_vehicle": {
      "id": 10,
      "vehicle_type": "Flatbed",
      "registration_number": "TR-111",
      "is_active": true,
      "is_verified": true
    },
    "ratings": {
      "review_count": 12,
      "rating_sum": 53,
      "average_rating": 4.42,
      "recent_reviews": [
        {
          "id": 101,
          "rating": 5,
          "comment": "On time delivery",
          "shipper_name": "Ahmed Khan",
          "created_at": "2026-04-13T10:20:00Z"
        }
      ]
    }
  }
}
```

### Error cases

- `404`: transporter user not found
- `400`: user exists but is not a transporter
