# Provider Order Details

> This document describes how client reviews and chat are attached to orders on the provider side.

## 1. Reviews Included in Order Details

Client reviews are now **returned directly inside the order details** for both Service Orders and Urgent Orders. You do not need to make a separate API call to fetch a review for an order.

### How it Works:
- Both `ServiceOrder` and `UrgentOrder` use a polymorphic relationship (`providerReview`) to attach the client's review.
- The review object is nested directly inside the order response when a provider fetches an order.
- Each order can only have **one** review attached to it.
- **Service Orders:** Clients can submit a review once the order reaches the `completed` status.
- **Urgent Orders:** Clients can submit a review once the order reaches the `completed` status.

### Review Structure
If the client has submitted a review, it will be included in the order response and will contain:
- Overall `rating` (1-5 stars)
- Detailed ratings (`response_speed_rating`, `interaction_quality_rating`, `output_clarity_rating`, `general_satisfaction_rating`)
- Optional written `comment`

When a client submits a review, the provider will receive a push notification:
```json
{
  "notify_type": "review",
  "notify_id": "<review_id>"
}
```

---

## 2. Chat

A chat room is automatically created between the client and provider, and its details are also attached to the order response when:
- **Service Order (Standard):** Provider accepts the order.
- **Service Order (Negotiation):** Client pays the agreed negotiated price.
- **Urgent Order:** Provider accepts the dispatched order.

---

## 3. Negotiation APIs

The negotiation process is fully turn-based between the Provider and the Client. The APIs have been split into explicit action endpoints for clarity.

### Flow Overview

```
CLIENT                          PROVIDER
  │                                │
  │  POST /orders/service          │
  │  { is_negotiating: true,       │
  │    negotiation_price: 200 }    │
  │                                │
  │── Order created ──────────────>│
  │   status: pending_negotiation  │
  │   negotiation_turn: provider   │
  │   negotiation_price: 200       │
  │                                │
  │                    ┌───────────┴───────────┐
  │                    │     PROVIDER RESPONDS  │
  │                    └───────────┬───────────┘
  │                                │
  │              ┌─────────────────┼──────────────────┐
  │          /accept           /counter             /reject
  │              │                 │                   │
  │   turn→client, price=200   turn→client         status: cancelled
  │   status stays             price=350           (done)
  │   pending_negotiation          │
  │              │                 │
  │              └────────┬────────┘
  │                       │
  │              CLIENT RESPONDS (negotiation_turn = client):
  │                       │
  │              ┌────────┴────────┐
  │          /accept            /reject
  │  { payment_method,              │
  │    broker_code? }          status: cancelled
  │              │              (done)
  │              ▼
  │   Payment processed atomically
  │   status: active ✅
  │   (chat opened, broker commission created if applicable)
```

> **No `pending_payment` state.** Accept and payment are a single atomic action on the client side. If payment fails, the order stays at `pending_negotiation` and the client can retry.

---

### Key Rules

| Rule | Detail |
|---|---|
| Turn enforcement | Only the current turn's party can act |
| Price validation | All prices (initial + counter) must be within service `price_from` / `price_to` |
| Counter direction | Provider can counter → Client can only accept+pay or reject (no re-counter from client) |
| Payment timing | No money is taken until the client calls `/accept` with payment details |
| Chat | Opens **only after** successful payment on negotiated orders |
| Timeout | If a party doesn't respond within `negotiation_timeout_minutes`, the order is auto-cancelled and both parties are notified |

---

### Prerequisites
For **all** negotiation endpoints the order must satisfy:
- `status = pending_negotiation`
- `negotiation_turn = <provider|client>` (matches the caller's role)
- The authenticated user must own the order (`provider_id` or `client_id`)

---

### Provider APIs
**Base:** `POST /api/v1/provider/service-orders/{id}/negotiation/`

---

#### `POST /accept`
No body required.

**Result:** `negotiation_turn` → `client`, `negotiation_accepted_at` is set. Status stays `pending_negotiation` — client must now accept+pay to activate the order.
Client receives a push notification to proceed.

```json
{
  "status": true,
  "message": "Offer accepted. Waiting for client payment.",
  "data": {
    "id": 1,
    "status": "pending_negotiation",
    "negotiation_turn": "client",
    "negotiation_price": 200.00,
    "negotiation_accepted_at": 1726567200
  }
}
```

---

#### `POST /reject`
No body required.

**Result:** Order `status` → `cancelled`, `cancelled_at` is set.
Client receives a push notification that the offer was rejected.

```json
{
  "status": true,
  "message": "Offer rejected. The order has been cancelled.",
  "data": {
    "id": 1,
    "status": "cancelled",
    "cancelled_at": 1726567200
  }
}
```

---

#### `POST /counter`
**Body:**
```json
{ "counter_price": 350 }
```

> `counter_price` must be `>= 1` and within the service's configured `price_from` / `price_to` range (if set by admin).

**Result:** `negotiation_price` updated to the counter value, `negotiation_turn` → `client`. Status stays `pending_negotiation`.
Client receives a push notification with the new counter price.

```json
{
  "status": true,
  "message": "Counter-offer sent to client.",
  "data": {
    "id": 1,
    "status": "pending_negotiation",
    "negotiation_turn": "client",
    "negotiation_price": 350.00
  }
}
```

---

### Client APIs
**Base:** `POST /api/v1/client/orders/service/{id}/negotiation/`

---

#### `POST /accept`
Accept the provider's offer **and pay in one atomic request**. If payment fails, the order stays at `pending_negotiation` and the client can retry.

**Body:**
```json
{
  "payment_method": "wallet",
  "broker_code": "BROKER01"
}
```

| Field | Required | Description |
|---|---|---|
| `payment_method` | Yes | `wallet` or `online` |
| `brand` | If `online` | Payment brand (e.g. `visa`, `mada`) |
| `transaction_id` | If `online` | Gateway transaction ID (must be unique) |
| `broker_code` | No | Optional broker discount code |

**Result:** Payment processed, order `status` → `active`, chat room opened, broker commission created if applicable.

```json
{
  "status": true,
  "message": "Payment successful. Your order is now active.",
  "data": {
    "id": 1,
    "status": "active",
    "negotiation_price": 350.00,
    "paid_at": 1726567200,
    "accepted_at": 1726567200
  }
}
```

---

#### `POST /reject`
No body required.

**Result:** Order `status` → `cancelled`. Provider receives a push notification.

```json
{
  "status": true,
  "message": "Negotiation cancelled.",
  "data": {
    "id": 1,
    "status": "cancelled",
    "cancelled_at": 1726567200
  }
}
```


---

## 4. Reviews Received (Sidebar)

**`GET /api/v1/provider/reviews`**

Paginated list of all reviews the provider has received, combining service orders and urgent orders in one feed sorted by newest.

### Query Parameters

| Parameter | Type | Description |
|---|---|---|
| `rating` | `integer` | Filter by star rating (`1`–`5`) |
| `per_page` | `integer` | Items per page (default: `15`) |

### Response (`200 OK`)

```json
{
  "status": "success",
  "message": "Data retrieved successfully",
  "data": [
    {
      "id": 12,
      "rating": 5,
      "comment": "خدمة ممتازة وسريعة",
      "sub_ratings": {
        "response_speed": 5,
        "interaction_quality": 5,
        "output_clarity": 5,
        "general_satisfaction": 5
      },
      "created_at": 1726567200,
      "client_data": {
        "id": 7,
        "full_name": "أحمد محمد",
        "avatar": "https://cdn.example.com/avatars/7.jpg"
      },
      "order_data": {
        "id": 101,
        "order_number": "ORD-20260001",
        "order_category": "service_order"
      }
    },
    {
      "id": 9,
      "rating": 4,
      "comment": "استجابة جيدة",
      "sub_ratings": {
        "response_speed": 4,
        "interaction_quality": 4,
        "output_clarity": 3,
        "general_satisfaction": 4
      },
      "created_at": 1726480800,
      "client_data": {
        "id": 15,
        "full_name": "سارة علي",
        "avatar": null
      },
      "order_data": {
        "id": 55,
        "order_number": "URG-20260055",
        "order_category": "urgent_order"
      }
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 3,
    "per_page": 15,
    "total": 38
  }
}
```

### Deep-linking to the order

Use `order_data.order_category` + `order_data.id` to navigate from the review to its order:

```
order_data.order_category = "service_order"  →  GET /api/v1/provider/service-orders/{order_data.id}
order_data.order_category = "urgent_order"   →  GET /api/v1/provider/urgent-orders/{order_data.id}
```

---

## 5. Team Orders — Member Visibility

Team members (non-leaders) can now see team orders in their orders list and order detail. All action endpoints remain leader-only.

### How it works

- `GET /api/v1/provider/service-orders` — returns both the provider's individual orders **and** any team orders for teams they belong to (leader or member)
- `GET /api/v1/provider/service-orders/{id}` — same scope, members can fetch team order details

Action endpoints (`/accept`, `/reject`, `/start`, `/upload-files`, `/finish`) still require `provider_id = auth user` — a member calling any of these on a team order gets `404`.

### Notifications

When a team order is created:
- **Team leader** receives the standard new order notification — same as always, they must accept or reject it
- **Team members** receive a separate awareness notification informing them a new order arrived for their team and that the leader will handle it

Member notification content:
```
Title: طلب جديد لفريقك / New Order for Your Team
Body:  وصل طلب جديد لخدمة {service} لفريق {team}. سيتولى قائد الفريق متابعة الطلب واتخاذ الإجراءات اللازمة.
       A new order for {service} has been received for team {team}. Your team leader will handle and manage the order.
```

Both notifications carry `notify_type: "orders"` and `notify_id: <order_id>` for deep-linking.

### `is_team_leader` flag

Every order response now includes `is_team_leader`:

| Scenario | `is_team_leader` |
|---|---|
| Individual order (provider owns it) | `true` |
| Team order, authenticated user is the leader | `true` |
| Team order, authenticated user is a regular member | `false` |

```json
{
  "id": 88,
  "order_number": "ORD-20260088",
  "order_type": "team",
  "is_team_leader": false,
  "status": "active",
  "team_data": { "id": 3, "name": "فريق التصميم", "avatar": null },
  "..."
}
```

### Frontend rules

```
// All conditions below apply when: order_type === "team" && is_team_leader === false

// 1. Order action buttons — hide for members
//    Applies to: accept, reject, start, upload files, finish
if order_type === "team" && is_team_leader === false
  → hide: Accept / Reject / Start / Upload Files / Finish buttons

// 2. Negotiation action buttons — hide for members
//    Applies to: accept offer, counter offer, reject offer
if order_type === "team" && is_team_leader === false
  → hide: Accept Offer / Counter / Reject Offer buttons

// 3. Hint banner — always show when member is viewing a team order
if order_type === "team" && is_team_leader === false
  → show banner:
      AR: "هذا الطلب خاص بفريقك — قائد الفريق هو المسؤول عن إدارته"
      EN: "This order belongs to your team — the team leader is responsible for managing it"
```

In short: if `is_team_leader === false`, the member sees the order in **read-only mode** with no actionable buttons at all — whether it's a normal order or a negotiation order.


---

## 6. Push Notification Types Reference

Every push notification carries two routing keys:

- **`notify_type`** — specific type used by the app to deep-link to the right screen
- **`notify_id`** — the ID of the related entity (order, team, withdrawal request, etc.)

The filter tab in the notifications list is controlled separately by the category grouping below.

---

### `notify_type` Values & Routing

#### `service_order` → navigate to `/provider/service-orders/{notify_id}`

| Trigger | Who receives it |
|---|---|
| New service order created | Leader / assigned provider |
| New team order (awareness) | Team members (non-leaders) |
| Order accepted by provider | Client |
| Order rejected by provider | Client |
| Order started | Client |
| Order finished (provider done) | Client |
| Order activated | Client |
| Order completed | Client |
| Order confirmed by client | Provider |
| Order cancelled | Provider or client (other party) |
| Order auto-completed | Both client and provider |
| Revision requested | Provider |
| Negotiation accepted | Other party |
| Negotiation rejected | Other party |
| Negotiation countered | Client |
| Negotiation timed out | Both client and provider |
| Golden Guarantee filed | Admin (internal) |
| Golden Guarantee approved | Client + Provider |
| Golden Guarantee rejected | Client + Provider |

---

#### `urgent_order` → navigate to `/provider/urgent-orders/{notify_id}`

| Trigger | Who receives it |
|---|---|
| New urgent order dispatched | Nearby providers |
| Urgent order accepted | Client |
| Urgent order completed | Client |
| Urgent order cancelled | Other party |

---

#### `withdrawal_request` → navigate to withdrawal request detail `{notify_id}`

Filters under: **Financial** tab

| Trigger | Who receives it |
|---|---|
| Withdrawal request submitted | Provider (confirmation) |
| Withdrawal approved | Provider |
| Withdrawal rejected | Provider |
| New withdrawal request (admin) | Admin |

---

#### `team` → navigate to team detail `{notify_id}`

Filters under: **System** tab

| Trigger | Who receives it |
|---|---|
| Added to a team | Provider |
| Removed from a team | Provider |
| Promoted to team leader | Provider |
| Team leadership transferred away | Provider |

---




---

## 7. Provider Statistics

All endpoints under `/api/v1/provider/statistics/`. Auth required.

### Endpoints

| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/api/v1/provider/statistics/overview` | Lightweight KPI cards — fast dashboard home |
| `GET` | `/api/v1/provider/statistics/service-orders` | Service order breakdown + volume chart |
| `GET` | `/api/v1/provider/statistics/urgent-orders` | Urgent order breakdown + volume chart |
| `GET` | `/api/v1/provider/statistics/financials` | Wallet, earnings, withdrawals, chart |
| `GET` | `/api/v1/provider/statistics/earnings` | Period earnings breakdown. `?period=monthly&year=2026` or `?period=yearly` |
| `GET` | `/api/v1/provider/statistics/ratings` | Rating distribution + sub-rating averages |
| `GET` | `/api/v1/provider/statistics/team-performance` | Team stats (only if provider belongs to a team) |

---

### 7.1 Overview

**`GET /api/v1/provider/statistics/overview`**

```json
{
  "service_orders": {
    "total": 82, "in_progress": 6, "completed": 71, "cancelled": 5,
    "completion_rate": 86.6, "completed_this_month": 8
  },
  "urgent_orders": {
    "total": 14, "in_progress": 1, "completed": 12, "cancelled": 1,
    "completion_rate": 85.7
  },
  "financials": {
    "wallet_balance": 3200.00,
    "pending_earnings": 450.00,
    "lifetime_earnings": 42800.00,
    "earnings_this_month": { "value": 2100.00, "previous": 1800.00, "change": 300.00, "change_pct": 16.7, "trend": "up" }
  },
  "ratings": { "average_rating": 4.6, "reviews_count": 58 },
  "recent_activity": { "...": "see 7.7" },
  "teams": { "count": 1, "team_orders": 30 }
}
```

> `teams` is only present if the provider belongs to at least one team.

> `earnings_this_month` is a delta object: `{ value, previous, change, change_pct, trend: "up|down|flat" }`.

---

### 7.2 Service Orders

**`GET /api/v1/provider/statistics/service-orders`**

```json
{
  "totals": {
    "all": 82, "pending": 3, "accepted": 2, "active": 1,
    "provider_finished": 0, "pending_admin_review": 0,
    "completed": 71, "cancelled_rejected": 5
  },
  "rates": { "completion_rate": 86.6, "cancellation_rate": 6.1 },
  "volume_chart": [
    { "period": "2026-08", "in_progress": 5, "completed": 9, "cancelled": 0 }
  ]
}
```

---

### 7.3 Urgent Orders

**`GET /api/v1/provider/statistics/urgent-orders`**

```json
{
  "totals": {
    "all": 14, "searching_for_provider": 0,
    "accepted": 1, "completed": 12, "cancelled": 1
  },
  "rates": { "completion_rate": 85.7, "cancellation_rate": 7.1 },
  "volume_chart": [
    { "period": "2026-08", "active": 1, "completed": 2, "cancelled": 0 }
  ]
}
```

---

### 7.4 Financials

**`GET /api/v1/provider/statistics/financials`**

```json
{
  "wallet_balance": 3200.00,
  "withdrawal_balance": 2800.00,
  "pending_earnings": 450.00,
  "total_wallet_credits": 48500.00,
  "total_wallet_debits": 5700.00,
  "lifetime_earnings": {
    "service_orders": 39400.00,
    "urgent_orders": 3400.00,
    "combined": 42800.00
  },
  "earnings_this_month": { "value": 2100.00, "previous": 1800.00, "change": 300.00, "change_pct": 16.7, "trend": "up" },
  "withdrawals": {
    "pending_count": 1, "pending_amount": 800.00,
    "approved_count": 8, "approved_amount": 4900.00,
    "rejected_count": 0
  },
  "earnings_chart": [
    { "period": "2026-08", "service_order_earnings": 1800.00, "urgent_order_earnings": 300.00, "total_earnings": 2100.00 }
  ]
}
```

> `provider_earnings` on service orders = `base_price - app_fee - package_provider_discount_amount`. Broker discount is absorbed by the platform — provider is never affected.

---

### 7.5 Earnings Breakdown

**`GET /api/v1/provider/statistics/earnings`**

| Param | Values | Description |
|---|---|---|
| `period` | `monthly` \| `yearly` | Group by month or year |
| `year` | integer | Required with `period=monthly` |

```json
{
  "period": "monthly",
  "year": 2026,
  "service_orders": [
    { "period": "2026-08", "orders_count": 9, "gross_revenue": 4500.00, "vat": 585.00, "net_earnings": 3600.00 }
  ],
  "urgent_orders": [
    { "period": "2026-08", "orders_count": 2, "earnings": 300.00 }
  ],
  "totals": {
    "so_gross": 39400.00, "so_vat": 5122.00, "so_net": 31520.00,
    "uo_earnings": 3400.00, "combined": 34920.00, "orders_count": 83
  }
}
```

---

### 7.6 Ratings

**`GET /api/v1/provider/statistics/ratings`**

```json
{
  "average_rating": 4.6,
  "reviews_count": 58,
  "rating_distribution": {
    "5": 38, "4": 12, "3": 5, "2": 2, "1": 1
  },
  "sub_rating_averages": {
    "response_speed": 4.7,
    "interaction_quality": 4.5,
    "output_clarity": 4.4,
    "general_satisfaction": 4.6
  }
}
```

`sub_rating_averages` shows the provider's average score across each dimension — useful for identifying specific areas for improvement.

---

### 7.7 Recent Activity (inside overview)

```json
{
  "latest_service_orders": [
    {
      "id": 101, "order_number": "ORD-20260001",
      "status": "completed", "amount": 420.00, "created_at": 1726567200,
      "client_data": { "id": 7, "full_name": "أحمد محمد" }
    }
  ],
  "latest_urgent_orders": [
    {
      "id": 55, "order_number": "URG-20260055",
      "status": "accepted", "amount": 230.00, "created_at": 1726480800,
      "client_data": { "id": 15, "full_name": "سارة علي" }
    }
  ]
}
```

All items include `id` for routing to the order detail screen.

---

### 7.8 Team Performance

**`GET /api/v1/provider/statistics/team-performance`**

Only available if the provider belongs to at least one team. Returns `is_team_member: false` otherwise.

```json
{
  "teams_count": 1,
  "teams": [
    {
      "team_data": { "id": 3, "name": "فريق التصميم" },
      "is_leader": true,
      "joined_at": "2026-07-01",
      "team_performance": {
        "total_orders": 30, "completed_orders": 25, "completion_rate": 83.3
      },
      "individual_vs_team": {
        "individual_orders": 52, "individual_completed": 46,
        "individual_completion_rate": 88.5,
        "team_orders": 30,
        "prefers_team_work": false
      }
    }
  ]
}
```

> `prefers_team_work: true` when the provider has more team orders than individual orders.
