# CRM Customer Status System — Implementation Plan

## Context

This project is a Vue/React + FastAPI + Firestore admin console located at `C:\development\bellsystems-cp`.

The frontend lives in `frontend/src/` and the backend in `backend/`.
The CRM module is at `frontend/src/crm/` and `backend/crm/`.

Currently, customers have two flat boolean flags on their Firestore document:
- `negotiating: bool`
- `has_problem: bool`

These need to be replaced with a richer, structured system as described below.

---

## 1. Target Data Model

### 1A. On the Customer Document (`customers/{id}`)

Remove `negotiating` and `has_problem`. Add the following:

```
relationship_status: string
  — one of: "lead" | "prospect" | "active" | "inactive" | "churned"
  — default: "lead"

technical_issues: array of {
  active: bool,
  opened_date: Firestore Timestamp,
  resolved_date: Firestore Timestamp | null,
  note: string,
  opened_by: string,       ← display name or user ID of staff member
  resolved_by: string | null
}

install_support: array of {
  active: bool,
  opened_date: Firestore Timestamp,
  resolved_date: Firestore Timestamp | null,
  note: string,
  opened_by: string,
  resolved_by: string | null
}

transaction_history: array of {
  date: Firestore Timestamp,
  flow: string,            ← "invoice" | "payment" | "refund" | "credit"
  payment_type: string | null,  ← "cash" | "bank_transfer" | "card" | "paypal" — null for invoices
  category: string,        ← "full_payment" | "advance" | "installment"
  amount: number,
  currency: string,        ← default "EUR"
  invoice_ref: string | null,
  order_ref: string | null,    ← references an order document ID, nullable
  recorded_by: string,
  note: string
}
```

### 1B. Orders Subcollection (`customers/{id}/orders/{order_id}`)

Orders live **exclusively** as a subcollection under each customer. There is no top-level `orders`
collection. The existing top-level `orders` collection in Firestore and its corresponding backend
routes should be **removed entirely** and replaced with subcollection-based routes under
`/crm/customers/{customer_id}/orders/`.

If cross-customer order querying is ever needed in the future, use Firestore's native
`collectionGroup("orders")` query — no top-level mirror collection is required.

Each order document carries the following fields:

```
order_number: string          ← e.g. "ORD-2026-041"  (already exists — keep)
title: string                 ← NEW: human-readable name e.g. "3x Wall Mount Units - Athens Office"
created_by: string            ← NEW: staff user ID or display name

status: string                ← REPLACE existing OrderStatus enum with new values:
  — "negotiating" | "awaiting_quotation" | "awaiting_customer_confirmation"
  | "awaiting_fulfilment" | "awaiting_payment" | "manufacturing"
  | "shipped" | "installed" | "declined" | "complete"

status_updated_date: Firestore Timestamp   ← NEW
status_updated_by: string                  ← NEW

payment_status: object {                   ← NEW — replaces the flat PaymentStatus enum
  required_amount: number,
  received_amount: number,       ← computed from transaction_history where order_ref matches
  balance_due: number,           ← computed: required_amount - received_amount
  advance_required: bool,
  advance_amount: number | null,
  payment_complete: bool
}

timeline: array of {            ← NEW — order event log
  date: Firestore Timestamp,
  type: string,  ← "quote_request" | "quote_sent" | "quote_accepted" | "quote_declined"
                    | "mfg_started" | "mfg_complete" | "order_shipped" | "installed"
                    | "payment_received" | "invoice_sent" | "note"
  note: string,
  updated_by: string
}
```

---

## 2. Backend Changes

### 2A. `backend/crm/models.py`

- **Remove** `negotiating: bool` and `has_problem: bool` from `CustomerCreate` and `CustomerUpdate`.
- **Add** `relationship_status: Optional[str] = "lead"` to `CustomerCreate` and `CustomerUpdate`.
- **Add** `technical_issues: List[dict] = []` to `CustomerCreate` and `CustomerUpdate`.
- **Add** `install_support: List[dict] = []` to `CustomerCreate` and `CustomerUpdate`.
- **Add** `transaction_history: List[dict] = []` to `CustomerCreate` and `CustomerUpdate`.
- **Add** proper Pydantic models for each of the above array item shapes:
  - `TechnicalIssue` model
  - `InstallSupportEntry` model
  - `TransactionEntry` model
- **Update** `OrderStatus` enum with the new values:
  `negotiating`, `awaiting_quotation`, `awaiting_customer_confirmation`,
  `awaiting_fulfilment`, `awaiting_payment`, `manufacturing`,
  `shipped`, `installed`, `declined`, `complete`
- **Replace** the flat `PaymentStatus` enum on `OrderCreate` / `OrderUpdate` with a new `OrderPaymentStatus` Pydantic model matching the structure above.
- **Add** `title: Optional[str]`, `created_by: Optional[str]`, `status_updated_date: Optional[str]`,
  `status_updated_by: Optional[str]`, and `timeline: List[dict] = []` to `OrderCreate` and `OrderUpdate`.

### 2B. `backend/crm/customers_router.py`

- Update any route that reads/writes `negotiating` or `has_problem` to use the new fields.
- Add new dedicated endpoints:

```
POST   /crm/customers/{id}/technical-issues
  — body: { note: str, opened_by: str }
  — appends a new active issue to the array

PATCH  /crm/customers/{id}/technical-issues/{index}/resolve
  — body: { resolved_by: str }
  — sets active=false and resolved_date=now on the item at that index

POST   /crm/customers/{id}/install-support
  — same pattern as technical-issues above

PATCH  /crm/customers/{id}/install-support/{index}/resolve
  — same as technical-issues resolve

POST   /crm/customers/{id}/transactions
  — body: TransactionEntry (see model above)
  — appends to transaction_history

PATCH  /crm/customers/{id}/relationship-status
  — body: { status: str }
  — updates relationship_status field
```

### 2C. `backend/crm/orders_router.py`

- **Remove** all top-level `/crm/orders/` routes entirely.
- Re-implement all order CRUD under `/crm/customers/{customer_id}/orders/`:

```
GET    /crm/customers/{customer_id}/orders/
POST   /crm/customers/{customer_id}/orders/
GET    /crm/customers/{customer_id}/orders/{order_id}
PATCH  /crm/customers/{customer_id}/orders/{order_id}
DELETE /crm/customers/{customer_id}/orders/{order_id}
```

- Add endpoint to append a timeline event:

```
POST   /crm/customers/{customer_id}/orders/{order_id}/timeline
  — body: { type: str, note: str, updated_by: str }
  — appends to the timeline array and updates status_updated_date + status_updated_by
```

- Add endpoint to update payment status:

```
PATCH  /crm/customers/{customer_id}/orders/{order_id}/payment-status
  — body: OrderPaymentStatus fields (partial update allowed)
```

- Add a dedicated "Init Negotiations" endpoint:

```
POST   /crm/customers/{customer_id}/orders/init-negotiations
  — body: { title: str, note: str, date: datetime, created_by: str }
  — creates a new order with status="negotiating", auto-fills all other fields
  — simultaneously updates the customer's relationship_status to "active"
    (only if currently "lead" or "prospect" — do not downgrade an already "active" customer)
  — returns the newly created order document
```

---

## 3. Frontend Changes

### 3A. `frontend/src/crm/customers/CustomerList.jsx`

- When Notes: Quick filter is set, replace the `negotiating` and `has_problem` boolean badge display in the Status column with:
  - A **relationship status chip** (color-coded pill: lead=grey, prospect=blue, active=green, inactive=amber, churned=soft red)
  - A small **red dot / warning icon** if `technical_issues.some(i => i.active)` is true, under a new "Support" column. Add this column to the list of arrangeable and toggleable columns.
  - A small **amber dot / support icon** if `install_support.some(i => i.active)` is true, under the same "Support" column.
  - These are derived from the arrays — do not store a separate boolean on the document.
- When Notes: Expanded filter is set, replace the `negotiating` and `has_problem` verbose displays with the active order status (if any) in this format:
  `"<Status Label> — <Date> — <Note>"` e.g. `"Negotiating — 24.03.26 — Customer requested a more affordable quotation"`

### 3B. `frontend/src/crm/customers/CustomerDetail.jsx`

The customer detail page currently has a tab structure: Overview, Orders, Quotations, Communication, Files & Media, Devices.

Make the following changes:

#### Whole page
- On the top of the page where we display the name, organization and full address, change it to:
  Line 1: `Full Title + Name + Surname`
  Line 2: `Organization · City` (city only, not full address)
- Remove the horizontal separation line after the title and before the tabs.
- On the top right side, there is an Edit Customer button. To its left, add **3 new buttons** in this
  order (left → right): **Init Negotiations**, **Record Issue/Support**, **Record Payment**, then
  the existing Edit button. All 4 buttons are the same size. Add solid single-color icons to each.

  **"Init Negotiations" button** (blue/indigo accent):
  - Opens a mini modal.
  - Fields: Date (defaults to NOW), Title (text input, required), Note (textarea, optional).
  - Auto-filled server-side: `status = "negotiating"`, `created_by` = current user,
    `status_updated_date` = now, `status_updated_by` = current user,
    `payment_status` defaults to zeroed object.
  - On confirm: calls `POST /crm/customers/{id}/orders/init-negotiations`.
  - After success: refreshes customer data and orders list. The customer's `relationship_status`
    is set to `"active"` server-side — no separate frontend call needed.
  - This is a fast-entry shortcut only. All subsequent edits to this order happen via the Orders tab.

  **"Record Issue/Support" button** (amber/orange accent):
  - Opens a mini modal.
  - At the top: a **2-button toggle selector** (not a dropdown) to choose: `Technical Issue` | `Install Support`.
  - Fields: Date (defaults to NOW), Note (textarea, required).
  - On confirm: calls `POST /crm/customers/{id}/technical-issues` or
    `POST /crm/customers/{id}/install-support` depending on selection.

  **"Record Payment" button** (green accent):
  - Opens a mini modal.
  - Fields: Date (defaults to NOW), Payment Type (cash | bank transfer | card | paypal),
    Category (full payment | advance | installment), Amount (number), Currency (defaults to EUR),
    Invoice Ref (searchable over the customer's invoices, optional),
    Order Ref (searchable/selectable from the customer's orders, optional),
    Note (textarea, optional).
  - On confirm: calls `POST /crm/customers/{id}/transactions`.

#### Overview Tab
- The main hero section gets a complete overhaul — start fresh:
  - **Row 1 — Relationship Status selector**: The 5 statuses (`lead | prospect | active | inactive | churned`) as styled pill/tab buttons in a row. Current status is highlighted with a glow effect. Color-code using global CSS variables (add to `index.css` if not already present). Clicking a status immediately calls `PATCH /crm/customers/{id}/relationship-status`.
  - **Row 2 — Customer info**: All fields except Name and Organization (shown in page header). Include language, religion, tags, etc.
  - **Row 3 — Contacts**: All contact entries (phone, email, WhatsApp, etc.).
  - **Row 4 — Notes**: Responsive column grid. 1 column below 1100px, 2 columns 1100–2000px, 3 columns above 2000px. Masonry/wrap layout with no gaps between note cards.
- Move the Latest Orders section to just below the hero section, before Latest Communications.
  Hide this section entirely if no orders exist for this customer.
- For all other sections (Latest Communications, Latest Quotations, Devices): hide each section
  entirely if it has no data. Show dynamically when data exists.

#### New "Support" Tab (add to TABS array, after Overview)
Two full-width section cards:

  **Technical Issues Card**
  - Header shows active count badge (e.g. "2 active")
  - All issues listed, newest first (active and resolved)
  - Each row: colored status dot, opened date, note, opened_by — "Resolve" button if active
  - If more than 5 items: list is scrollable (fixed max-height), does not expand the page
  - "Report New Issue" button → small inline form with note field + submit

  **Install Support Card**
  - Identical structure to Technical Issues card
  - Same scrollable behavior if more than 5 items

#### New "Financials" Tab (add to TABS array, after Support)
Two sections:

  **Active Order Payment Status** (shown only if an active order exists)
  - required_amount, received_amount, balance_due
  - Advance required indicator + advance amount if applicable
  - Payment complete indicator

  **Transaction History**
  - Ledger table: Date | Flow | Amount | Currency | Method | Category | Order Ref | Invoice Ref | Note | Recorded By | Actions
  - "Add Transaction" button → modal with all TransactionEntry fields
  - Totals row: Total Invoiced vs Total Paid vs Outstanding Balance
  - Each row: right-aligned **Actions** button (consistent with other tables in the project)
    with options: **Edit** (opens edit form) and **Delete** (requires confirmation dialog)

#### Orders Tab (existing — update in place)
- Each order card/row shows:
  - `title` as primary heading
  - `status` with human-readable label and color coding (see Section 4)
  - `payment_status` summary: required / received / balance due
  - **"View Timeline"** toggle: expands a vertical event log below the order card
  - **"Add Timeline Event"** button: small inline form with type dropdown + note field
- Update all API calls to use `/crm/customers/{customer_id}/orders/` routes.

### 3C. `frontend/src/crm/customers/CustomerForm.jsx`

- Remove `negotiating` and `has_problem` fields.
- Add `relationship_status` dropdown (default: `"lead"`).
- No issue/transaction forms needed here — managed from the detail page.

### 3D. `frontend/src/crm/orders/OrderForm.jsx` and `OrderDetail.jsx`

- Update status dropdown with new values and labels:
  - `negotiating` → "Negotiating"
  - `awaiting_quotation` → "Awaiting Quotation"
  - `awaiting_customer_confirmation` → "Awaiting Customer Confirmation"
  - `awaiting_fulfilment` → "Awaiting Fulfilment"
  - `awaiting_payment` → "Awaiting Payment"
  - `manufacturing` → "Manufacturing"
  - `shipped` → "Shipped"
  - `installed` → "Installed"
  - `declined` → "Declined"
  - `complete` → "Complete"
- Add `title` input field (required).
- Replace flat `payment_status` enum with the new `payment_status` object fields.
- Add Timeline section to `OrderDetail.jsx`: vertical event log + add-entry inline form.
- Update all API calls to use `/crm/customers/{customer_id}/orders/` routes.

---

## 4. Status Color Coding Reference

Define all as CSS variables in `index.css` and use consistently across all views:

### Relationship Status
| Status | Color |
|---|---|
| lead | grey / muted |
| prospect | blue |
| active | green |
| inactive | amber |
| churned | dark or soft red |

### Order Status
| Status | Color |
|---|---|
| negotiating | blue |
| awaiting_quotation | purple |
| awaiting_customer_confirmation | indigo |
| awaiting_fulfilment | amber |
| awaiting_payment | orange |
| manufacturing | cyan |
| shipped | teal |
| installed | green |
| declined | red |
| complete | muted/grey |

### Issue / Support Flags
| State | Color |
|---|---|
| active issue | red |
| active support | amber |
| resolved | muted/grey |

---

## 5. Migration Notes

- The old `negotiating` and `has_problem` fields will remain in Firestore until the migration script is run. The backend should **read both old and new fields** during the transition period, preferring the new structure if present.
- A one-time migration script (`backend/migrate_customer_flags.py`) should:
  1. Read all customer documents
  2. If `negotiating: true` → create an order in the customer's `orders` subcollection with `status = "negotiating"` and set `relationship_status = "active"` on the customer
  3. If `has_problem: true` → append one entry to `technical_issues` with `active: true`, `opened_date: customer.updated_at`, `note: "Migrated from legacy has_problem flag"`, `opened_by: "system"`
  4. Remove `negotiating` and `has_problem` from the customer document
- Do **not** run the migration script until all frontend and backend changes are deployed and tested.

---

## 6. File Summary — What to Touch

```
backend/crm/models.py                  ← model updates (primary changes)
backend/crm/customers_router.py        ← new endpoints + field updates
backend/crm/orders_router.py           ← remove top-level routes, re-implement as subcollection,
                                          add timeline + payment-status + init-negotiations endpoints
backend/migrate_customer_flags.py      ← NEW one-time migration script

frontend/src/index.css                         ← add CSS variables for all new status colors
frontend/src/crm/customers/CustomerList.jsx    ← relationship status chip + support flag dots column
frontend/src/crm/customers/CustomerDetail.jsx  ← page header, 3 new quick-entry buttons + modals,
                                                  Overview tab overhaul, new Support tab,
                                                  new Financials tab, Orders tab updates
frontend/src/crm/customers/CustomerForm.jsx    ← remove old flags, add relationship_status
frontend/src/crm/orders/OrderForm.jsx          ← new status values, title field, payment_status,
                                                  updated API route paths
frontend/src/crm/orders/OrderDetail.jsx        ← timeline section, updated status/payment,
                                                  updated API route paths
```

---

## 7. Do NOT Change (out of scope)

- Quotations system — leave as-is
- Communications / inbox — leave as-is
- Files & Media tab — leave as-is
- Devices tab — leave as-is
- Any other module outside `crm/`
