# Deploy — Product Management + Pending Services Review

## 1. Files to upload (MODIFIED — no new files)

| File | What changed |
|---|---|
| `includes/shares.php` | Gate engine: KYC + area checks, per-request caching, `product_gate_payload()`, `product_gate_message()` |
| `category.php` | Purchase-gate popup (KYC / Available Area), blocked "Buy Now" states, server-side re-check at checkout |
| `admin/product_management.php` | Server-side >100% share guard, textarea binding fix, Rejected status support, updated info panel |
| `admin/pending_services.php` | Full request details, Edit modal, Reject-with-reason, Pending/Rejected tabs, audit log |
| `seller/services.php` | Rejected badge + reason shown to the seller; resubmit clears the reason |
| `newproductmigration.php` | New columns, indexes, company-share backfill |

**Upload order:** `includes/shares.php` → `category.php` → `admin/product_management.php` → `admin/pending_services.php` → `seller/services.php` → `newproductmigration.php`

## 2. Run the migration

Open once on the live server:

```
https://yourdomain.com/newproductmigration.php
```

**Delete the file afterwards.**

### What the migration adds

**Columns on `seller_services` AND `agency_services`:**

| Column | Type | Purpose |
|---|---|---|
| `seller_share_pct` | `DECIMAL(5,2) DEFAULT 0.00` | Seller share % |
| `subscription_discount_pct` | `DECIMAL(5,2) DEFAULT 0.00` | Subscriber discount % |
| `referral_share_pct` | `DECIMAL(5,2) DEFAULT 0.00` | Referral share % |
| `staff_share_pct` | `DECIMAL(5,2) DEFAULT 0.00` | Staff share % |
| `company_share_pct` | `DECIMAL(5,2) DEFAULT 0.00` | **Auto-calculated — never entered by hand** |
| `required_kyc` | `VARCHAR(255) NULL` | CSV of required KYC sections, e.g. `personal,address` |
| `area_mode` | `VARCHAR(20) DEFAULT 'all'` | `all` \| `single` \| `bulk` |

**Review-workflow columns on `seller_services`:**

| Column | Type | Purpose |
|---|---|---|
| `rejection_reason` | `TEXT NULL` | Why the admin rejected it — shown to the seller |
| `reviewed_by` | `INT NULL` | Admin user id |
| `reviewed_by_name` | `VARCHAR(120) NULL` | Admin name |
| `reviewed_at` | `DATETIME NULL` | When it was approved/rejected |
| `submitted_at` | `DATETIME NULL` | Reserved for resubmission tracking |

Plus index `idx_ss_status (status)`.

**`seller_services.status` values:** `0` = pending review, `1` = approved / live, `2` = rejected (kept, not deleted).

**Columns on `users`** (safety net — normally already present from `migration.php`):
`pincode VARCHAR(20)`, `is_subscribed TINYINT(1)`, `referred_by INT NULL`

**New tables:**

- `product_notes` — notes against a product
- `product_update_history` — audit log of every field change
- `product_areas` — serviceable pincodes  
  `(id, service_id, service_type, pincode, created_at)`  
  unique `(service_id, service_type, pincode)`, indexes on `(service_type, service_id)` and `(pincode)`
- `product_share_ledger` — every share paid out per purchase, indexed on `service_id`, `order_id`, `share_type`

**Data backfill:**

- Products with all shares `0` → `company_share_pct = 100`
- All other products → `company_share_pct` re-synced to the remainder

## 3. How it works now

### Company Share (auto)

```
company_share_pct = 100 − (seller + subscription discount + referral + staff)
```

- Field is **read-only** in the Update modal (grey, not editable)
- Recalculated live in the browser as you type
- Recalculated again on the server on save — the posted value is ignored
- Saving is **rejected** if the four editable shares total more than 100%
- Amounts are calculated on the **discount price** (selling price)

**Example — discount price ₹800:**

| Share | % | Amount |
|---|---|---|
| Seller | 40% | ₹320 |
| Subscription discount | 10% | ₹80 |
| Referral | 5% | ₹40 |
| Staff | 5% | ₹40 |
| **Company (auto)** | **40%** | **₹320** |
| | **100%** | **₹800** |

### Customer Data Recruitment → tab 1: Required KYC

Multi-select from your 4 KYC categories: Personal, Address, Bank, Business.

Buyer can purchase **only if** every ticked section is filled **and** KYC status is `approved`.

Otherwise the "Buy Now" button turns amber ("KYC Required") and the popup shows:

- a per-section checklist — green = Filled, red = Not filled
- the approval status badge
- the admin's rejection remark, if any
- a "Complete KYC now" button → `profile.php#kyc`

Popup messages by state:

| State | Message |
|---|---|
| Half / not filled | "Please fill these KYC section(s) first: … Purchase unlocks once admin approves them." |
| Filled, not approved | "Your KYC is submitted but not approved yet." |
| Rejected | "Your KYC was rejected. Please correct and resubmit." |

### Customer Data Recruitment → tab 2: Available Area

Three modes:

- **All India** — no restriction (deletes any saved pincodes)
- **Single** — one pincode
- **Bulk** — paste many (comma / space / newline separated) **or** upload a `.txt` / `.csv`

Matching is against the user's **registration pincode** (`users.pincode`, falling back to their KYC address pincode).

Example: product set to `700010` → only users registered with pincode `700010` see "Buy Now". Everyone else gets a grey button "Not available in your area" and a popup explaining it.

### Security

The gates are re-checked **server-side** in `category.php` before any wallet debit or Razorpay verification, so a forged/hidden form cannot bypass the popup.

## 4. Pending Services — review workflow

### Two tabs

**Pending Review** (status 0) and **Rejected** (status 2), each with a live count badge. Category and seller filters carry across both tabs.

### Every request card shows

Header: request no. `#REQ-00123`, status chip, category + sub-category chips, service name, seller business name, submitted date/time, price (with % off), and the action buttons.

Expand (chevron) to see **everything the seller submitted**:

- full description, exactly as typed (scrollable, line breaks preserved)
- Website / App / Tutorial links as clickable buttons, or "Not provided"
- a full field table — request id, name, category + id, sub-category + id, MRP, discount price, icon/image path, image mode, card colour, submitted on, last reviewed by/when
- seller card — business name, name, seller id, phone, email, plus Call and WhatsApp buttons
- **customer card preview** — exactly how the product will look on the storefront

### 3 action buttons

| Button | What it does |
|---|---|
| **Edit** (blue) | Opens the full edit modal |
| **Approve** (green) | `status = 1`, goes live immediately, records who approved and when |
| **Reject** (red) | Opens the reason modal |

On the **Rejected** tab, Reject is replaced by **Restore** (back to pending) and a **Delete** icon (permanent, with the image file removed).

### Edit modal

Admin can change **anything** the seller submitted:

- Category and Sub Category (the sub-category list re-filters automatically per category)
- Service name, description (with a live character count)
- MRP and Discount Price, with live savings calculation. If the discount is above the MRP the field turns red and **both save buttons are disabled** — also re-checked on the server.
- Government Portals (category 1) hide pricing entirely and are forced to ₹0.00
- Image — live preview, upload a replacement, or type a Font Awesome class / image URL
- Card colour, Website / App / Tutorial URLs
- **Change history** at the bottom — every earlier admin edit

Two save buttons: **Save Changes** (stays pending) and **Save & Approve** (saves and goes live in one step).

Every changed field is written to `product_update_history` as `Admin edit — <field>` with the old and new value, so nothing is silently altered.

### Reject with reason

Reason is **mandatory** — rejecting with an empty box is blocked server-side. Six one-click quick reasons are available (poor image, incomplete description, wrong pricing, wrong category, broken link, duplicate).

On reject:

- the record is **kept**, `status = 2`, reason and reviewer stored
- a notification row is inserted for the seller
- in **Seller → Services** the row shows a red **Rejected** badge with the reason and the hint "Edit this service to fix it"
- when the seller edits and resubmits, status goes back to `0` and the old reason is cleared

## 5. Post-deploy check

1. Admin → Product Management → **Update** on any product. Set Seller 40, Subscription 10, Referral 5, Staff 5 → Company must show **40.00 %** and be uneditable. Save.
2. Try Seller 70 + Sub 20 + Ref 10 + Staff 5 (105%) → save must be **rejected** with an error.
3. **Customer Data** → Required KYC → tick Personal + Address → Save.
4. Log in as a customer with incomplete KYC → the product shows "KYC Required" → popup lists the missing sections.
5. **Customer Data** → Available Area → Single → `700010` → Save.
6. Log in as a user registered with a different pincode → "Not available in your area".
7. Complete + approve KYC, use a `700010` user → "Buy Now" works, and `product_share_ledger` gets one row per share.
8. Seller panel → add a new service. Admin → **Pending Services** → the request appears; expand it and confirm every field the seller typed is visible.
9. **Edit** → change the description and set Discount Price above MRP → both save buttons must go grey. Fix it, then **Save Changes** → check the change history inside the modal.
10. **Reject** with an empty reason → blocked. Add a reason → the row moves to the **Rejected** tab.
11. Log in as that seller → the service shows **Rejected** with your reason. Edit and resubmit → it returns to the admin's **Pending** tab with the reason cleared.
12. **Save & Approve** on any pending request → it goes live and appears in Product Management as **Active**.
