# Collections Process Status Enhancement — Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** Add a collections process tracking workflow to `admin/collections.cgi` so dmoss can update invoice status (no contact, pending review, payment arrangements, paid, delete request, send for review) with automated email notifications, plus filter invoices by process status.

**Architecture:** Single new ENUM column `collections_process_status` on `career_center.invoices`. New AJAX action `update_process_status` in `collections.cgi` handles all 6 statuses. Three statuses trigger email notifications via `html_notify()`. Frontend gets a status dropdown in the detail panel and a filter dropdown in the filter row.

**Tech Stack:** Perl CGI, MySQL, JavaScript (vanilla), Tailwind CSS, `html_notify()` for email

---

## Context for Implementer

- **File:** `/var/www/vhosts/hbcuconnect.com/httpdocs/admin/collections.cgi` (~1075 lines)
- **Pattern:** Single-page AJAX app. Perl subroutines return JSON via `json_ok()` / `json_err()`. Frontend uses `fetch()` and `renderDetail()` to build HTML.
- **DB handle:** `$dbh` connects to `career_center` database
- **Auth:** `$USER` = `$ENV{'REMOTE_USER'}`, `$USER_INFO` = sales_contacts row
- **Email:** `html_notify($to, $from, $subject, $text, $from_name, $cc, $html)` from `niceMail.pl`
- **Logging:** `&logEvent($employer_id, $contact, $summary, $event, $dbh, $priority)` from `commonFuncs.pm`
- **CRITICAL:** After editing files, run `chown hbcuconnect:psacln` on every modified file
- **CRITICAL:** In `qq~` strings, escape `@` as `\@`, `$` in JS regex as `\$`

---

### Task 1: Add Database Column

**Step 1: Run ALTER TABLE**

```bash
mysql -h newdb.hbcuconnect.com -u $(perl -e 'require "lib/config.pl"; my $c = getConfiguration(); print $c->{CC_DB_USER}') -p$(perl -e 'require "lib/config.pl"; my $c = getConfiguration(); print $c->{CC_DB_PASS}') career_center -e "
ALTER TABLE invoices ADD COLUMN collections_process_status
  ENUM('no_contact','pending_review','payment_arrangements','paid','delete_requested','sent_for_review')
  DEFAULT NULL
  AFTER collections_protected_by;
"
```

Run from `/var/www/vhosts/hbcuconnect.com/httpdocs/admin/`.

**Step 2: Verify column exists**

```bash
mysql -h newdb.hbcuconnect.com -u [user] -p[pass] career_center -e "DESCRIBE invoices collections_process_status;"
```

Expected: One row showing the ENUM column with NULL default.

---

### Task 2: Add Action Dispatch + `updateProcessStatus` Subroutine

**Files:**
- Modify: `admin/collections.cgi:30-40` (action dispatch)
- Modify: `admin/collections.cgi` (add new subroutine after `markPaid`, before `printMain`)

**Step 1: Add dispatch entry**

In the action dispatch block (line 30-40), add a new `elsif` before the `else`:

```perl
elsif ($action eq 'update_process_status') { updateProcessStatus(); }
```

Add it right before the `else { printMain(); }` line.

**Step 2: Write the `updateProcessStatus` subroutine**

Insert after the `markPaid` subroutine (after line 578) and before `printMain`:

```perl
######################################################################
#### AJAX: update_process_status
######################################################################
sub updateProcessStatus {
    my $invoice_id = int($q->param('invoice_id') || 0);
    my $new_status = $q->param('process_status') || '';
    my $justification = $q->param('justification') || '';

    json_err('Missing invoice_id') unless $invoice_id;

    my %valid = map { $_ => 1 } qw(no_contact pending_review payment_arrangements paid delete_requested sent_for_review);
    json_err('Invalid status') unless $valid{$new_status};

    # Load invoice + employer data
    my $sth = $dbh->prepare("
        SELECT a.*, b.company_name, b.email AS contact_email, b.first_name, b.last_name,
               b.employer_id, DATE_FORMAT(a.due_date, '%m/%d/%Y') AS due_formatted,
               DATEDIFF(CURDATE(), a.due_date) AS days_overdue
        FROM invoices a
        JOIN employer_data b ON a.employer_id = b.employer_id
        WHERE a.invoice_id = ?
    ");
    $sth->execute($invoice_id);
    my $inv = $sth->fetchrow_hashref;
    json_err('Invoice not found') unless $inv;

    my $client_name = $inv->{actual_client} || $inv->{company_name} || 'Unknown';
    my $total_formatted = sprintf('%.2f', $inv->{total_price});
    my $original_sales = $inv->{split_commission} || $inv->{sales_person} || '';

    # Map status to display label
    my %labels = (
        no_contact           => 'No Contact Made',
        pending_review       => 'Pending Client Review',
        payment_arrangements => 'Payment Arrangements Made',
        paid                 => 'Paid',
        delete_requested     => 'Delete Requested',
        sent_for_review      => 'Sent for Review',
    );
    my $label = $labels{$new_status};

    # Handle each status
    if ($new_status eq 'paid') {
        # Mark as paid
        $sth = $dbh->prepare("UPDATE invoices SET paid_date = CURDATE(), collections_process_status = 'paid' WHERE invoice_id = ?");
        $sth->execute($invoice_id);
        &logEvent($inv->{employer_id}, $USER, "Payment Received", "Invoice #$invoice_id marked as paid (\$$total_formatted) via Collections Manager", $dbh);

        # Email full team: wrmoss, dmoss, original sales rep
        _notifyPaid($inv, $total_formatted, $client_name, $original_sales);

        json_ok({ message => "Invoice #$invoice_id marked as PAID. Team notified." });

    } elsif ($new_status eq 'delete_requested') {
        # Update status, email wrmoss for approval
        $sth = $dbh->prepare("UPDATE invoices SET collections_process_status = 'delete_requested' WHERE invoice_id = ?");
        $sth->execute($invoice_id);
        &logEvent($inv->{employer_id}, $USER, "Delete Requested", "Invoice #$invoice_id - deletion requested via Collections Manager. Justification: $justification", $dbh);

        _notifyDeleteRequest($inv, $total_formatted, $client_name, $justification);

        json_ok({ message => "Delete request sent to wrmoss for Invoice #$invoice_id." });

    } elsif ($new_status eq 'sent_for_review') {
        json_err('Justification is required for review requests') unless $justification;

        $sth = $dbh->prepare("UPDATE invoices SET collections_process_status = 'sent_for_review' WHERE invoice_id = ?");
        $sth->execute($invoice_id);
        &logEvent($inv->{employer_id}, $USER, "Sent for Review", "Invoice #$invoice_id sent for review. Justification: $justification", $dbh);

        _notifySentForReview($inv, $total_formatted, $client_name, $original_sales, $justification);

        json_ok({ message => "Invoice #$invoice_id sent for review. wrmoss and sales rep notified." });

    } else {
        # Simple status update (no_contact, pending_review, payment_arrangements)
        $sth = $dbh->prepare("UPDATE invoices SET collections_process_status = ? WHERE invoice_id = ?");
        $sth->execute($new_status, $invoice_id);
        &logEvent($inv->{employer_id}, $USER, "Collections Status Update", "Invoice #$invoice_id status changed to: $label", $dbh);

        json_ok({ message => "Invoice #$invoice_id status updated to: $label" });
    }
}
```

**Step 3: Syntax check**

```bash
cd /var/www/vhosts/hbcuconnect.com/httpdocs/admin && perl -c collections.cgi
```

Expected: `collections.cgi syntax OK`

---

### Task 3: Add Email Notification Helper Subroutines

**Files:**
- Modify: `admin/collections.cgi` (add 3 helper subs right after `updateProcessStatus`)

Insert these three subroutines immediately after `updateProcessStatus`:

**Step 1: `_notifyPaid` — full team notification**

```perl
sub _notifyPaid {
    my ($inv, $total_formatted, $client_name, $original_sales) = @_;
    my $invoice_id = $inv->{invoice_id};
    my $days = $inv->{days_overdue} || 0;

    my $html = qq~<!DOCTYPE html>
<html><head><meta charset="UTF-8"></head>
<body style="margin:0;padding:0;background-color:#f4f4f7;font-family:Arial,Helvetica,sans-serif;">
<table width="100%" cellpadding="0" cellspacing="0" style="background-color:#f4f4f7;padding:20px 0;">
<tr><td align="center">
<table width="700" cellpadding="0" cellspacing="0" style="background-color:#ffffff;border-radius:8px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,0.08);">
<tr><td style="background-color:#065f46;padding:25px 40px;text-align:center;">
    <img src="https://hbcuconnect.com/images/logoOverBlack.png" alt="HBCU Connect" width="180" style="width:180px;margin-bottom:12px;">
    <h1 style="color:#ffffff;font-size:22px;margin:0 0 4px 0;font-weight:700;">Invoice Collected!</h1>
    <p style="color:rgba(255,255,255,0.8);font-size:13px;margin:0;">Invoice #$invoice_id &mdash; $client_name</p>
</td></tr>
<tr><td style="padding:20px 40px;">
    <table width="100%" cellpadding="0" cellspacing="0"><tr>
        <td width="48%" style="text-align:center;padding:14px 8px;background-color:#ecfdf5;border-radius:8px;">
            <div style="font-size:28px;font-weight:700;color:#065f46;">\$$total_formatted</div>
            <div style="font-size:10px;color:#6b7280;text-transform:uppercase;">Amount Collected</div>
        </td>
        <td width="4%"></td>
        <td width="48%" style="text-align:center;padding:14px 8px;background-color:#f0fdf4;border-radius:8px;">
            <div style="font-size:28px;font-weight:700;color:#16a34a;">$days</div>
            <div style="font-size:10px;color:#6b7280;text-transform:uppercase;">Days Overdue at Collection</div>
        </td>
    </tr></table>
</td></tr>
<tr><td style="padding:10px 40px;">
    <div style="background-color:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;padding:14px 18px;">
        <div style="font-size:13px;font-weight:700;color:#065f46;margin-bottom:4px;">Payment received via Collections</div>
        <div style="font-size:12px;color:#555;line-height:1.4;">Marked as paid by $USER_INFO->{name} in the Collections Manager. Commission split with: $original_sales.</div>
    </div>
</td></tr>
<tr><td style="padding:25px 40px;text-align:center;">
    <a href="https://hbcuconnect.com/admin/invoice.cgi?invoice_id=$invoice_id" style="display:inline-block;background:linear-gradient(135deg,#065f46 0%,#064e3b 100%);color:#ffffff;text-decoration:none;padding:12px 30px;border-radius:6px;font-size:14px;font-weight:700;">View Invoice</a>
</td></tr>
<tr><td style="background-color:#f9fafb;padding:15px 40px;border-top:1px solid #e5e7eb;text-align:center;">
    <p style="font-size:11px;color:#999;margin:0;">Automated notification &bull; HBCU Connect Collections System</p>
</td></tr>
</table>
</td></tr></table>
</body></html>~;

    my $subject = "COLLECTED: Invoice #$invoice_id - $client_name (\$$total_formatted)";

    # Send to wrmoss
    html_notify('wrmoss\@hbcuconnect.com', 'collections\@hbcuconnect.com', $subject, $html, 'HBCU Collections');

    # Send to dmoss
    html_notify('dmoss\@hbcuconnect.com', 'collections\@hbcuconnect.com', $subject, $html, 'HBCU Collections');

    # Send to original sales rep
    if ($original_sales && $original_sales ne 'dmoss' && $original_sales ne 'wrmoss') {
        my $sth = $dbh->prepare('SELECT email FROM sales_contacts WHERE login_id = ?');
        $sth->execute($original_sales);
        my ($rep_email) = $sth->fetchrow_array;
        if ($rep_email) {
            html_notify($rep_email, 'collections\@hbcuconnect.com', $subject, $html, 'HBCU Collections');
        }
    }
}
```

**Step 2: `_notifyDeleteRequest` — wrmoss approval request**

```perl
sub _notifyDeleteRequest {
    my ($inv, $total_formatted, $client_name, $justification) = @_;
    my $invoice_id = $inv->{invoice_id};
    $justification ||= 'No justification provided';

    my $html = qq~<!DOCTYPE html>
<html><head><meta charset="UTF-8"></head>
<body style="margin:0;padding:0;background-color:#f4f4f7;font-family:Arial,Helvetica,sans-serif;">
<table width="100%" cellpadding="0" cellspacing="0" style="background-color:#f4f4f7;padding:20px 0;">
<tr><td align="center">
<table width="700" cellpadding="0" cellspacing="0" style="background-color:#ffffff;border-radius:8px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,0.08);">
<tr><td style="background-color:#991b1b;padding:25px 40px;text-align:center;">
    <img src="https://hbcuconnect.com/images/logoOverBlack.png" alt="HBCU Connect" width="180" style="width:180px;margin-bottom:12px;">
    <h1 style="color:#ffffff;font-size:22px;margin:0 0 4px 0;font-weight:700;">Invoice Deletion Request</h1>
    <p style="color:rgba(255,255,255,0.8);font-size:13px;margin:0;">Invoice #$invoice_id &mdash; $client_name</p>
</td></tr>
<tr><td style="padding:20px 40px;">
    <table width="100%" cellpadding="0" cellspacing="0"><tr>
        <td width="48%" style="text-align:center;padding:14px 8px;background-color:#fef2f2;border-radius:8px;">
            <div style="font-size:22px;font-weight:700;color:#dc2626;">\$$total_formatted</div>
            <div style="font-size:10px;color:#6b7280;text-transform:uppercase;">Invoice Amount</div>
        </td>
        <td width="4%"></td>
        <td width="48%" style="text-align:center;padding:14px 8px;background-color:#fff7ed;border-radius:8px;">
            <div style="font-size:22px;font-weight:700;color:#92400e;">$inv->{days_overdue}</div>
            <div style="font-size:10px;color:#6b7280;text-transform:uppercase;">Days Overdue</div>
        </td>
    </tr></table>
</td></tr>
<tr><td style="padding:10px 40px;">
    <div style="background-color:#fef2f2;border:1px solid #fecaca;border-radius:8px;padding:14px 18px;">
        <div style="font-size:13px;font-weight:700;color:#991b1b;margin-bottom:4px;">Justification from $USER_INFO->{name}:</div>
        <div style="font-size:12px;color:#555;line-height:1.5;white-space:pre-wrap;">$justification</div>
    </div>
</td></tr>
<tr><td style="padding:25px 40px;text-align:center;">
    <a href="https://hbcuconnect.com/admin/invoice.cgi?invoice_id=$invoice_id" style="display:inline-block;background:linear-gradient(135deg,#991b1b 0%,#7f1d1d 100%);color:#ffffff;text-decoration:none;padding:12px 30px;border-radius:6px;font-size:14px;font-weight:700;">Review Invoice</a>
</td></tr>
<tr><td style="background-color:#f9fafb;padding:15px 40px;border-top:1px solid #e5e7eb;text-align:center;">
    <p style="font-size:11px;color:#999;margin:0;">Action required &bull; HBCU Connect Collections System</p>
</td></tr>
</table>
</td></tr></table>
</body></html>~;

    html_notify('wrmoss\@hbcuconnect.com', 'collections\@hbcuconnect.com',
        "DELETE REQUEST: Invoice #$invoice_id - $client_name (\$$total_formatted)",
        $html, 'HBCU Collections');
}
```

**Step 3: `_notifySentForReview` — wrmoss + original sales rep**

```perl
sub _notifySentForReview {
    my ($inv, $total_formatted, $client_name, $original_sales, $justification) = @_;
    my $invoice_id = $inv->{invoice_id};

    my $html = qq~<!DOCTYPE html>
<html><head><meta charset="UTF-8"></head>
<body style="margin:0;padding:0;background-color:#f4f4f7;font-family:Arial,Helvetica,sans-serif;">
<table width="100%" cellpadding="0" cellspacing="0" style="background-color:#f4f4f7;padding:20px 0;">
<tr><td align="center">
<table width="700" cellpadding="0" cellspacing="0" style="background-color:#ffffff;border-radius:8px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,0.08);">
<tr><td style="background-color:#1e40af;padding:25px 40px;text-align:center;">
    <img src="https://hbcuconnect.com/images/logoOverBlack.png" alt="HBCU Connect" width="180" style="width:180px;margin-bottom:12px;">
    <h1 style="color:#ffffff;font-size:22px;margin:0 0 4px 0;font-weight:700;">Invoice Sent for Review</h1>
    <p style="color:rgba(255,255,255,0.8);font-size:13px;margin:0;">Invoice #$invoice_id &mdash; $client_name</p>
</td></tr>
<tr><td style="padding:20px 40px;">
    <table width="100%" cellpadding="0" cellspacing="0"><tr>
        <td width="48%" style="text-align:center;padding:14px 8px;background-color:#eff6ff;border-radius:8px;">
            <div style="font-size:22px;font-weight:700;color:#1e40af;">\$$total_formatted</div>
            <div style="font-size:10px;color:#6b7280;text-transform:uppercase;">Invoice Amount</div>
        </td>
        <td width="4%"></td>
        <td width="48%" style="text-align:center;padding:14px 8px;background-color:#f0f9ff;border-radius:8px;">
            <div style="font-size:22px;font-weight:700;color:#0369a1;">$inv->{days_overdue}</div>
            <div style="font-size:10px;color:#6b7280;text-transform:uppercase;">Days Overdue</div>
        </td>
    </tr></table>
</td></tr>
<tr><td style="padding:10px 40px;">
    <div style="background-color:#eff6ff;border:1px solid #bfdbfe;border-radius:8px;padding:14px 18px;">
        <div style="font-size:13px;font-weight:700;color:#1e40af;margin-bottom:4px;">Review notes from $USER_INFO->{name}:</div>
        <div style="font-size:12px;color:#555;line-height:1.5;white-space:pre-wrap;">$justification</div>
    </div>
</td></tr>
<tr><td style="padding:25px 40px;text-align:center;">
    <a href="https://hbcuconnect.com/admin/invoice.cgi?invoice_id=$invoice_id" style="display:inline-block;background:linear-gradient(135deg,#1e40af 0%,#1e3a8a 100%);color:#ffffff;text-decoration:none;padding:12px 30px;border-radius:6px;font-size:14px;font-weight:700;">Review Invoice</a>
    &nbsp;
    <a href="https://hbcuconnect.com/admin/clients.cgi?employer_id=$inv->{employer_id}" style="display:inline-block;background:linear-gradient(135deg,#993300 0%,#661100 100%);color:#ffffff;text-decoration:none;padding:12px 30px;border-radius:6px;font-size:14px;font-weight:700;">View Client</a>
</td></tr>
<tr><td style="background-color:#f9fafb;padding:15px 40px;border-top:1px solid #e5e7eb;text-align:center;">
    <p style="font-size:11px;color:#999;margin:0;">Review requested &bull; HBCU Connect Collections System</p>
</td></tr>
</table>
</td></tr></table>
</body></html>~;

    my $subject = "REVIEW: Invoice #$invoice_id - $client_name (\$$total_formatted)";

    # Send to wrmoss
    html_notify('wrmoss\@hbcuconnect.com', 'collections\@hbcuconnect.com', $subject, $html, 'HBCU Collections');

    # Send to original sales rep
    if ($original_sales && $original_sales ne 'wrmoss') {
        my $sth = $dbh->prepare('SELECT email FROM sales_contacts WHERE login_id = ?');
        $sth->execute($original_sales);
        my ($rep_email) = $sth->fetchrow_array;
        if ($rep_email) {
            html_notify($rep_email, 'collections\@hbcuconnect.com', $subject, $html, 'HBCU Collections');
        }
    }
}
```

**Step 4: Syntax check**

```bash
cd /var/www/vhosts/hbcuconnect.com/httpdocs/admin && perl -c collections.cgi
```

---

### Task 4: Update Backend Queries to Include + Filter by Process Status

**Files:**
- Modify: `admin/collections.cgi` — `getQueue()`, `getClaimable()`, `getInvoiceDetail()`

**Step 1: Update `getQueue()` (line 140)**

Add `collections_process_status` filter param parsing after the `$amt_max` line (after line 145):

```perl
    my $process_status = $q->param('process_status') || '';
```

Add filter condition after the `$amt_max` block (after line 178):

```perl
    if ($process_status) {
        push @where, "a.collections_process_status = ?";
        push @bind, $process_status;
    }
```

Add `a.collections_process_status` to the SELECT column list (line 184, after `a.last_reminder,`):

```
               a.collections_process_status,
```

Add `collections_process_status` to the hash pushed into `@invoices` (after the `campaign_brief` line, line 215):

```perl
            collections_process_status => $row->{collections_process_status} || '',
```

**Step 2: Update `getClaimable()` (line 225)**

Same changes — add `process_status` param, filter, SELECT column, and hash field. Mirror the exact same pattern as `getQueue`.

Add after line 230:
```perl
    my $process_status = $q->param('process_status') || '';
```

Add after line 264 (the `$amt_max` block):
```perl
    if ($process_status) {
        push @where, "a.collections_process_status = ?";
        push @bind, $process_status;
    }
```

Add `a.collections_process_status` to the SELECT (line 271, after `a.collections_status,`):
```
               a.collections_process_status,
```

Add to the hash (after `collections_status` line 298):
```perl
            collections_process_status => $row->{collections_process_status} || '',
```

**Step 3: Update `getInvoiceDetail()` (line 308)**

The SELECT already uses `a.*` so the column is included. Just add it to the JSON response hash.

In the `json_ok` invoice hash (around line 363, after the `collections_status` line):
```perl
            collections_process_status => $inv->{collections_process_status} || '',
```

**Step 4: Syntax check**

```bash
cd /var/www/vhosts/hbcuconnect.com/httpdocs/admin && perl -c collections.cgi
```

---

### Task 5: Update Frontend — Process Status Filter Dropdown

**Files:**
- Modify: `admin/collections.cgi` — the filter row HTML (around line 648-677) and `getFilterParams()` JS function

**Step 1: Add process status dropdown to filter row**

In the filter row div (around line 649-677), add a new `<select>` after the sort dropdown and before the Clear button:

```html
<select id="f-process-status" onchange="loadCurrentTab()" class="border border-gray-200 rounded-lg px-3 py-2 text-sm bg-gray-50 focus:ring-2 focus:ring-navy-500/20">
    <option value="">All Process Status</option>
    <option value="no_contact">No Contact Made</option>
    <option value="pending_review">Pending Client Review</option>
    <option value="payment_arrangements">Payment Arrangements</option>
    <option value="paid">Paid</option>
    <option value="delete_requested">Delete Requested</option>
    <option value="sent_for_review">Sent for Review</option>
</select>
```

**Step 2: Update `getFilterParams()` JS function (line 763)**

Add after the sort param (before the `return`):

```javascript
    const processStatus = document.getElementById('f-process-status').value;
    if (processStatus) params.set('process_status', processStatus);
```

**Step 3: Update `clearFilters()` JS function (line 786)**

Add before `loadCurrentTab()`:
```javascript
    document.getElementById('f-process-status').value = '';
```

---

### Task 6: Update Frontend — Process Status Dropdown in Detail Panel

**Files:**
- Modify: `admin/collections.cgi` — the `renderDetail()` JS function (line 882)

**Step 1: Add process status section to `renderDetail()`**

Insert AFTER the header block (after the closing `</div>` for the gradient header, around line 898) and BEFORE the Quick Actions bar (before the `// Quick Actions` comment around line 901):

```javascript
    // Process Status Section
    const statusOptions = [
        { value: 'no_contact', label: 'No Contact Made', color: 'gray' },
        { value: 'pending_review', label: 'Pending Client Review', color: 'blue' },
        { value: 'payment_arrangements', label: 'Payment Arrangements Made', color: 'amber' },
        { value: 'paid', label: 'Paid', color: 'green' },
        { value: 'delete_requested', label: 'Delete Invoice', color: 'red' },
        { value: 'sent_for_review', label: 'Send for Review', color: 'purple' },
    ];
    const currentStatus = inv.collections_process_status || '';
    const currentLabel = statusOptions.find(s => s.value === currentStatus);

    html += '<div class="px-6 py-3 border-b border-gray-200 bg-gradient-to-r from-gray-50 to-white">';
    html += '<div class="flex items-center justify-between mb-2">';
    html += '<h3 class="text-xs font-semibold text-gray-500 uppercase tracking-wide">Collections Process Status</h3>';
    if (currentLabel) {
        html += '<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-semibold bg-' + currentLabel.color + '-100 text-' + currentLabel.color + '-700">' + currentLabel.label + '</span>';
    } else {
        html += '<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-500">Not Set</span>';
    }
    html += '</div>';
    html += '<div class="flex items-center gap-2">';
    html += '<select id="process-status-select" class="flex-1 border border-gray-300 rounded-lg px-3 py-2 text-sm bg-white focus:ring-2 focus:ring-navy-500/20 focus:border-navy-500">';
    html += '<option value="">-- Select Status --</option>';
    statusOptions.forEach(s => {
        html += '<option value="' + s.value + '"' + (s.value === currentStatus ? ' selected' : '') + '>' + s.label + '</option>';
    });
    html += '</select>';
    html += '<button onclick="doUpdateProcessStatus(' + inv.invoice_id + ')" class="inline-flex items-center gap-1.5 px-4 py-2 bg-navy-700 hover:bg-navy-800 text-white text-sm font-semibold rounded-lg transition whitespace-nowrap"><svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>Update Status</button>';
    html += '</div>';
    // Justification textarea (hidden, shown for review/delete)
    html += '<div id="justification-row" class="mt-2 hidden">';
    html += '<textarea id="justification-text" rows="2" class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-navy-500/20 focus:border-navy-500" placeholder="Enter justification or notes for this status change..."></textarea>';
    html += '</div>';
    html += '</div>';
```

**Step 2: Add JS to show/hide justification field**

Add an onchange handler to the select. Replace the select line with:

```javascript
    html += '<select id="process-status-select" onchange="toggleJustification()" class="flex-1 border border-gray-300 rounded-lg px-3 py-2 text-sm bg-white focus:ring-2 focus:ring-navy-500/20 focus:border-navy-500">';
```

---

### Task 7: Add Frontend JS Action Functions

**Files:**
- Modify: `admin/collections.cgi` — add JS functions in the `<script>` block (before `</script>`, around line 1050)

**Step 1: Add `toggleJustification()` and `doUpdateProcessStatus()` functions**

Insert before the closing `</script>` tag:

```javascript
// ---- Process Status ----
function toggleJustification() {
    const sel = document.getElementById('process-status-select');
    const row = document.getElementById('justification-row');
    if (!sel || !row) return;
    const val = sel.value;
    if (val === 'sent_for_review' || val === 'delete_requested') {
        row.classList.remove('hidden');
        document.getElementById('justification-text').placeholder =
            val === 'sent_for_review' ? 'Enter justification for review request...' : 'Enter reason for deletion request...';
    } else {
        row.classList.add('hidden');
    }
}

function doUpdateProcessStatus(invoiceId) {
    const sel = document.getElementById('process-status-select');
    if (!sel || !sel.value) { showToast('Please select a status', 'error'); return; }
    const status = sel.value;
    const justification = (document.getElementById('justification-text') || {}).value || '';

    // Confirmations for destructive actions
    if (status === 'paid') {
        if (!confirm('Mark this invoice as PAID?\\n\\nThis will:\\n- Set the paid date to today\\n- Send notification to the full team (wrmoss, dmoss, sales rep)')) return;
    } else if (status === 'delete_requested') {
        if (!justification.trim()) { showToast('Please enter a reason for the deletion request', 'error'); return; }
        if (!confirm('Request deletion of this invoice?\\n\\nThis will send an approval request to wrmoss.')) return;
    } else if (status === 'sent_for_review') {
        if (!justification.trim()) { showToast('Please enter justification for the review request', 'error'); return; }
        if (!confirm('Send this invoice for review?\\n\\nThis will notify wrmoss and the original sales rep.')) return;
    }

    const fd = new FormData();
    fd.append('action', 'update_process_status');
    fd.append('invoice_id', invoiceId);
    fd.append('process_status', status);
    if (justification) fd.append('justification', justification);

    fetch('collections.cgi', { method: 'POST', body: fd })
        .then(r => r.json())
        .then(d => {
            if (d.success) {
                showToast(d.message || 'Status updated', 'success');
                loadStats();
                loadCurrentTab();
                setTimeout(() => selectInvoice(invoiceId), 500);
            } else {
                showToast(d.message || 'Update failed', 'error');
            }
        })
        .catch(() => showToast('Network error', 'error'));
}
```

**Step 2: Update `renderQueue()` to show process status badge on each card**

In the `renderQueue()` function, add a process status badge after the days overdue line. Find the line that shows `inv.days_overdue + ' days'` and add after it:

```javascript
        if (inv.collections_process_status) {
            const pLabels = { no_contact:'No Contact', pending_review:'Pending Review', payment_arrangements:'Arrangements', paid:'Paid', delete_requested:'Delete Req', sent_for_review:'In Review' };
            const pColors = { no_contact:'gray', pending_review:'blue', payment_arrangements:'amber', paid:'green', delete_requested:'red', sent_for_review:'purple' };
            const pLabel = pLabels[inv.collections_process_status] || inv.collections_process_status;
            const pColor = pColors[inv.collections_process_status] || 'gray';
            html += '<div class="text-[10px] mt-0.5"><span class="inline-flex px-1.5 py-0.5 rounded-full bg-' + pColor + '-100 text-' + pColor + '-700 font-medium">' + pLabel + '</span></div>';
        }
```

---

### Task 8: Fix File Ownership + Syntax Check + Smoke Test

**Step 1: Fix ownership**

```bash
chown hbcuconnect:psacln /var/www/vhosts/hbcuconnect.com/httpdocs/admin/collections.cgi
```

**Step 2: Final syntax check**

```bash
cd /var/www/vhosts/hbcuconnect.com/httpdocs/admin && perl -c collections.cgi
```

Expected: `collections.cgi syntax OK`

**Step 3: Smoke test AJAX endpoints**

```bash
cd /var/www/vhosts/hbcuconnect.com/httpdocs/admin
REMOTE_USER=dmoss QUERY_STRING="action=get_queue" perl collections.cgi 2>/dev/null | head -5
REMOTE_USER=dmoss QUERY_STRING="action=get_queue&process_status=no_contact" perl collections.cgi 2>/dev/null | head -5
```

Both should return valid JSON with `"success":true`.

**Step 4: Commit**

```bash
cd /var/www/vhosts/hbcuconnect.com/httpdocs/admin
git add collections.cgi
git commit -m "feat: add collections process status tracking with email notifications"
```
