403Webshell
Server IP : 72.60.21.38  /  Your IP : 216.73.216.25
Web Server : LiteSpeed
System : Linux uk-fast-web1372.main-hosting.eu 4.18.0-553.121.1.lve.el8.x86_64 #1 SMP Thu Apr 30 16:40:41 UTC 2026 x86_64
User : u390967363 ( 390967363)
PHP Version : 8.2.30
Disable Function : system, exec, shell_exec, passthru, mysql_list_dbs, ini_alter, dl, symlink, link, chgrp, leak, popen, apache_child_terminate, virtual, mb_send_mail
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/u390967363/domains/aibenproperties.com/public_html/app/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/u390967363/domains/aibenproperties.com/public_html/app/deal-submission.php
<?php
if (session_status() === PHP_SESSION_NONE) { session_start(); }
ob_start();
require_once __DIR__ . '/includes/db.php';
require_once __DIR__ . '/includes/functions.php';
@require_once __DIR__ . '/includes/mailer.php';
global $pdo;
$companyId = function_exists('getCurrentCompanyId') ? getCurrentCompanyId() : 0;
$role = strtolower($_SESSION['user_role'] ?? '');
$userId = (int)($_SESSION['user_id'] ?? 0);
$success_msg = $_SESSION['deal_success'] ?? '';
if ($success_msg !== '') { unset($_SESSION['deal_success']); }
$clientAccessSetup = $_SESSION['client_access_setup'] ?? null;
if (!empty($clientAccessSetup)) { unset($_SESSION['client_access_setup']); }
$error_msg = '';
// Variant: render differences for Contact Centre vs Marketing pages
$variant = strtolower($_GET['variant'] ?? ((strpos($role, 'contact') !== false || strpos($role, 'customer') !== false) ? 'contact' : 'marketing'));
$isAjax = ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['xhr']) && $_POST['xhr'] === '1');
if (isset($_GET['action']) && is_string($_GET['action'])) {
    $act = trim((string)$_GET['action']);
    if ($act === 'picker_properties') {
        header('Content-Type: application/json; charset=utf-8');
        $out = ['ok' => false, 'rows' => []];
        try {
            $companyIdPicker = function_exists('getCurrentCompanyId') ? (int)getCurrentCompanyId() : 0;
            $q = trim((string)($_GET['search'] ?? ''));
            $hasProps = $pdo->query("SHOW TABLES LIKE 'properties'")->rowCount() > 0;
            if ($hasProps) {
                $sel = "p.id, p.title, p.location, p.address, p.price, p.status";
                if (function_exists('tableHasColumn') && tableHasColumn('properties','area_sqm')) { $sel .= ", p.area_sqm"; } else { $sel .= ", NULL AS area_sqm"; }
                if (function_exists('tableHasColumn') && tableHasColumn('properties','total_sqm')) { $sel .= ", p.total_sqm"; } else { $sel .= ", NULL AS total_sqm"; }
                $sql = "SELECT $sel FROM properties p JOIN (SELECT MAX(id) AS id FROM properties GROUP BY LOWER(TRIM(title))) t ON t.id = p.id";
                $where = [];
                $params = [];
                $rolePicker = strtolower((string)($_SESSION['user_role'] ?? 'guest'));
                $isPrivilegedPicker = in_array($rolePicker, ['super_admin', 'marketing', 'agent', 'sales', 'sales_agent', 'chairman_ceo', 'executive']);
                if (function_exists('tableHasColumn') && tableHasColumn('properties','is_active')) { $where[] = "p.is_active = 1"; }
                elseif (function_exists('tableHasColumn') && tableHasColumn('properties','status')) { $where[] = "(p.status IS NULL OR p.status <> 'archived')"; }
                if (!$isPrivilegedPicker && $companyIdPicker && function_exists('tableHasColumn') && tableHasColumn('properties','company_id')) { 
                    $where[] = "(p.company_id = ? OR p.company_id IS NULL OR p.company_id = 0)"; 
                    $params[] = $companyIdPicker; 
                }
                if ($q !== '') { $where[] = "(p.title LIKE ? OR p.location LIKE ? OR p.address LIKE ?)"; $params[] = '%' . $q . '%'; $params[] = '%' . $q . '%'; $params[] = '%' . $q . '%'; }
                if ($where) { $sql .= " WHERE " . implode(" AND ", $where); }
                $sql .= " ORDER BY p.sort_order ASC, p.id DESC LIMIT 400";
                $st = $pdo->prepare($sql);
                $st->execute($params);
                $out['rows'] = $st->fetchAll(PDO::FETCH_ASSOC) ?: [];
            }
            $out['ok'] = true;
        } catch (Throwable $e) {
            $out = ['ok' => false, 'rows' => [], 'error' => 'server_error'];
        }
        echo json_encode($out);
        exit;
    }
    if ($act === 'balances') {
        header('Content-Type: application/json; charset=utf-8');
        $out = [
            'ok' => false,
            'property_id' => 0,
            'client_id' => 0,
            'land' => ['total' => 0.0, 'paid' => 0.0, 'balance' => 0.0],
            'infrastructure' => ['total' => 0.0, 'paid' => 0.0, 'balance' => 0.0],
            'excavation' => ['total' => 0.0, 'paid' => 0.0, 'balance' => 0.0],
            'accounts' => ['land' => false, 'infrastructure' => false, 'excavation' => false],
        ];
        try {
            $propertyIdB = isset($_GET['property_id']) ? (int)$_GET['property_id'] : 0;
            $clientIdB = isset($_GET['client_id']) ? (int)$_GET['client_id'] : 0;
            $companyIdB = function_exists('getCurrentCompanyId') ? (int)getCurrentCompanyId() : 0;
            $out['property_id'] = $propertyIdB;
            $out['client_id'] = $clientIdB;
            if ($propertyIdB > 0) {
                try {
                    $hasAcc = $pdo->query("SHOW TABLES LIKE 'accounts'")->rowCount() > 0;
                    if ($hasAcc && function_exists('tableHasColumn') && tableHasColumn('accounts', 'property_id') && tableHasColumn('accounts', 'account_type') && tableHasColumn('accounts', 'is_active')) {
                        $q = "SELECT account_type FROM accounts WHERE property_id = ? AND is_active = 1 AND account_type IN ('land','infrastructure','excavation')";
                        $params = [$propertyIdB];
                        if ($companyIdB && tableHasColumn('accounts','company_id')) { $q .= " AND (company_id = ? OR company_id IS NULL)"; $params[] = $companyIdB; }
                        $st = $pdo->prepare($q);
                        $st->execute($params);
                        foreach (($st->fetchAll(PDO::FETCH_COLUMN) ?: []) as $tRaw) {
                            $t = strtolower(trim((string)$tRaw));
                            if (isset($out['accounts'][$t])) { $out['accounts'][$t] = true; }
                        }
                    }
                } catch (Throwable $e) {}
            }
            if ($propertyIdB > 0 && $clientIdB > 0) {
                $finalStatuses = function_exists('kpiPaymentFinalizedStatuses') ? (array)kpiPaymentFinalizedStatuses() : ['verified','approved','paid','completed','success'];
                $statusSql = function_exists('kpiSqlList') ? kpiSqlList($finalStatuses) : "('verified','approved','paid','completed','success')";
                $payCompany = ($companyIdB && function_exists('tableHasColumn') && tableHasColumn('payments','company_id')) ? " AND (company_id = " . (int)$companyIdB . " OR company_id IS NULL)" : "";

                $landTotal = 0.0;
                $landDiscount = 0.0;
                try {
                    $hasDS = $pdo->query("SHOW TABLES LIKE 'deals_submit'")->rowCount() > 0;
                    if ($hasDS && function_exists('hasColumn') && hasColumn($pdo,'deals_submit','meta_json')) {
                        $qds = $pdo->prepare("SELECT meta_json FROM deals_submit WHERE user_id = ?" . ($companyIdB && function_exists('hasColumn') && hasColumn($pdo,'deals_submit','company_id') ? " AND (company_id = " . (int)$companyIdB . " OR company_id IS NULL)" : "") . " ORDER BY created_at DESC LIMIT 50");
                        $qds->execute([$clientIdB]);
                        $rows = $qds->fetchAll(PDO::FETCH_COLUMN) ?: [];
                        foreach ($rows as $mjRaw) {
                            if (!$mjRaw) continue;
                            $mj = json_decode((string)$mjRaw, true);
                            if (!is_array($mj)) continue;
                            if ((int)($mj['property_id'] ?? 0) !== $propertyIdB) continue;
                            $landTotal = (float)($mj['amount_offered'] ?? 0);
                            $landDiscount = (float)($mj['discount_amount'] ?? 0);
                            break;
                        }
                    }
                } catch (Throwable $e) {}
                $landDue = max(0.0, $landTotal - $landDiscount);
                $landPaid = 0.0;
                try {
                    $typeClause = (function_exists('tableHasColumn') && tableHasColumn('payments','payment_type')) ? " AND LOWER(TRIM(payment_type)) = 'land'" : "";
                    $propClause = (function_exists('tableHasColumn') && tableHasColumn('payments','property_id')) ? " AND property_id = " . (int)$propertyIdB : "";
                    $userWhere = (function_exists('tableHasColumn') && tableHasColumn('payments','user_id')) ? "user_id = " . (int)$clientIdB : "1=0";
                    $clientWhere = (function_exists('tableHasColumn') && tableHasColumn('payments','client_id')) ? "client_id = " . (int)$clientIdB : "1=0";
                    $landPaid = (float)$pdo->query("SELECT COALESCE(SUM(amount),0) FROM payments WHERE (" . $userWhere . " OR " . $clientWhere . ") AND status IN {$statusSql}{$payCompany}{$propClause}{$typeClause}")->fetchColumn();
                } catch (Throwable $e) { $landPaid = 0.0; }

                $chargeTotals = ['infrastructure' => 0.0, 'excavation' => 0.0];
                try {
                    $hasPc = $pdo->query("SHOW TABLES LIKE 'property_charges'")->rowCount() > 0;
                    if ($hasPc) {
                        $q = "SELECT charge_name, amount FROM property_charges WHERE property_id = ? AND is_active = 1";
                        $params = [$propertyIdB];
                        if ($companyIdB && function_exists('tableHasColumn') && tableHasColumn('property_charges','company_id')) { $q .= " AND (company_id = ? OR company_id IS NULL OR company_id = 0)"; $params[] = $companyIdB; }
                        $st = $pdo->prepare($q);
                        $st->execute($params);
                        $rows = $st->fetchAll(PDO::FETCH_ASSOC) ?: [];
                        foreach ($rows as $r) {
                            $nm = strtolower(trim((string)($r['charge_name'] ?? '')));
                            $amt = (float)($r['amount'] ?? 0);
                            if (!is_finite($amt) || $amt < 0) $amt = 0.0;
                            if ($nm === '') continue;
                            if (strpos($nm, 'infra') !== false || strpos($nm, 'infrastructure') !== false) { $chargeTotals['infrastructure'] += $amt; }
                            if (strpos($nm, 'excav') !== false || strpos($nm, 'excavation') !== false || strpos($nm, 'escav') !== false) { $chargeTotals['excavation'] += $amt; }
                        }
                    }
                } catch (Throwable $e) {}

                $paidByType = ['infrastructure' => 0.0, 'excavation' => 0.0];
                try {
                    $propClause = (function_exists('tableHasColumn') && tableHasColumn('payments','property_id')) ? " AND property_id = " . (int)$propertyIdB : "";
                    $userWhere = (function_exists('tableHasColumn') && tableHasColumn('payments','user_id')) ? "user_id = " . (int)$clientIdB : "1=0";
                    $clientWhere = (function_exists('tableHasColumn') && tableHasColumn('payments','client_id')) ? "client_id = " . (int)$clientIdB : "1=0";
                    $typeCol = (function_exists('tableHasColumn') && tableHasColumn('payments','payment_type')) ? "LOWER(TRIM(payment_type))" : "''";
                    $st = $pdo->query("SELECT {$typeCol} AS t, COALESCE(SUM(amount),0) AS s FROM payments WHERE (" . $userWhere . " OR " . $clientWhere . ") AND status IN {$statusSql}{$payCompany}{$propClause} GROUP BY {$typeCol}");
                    $rows = $st ? ($st->fetchAll(PDO::FETCH_ASSOC) ?: []) : [];
                    foreach ($rows as $r) {
                        $t = strtolower(trim((string)($r['t'] ?? '')));
                        $s = (float)($r['s'] ?? 0);
                        if ($t === 'infrastructure' || $t === 'infra') { $paidByType['infrastructure'] += $s; }
                        if ($t === 'excavation' || $t === 'excav') { $paidByType['excavation'] += $s; }
                    }
                } catch (Throwable $e) {}

                $out['land'] = ['total' => $landDue, 'paid' => $landPaid, 'balance' => max(0.0, $landDue - $landPaid)];
                $out['infrastructure'] = ['total' => $chargeTotals['infrastructure'], 'paid' => $paidByType['infrastructure'], 'balance' => max(0.0, $chargeTotals['infrastructure'] - $paidByType['infrastructure'])];
                $out['excavation'] = ['total' => $chargeTotals['excavation'], 'paid' => $paidByType['excavation'], 'balance' => max(0.0, $chargeTotals['excavation'] - $paidByType['excavation'])];
            }
            $out['ok'] = true;
        } catch (Throwable $e) {
            $out = ['ok' => false, 'error' => 'server_error'];
        }
        echo json_encode($out);
        exit;
    }
}
if (!$isAjax) { include __DIR__ . '/includes/header.php'; }
if ($isAjax && !isset($_POST['submit_deal'])) { $_POST['submit_deal'] = '1'; }
// Ensure schema for deals table and payments.deal_id linkage (skip during AJAX POST for responsiveness)
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    try {
        if (function_exists('ensurePropertyAccountsTable')) { ensurePropertyAccountsTable(); }
        if (function_exists('ensurePropertyExpensesTable')) { ensurePropertyExpensesTable(); }
        if (function_exists('ensurePropertyPaymentsColumns')) { ensurePropertyPaymentsColumns(); }
        $hasDeals = $pdo->query("SHOW TABLES LIKE 'deals'")->rowCount() > 0;
        if (!$hasDeals) {
            $pdo->exec("
                CREATE TABLE IF NOT EXISTS deals (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    user_id INT NULL,
                    marketer_id INT NULL,
                    marketer_name VARCHAR(255) NULL,
                    deal_source VARCHAR(100) NULL,
                    project_desc VARCHAR(255) NULL,
                    project_name VARCHAR(255) NULL,
                    payment_plan VARCHAR(50) NULL,
                    amount_offered DECIMAL(14,2) NULL,
                    amount_paid_so_far DECIMAL(14,2) NULL,
                    discount_amount DECIMAL(14,2) NULL,
                    discount_approved_by VARCHAR(120) NULL,
                    commission_percent DECIMAL(6,2) NULL,
                    marketer_commission DECIMAL(14,2) NULL,
                    agent_commission DECIMAL(14,2) NULL,
                    balance_remaining DECIMAL(14,2) NULL,
                    marketer_bank JSON NULL,
                    agent_bank JSON NULL,
                    notes TEXT NULL,
                    receipt_file VARCHAR(255) NULL,
                    status VARCHAR(50) NULL,
                    submitted_by INT NULL,
                    company_id INT NULL,
                    meta_json JSON NULL,
                    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
                )
            ");
        }
        $hasDealsSubmit = $pdo->query("SHOW TABLES LIKE 'deals_submit'")->rowCount() > 0;
        if (!$hasDealsSubmit) {
            $pdo->exec("
                CREATE TABLE IF NOT EXISTS deals_submit (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    user_id INT NULL,
                    marketer_id INT NULL,
                    marketer_name VARCHAR(255) NULL,
                    deal_source VARCHAR(100) NULL,
                    project_desc VARCHAR(255) NULL,
                    project_name VARCHAR(255) NULL,
                    payment_plan VARCHAR(50) NULL,
                    installment_start_date DATE NULL,
                    policy_accepted TINYINT(1) DEFAULT 0,
                    amount_offered DECIMAL(14,2) NULL,
                    amount_paid_so_far DECIMAL(14,2) NULL,
                    discount_amount DECIMAL(14,2) NULL,
                    discount_approved_by VARCHAR(120) NULL,
                    commission_percent DECIMAL(6,2) NULL,
                    marketer_commission DECIMAL(14,2) NULL,
                    agent_commission DECIMAL(14,2) NULL,
                    balance_remaining DECIMAL(14,2) NULL,
                    marketer_bank JSON NULL,
                    agent_bank JSON NULL,
                    notes TEXT NULL,
                    receipt_file VARCHAR(255) NULL,
                    status VARCHAR(50) NULL,
                    submitted_by INT NULL,
                    company_id INT NULL,
                    meta_json JSON NULL,
                    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
                )
            ");
        }
        if (function_exists('tableHasColumn') && !tableHasColumn('payments','deal_id')) {
            $pdo->exec("ALTER TABLE payments ADD COLUMN deal_id INT NULL");
        }
    } catch (Throwable $eSchema) {}
}
function safeUploadReceipt($file, string $dir = 'uploads/deals') {
    try {
        if (!is_array($file) || !isset($file['error']) || $file['error'] !== UPLOAD_ERR_OK) return '';
        if (!isset($file['tmp_name']) || !is_string($file['tmp_name']) || $file['tmp_name'] === '') return '';
        if (!isset($file['name']) || !is_string($file['name']) || $file['name'] === '') return '';
        $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
        if (!is_dir($dir)) { @mkdir($dir, 0777, true); }
        $name = $dir . '/deal_receipt_' . date('Ymd_His') . '_' . mt_rand(1000,9999) . '.' . $ext;
        if (move_uploaded_file($file['tmp_name'], $name)) {
            global $pdo;
            if (function_exists('tableHasColumn') && tableHasColumn('payments','proof_file')) {
                try {
                    $chk = $pdo->prepare("SELECT id FROM payments WHERE proof_file = ? AND status <> 'rejected' LIMIT 1");
                    $chk->execute([$name]);
                    if ($chk->fetchColumn()) {
                        return $name;
                    }
                } catch (Throwable $e) {}
            }
            return $name;
        }
    } catch (Throwable $e) {}
    return '';
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit_deal'])) {
    try {
        try {
            $env = strtolower((string)(getenv('APP_ENV') ?: ($_ENV['APP_ENV'] ?? '')));
            $dbg = strtolower((string)(getenv('APP_DEBUG') ?: ($_ENV['APP_DEBUG'] ?? '')));
            $isLocal = ($env === 'local') || ($env === 'development') || (strpos((string)($_SERVER['HTTP_HOST'] ?? ''), 'localhost') !== false);
            if ($isLocal && ($dbg === '1' || $dbg === 'true' || $dbg === 'yes')) {
                @file_put_contents(__DIR__ . '/debug_form.txt', print_r($_POST, true));
            }
        } catch (Throwable $eLog) {}
        $client_id = (int)($_POST['client_id'] ?? 0);
        $client_name = trim($_POST['client_name'] ?? '');
        $client_email = trim($_POST['client_email'] ?? '');
        $project_name = trim($_POST['project_name'] ?? '');
        $project_desc = trim($_POST['project_desc'] ?? '');
        $property_id = (int)($_POST['property_id'] ?? 0);
        $payment_type = strtolower(trim((string)($_POST['payment_type'] ?? 'land')));
        if (!in_array($payment_type, ['land','infrastructure','excavation'], true)) { $payment_type = 'land'; }
        $deal_source = trim($_POST['deal_source'] ?? '');
        $plan_type = trim($_POST['plan_type'] ?? 'full');
        $custom_months = (int)($_POST['custom_months'] ?? 0);
        $installment_start_date = trim($_POST['installment_start_date'] ?? '');
        $sqm = isset($_POST['sqm']) ? (float)str_replace(',', '', (string)$_POST['sqm']) : 0.0;
        $policy_accepted = isset($_POST['policy_acceptance']) ? 1 : 0;
        $amount_offered = (float)str_replace(',', '', $_POST['amount_offered'] ?? '0');
        $amount_paid_so_far = (float)str_replace(',', '', $_POST['amount_paid_so_far'] ?? '0');
        $commission_pct = (float)($_POST['commission_pct'] ?? 5.0);
        $marketer_pct = (float)($_POST['marketer_pct'] ?? 3.0);
        $agent_pct = (float)($_POST['agent_pct'] ?? 2.0);
        $marketer_comm = (float)str_replace(',', '', $_POST['marketer_comm'] ?? '0');
        $agent_comm = (float)str_replace(',', '', $_POST['agent_comm'] ?? '0');
        $discount_amount = (float)str_replace(',', '', $_POST['discount_amount'] ?? '0');
        $discount_approved_by = trim($_POST['discount_approved_by'] ?? '');
        $paid_now = (float)str_replace(',', '', $_POST['amount_paid_now'] ?? '0');
        $balance_remaining = (float)str_replace(',', '', $_POST['balance_remaining'] ?? '0');
        $marketer_name = trim($_POST['marketer_name'] ?? '');
        $client_payment_status = trim($_POST['client_payment_status'] ?? '');
        $mk_acc_no = trim($_POST['mk_acc_no'] ?? '');
        $mk_bank = trim($_POST['mk_bank'] ?? '');
        $mk_acc_name = trim($_POST['mk_acc_name'] ?? '');
        $ag_acc_no = trim($_POST['ag_acc_no'] ?? '');
        $ag_bank = trim($_POST['ag_bank'] ?? '');
        $ag_acc_name = trim($_POST['ag_acc_name'] ?? '');
        $existing_deal_id = (int)($_POST['existing_deal_id'] ?? 0);
        $receipt = safeUploadReceipt($_FILES['receipt'] ?? null);
        if (!$receipt) {
            $error_msg = 'Please upload the payment receipt before submitting.';
            throw new Exception($error_msg);
        }

        $isPrivilegedSubmitter = in_array($role, ['super_admin','admin','finance','finance_officer','finance_manager','accountant','accounting'], true);
        if (!$isPrivilegedSubmitter && $client_id > 0) {
            $allowedClient = false;
            $companyIdCheck = (int)($companyId ?: 0);
            try {
                if (function_exists('hasColumn') && hasColumn($pdo,'users','created_by')) {
                    $q = "SELECT 1 FROM users WHERE id = ? AND role = 'client' AND created_by = ?";
                    $params = [$client_id, $userId];
                    if ($companyIdCheck && function_exists('hasColumn') && hasColumn($pdo,'users','company_id')) { $q .= " AND (company_id = ? OR company_id IS NULL)"; $params[] = $companyIdCheck; }
                    $st = $pdo->prepare($q);
                    $st->execute($params);
                    $allowedClient = (bool)$st->fetchColumn();
                }
            } catch (Throwable $e) {}
            if (!$allowedClient) {
                try {
                    if ($pdo->query("SHOW TABLES LIKE 'deals_submit'")->rowCount() > 0 && function_exists('tableHasColumn') && tableHasColumn('deals_submit','submitted_by_user')) {
                        $w = "submitted_by_user = ?";
                        $params = [$client_id, $userId];
                        if (function_exists('tableHasColumn') && tableHasColumn('deals_submit','marketer_id')) { $w .= " OR marketer_id = ?"; $params[] = $userId; }
                        $q = "SELECT 1 FROM deals_submit WHERE user_id = ? AND ($w)";
                        if ($companyIdCheck && function_exists('tableHasColumn') && tableHasColumn('deals_submit','company_id')) { $q .= " AND (company_id = ? OR company_id IS NULL)"; $params[] = $companyIdCheck; }
                        $q .= " LIMIT 1";
                        $st = $pdo->prepare($q);
                        $st->execute($params);
                        $allowedClient = (bool)$st->fetchColumn();
                    }
                } catch (Throwable $e) {}
            }
            if (!$allowedClient) {
                try {
                    if ($pdo->query("SHOW TABLES LIKE 'payments'")->rowCount() > 0 && function_exists('tableHasColumn') && tableHasColumn('payments','submitted_by_user')) {
                        $clientCol = (function_exists('tableHasColumn') && tableHasColumn('payments','client_id')) ? 'client_id' : 'user_id';
                        $q = "SELECT 1 FROM payments WHERE {$clientCol} = ? AND submitted_by_user = ?";
                        $params = [$client_id, $userId];
                        if ($companyIdCheck && function_exists('tableHasColumn') && tableHasColumn('payments','company_id')) { $q .= " AND (company_id = ? OR company_id IS NULL)"; $params[] = $companyIdCheck; }
                        $q .= " LIMIT 1";
                        $st = $pdo->prepare($q);
                        $st->execute($params);
                        $allowedClient = (bool)$st->fetchColumn();
                    }
                } catch (Throwable $e) {}
            }
            if (!$allowedClient) {
                throw new Exception("You can only submit deals for your own clients.");
            }
        }

    $plan_type = strtolower(trim((string)$plan_type));
    if ($plan_type === 'custom') {
        if ($custom_months <= 0) {
            $error_msg = 'Please enter the custom plan duration in months.';
            throw new Exception($error_msg);
        }
        if ($custom_months < 1 || $custom_months > 120) {
            $error_msg = 'Custom plan months must be between 1 and 120.';
            throw new Exception($error_msg);
        }
        if ($custom_months === 3) { $plan_type = '3_months'; }
        elseif ($custom_months === 6) { $plan_type = '6_months'; }
        else { $plan_type = 'custom_' . $custom_months . '_months'; }
    }
    // Normalize missing marketer_name and deal_source from session and auxiliary fields
    try {
        if (!in_array($role, ['super_admin','admin'], true) && $marketer_name === '' && isset($_POST['submitted_by_name']) && trim((string)$_POST['submitted_by_name']) !== '') {
            $marketer_name = trim((string)$_POST['submitted_by_name']);
        }
        if ($marketer_name === '' && $userId > 0 && function_exists('tableHasColumn') && tableHasColumn('users','name')) {
            $qs = $pdo->prepare("SELECT name FROM users WHERE id = ? LIMIT 1");
            $qs->execute([$userId]);
            $nm = (string)($qs->fetchColumn() ?: '');
            if ($nm !== '' && $role && $role !== 'client') { $marketer_name = $nm; }
        }
    } catch (Throwable $eNorm1) {}
    try {
        if ($deal_source === '' && isset($_POST['submitted_by_role']) && trim((string)$_POST['submitted_by_role']) !== '') {
            $deal_source = ucfirst(strtolower((string)$_POST['submitted_by_role']));
        }
        if ($deal_source === '' && $role !== '') { $deal_source = ucfirst(strtolower($role)); }
        if ($deal_source === '') { $deal_source = 'Marketing'; }
    } catch (Throwable $eNorm2) {}
    $submittedByRole = $role;
    try {
        $dsLower = strtolower(trim((string)$deal_source));
        if ($dsLower !== '') {
            if (strpos($dsLower, 'contact') !== false) { $submittedByRole = 'contact_centre'; }
            elseif (strpos($dsLower, 'marketer') !== false || strpos($dsLower, 'marketing') !== false || strpos($dsLower, 'sales') !== false) { $submittedByRole = 'marketing'; }
            elseif (strpos($dsLower, 'client') !== false) { $submittedByRole = 'client'; }
            elseif (strpos($dsLower, 'referral') !== false) { $submittedByRole = 'referral'; }
            elseif (strpos($dsLower, 'internal') !== false || strpos($dsLower, 'staff') !== false) { $submittedByRole = 'staff'; }
        }
    } catch (Throwable $eRoleNorm) { $submittedByRole = $role; }

    $creditedUserId = $userId;
    $creditedByRole = $submittedByRole;
    $canCredit = in_array($role, ['super_admin','admin'], true);
    try {
        if ($canCredit && $marketer_name !== '' && function_exists('tableHasColumn') && tableHasColumn('users','name') && tableHasColumn('users','role')) {
            $stC = $pdo->prepare("SELECT id, role FROM users WHERE name = ? LIMIT 1");
            $stC->execute([$marketer_name]);
            $rowC = $stC->fetch(PDO::FETCH_ASSOC) ?: [];
            $cid = (int)($rowC['id'] ?? 0);
            $crole = strtolower(trim((string)($rowC['role'] ?? '')));
            if ($cid > 0 && $crole !== '' && $crole !== 'client') {
                $creditedUserId = $cid;
                if (strpos($crole, 'contact') !== false || strpos($crole, 'customer') !== false) { $creditedByRole = 'contact_centre'; }
                elseif (in_array($crole, ['marketing','sales','agent','sales_agent'], true)) { $creditedByRole = 'marketing'; }
                else { $creditedByRole = $submittedByRole; }
            }
        }
    } catch (Throwable $eCredit) {}
    $recordedByUserId = $userId;
    $recordedByRole = $role;
    $recordedByName = trim((string)($_SESSION['user_name'] ?? $_SESSION['name'] ?? $_SESSION['full_name'] ?? $_SESSION['username'] ?? ''));
    $performedByUserId = $userId;
    $performedByRole = $submittedByRole;
    $performedByName = $recordedByName;
    if (!empty($canCredit) && $creditedUserId > 0 && $creditedUserId !== $userId) {
        $performedByUserId = $creditedUserId;
        $performedByRole = $creditedByRole;
        $performedByName = $marketer_name !== '' ? $marketer_name : $performedByName;
    }
    if ($performedByName === '' && $performedByUserId > 0) {
        try {
            $cols = [];
            if (function_exists('tableHasColumn') && tableHasColumn('users','name')) { $cols[] = 'name'; }
            if (function_exists('tableHasColumn') && tableHasColumn('users','full_name')) { $cols[] = 'full_name'; }
            if (function_exists('tableHasColumn') && tableHasColumn('users','first_name')) { $cols[] = 'first_name'; }
            if (function_exists('tableHasColumn') && tableHasColumn('users','last_name')) { $cols[] = 'last_name'; }
            if (!empty($cols)) {
                $stU = $pdo->prepare("SELECT " . implode(',', array_unique($cols)) . " FROM users WHERE id = ? LIMIT 1");
                $stU->execute([(int)$performedByUserId]);
                $urow = $stU->fetch(PDO::FETCH_ASSOC) ?: [];
                $nm = trim((string)($urow['name'] ?? ''));
                if ($nm === '') { $nm = trim((string)($urow['full_name'] ?? '')); }
                if ($nm === '') { $nm = trim((string)((string)($urow['first_name'] ?? '') . ' ' . (string)($urow['last_name'] ?? ''))); }
                if ($nm !== '') { $performedByName = $nm; }
            }
        } catch (Throwable $ePbn) {}
    }
    if ($performedByName === '') { $performedByName = ucfirst(strtolower((string)$performedByRole)); }
    $receipt_hash = '';
    $isDuplicate = false;
    if ($receipt && file_exists($receipt)) {
        try {
            $receipt_hash = sha1_file($receipt);
            if (tableHasColumn('payments','receipt_hash')) {
                $chk = $pdo->prepare("SELECT id FROM payments WHERE receipt_hash = ? AND status <> 'rejected' LIMIT 1");
                $chk->execute([$receipt_hash]);
                $isDuplicate = (bool)$chk->fetchColumn();
            } elseif (tableHasColumn('payments','proof_file')) {
                $chk2 = $pdo->prepare("SELECT id FROM payments WHERE proof_file = ? AND status <> 'rejected' LIMIT 1");
                $chk2->execute([$receipt]);
                $isDuplicate = (bool)$chk2->fetchColumn();
            }
        } catch (Throwable $e) {}
    }
    $transactions = [];
    if (!empty($_POST['txn_date']) && is_array($_POST['txn_date'])) {
        $dates = $_POST['txn_date']; $amounts = $_POST['txn_amount'] ?? [];
        foreach ($dates as $i => $d) {
            $raw_amount = isset($amounts[$i]) ? (string)$amounts[$i] : '0';
            $a = (float)str_replace(',', '', $raw_amount);
            if (trim($d) !== '' && $a > 0) $transactions[] = ['date'=>$d,'amount'=>$a];
        }
    }
    $clientId = $client_id;
    if (!$clientId && $client_email !== '') {
        try {
            $stmt = $pdo->prepare("SELECT id FROM users WHERE email = ? LIMIT 1");
            $stmt->execute([$client_email]);
            $clientId = (int)($stmt->fetchColumn() ?: 0);
        } catch (Throwable $e) {}
    }
    if (!$clientId && $client_name !== '') {
        try {
            $stmt = $pdo->prepare("SELECT id FROM users WHERE role = 'client' AND name = ? LIMIT 1");
            $stmt->execute([$client_name]);
            $clientId = (int)($stmt->fetchColumn() ?: 0);
        } catch (Throwable $e) {}
    }
    if ($clientId && $client_name === '') {
        try {
            $stmt = $pdo->prepare("SELECT name FROM users WHERE id = ? LIMIT 1");
            $stmt->execute([$clientId]);
            $client_name = (string)($stmt->fetchColumn() ?: '');
        } catch (Throwable $e) {}
    }
    $setup_link = ''; $setup_code = '';
    $client_created_password = '';
    $client_was_created = false;
    if (!$clientId && $client_email !== '') {
        try {
            $pwd = bin2hex(random_bytes(6));
            $hash = password_hash($pwd, PASSWORD_BCRYPT);
            $cols = []; $vals = [];
            if (function_exists('tableHasColumn') && tableHasColumn('users','company_id') && $companyId) { $cols[]='company_id'; $vals[]=$companyId; }
            if (function_exists('tableHasColumn') && tableHasColumn('users','name')) { $cols[]='name'; $vals[]= $client_name ?: $client_email; }
            if (function_exists('tableHasColumn') && tableHasColumn('users','username') && !tableHasColumn('users','name')) { $cols[]='username'; $vals[]= $client_name ?: $client_email; }
            $cols[]='email'; $vals[]=$client_email;
            if (function_exists('tableHasColumn') && tableHasColumn('users','password')) { $cols[]='password'; $vals[]=$hash; }
            if (function_exists('tableHasColumn') && tableHasColumn('users','role')) { $cols[]='role'; $vals[]='client'; }
            if (function_exists('tableHasColumn') && tableHasColumn('users','status')) { $cols[]='status'; $vals[]='registered'; }
            $sqlU = "INSERT INTO users (" . implode(',', $cols) . ") VALUES (" . implode(',', array_fill(0, count($cols), '?')) . ")";
            $insU = $pdo->prepare($sqlU); $insU->execute($vals);
            $clientId = (int)$pdo->lastInsertId();
            $client_created_password = $pwd;
            $client_was_created = ($clientId > 0);
            try {
                if (function_exists('tableHasColumn') && tableHasColumn('users','exec_otp_code') && tableHasColumn('users','exec_otp_expires')) {
                    $code = str_pad((string)random_int(0, 999999), 6, '0', STR_PAD_LEFT);
                    $exp = date('Y-m-d H:i:s', time() + 172800);
                    $pdo->prepare("UPDATE users SET exec_otp_code = ?, exec_otp_expires = ? WHERE id = ?")->execute([$code, $exp, $clientId]);
                    $setup_code = $code;
                }
            } catch (Throwable $e2) {}
            try {
                $appUrl = function_exists('getSetting') ? getSetting('app_url', '') : '';
                if (!$appUrl) { $appUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost') . rtrim(dirname($_SERVER['PHP_SELF'] ?? '/'), '/'); }
                $setup_link = rtrim($appUrl, '/') . '/login.php';
            } catch (Throwable $e3) { $setup_link = 'login.php'; }
        } catch (Throwable $e) {}
    }
    if ($plan_type === 'full') {
        $amount_paid_so_far = 0.0;
        $discount_amount = 0.0;
        $balance_remaining = 0.0;
        if (!is_finite($amount_offered) || $amount_offered <= 0) { $amount_offered = $paid_now; }
    }
    if ($payment_type !== 'land') {
        $plan_type = 'full';
        $custom_months = 0;
        $installment_start_date = '';
        $amount_offered = 0.0;
        $amount_paid_so_far = 0.0;
        $discount_amount = 0.0;
        $discount_approved_by = '';
        $balance_remaining = 0.0;
        $commission_pct = 0.0;
        $marketer_pct = 0.0;
        $agent_pct = 0.0;
        $marketer_comm = 0.0;
        $agent_comm = 0.0;
    }
    if (!is_finite($commission_pct) || $commission_pct < 0) $commission_pct = 0.0;
    if ($commission_pct > 100.0) $commission_pct = 100.0;
    $commission_pct = round($commission_pct, 2);

    if ($marketer_pct < 0) $marketer_pct = 0.0; if ($marketer_pct > $commission_pct) $marketer_pct = $commission_pct;
    if ($agent_pct < 0) $agent_pct = 0.0; if ($agent_pct > $commission_pct) $agent_pct = $commission_pct;
    $sumPct = round($marketer_pct + $agent_pct, 2);
    if (abs($sumPct - $commission_pct) > 0.01) {
        $agent_pct = round(max(0.0, $commission_pct - $marketer_pct), 2);
    }
    $txnSum = 0.0;
    if (!empty($transactions)) {
        foreach ($transactions as $t) {
            if (isset($t['amount']) && is_finite((float)$t['amount']) && (float)$t['amount'] > 0) {
                $txnSum += (float)$t['amount'];
            }
        }
    }
    if ($payment_type === 'land') {
        $commissionBase = $paid_now;
        if (!is_finite($commissionBase) || $commissionBase <= 0) {
            if (is_finite($txnSum) && $txnSum > 0) { $commissionBase = $txnSum; }
            elseif (is_finite($amount_paid_so_far) && $amount_paid_so_far > 0) { $commissionBase = $amount_paid_so_far; }
            elseif (is_finite($amount_offered) && $amount_offered > 0) { $commissionBase = $amount_offered; }
            else { $commissionBase = 0.0; }
        }
        if ($commissionBase > 0) {
            $marketer_comm = ($commissionBase * ($marketer_pct/100));
            $agent_comm = ($commissionBase * ($agent_pct/100));
        }
    }
    if ($plan_type !== 'full') {
        $discBase = max($amount_offered - $discount_amount, 0);
        $computedBalance = max($discBase - ($amount_paid_so_far + $paid_now), 0);
        
        // SERVER-SIDE OVERPAYMENT PROTECTION
        if (($amount_paid_so_far + $paid_now) > $discBase && $discBase > 0) {
            $error_msg = 'Payment error: Total payments (₦'.number_format($amount_paid_so_far + $paid_now).') exceed the offer amount (₦'.number_format($discBase).').';
            throw new Exception($error_msg);
        }

        if ($balance_remaining <= 0) { $balance_remaining = $computedBalance; }
    }
    // Prepare a unique reference early so it can be included in meta for Finance views
    $uniqRef = date('YmdHis') . '-' . random_int(1000,9999);
    $meta = [
        'client_id' => $clientId,
        'client_name' => $client_name,
        'client_email' => $client_email,
        'marketer_name' => $marketer_name,
        'project_desc' => $project_desc,
        'deal_source' => $deal_source,
        'property_id' => $property_id,
        'payment_type' => $payment_type,
        'sqm' => $sqm,
        'plan_type' => $plan_type,
        'custom_months' => $custom_months,
        'installment_start_date' => $installment_start_date,
        'policy_accepted' => $policy_accepted,
        'amount_offered' => $amount_offered,
        'amount_paid_so_far' => $amount_paid_so_far,
        'discount_amount' => $discount_amount,
        'discount_approved_by' => $discount_approved_by,
        'commission_pct' => $commission_pct,
        'commission_total_pct' => $commission_pct,
        'marketer_pct' => $marketer_pct,
        'agent_pct' => $agent_pct,
        'marketer_comm' => $marketer_comm,
        'agent_comm' => $agent_comm,
        'balance_remaining' => $balance_remaining,
        'client_payment_status' => $client_payment_status,
        'payment_reference' => 'deal-submission-' . $uniqRef,
        'payment_method' => 'Bank Transfer',
        'marketer_bank' => ['acc_no'=>$mk_acc_no,'bank'=>$mk_bank,'acc_name'=>$mk_acc_name],
        'agent_bank' => ['acc_no'=>$ag_acc_no,'bank'=>$ag_bank,'acc_name'=>$ag_acc_name],
        'transactions' => $transactions,
        'submitted_by_role' => $performedByRole,
        'submitted_by_user' => $performedByUserId,
        'submitted_by_name' => $performedByName,
        'recorded_by_role' => $recordedByRole,
        'recorded_by_user' => $recordedByUserId,
        'recorded_by_name' => $recordedByName,
        'credited_to_role' => $creditedByRole,
        'credited_to_user' => $creditedUserId,
        'credited_to_name' => $marketer_name,
    ];
    if ($payment_type !== 'land' && $existing_deal_id <= 0) {
        $error_msg = 'Please select an existing deal/property record before submitting an ' . ucfirst($payment_type) . ' payment.';
        throw new Exception($error_msg);
    }
    $resolvedDealPropertyId = 0;
    if ($existing_deal_id > 0) {
        try {
            $hasDealsTbl = $pdo->query("SHOW TABLES LIKE 'deals'")->rowCount() > 0;
            if ($hasDealsTbl && function_exists('tableHasColumn') && tableHasColumn('deals', 'property_id')) {
                $stDp = $pdo->prepare("SELECT property_id FROM deals WHERE id = ? LIMIT 1");
                $stDp->execute([$existing_deal_id]);
                $resolvedDealPropertyId = (int)($stDp->fetchColumn() ?: 0);
            }
        } catch (Throwable $e) { $resolvedDealPropertyId = 0; }
        if ($resolvedDealPropertyId <= 0) {
            try {
                $hasDsTbl = $pdo->query("SHOW TABLES LIKE 'deals_submit'")->rowCount() > 0;
                if ($hasDsTbl && function_exists('tableHasColumn') && tableHasColumn('deals_submit', 'meta_json')) {
                    $stMj = $pdo->prepare("SELECT meta_json FROM deals_submit WHERE id = ? LIMIT 1");
                    $stMj->execute([$existing_deal_id]);
                    $mjRaw = (string)($stMj->fetchColumn() ?: '');
                    if ($mjRaw !== '') {
                        $mj = json_decode($mjRaw, true);
                        if (is_array($mj)) {
                            $resolvedDealPropertyId = (int)($mj['property_id'] ?? 0);
                        }
                    }
                }
            } catch (Throwable $e) { $resolvedDealPropertyId = 0; }
        }
    }
    if ($resolvedDealPropertyId > 0 && ($payment_type !== 'land' || $property_id <= 0)) {
        $property_id = $resolvedDealPropertyId;
        $meta['property_id'] = $resolvedDealPropertyId;
    }
    $paymentPropertyId = $property_id > 0 ? $property_id : 0;
    if ($paymentPropertyId <= 0) {
        $error_msg = 'Please select a property.';
        throw new Exception($error_msg);
    }
    $accountId = 0;
    $accountMeta = [];
    try {
        $hasAcc = false;
        try { $hasAcc = $pdo->query("SHOW TABLES LIKE 'accounts'")->rowCount() > 0; } catch (Throwable $eTbl) { $hasAcc = false; }
        if ($hasAcc) {
            $sqlA = "SELECT id, account_name, bank_name, account_number FROM accounts WHERE property_id = ? AND account_type = ? AND is_active = 1";
            $paramsA = [$paymentPropertyId, $payment_type];
            if ($companyId && function_exists('tableHasColumn') && tableHasColumn('accounts','company_id')) { $sqlA .= " AND (company_id = ? OR company_id IS NULL)"; $paramsA[] = $companyId; }
            $sqlA .= " ORDER BY id DESC LIMIT 1";
            $stA = $pdo->prepare($sqlA);
            $stA->execute($paramsA);
            $rowA = $stA->fetch(PDO::FETCH_ASSOC);
            if ($rowA) {
                $accountId = (int)($rowA['id'] ?? 0);
                $accountMeta = [
                    'account_name' => (string)($rowA['account_name'] ?? ''),
                    'bank_name' => (string)($rowA['bank_name'] ?? ''),
                    'account_number' => (string)($rowA['account_number'] ?? ''),
                ];
            }
        }
    } catch (Throwable $eAcc) {}
    if ($accountId <= 0) {
        $error_msg = 'No active bank account configured for this property and payment type (' . $payment_type . '). Please open Finance → Property Bank Accounts and ensure the ' . ucfirst($payment_type) . ' account is saved and Active.';
        throw new Exception($error_msg);
    }
    $meta['account_id'] = $accountId;
    $meta['account'] = $accountMeta;
    if ($payment_type !== 'land') {
        $chargeTotal = 0.0;
        try {
            $hasPc = $pdo->query("SHOW TABLES LIKE 'property_charges'")->rowCount() > 0;
            if ($hasPc) {
                $q = "SELECT charge_name, amount FROM property_charges WHERE property_id = ? AND is_active = 1";
                $paramsPc = [$paymentPropertyId];
                if ($companyId && function_exists('tableHasColumn') && tableHasColumn('property_charges','company_id')) { $q .= " AND (company_id = ? OR company_id IS NULL OR company_id = 0)"; $paramsPc[] = $companyId; }
                $stPc = $pdo->prepare($q);
                $stPc->execute($paramsPc);
                $rowsPc = $stPc->fetchAll(PDO::FETCH_ASSOC) ?: [];
                foreach ($rowsPc as $r) {
                    $nm = strtolower(trim((string)($r['charge_name'] ?? '')));
                    $amt = (float)($r['amount'] ?? 0);
                    if (!is_finite($amt) || $amt < 0) $amt = 0.0;
                    if ($payment_type === 'infrastructure' && (strpos($nm, 'infra') !== false || strpos($nm, 'infrastructure') !== false)) { $chargeTotal += $amt; }
                    if ($payment_type === 'excavation' && (strpos($nm, 'excav') !== false || strpos($nm, 'excavation') !== false || strpos($nm, 'escav') !== false)) { $chargeTotal += $amt; }
                }
            }
        } catch (Throwable $ePc) {}
        if ($chargeTotal <= 0) {
            $error_msg = 'No ' . ucfirst($payment_type) . ' charge configured for this property. Please open Finance → Property Bank Accounts, select this property, and add an Active charge named "' . ucfirst($payment_type) . ' Fee" with the correct amount.';
            throw new Exception($error_msg);
        }
        $finalStatuses = function_exists('kpiPaymentFinalizedStatuses') ? (array)kpiPaymentFinalizedStatuses() : ['verified','approved','paid','completed','success'];
        $statusSql = function_exists('kpiSqlList') ? kpiSqlList($finalStatuses) : "('verified','approved','paid','completed','success')";
        $payCompany = ($companyId && function_exists('tableHasColumn') && tableHasColumn('payments','company_id')) ? " AND (company_id = " . (int)$companyId . " OR company_id IS NULL)" : "";
        $propClause = (function_exists('tableHasColumn') && tableHasColumn('payments','property_id')) ? " AND property_id = " . (int)$paymentPropertyId : "";
        $typeClause = (function_exists('tableHasColumn') && tableHasColumn('payments','payment_type')) ? " AND LOWER(TRIM(payment_type)) = " . $pdo->quote($payment_type) : "";
        $userWhere = (function_exists('tableHasColumn') && tableHasColumn('payments','user_id')) ? "user_id = " . (int)$clientId : "1=0";
        $clientWhere = (function_exists('tableHasColumn') && tableHasColumn('payments','client_id')) ? "client_id = " . (int)$clientId : "1=0";
        $paidApproved = 0.0;
        try {
            $paidApproved = (float)$pdo->query("SELECT COALESCE(SUM(amount),0) FROM payments WHERE (" . $userWhere . " OR " . $clientWhere . ") AND status IN {$statusSql}{$payCompany}{$propClause}{$typeClause}")->fetchColumn();
        } catch (Throwable $ePaid) { $paidApproved = 0.0; }
        $outstanding = max(0.0, $chargeTotal - $paidApproved);
        if ($paid_now > ($outstanding + 0.01) && $outstanding > 0) {
            $error_msg = ucfirst($payment_type) . ' payment exceeds outstanding balance. Outstanding: ₦' . number_format($outstanding, 2);
            throw new Exception($error_msg);
        }
        $meta['charge_total'] = $chargeTotal;
        $meta['charge_paid'] = $paidApproved;
        $meta['charge_balance'] = $outstanding;
    }
    $crmClientId = 0;
    try {
        $hasClientsTbl = $pdo->query("SHOW TABLES LIKE 'clients'")->rowCount() > 0;
        if ($hasClientsTbl) {
            $uEmail = $client_email;
            $uName = $client_name;
            $uPhone = '';
            if ($clientId > 0) {
                try {
                    $sel = [];
                    if (function_exists('tableHasColumn') && tableHasColumn('users','email')) { $sel[] = 'email'; }
                    if (function_exists('tableHasColumn') && tableHasColumn('users','name')) { $sel[] = 'name'; }
                    if (function_exists('tableHasColumn') && tableHasColumn('users','phone')) { $sel[] = 'phone'; }
                    if (!empty($sel)) {
                        $stU = $pdo->prepare("SELECT " . implode(',', $sel) . " FROM users WHERE id = ? LIMIT 1");
                        $stU->execute([$clientId]);
                        $ru = $stU->fetch(PDO::FETCH_ASSOC) ?: [];
                        if ($uEmail === '' && isset($ru['email'])) { $uEmail = trim((string)$ru['email']); }
                        if ($uName === '' && isset($ru['name'])) { $uName = trim((string)$ru['name']); }
                        if (isset($ru['phone'])) { $uPhone = trim((string)$ru['phone']); }
                    }
                } catch (Throwable $eU) {}
            }
            try {
                if (function_exists('tableHasColumn') && tableHasColumn('clients','user_id') && $clientId > 0) {
                    $q = $pdo->prepare("SELECT id FROM clients WHERE user_id = ? ORDER BY id DESC LIMIT 1");
                    $q->execute([$clientId]);
                    $crmClientId = (int)($q->fetchColumn() ?: 0);
                }
            } catch (Throwable $eC1) {}
            if ($crmClientId <= 0 && $uEmail !== '' && function_exists('tableHasColumn') && tableHasColumn('clients','email')) {
                try {
                    $q = $pdo->prepare("SELECT id FROM clients WHERE email = ? ORDER BY id DESC LIMIT 1");
                    $q->execute([$uEmail]);
                    $crmClientId = (int)($q->fetchColumn() ?: 0);
                } catch (Throwable $eC2) {}
            }
            if ($crmClientId <= 0) {
                try {
                    $cCols = []; $cPh = []; $cVals = [];
                    if (function_exists('tableHasColumn') && tableHasColumn('clients','user_id')) { $cCols[]='user_id'; $cPh[]='?'; $cVals[]=$clientId ?: null; }
                    if (function_exists('tableHasColumn') && tableHasColumn('clients','email')) {
                        $em = $uEmail !== '' ? $uEmail : ('client' . ($clientId ?: time()) . '+' . $uniqRef . '@local.invalid');
                        $cCols[]='email'; $cPh[]='?'; $cVals[]=$em;
                    }
                    if (function_exists('tableHasColumn') && tableHasColumn('clients','phone')) {
                        $ph = $uPhone !== '' ? $uPhone : '0000000000';
                        $cCols[]='phone'; $cPh[]='?'; $cVals[]=$ph;
                    }
                    if (function_exists('tableHasColumn') && tableHasColumn('clients','agent_id') && $userId > 0) { $cCols[]='agent_id'; $cPh[]='?'; $cVals[]=$userId; }
                    if (function_exists('tableHasColumn') && tableHasColumn('clients','status')) { $cCols[]='status'; $cPh[]='?'; $cVals[]='active'; }
                    if (function_exists('tableHasColumn') && tableHasColumn('clients','company_id') && $companyId) { $cCols[]='company_id'; $cPh[]='?'; $cVals[]=$companyId; }
                    if (function_exists('tableHasColumn') && tableHasColumn('clients','first_name')) {
                        $first = $uName !== '' ? preg_split('/\s+/', trim($uName))[0] : 'Client';
                        $cCols[]='first_name'; $cPh[]='?'; $cVals[]=$first;
                    }
                    if (function_exists('tableHasColumn') && tableHasColumn('clients','last_name')) {
                        $parts = $uName !== '' ? preg_split('/\s+/', trim($uName)) : [];
                        $last = count($parts) > 1 ? trim(implode(' ', array_slice($parts, 1))) : 'Client';
                        $cCols[]='last_name'; $cPh[]='?'; $cVals[]=$last;
                    }
                    if (function_exists('tableHasColumn') && tableHasColumn('clients','name') && $uName !== '') { $cCols[]='name'; $cPh[]='?'; $cVals[]=$uName; }
                    if (function_exists('tableHasColumn') && tableHasColumn('clients','created_at')) { $cCols[]='created_at'; $cPh[]='NOW()'; }
                    if (!empty($cCols)) {
                        $sqlC = "INSERT INTO clients (" . implode(',', $cCols) . ") VALUES (" . implode(',', $cPh) . ")";
                        $insC = $pdo->prepare($sqlC);
                        $insC->execute($cVals);
                        $crmClientId = (int)$pdo->lastInsertId();
                    }
                } catch (Throwable $eInsC) { $crmClientId = 0; }
            }
        }
    } catch (Throwable $eClients) { $crmClientId = 0; }
        $dealId = (int)$existing_deal_id;
        if ($dealId > 0) {
            $existsInDeals = 0;
            try {
                $chk = $pdo->prepare("SELECT id FROM deals WHERE id = ? LIMIT 1");
                $chk->execute([$dealId]);
                $existsInDeals = (int)($chk->fetchColumn() ?: 0);
            } catch (Throwable $eChkDeal) { $existsInDeals = 0; }
            if ($existsInDeals <= 0) {
                $resolved = 0;
                try {
                    $hasDsTbl = $pdo->query("SHOW TABLES LIKE 'deals_submit'")->rowCount() > 0;
                    if ($hasDsTbl && function_exists('tableHasColumn') && tableHasColumn('deals_submit','deal_id')) {
                        $st = $pdo->prepare("SELECT deal_id FROM deals_submit WHERE id = ? LIMIT 1");
                        $st->execute([$dealId]);
                        $resolved = (int)($st->fetchColumn() ?: 0);
                    }
                } catch (Throwable $eResolve) { $resolved = 0; }
                if ($resolved > 0) {
                    $dealId = $resolved;
                } else {
                    try {
                        $pdo->exec("INSERT INTO deals (id) VALUES (NULL)");
                        $newDealId = (int)$pdo->lastInsertId();
                        if ($newDealId > 0) {
                            try {
                                $sets = [];
                                $valsSet = [];
                                if (function_exists('tableHasColumn') && tableHasColumn('deals','user_id') && $clientId > 0) { $sets[] = "user_id = ?"; $valsSet[] = $clientId; }
                                if (function_exists('tableHasColumn') && tableHasColumn('deals','property_id') && $paymentPropertyId > 0) { $sets[] = "property_id = ?"; $valsSet[] = $paymentPropertyId; }
                                if (function_exists('tableHasColumn') && tableHasColumn('deals','project_desc') && $project_desc !== '') { $sets[] = "project_desc = ?"; $valsSet[] = $project_desc; }
                                if (!empty($sets)) {
                                    $valsSet[] = $newDealId;
                                    $pdo->prepare("UPDATE deals SET " . implode(', ', $sets) . " WHERE id = ?")->execute($valsSet);
                                }
                            } catch (Throwable $eBackfill) {}
                            try {
                                $hasDsTbl2 = $pdo->query("SHOW TABLES LIKE 'deals_submit'")->rowCount() > 0;
                                if ($hasDsTbl2 && function_exists('tableHasColumn') && tableHasColumn('deals_submit','deal_id')) {
                                    $pdo->prepare("UPDATE deals_submit SET deal_id = ? WHERE id = ?")->execute([$newDealId, (int)$existing_deal_id]);
                                }
                            } catch (Throwable $eLinkNew) {}
                            $dealId = $newDealId;
                        }
                    } catch (Throwable $eCreateDeal) {}
                }
            }
            if ($dealId <= 0) {
                throw new Exception('Payment must be linked to an existing deal.');
            }
        } else {
            try {
                if (function_exists('tableHasColumn')) {
                    $defs = [
                        'user_id INT NULL',
                        'deal_id INT NULL',
                        'marketer_id INT NULL',
                        'marketer_name VARCHAR(255) NULL',
                        'deal_source VARCHAR(100) NULL',
                        'project_name VARCHAR(255) NULL',
                        'project_desc VARCHAR(255) NULL',
                        'project_id INT NULL',
                        'payment_plan VARCHAR(50) NULL',
                        'installment_start_date DATE NULL',
                        'policy_accepted TINYINT(1) DEFAULT 0',
                        'amount_offered DECIMAL(15,2) NULL',
                        'amount_paid_so_far DECIMAL(15,2) NULL',
                        'discount_amount DECIMAL(15,2) NULL',
                        'discount_approved_by VARCHAR(255) NULL',
                        'commission_percent DECIMAL(5,2) NULL',
                        'marketer_commission DECIMAL(15,2) NULL',
                        'agent_commission DECIMAL(15,2) NULL',
                        'balance_remaining DECIMAL(15,2) NULL',
                        'marketer_bank JSON NULL',
                        'agent_bank JSON NULL',
                        'notes TEXT NULL',
                        'receipt_file VARCHAR(255) NULL',
                        'status VARCHAR(50) NULL',
                        'submitted_by INT NULL',
                        'submitted_by_user INT NULL',
                        'submitted_by_role VARCHAR(50) NULL',
                        'company_id INT NULL',
                        'meta_json JSON NULL',
                        'created_at DATETIME DEFAULT CURRENT_TIMESTAMP'
                    ];
                    foreach ($defs as $def) {
                        $col = trim(strtok($def, ' '));
                        try { $pdo->exec("ALTER TABLE deals_submit ADD COLUMN IF NOT EXISTS $def"); } catch (Throwable $eAdd) {
                            if (!tableHasColumn('deals_submit', $col)) {
                                try { $pdo->exec("ALTER TABLE deals_submit ADD COLUMN $def"); } catch (Throwable $eAdd2) {}
                            }
                        }
                    }
                }
            } catch (Throwable $eSchema) {}

            $resolvedPropertyId = (int)($property_id ?? 0);
            try {
                if ($resolvedPropertyId <= 0) {
                    $hasProps = $pdo->query("SHOW TABLES LIKE 'properties'")->rowCount() > 0;
                    if ($hasProps && function_exists('tableHasColumn') && tableHasColumn('properties', 'title')) {
                        $cand = trim((string)($project_desc ?? ''));
                        if ($cand === '') { $cand = trim((string)($project_name ?? '')); }
                        if ($cand !== '') {
                            $stP1 = $pdo->prepare("SELECT id FROM properties WHERE LOWER(title) = LOWER(?) ORDER BY id DESC LIMIT 1");
                            $stP1->execute([$cand]);
                            $resolvedPropertyId = (int)($stP1->fetchColumn() ?: 0);
                            if ($resolvedPropertyId <= 0) {
                                $stP2 = $pdo->prepare("SELECT id FROM properties WHERE LOWER(title) LIKE ? ORDER BY id DESC LIMIT 1");
                                $stP2->execute(['%' . strtolower($cand) . '%']);
                                $resolvedPropertyId = (int)($stP2->fetchColumn() ?: 0);
                            }
                        }
                    }
                }
            } catch (Throwable $ePropResolve) { $resolvedPropertyId = 0; }

            try {
                $dCols = []; $dPh = []; $dVals = [];
                // ALWAYS write core fields into deals (columns ensured at startup)
                $dCols[]='user_id'; $dPh[]='?'; $dVals[]=$clientId ?: null;
                // Attempt to resolve marketer_id from marketer_name if users table is present
                $marketerId = 0;
                try {
                    if ($marketer_name !== '' && function_exists('tableHasColumn') && tableHasColumn('users','name')) {
                        $qm = $pdo->prepare("SELECT id FROM users WHERE name = ? LIMIT 1");
                        $qm->execute([$marketer_name]);
                        $marketerId = (int)($qm->fetchColumn() ?: 0);
                    }
                } catch (Throwable $eMk) {}
                $dCols[]='marketer_id'; $dPh[]='?'; $dVals[]=$marketerId ?: null;
                $dCols[]='marketer_name'; $dPh[]='?'; $dVals[]=$marketer_name ?: null;
                $dCols[]='deal_source'; $dPh[]='?'; $dVals[]=$deal_source ?: null;
                $resolvedProjectId = 0;
                try {
                    if ($project_name !== '' && $pdo->query("SHOW TABLES LIKE 'projects'")->rowCount() > 0) {
                        $q = "SELECT id FROM projects WHERE (name = ? OR name LIKE ? OR ? LIKE CONCAT('%', name, '%'))";
                        $params = [$project_name, '%' . $project_name . '%', $project_name];
                        if ($companyId && function_exists('tableHasColumn') && tableHasColumn('projects','company_id')) {
                            $q .= " AND (company_id = ? OR company_id IS NULL)";
                            $params[] = $companyId;
                        }
                        $q .= " ORDER BY (name = ?) DESC, CHAR_LENGTH(name) DESC LIMIT 1";
                        $params[] = $project_name;
                        $stP = $pdo->prepare($q);
                        $stP->execute($params);
                        $resolvedProjectId = (int)($stP->fetchColumn() ?: 0);
                    }
                } catch (Throwable $eProj) { $resolvedProjectId = 0; }
                if (isset($meta) && is_array($meta)) { $meta['project_id'] = $resolvedProjectId ?: null; }
                // Always store project_name (canonical) and project_desc for reference
                $dCols[]='project_name'; $dPh[]='?'; $dVals[]=($project_name !== '' ? $project_name : ($project_desc ?: null));
                $dCols[]='project_desc'; $dPh[]='?'; $dVals[]=$project_desc ?: null;
                if (function_exists('tableHasColumn') && tableHasColumn('deals_submit','project_id')) { $dCols[]='project_id'; $dPh[]='?'; $dVals[]=$resolvedProjectId ?: null; }
                $dCols[]='payment_plan'; $dPh[]='?'; $dVals[]=$plan_type ?: null;
                if (function_exists('tableHasColumn') && tableHasColumn('deals_submit','installment_start_date')) { $dCols[]='installment_start_date'; $dPh[]='?'; $dVals[]=$installment_start_date ?: null; }
                if (function_exists('tableHasColumn') && tableHasColumn('deals_submit','policy_accepted')) { $dCols[]='policy_accepted'; $dPh[]='?'; $dVals[]=$policy_accepted; }
                $dCols[]='amount_offered'; $dPh[]='?'; $dVals[]=$amount_offered;
                $dCols[]='amount_paid_so_far'; $dPh[]='?'; $dVals[]=$amount_paid_so_far;
                $dCols[]='discount_amount'; $dPh[]='?'; $dVals[]=$discount_amount;
                $dCols[]='discount_approved_by'; $dPh[]='?'; $dVals[]=$discount_approved_by ?: null;
                $dCols[]='commission_percent'; $dPh[]='?'; $dVals[]=$commission_pct;
                $dCols[]='marketer_commission'; $dPh[]='?'; $dVals[]=$marketer_comm;
                $dCols[]='agent_commission'; $dPh[]='?'; $dVals[]=$agent_comm;
                $dCols[]='balance_remaining'; $dPh[]='?'; $dVals[]=$balance_remaining;
                $dCols[]='notes'; $dPh[]='?'; $dVals[]=$client_payment_status ?: null;
                $dCols[]='receipt_file'; $dPh[]='?'; $dVals[]=$receipt ?: null;
                $dCols[]='status'; $dPh[]='?'; $dVals[]='pending_verification';
                $dCols[]='submitted_by'; $dPh[]='?'; $dVals[]=$performedByUserId > 0 ? (int)$performedByUserId : null;
                if (function_exists('tableHasColumn') && tableHasColumn('deals_submit','submitted_by_user')) { $dCols[]='submitted_by_user'; $dPh[]='?'; $dVals[]=(int)$performedByUserId; }
                if (function_exists('tableHasColumn') && tableHasColumn('deals_submit','submitted_by_role')) { $dCols[]='submitted_by_role'; $dPh[]='?'; $dVals[]=$performedByRole !== '' ? $performedByRole : null; }
                if ($companyId) { $dCols[]='company_id'; $dPh[]='?'; $dVals[]=$companyId; }
                $dCols[]='created_at'; $dPh[]='NOW()';
                if (function_exists('tableHasColumn') ? tableHasColumn('deals_submit','marketer_bank') : true) {
                    $dCols[]='marketer_bank'; $dPh[]='?';
                    $dVals[] = !empty($meta['marketer_bank']) && is_array($meta['marketer_bank']) ? json_encode($meta['marketer_bank']) : null;
                }
                if (function_exists('tableHasColumn') ? tableHasColumn('deals_submit','agent_bank') : true) {
                    $dCols[]='agent_bank'; $dPh[]='?';
                    $dVals[] = !empty($meta['agent_bank']) && is_array($meta['agent_bank']) ? json_encode($meta['agent_bank']) : null;
                }
                if (function_exists('tableHasColumn') ? tableHasColumn('deals_submit','meta_json') : true) { $dCols[]='meta_json'; $dPh[]='?'; $dVals[] = json_encode($meta); }
                if (!empty($dCols)) {
                    $sqlD = "INSERT INTO deals_submit (" . implode(',', $dCols) . ") VALUES (" . implode(',', $dPh) . ")";
                    try { @file_put_contents(__DIR__ . '/debug_sql.txt', "DEAL_SQL:\n".$sqlD."\nPARAMS:\n".print_r($dVals, true)."\n", FILE_APPEND); } catch (Throwable $eDbg) {}
                    try {
                        $insD = $pdo->prepare($sqlD);
                        $insD->execute($dVals);
                        $submitId = (int)$pdo->lastInsertId();
                    } catch (Throwable $eInsD) {
                        try { @file_put_contents(__DIR__ . '/debug_sql.txt', "DEAL_SQL_ERROR:\n".(string)$eInsD."\n", FILE_APPEND); } catch (Throwable $eDbgE) {}
                        $submitId = 0;
                    }
                    if (!empty($_GET['break_deal']) || !empty($_POST['break_deal'])) {
                        echo "SUBMIT ID: ".$submitId;
                        exit;
                    }
                    if ($submitId > 0) { 
                        $dealId = $submitId; 
                        try {
                            $cols2 = []; $ph2 = []; $vals2 = [];
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','user_id')) { $cols2[]='user_id'; $ph2[]='?'; $vals2[]=$clientId ?: null; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','marketer_id')) { 
                                // reuse marketerId if available
                                $cols2[]='marketer_id'; $ph2[]='?'; $vals2[]=$marketerId ?: null; 
                            }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','marketer_name')) { $cols2[]='marketer_name'; $ph2[]='?'; $vals2[]=$marketer_name ?: null; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','deal_source')) { $cols2[]='deal_source'; $ph2[]='?'; $vals2[]=$deal_source ?: null; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','project_name')) { $cols2[]='project_name'; $ph2[]='?'; $vals2[]=($project_name !== '' ? $project_name : ($project_desc ?: null)); }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','project_desc')) { $cols2[]='project_desc'; $ph2[]='?'; $vals2[]=$project_desc ?: null; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','project_id')) { $cols2[]='project_id'; $ph2[]='?'; $vals2[]=$resolvedProjectId ?: null; }
                            
                            // Try to satisfy legacy 'deals' table requirements
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','property_id') && $resolvedPropertyId > 0) { $cols2[]='property_id'; $ph2[]='?'; $vals2[]=$resolvedPropertyId; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','client_id') && $crmClientId > 0) { $cols2[]='client_id'; $ph2[]='?'; $vals2[]=$crmClientId; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','agent_id') && $userId > 0) { $cols2[]='agent_id'; $ph2[]='?'; $vals2[]=$userId; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','type')) { $cols2[]='type'; $ph2[]='?'; $vals2[]='Sale'; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','value')) { $cols2[]='value'; $ph2[]='?'; $vals2[]=$amount_offered ?: $paid_now; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','date')) { $cols2[]='date'; $ph2[]='?'; $vals2[]=date('Y-m-d'); }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','reference')) { $cols2[]='reference'; $ph2[]='?'; $vals2[]='DEAL-' . $uniqRef; }

                            if (function_exists('tableHasColumn') && tableHasColumn('deals','payment_plan')) { $cols2[]='payment_plan'; $ph2[]='?'; $vals2[]=$plan_type ?: null; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','amount_offered')) { $cols2[]='amount_offered'; $ph2[]='?'; $vals2[]=$amount_offered; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','amount_paid_so_far')) { $cols2[]='amount_paid_so_far'; $ph2[]='?'; $vals2[]=$amount_paid_so_far; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','discount_amount')) { $cols2[]='discount_amount'; $ph2[]='?'; $vals2[]=$discount_amount; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','discount_approved_by')) { $cols2[]='discount_approved_by'; $ph2[]='?'; $vals2[]=$discount_approved_by ?: null; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','commission_percent')) { $cols2[]='commission_percent'; $ph2[]='?'; $vals2[]=$commission_pct; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','marketer_commission')) { $cols2[]='marketer_commission'; $ph2[]='?'; $vals2[]=$marketer_comm; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','agent_commission')) { $cols2[]='agent_commission'; $ph2[]='?'; $vals2[]=$agent_comm; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','balance_remaining')) { $cols2[]='balance_remaining'; $ph2[]='?'; $vals2[]=$balance_remaining; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','notes')) { $cols2[]='notes'; $ph2[]='?'; $vals2[]=$client_payment_status ?: null; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','receipt_file')) { $cols2[]='receipt_file'; $ph2[]='?'; $vals2[]=$receipt ?: null; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','status')) { $cols2[]='status'; $ph2[]='?'; $vals2[]='pending_verification'; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','submitted_by')) { $cols2[]='submitted_by'; $ph2[]='?'; $vals2[]=$performedByUserId > 0 ? (int)$performedByUserId : null; }
                            if ($companyId && function_exists('tableHasColumn') && tableHasColumn('deals','company_id')) { $cols2[]='company_id'; $ph2[]='?'; $vals2[]=$companyId; }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','meta_json')) { $cols2[]='meta_json'; $ph2[]='?'; $vals2[] = json_encode($meta); }
                            if (function_exists('tableHasColumn') && tableHasColumn('deals','created_at')) { $cols2[]='created_at'; $ph2[]='NOW()'; }
                            if (!empty($cols2)) {
                                $sql2 = "INSERT INTO deals (" . implode(',', $cols2) . ") VALUES (" . implode(',', $ph2) . ")";
                                $ins2 = $pdo->prepare($sql2);
                                $bindVals2 = $vals2;
                                $ins2->execute($bindVals2);
                                $dealRowId = (int)$pdo->lastInsertId();
                                if ($dealRowId > 0) {
                                    $dealId = $dealRowId;
                                    try {
                                        if (function_exists('tableHasColumn') && tableHasColumn('deals_submit','deal_id')) {
                                            $pdo->prepare("UPDATE deals_submit SET deal_id = ? WHERE id = ?")->execute([$dealRowId, $submitId]);
                                        }
                                    } catch (Throwable $eLinkSub) {}
                                }
                            } else {
                                try {
                                    $pdo->exec("INSERT INTO deals (id) VALUES (NULL)");
                                    $dealRowId = (int)$pdo->lastInsertId();
                                    if ($dealRowId > 0) { $dealId = $dealRowId; }
                                } catch (Throwable $eOnlyId) {}
                            }
                        } catch (Throwable $eDealShadow) {}
                    }
                }
            } catch (Throwable $de) {}
        }

        $fields = []; $places = []; $vals = [];
        if ($clientId > 0 && tableHasColumn('payments','user_id')) { $fields[]='user_id'; $places[]='?'; $vals[]=$clientId; }
        if ($clientId > 0 && tableHasColumn('payments','client_id')) { $fields[]='client_id'; $places[]='?'; $vals[]=$clientId; }
        if ($paymentPropertyId > 0 && tableHasColumn('payments','property_id')) { $fields[]='property_id'; $places[]='?'; $vals[]=$paymentPropertyId; }
        if (tableHasColumn('payments','payment_type')) { $fields[]='payment_type'; $places[]='?'; $vals[]=$payment_type; }
        if ($accountId > 0 && tableHasColumn('payments','account_id')) { $fields[]='account_id'; $places[]='?'; $vals[]=$accountId; }
        if ($performedByUserId > 0 && tableHasColumn('payments','submitted_by_user')) { $fields[]='submitted_by_user'; $places[]='?'; $vals[]=(int)$performedByUserId; }
        if (tableHasColumn('payments','submitted_by_name')) { $fields[]='submitted_by_name'; $places[]='?'; $vals[]=$performedByName !== '' ? $performedByName : null; }
        if (tableHasColumn('payments','submitted_by_role')) { $fields[]='submitted_by_role'; $places[]='?'; $vals[]=$performedByRole !== '' ? $performedByRole : null; }
        $validDealId = 0;
        if ($dealId > 0) {
            try { $chk = $pdo->prepare("SELECT id FROM deals WHERE id = ? LIMIT 1"); $chk->execute([$dealId]); $validDealId = (int)($chk->fetchColumn() ?: 0); } catch (Throwable $e) {}
        }
        if ($validDealId <= 0) {
            throw new Exception('Payment must be linked to a valid deal.');
        }
        if ($validDealId > 0 && tableHasColumn('payments','deal_id')) { $fields[]='deal_id'; $places[]='?'; $vals[]=$validDealId; }
        if (tableHasColumn('payments','amount')) { $fields[]='amount'; $places[]='?'; $vals[]=$paid_now; }
        if (tableHasColumn('payments','status')) { $fields[]='status'; $places[]='?'; $vals[]=$isDuplicate ? 'duplicate' : 'pending_verification'; }
        if (tableHasColumn('payments','payment_method')) { $fields[]='payment_method'; $places[]='?'; $vals[]='Bank Transfer'; }
        elseif (tableHasColumn('payments','method')) { $fields[]='method'; $places[]='?'; $vals[]='Bank Transfer'; }
        if (tableHasColumn('payments','reference')) {
            $fields[]='reference'; $places[]='?';
            $vals[]='deal-submission-' . $uniqRef;
        }
        if (tableHasColumn('payments','proof_file')) { $fields[]='proof_file'; $places[]='?'; $vals[]=$receipt ?: null; }
        if ($receipt_hash && tableHasColumn('payments','receipt_hash')) { $fields[]='receipt_hash'; $places[]='?'; $vals[]=$receipt_hash; }
        if ($sqm > 0 && tableHasColumn('payments','sqm')) { $fields[]='sqm'; $places[]='?'; $vals[]=$sqm; }
        if ($companyId && tableHasColumn('payments','company_id')) { $fields[]='company_id'; $places[]='?'; $vals[]=$companyId; }
        if (tableHasColumn('payments','created_at')) { $fields[]='created_at'; $places[]='NOW()'; }
        if ($fields) {
            $sql = "INSERT INTO payments (" . implode(',', $fields) . ") VALUES (" . implode(',', $places) . ")";
            try { @file_put_contents(__DIR__ . '/debug_sql.txt', "PAYMENT_SQL:\n".$sql."\nPARAMS:\n".print_r($vals, true)."\n", FILE_APPEND); } catch (Throwable $eDbg2) {}
            $ins = $pdo->prepare($sql);
            $ins->execute($vals);
            $pid = (int)$pdo->lastInsertId();

            if ($validDealId > 0) {
                try {
                    $hasDealIdCol = true;
                    if (function_exists('tableHasColumn')) {
                        $hasDealIdCol = tableHasColumn('payments','deal_id');
                    }
                    if (!$hasDealIdCol) {
                        try { $pdo->exec("ALTER TABLE payments ADD COLUMN deal_id INT NULL"); } catch (Throwable $eAlt) {}
                    }
                    $pdo->prepare("UPDATE payments SET deal_id = ? WHERE id = ?")->execute([$validDealId, $pid]);
                    try { @file_put_contents(__DIR__ . '/debug_sql.txt', "PAYMENT_LINK:\nUPDATE payments SET deal_id = {$validDealId} WHERE id = {$pid}\n", FILE_APPEND); } catch (Throwable $eDbg3) {}
                } catch (Throwable $eLink) {
                    try { @file_put_contents(__DIR__ . '/debug_sql.txt', "PAYMENT_LINK_ERROR:\n".(string)$eLink."\n", FILE_APPEND); } catch (Throwable $eDbg4) {}
                }
            }
            // Optional debug capture when requested
            if (!empty($_GET['debug']) || !empty($_POST['debug'])) {
                echo "<pre style=\"white-space:pre-wrap\">";
                echo "deal_data:\n"; print_r(['id'=>$dealId,'cols'=>$dCols ?? [],'vals'=>$dVals ?? []]);
                echo "\npayment_data:\n"; print_r(['id'=>$pid,'fields'=>$fields,'vals'=>$vals]);
                echo "</pre>";
            }
            if (tableHasColumn('payments','meta_json')) {
                $up = $pdo->prepare("UPDATE payments SET meta_json = ? WHERE id = ?");
                $up->execute([json_encode($meta), $pid]);
            } else {
                if (function_exists('logActivity')) {
                    logActivity($userId, 'Deal Submission', 'Payment ID '.$pid.' | '.json_encode($meta));
                }
            }
            try {
                $hasTx = $pdo->query("SHOW TABLES LIKE 'transactions'")->rowCount() > 0;
                if ($hasTx) {
                    $tCols = []; $tPh = []; $tVals = [];
                    if ($clientId > 0 && tableHasColumn('transactions','user_id')) { $tCols[]='user_id'; $tPh[]='?'; $tVals[]=$clientId; }
                    if ($dealId > 0 && tableHasColumn('transactions','deal_id')) { $tCols[]='deal_id'; $tPh[]='?'; $tVals[]=$dealId; }
                    if (tableHasColumn('transactions','amount')) { $tCols[]='amount'; $tPh[]='?'; $tVals[]=$paid_now; }
                    if (tableHasColumn('transactions','transaction_type')) { $tCols[]='transaction_type'; $tPh[]='?'; $tVals[]='deal_submission'; }
                    if (tableHasColumn('transactions','status')) { $tCols[]='status'; $tPh[]='?'; $tVals[]=$isDuplicate ? 'duplicate' : 'pending_verification'; }
                    if (tableHasColumn('transactions','reference')) { $tCols[]='reference'; $tPh[]='?'; $tVals[]=('deal-submission-' . $uniqRef); }
                    elseif (tableHasColumn('transactions','ref')) { $tCols[]='ref'; $tPh[]='?'; $tVals[]=('deal-submission-' . $uniqRef); }
                    if ($companyId && tableHasColumn('transactions','company_id')) { $tCols[]='company_id'; $tPh[]='?'; $tVals[]=$companyId; }
                    if (tableHasColumn('transactions','created_at')) { $tCols[]='created_at'; $tPh[]='NOW()'; }
                    if (!empty($tCols)) {
                        $sqlT = "INSERT INTO transactions (" . implode(',', $tCols) . ") VALUES (" . implode(',', $tPh) . ")";
                        $insT = $pdo->prepare($sqlT); $insT->execute($tVals);
                    }
                    if (!empty($transactions) && tableHasColumn('transactions','amount')) {
                        foreach ($transactions as $tx) {
                            $txAmt = (float)($tx['amount'] ?? 0);
                            $txDate = (string)($tx['date'] ?? '');
                            if ($txAmt > 0 && $txDate !== '') {
                                $tCols2 = []; $tPh2 = []; $tVals2 = [];
                                if ($clientId > 0 && tableHasColumn('transactions','user_id')) { $tCols2[]='user_id'; $tPh2[]='?'; $tVals2[]=$clientId; }
                                if ($dealId > 0 && tableHasColumn('transactions','deal_id')) { $tCols2[]='deal_id'; $tPh2[]='?'; $tVals2[]=$dealId; }
                                if (tableHasColumn('transactions','amount')) { $tCols2[]='amount'; $tPh2[]='?'; $tVals2[]=$txAmt; }
                                if (tableHasColumn('transactions','transaction_type')) { $tCols2[]='transaction_type'; $tPh2[]='?'; $tVals2[]='installment'; }
                                if (tableHasColumn('transactions','status')) { $tCols2[]='status'; $tPh2[]='?'; $tVals2[]='pending_verification'; }
                                if (tableHasColumn('transactions','reference')) { $tCols2[]='reference'; $tPh2[]='?'; $tVals2[]=('deal-submission-' . $uniqRef); }
                                elseif (tableHasColumn('transactions','ref')) { $tCols2[]='ref'; $tPh2[]='?'; $tVals2[]=('deal-submission-' . $uniqRef); }
                                if ($companyId && tableHasColumn('transactions','company_id')) { $tCols2[]='company_id'; $tPh2[]='?'; $tVals2[]=$companyId; }
                                if (tableHasColumn('transactions','created_at')) { $tCols2[]='created_at'; $tPh2[]='?'; $tVals2[]=$txDate.' 00:00:00'; }
                                $sqlT2 = "INSERT INTO transactions (" . implode(',', $tCols2) . ") VALUES (" . implode(',', $tPh2) . ")";
                                $insT2 = $pdo->prepare($sqlT2); $insT2->execute($tVals2);
                            }
                        }
                    }
                }
            } catch (Throwable $eTx) {}
            $success_msg = 'Submission recorded. Status: ' . ($isDuplicate ? 'Duplicate' : 'Pending Finance Verification') . '.';
            if ($client_was_created && $client_email !== '') {
                try {
                    $appUrlSetup = $setup_link;
                    if ($appUrlSetup === '') {
                        $appUrlSetup = function_exists('getSetting') ? (string)getSetting('app_url', '') : '';
                        if ($appUrlSetup === '') { $appUrlSetup = 'login.php'; }
                    }
                    $_SESSION['client_access_setup'] = [
                        'email' => $client_email,
                        'password' => $client_created_password,
                        'login_link' => $appUrlSetup,
                        'otp_code' => $setup_code,
                        'client_id' => (int)$clientId,
                    ];
                } catch (Throwable $eSess) {}
            }
            $sendEmails = (function_exists('getSetting') ? (getSetting('onboarding_send_emails','off') === 'on') : false);
            $isWindowsOs = (stripos(PHP_OS, 'WIN') === 0);
            if ($sendEmails && !$isWindowsOs) {
                try {
                    $clientEmail = '';
                    $clientName = $client_name;
                    if ($clientId > 0 && function_exists('tableHasColumn') && tableHasColumn('users','email')) {
                        $se = $pdo->prepare("SELECT email, " . (tableHasColumn('users','name') ? "name" : "email") . " AS display_name FROM users WHERE id = ? LIMIT 1");
                        $se->execute([$clientId]);
                        $rowE = $se->fetch(PDO::FETCH_ASSOC);
                        if ($rowE) { $clientEmail = (string)($rowE['email'] ?? ''); $clientName = (string)($rowE['display_name'] ?? $client_name); }
                    }
                    $companyName = function_exists('getSetting') ? getSetting('company_name', 'Aiben Properties') : 'Aiben Properties';
                    $noreplyEmail = function_exists('getSetting') ? getSetting('noreply_email', 'no-reply@aibenproperties.local') : 'no-reply@aibenproperties.local';
                    $appUrl = function_exists('getSetting') ? getSetting('app_url', 'http://localhost/Aibenproperties/index.php') : 'http://localhost/Aibenproperties/index.php';
                    if ($clientEmail !== '') {
                        $subjectC = $client_was_created ? "Your Client Portal Login Details" : "Payment received - Pending Verification";
                        if ($client_was_created && $client_created_password !== '') {
                            $bodyC = "Dear {$clientName},\n\nYour client portal account has been created.\n\nLogin URL: {$appUrl}\nEmail: {$clientEmail}\nPassword: {$client_created_password}\n\nPlease login and change your password immediately.\n\nThank you,\n{$companyName}";
                        } else {
                            $bodyC = "Dear {$clientName},\n\nWe have recorded your payment submission and it is pending verification by Accounts.\n\nClient Dashboard: {$appUrl}\nLogin with your email.\n\nThank you,\n{$companyName}";
                        }
                        if (function_exists('sendEmail')) {
                            @sendEmail($clientEmail, $subjectC, $bodyC);
                        } else {
                            $headersC = "From: {$noreplyEmail}\r\n";
                            @mail($clientEmail, $subjectC, $bodyC, $headersC);
                        }
                    }
                    if ($userId > 0 && function_exists('tableHasColumn') && tableHasColumn('users','email')) {
                        $su = $pdo->prepare("SELECT email, " . (tableHasColumn('users','name') ? "name" : "email") . " AS display_name FROM users WHERE id = ? LIMIT 1");
                        $su->execute([$userId]);
                        $rowS = $su->fetch(PDO::FETCH_ASSOC);
                        if ($rowS && !empty($rowS['email'])) {
                            $subjectS = "Submission recorded for client";
                            $extra = '';
                            if ($client_was_created && $client_created_password !== '') {
                                $extra = "\n\nClient portal login created:\nEmail: {$clientEmail}\nPassword: {$client_created_password}\nLogin: {$appUrl}\n";
                            }
                            $bodyS = "Hello " . (string)($rowS['display_name'] ?? '') . ",\n\nA client payment submission has been recorded and is pending verification.\nClient: {$clientName}\nAmount: " . number_format($paid_now, 2) . "\nStatus: " . ($isDuplicate ? "Duplicate" : "Pending Finance Verification") . "{$extra}\n\nRegards,\n{$companyName}";
                            if (function_exists('sendEmail')) {
                                @sendEmail((string)$rowS['email'], $subjectS, $bodyS);
                            } else {
                                $headersS = "From: {$noreplyEmail}\r\n";
                                @mail((string)$rowS['email'], $subjectS, $bodyS, $headersS);
                            }
                        }
                    }
                } catch (Throwable $eNot) {}
            }
        } else {
            $error_msg = 'Unable to record submission with current schema.';
        }

        if (empty($error_msg) && !$isAjax) {
            $_SESSION['deal_success'] = $success_msg;
            header("Location: deal-submission.php?success=1");
            exit;
        }

    } catch (Throwable $e) {
        $error_msg = 'Submission failed: ' . (string)$e->getMessage();
    }
}
if ($isAjax && $_SERVER['REQUEST_METHOD'] === 'POST') {
    if (empty($error_msg) && empty($success_msg)) {
        $error_msg = 'Submission failed. Please try again.';
    }
    try {
        if (session_status() === PHP_SESSION_NONE) { @session_start(); }
        if (empty($error_msg) && !empty($success_msg)) {
            $_SESSION['deal_success'] = $success_msg;
        }
    } catch (Throwable $e) {}
    try {
        while (ob_get_level() > 0) { @ob_end_clean(); }
    } catch (Throwable $e) {}
    header('Content-Type: application/json; charset=utf-8');
    $payload = [
        'success' => empty($error_msg),
        'message' => $success_msg,
        'error' => $error_msg
    ];
    $json = json_encode($payload);
    if ($json === false) {
        $json = json_encode(['success' => false, 'message' => '', 'error' => 'Server encoding error.']);
    }
    echo $json;
    exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['quick_deal'])) {
    $q_client_id = (int)($_POST['q_client_id'] ?? 0);
    $q_client = trim($_POST['q_client_name'] ?? '');
    $q_property = trim($_POST['q_property'] ?? '');
    $q_amount = (float)str_replace(',', '', $_POST['q_amount_paid'] ?? '0');
    $q_notes = trim($_POST['q_payment_notes'] ?? '');
    $q_receipt = safeUploadReceipt($_FILES['q_receipt_file'] ?? null);
    $q_receipt_hash = '';
    $qIsDuplicate = false;
    if ($q_receipt && file_exists($q_receipt)) {
        try {
            $q_receipt_hash = sha1_file($q_receipt);
            if (tableHasColumn('payments','receipt_hash')) {
                $chk = $pdo->prepare("SELECT id FROM payments WHERE receipt_hash = ? AND status <> 'rejected' LIMIT 1");
                $chk->execute([$q_receipt_hash]);
                $qIsDuplicate = (bool)$chk->fetchColumn();
            } elseif (tableHasColumn('payments','proof_file')) {
                $chk2 = $pdo->prepare("SELECT id FROM payments WHERE proof_file = ? AND status <> 'rejected' LIMIT 1");
                $chk2->execute([$q_receipt]);
                $qIsDuplicate = (bool)$chk2->fetchColumn();
            }
        } catch (Throwable $e) {}
    }
    if ($q_client_id && $q_client === '') {
        try {
            $stmt = $pdo->prepare("SELECT name FROM users WHERE id = ? LIMIT 1");
            $stmt->execute([$q_client_id]);
            $q_client = (string)($stmt->fetchColumn() ?: '');
        } catch (Throwable $e) {}
    }
    $meta = [
        'client_id' => $q_client_id,
        'client_name' => $q_client,
        'property' => $q_property,
        'notes' => $q_notes,
        'submitted_by_role' => $role,
        'submitted_by_user' => $userId,
        'recorded_by_role' => $role,
        'recorded_by_user' => $userId,
    ];
    try {
        $dealId = 0;
        try {
            $dCols = []; $dPh = []; $dVals = [];
                $marketer_name_q = '';
                $role_q = $role;
                try {
                    if ($userId > 0 && function_exists('tableHasColumn') && tableHasColumn('users','name')) {
                        $qs = $pdo->prepare("SELECT name, role FROM users WHERE id = ? LIMIT 1");
                        $qs->execute([$userId]);
                        $rowU = $qs->fetch(PDO::FETCH_ASSOC);
                        $marketer_name_q = (string)($rowU['name'] ?? '');
                        $role_q = strtolower((string)($rowU['role'] ?? $role_q));
                    }
                } catch (Throwable $eMkQ) {}
                $performedNameQ = $marketer_name_q;
                try {
                    if ($performedNameQ === '' && $userId > 0) {
                        $qs2 = $pdo->prepare("SELECT name, full_name, first_name, last_name FROM users WHERE id = ? LIMIT 1");
                        $qs2->execute([$userId]);
                        $u2 = $qs2->fetch(PDO::FETCH_ASSOC) ?: [];
                        $performedNameQ = trim((string)($u2['name'] ?? ''));
                        if ($performedNameQ === '') { $performedNameQ = trim((string)($u2['full_name'] ?? '')); }
                        if ($performedNameQ === '') { $performedNameQ = trim((string)((string)($u2['first_name'] ?? '') . ' ' . (string)($u2['last_name'] ?? ''))); }
                    }
                } catch (Throwable $ePq) {}
                if ($performedNameQ !== '') { $meta['submitted_by_name'] = $performedNameQ; $meta['recorded_by_name'] = $performedNameQ; }
                $deal_source_q = ucfirst($role_q ?: 'Marketing');
                $marketerId_q = 0;
                try {
                    if ($marketer_name_q !== '' && function_exists('tableHasColumn') && tableHasColumn('users','name')) {
                        $qm = $pdo->prepare("SELECT id FROM users WHERE name = ? LIMIT 1");
                        $qm->execute([$marketer_name_q]);
                        $marketerId_q = (int)($qm->fetchColumn() ?: 0);
                    }
                } catch (Throwable $eM2) {}
            if (tableHasColumn('deals_submit','user_id')) { $dCols[]='user_id'; $dPh[]='?'; $dVals[]=$q_client_id ?: null; }
            if (tableHasColumn('deals_submit','marketer_id')) { $dCols[]='marketer_id'; $dPh[]='?'; $dVals[]=$marketerId_q ?: null; }
            if (tableHasColumn('deals_submit','marketer_name')) { $dCols[]='marketer_name'; $dPh[]='?'; $dVals[]=$marketer_name_q ?: null; }
            if (tableHasColumn('deals_submit','deal_source')) { $dCols[]='deal_source'; $dPh[]='?'; $dVals[]=$deal_source_q ?: null; }
            if (tableHasColumn('deals_submit','project_name')) { $dCols[]='project_name'; $dPh[]='?'; $dVals[]=$q_property ?: null; }
            if (tableHasColumn('deals_submit','project_desc')) { $dCols[]='project_desc'; $dPh[]='?'; $dVals[]=$q_property ?: null; }
            if (tableHasColumn('deals_submit','payment_plan')) { $dCols[]='payment_plan'; $dPh[]='?'; $dVals[]='installment'; }
            if (tableHasColumn('deals_submit','amount_offered')) { $dCols[]='amount_offered'; $dPh[]='?'; $dVals[]=0.00; }
            if (tableHasColumn('deals_submit','amount_paid_so_far')) { $dCols[]='amount_paid_so_far'; $dPh[]='?'; $dVals[]=0.00; }
            if (tableHasColumn('deals_submit','discount_amount')) { $dCols[]='discount_amount'; $dPh[]='?'; $dVals[]=0.00; }
            if (tableHasColumn('deals_submit','discount_approved_by')) { $dCols[]='discount_approved_by'; $dPh[]='?'; $dVals[]=null; }
            if (tableHasColumn('deals_submit','commission_percent')) { $dCols[]='commission_percent'; $dPh[]='?'; $dVals[]=0.00; }
            if (tableHasColumn('deals_submit','marketer_commission')) { $dCols[]='marketer_commission'; $dPh[]='?'; $dVals[]=0.00; }
            if (tableHasColumn('deals_submit','agent_commission')) { $dCols[]='agent_commission'; $dPh[]='?'; $dVals[]=0.00; }
            if (tableHasColumn('deals_submit','balance_remaining')) { $dCols[]='balance_remaining'; $dPh[]='?'; $dVals[]=0.00; }
            if (tableHasColumn('deals_submit','notes')) { $dCols[]='notes'; $dPh[]='?'; $dVals[]=$q_notes ?: null; }
            if (tableHasColumn('deals_submit','receipt_file')) { $dCols[]='receipt_file'; $dPh[]='?'; $dVals[]=$q_receipt ?: null; }
            if (tableHasColumn('deals_submit','status')) { $dCols[]='status'; $dPh[]='?'; $dVals[]='pending_verification'; }
            if (tableHasColumn('deals_submit','submitted_by')) { $dCols[]='submitted_by'; $dPh[]='?'; $dVals[]=$userId > 0 ? (int)$userId : null; }
            if (function_exists('tableHasColumn') && tableHasColumn('deals_submit','submitted_by_user')) { $dCols[]='submitted_by_user'; $dPh[]='?'; $dVals[]=(int)$userId; }
            if (function_exists('tableHasColumn') && tableHasColumn('deals_submit','submitted_by_role')) { $dCols[]='submitted_by_role'; $dPh[]='?'; $dVals[]=$role !== '' ? $role : null; }
            if ($companyId && tableHasColumn('deals_submit','company_id')) { $dCols[]='company_id'; $dPh[]='?'; $dVals[]=$companyId; }
            if (tableHasColumn('deals_submit','created_at')) { $dCols[]='created_at'; $dPh[]='NOW()'; }
            if (tableHasColumn('deals_submit','marketer_bank')) { $dCols[]='marketer_bank'; $dPh[]='?'; $dVals[] = !empty($meta['marketer_bank']) && is_array($meta['marketer_bank']) ? json_encode($meta['marketer_bank']) : null; }
            if (tableHasColumn('deals_submit','agent_bank')) { $dCols[]='agent_bank'; $dPh[]='?'; $dVals[] = !empty($meta['agent_bank']) && is_array($meta['agent_bank']) ? json_encode($meta['agent_bank']) : null; }
            if (tableHasColumn('deals_submit','meta_json')) { $dCols[]='meta_json'; $dPh[]='?'; $dVals[] = json_encode($meta); }
            if (!empty($dCols)) {
                $sqlD = "INSERT INTO deals_submit (" . implode(',', $dCols) . ") VALUES (" . implode(',', $dPh) . ")";
                $insD = $pdo->prepare($sqlD);
                $insD->execute($dVals);
                $submitId = (int)$pdo->lastInsertId();
            }
        } catch (Throwable $de) {}
        $fields = []; $places = []; $vals = [];
        if (tableHasColumn('payments','user_id')) { $fields[]='user_id'; $places[]='?'; $vals[]=$q_client_id ?: null; }
        if ($dealId && tableHasColumn('payments','deal_id')) { $fields[]='deal_id'; $places[]='?'; $vals[]=$dealId; }
        if (tableHasColumn('payments','amount')) { $fields[]='amount'; $places[]='?'; $vals[]=$q_amount; }
        if (tableHasColumn('payments','status')) { $fields[]='status'; $places[]='?'; $vals[]=$qIsDuplicate ? 'duplicate' : 'pending_verification'; }
        if ($userId > 0 && tableHasColumn('payments','submitted_by_user')) { $fields[]='submitted_by_user'; $places[]='?'; $vals[]=(int)$userId; }
        if (tableHasColumn('payments','submitted_by_name')) { $fields[]='submitted_by_name'; $places[]='?'; $vals[]=!empty($performedNameQ) ? $performedNameQ : ($marketer_name_q ?: null); }
        if (tableHasColumn('payments','submitted_by_role')) { $fields[]='submitted_by_role'; $places[]='?'; $vals[]=$role !== '' ? $role : null; }
        if (tableHasColumn('payments','reference')) {
            $fields[]='reference'; $places[]='?';
            $uniq = date('YmdHis') . '-' . random_int(1000,9999);
            $vals[]='deal-quick-' . $uniq;
        }
        if (tableHasColumn('payments','proof_file')) { $fields[]='proof_file'; $places[]='?'; $vals[]=$q_receipt ?: null; }
        if ($q_receipt_hash && tableHasColumn('payments','receipt_hash')) { $fields[]='receipt_hash'; $places[]='?'; $vals[]=$q_receipt_hash; }
        if ($companyId && tableHasColumn('payments','company_id')) { $fields[]='company_id'; $places[]='?'; $vals[]=$companyId; }
        if (tableHasColumn('payments','created_at')) { $fields[]='created_at'; $places[]='NOW()'; }
        if ($fields) {
            $sql = "INSERT INTO payments (" . implode(',', $fields) . ") VALUES (" . implode(',', $places) . ")";
            $ins = $pdo->prepare($sql);
            $ins->execute($vals);
            $pid = (int)$pdo->lastInsertId();
            if (tableHasColumn('payments','meta_json')) {
                $up = $pdo->prepare("UPDATE payments SET meta_json = ? WHERE id = ?");
                $up->execute([json_encode($meta), $pid]);
            }
            try {
                $hasTx = $pdo->query("SHOW TABLES LIKE 'transactions'")->rowCount() > 0;
                if ($hasTx) {
                    $tCols = []; $tPh = []; $tVals = [];
                    if ($q_client_id > 0 && tableHasColumn('transactions','user_id')) { $tCols[]='user_id'; $tPh[]='?'; $tVals[]=$q_client_id; }
                    if ($dealId > 0 && tableHasColumn('transactions','deal_id')) { $tCols[]='deal_id'; $tPh[]='?'; $tVals[]=$dealId; }
                    if (tableHasColumn('transactions','amount')) { $tCols[]='amount'; $tPh[]='?'; $tVals[]=$q_amount; }
                    if (tableHasColumn('transactions','transaction_type')) { $tCols[]='transaction_type'; $tPh[]='?'; $tVals[]='deal_quick'; }
                    if (tableHasColumn('transactions','status')) { $tCols[]='status'; $tPh[]='?'; $tVals[]=$qIsDuplicate ? 'duplicate' : 'pending_verification'; }
                    if (tableHasColumn('transactions','reference')) { $tCols[]='reference'; $tPh[]='?'; $tVals[]=('deal-quick-' . date('YmdHis')); }
                    elseif (tableHasColumn('transactions','ref')) { $tCols[]='ref'; $tPh[]='?'; $tVals[]=('deal-quick-' . date('YmdHis')); }
                    if ($companyId && tableHasColumn('transactions','company_id')) { $tCols[]='company_id'; $tPh[]='?'; $tVals[]=$companyId; }
                    if (tableHasColumn('transactions','created_at')) { $tCols[]='created_at'; $tPh[]='NOW()'; }
                    if (!empty($tCols)) {
                        $sqlT = "INSERT INTO transactions (" . implode(',', $tCols) . ") VALUES (" . implode(',', $tPh) . ")";
                        $insT = $pdo->prepare($sqlT); $insT->execute($tVals);
                    }
                    if (!empty($meta['notes']) && tableHasColumn('transactions','notes')) {
                        $pdo->prepare("UPDATE transactions SET notes = ? WHERE " . (tableHasColumn('transactions','reference') ? "reference" : "ref") . " = ? ORDER BY id DESC LIMIT 1")->execute([(string)$meta['notes'], (string)($meta['payment_reference'] ?? '')]);
                    }
                }
            } catch (Throwable $eTx2) {}
            $success_msg = 'Submission recorded. Status: ' . ($qIsDuplicate ? 'Duplicate' : 'Pending Finance Verification') . '.';
            if (!$qIsDuplicate) {
                try {
                    if (function_exists('ap_notify_roles')) {
                        $clientLabel = '';
                        try {
                            if ($q_client_id > 0 && function_exists('tableHasColumn') && tableHasColumn('users','email')) {
                                $nmCol = (function_exists('tableHasColumn') && tableHasColumn('users','name')) ? 'name' : (function_exists('tableHasColumn') && tableHasColumn('users','full_name') ? 'full_name' : null);
                                $sel = "email" . ($nmCol ? ", {$nmCol} AS nm" : "");
                                $stC = $pdo->prepare("SELECT {$sel} FROM users WHERE id = ? LIMIT 1");
                                $stC->execute([$q_client_id]);
                                $rC = $stC->fetch(PDO::FETCH_ASSOC) ?: [];
                                $em = trim((string)($rC['email'] ?? ''));
                                $nm = trim((string)($rC['nm'] ?? ''));
                                $clientLabel = trim($nm !== '' ? $nm : $em);
                            }
                        } catch (Throwable $eCl) { $clientLabel = ''; }
                        if ($clientLabel === '') { $clientLabel = 'Client #' . (int)$q_client_id; }
                        $amtLabel = function_exists('formatCurrency') ? formatCurrency((float)$q_amount) : ('₦' . number_format((float)$q_amount, 2));
                        $proj = trim((string)$q_property);
                        $msg = ($clientLabel !== '' ? ($clientLabel . ' ') : '') . 'submitted a deal payment of ' . $amtLabel . ($proj !== '' ? (' for ' . $proj) : '') . '.';
                        ap_notify_roles($pdo, ['finance_manager','finance','finance_officer','accountant','accounting'], [
                            'department' => 'Finance',
                            'title' => 'Deal submitted (Finance verification)',
                            'message' => $msg,
                            'type' => 'approval',
                            'priority' => 'approval',
                            'related_id' => (int)$pid,
                            'related_module' => 'finance-payments.php'
                        ]);
                    }
                } catch (Throwable $eNote) {}
            }
            if (empty($error_msg) && !$isAjax) {
                $_SESSION['deal_success'] = $success_msg;
                header("Location: deal-submission.php?success=1");
                exit;
            }
        } else {
            $error_msg = 'Unable to record submission.';
        }
    } catch (Throwable $e) {
        $error_msg = 'Submission failed: ' . (string)$e->getMessage();
    }
}
if ($isAjax && $_SERVER['REQUEST_METHOD'] === 'POST') {
    header('Content-Type: application/json');
    echo json_encode([
        'success' => empty($error_msg),
        'message' => $success_msg,
        'error' => $error_msg
    ]);
    exit;
}
if ($isAjax) {
    $ok = ($error_msg === '' && $success_msg !== '');
    $resp = ['success' => $ok, 'message' => $success_msg, 'error' => $error_msg];
    if (function_exists('http_response_code')) { http_response_code($ok ? 200 : 400); }
    @ob_end_clean();
    header('Content-Type: application/json');
    echo json_encode($resp);
    exit;
}
try {
    $clients = [];
    $nameCol = (function_exists('tableHasColumn') && tableHasColumn('users','name')) ? 'name' : (function_exists('tableHasColumn') && tableHasColumn('users','username') ? 'username' : 'id');
    $isSuper = in_array($role, ['super_admin','admin'], true);
    $isFinance = in_array($role, ['finance','finance_officer','finance_manager','accountant','accounting'], true);
    $isMarketing = in_array($role, ['marketing','sales','agent','sales_agent'], true);
    $isContact = in_array($role, ['contact_rep','customer_rep','contact_centre','contact_center'], true);
    if ($isSuper || $isFinance) {
        $sql = "SELECT id, {$nameCol} AS name, email FROM users WHERE role = 'client'";
        $params = [];
        if ($companyId && function_exists('tableHasColumn') && tableHasColumn('users','company_id')) { $sql .= " AND (company_id = ? OR company_id IS NULL)"; $params[] = $companyId; }
        $sql .= " ORDER BY {$nameCol} ASC";
        $clq = $pdo->prepare($sql);
        $clq->execute($params);
        $clients = $clq->fetchAll(PDO::FETCH_ASSOC) ?: [];
    } else {
        $ids = [];
        try {
            if (function_exists('hasColumn') && hasColumn($pdo,'users','created_by')) {
                $qU = "SELECT id FROM users WHERE role = 'client' AND created_by = ?";
                $paramsU = [$userId];
                if ($companyId && function_exists('hasColumn') && hasColumn($pdo,'users','company_id')) { $qU .= " AND (company_id = ? OR company_id IS NULL)"; $paramsU[] = $companyId; }
                $stU = $pdo->prepare($qU);
                $stU->execute($paramsU);
                foreach ($stU->fetchAll(PDO::FETCH_COLUMN) ?: [] as $cid) {
                    $cid = (int)$cid;
                    if ($cid > 0) { $ids[$cid] = true; }
                }
            }
        } catch (Throwable $eOwn) {}
        try {
            if ($pdo->query("SHOW TABLES LIKE 'payments'")->rowCount() > 0) {
                $pCols = [];
                $pCols[] = "user_id";
                if (function_exists('tableHasColumn') && tableHasColumn('payments','client_id')) { $pCols[] = "client_id"; }
                $pWhere = [];
                $pWhere[] = "(submitted_by_user = ?)";
                $pParams = [$userId];
                if ($companyId && function_exists('tableHasColumn') && tableHasColumn('payments','company_id')) { $pWhere[] = "(company_id = ? OR company_id IS NULL)"; $pParams[] = $companyId; }
                if ($isContact) { $pWhere[] = "(submitted_by_role IS NULL OR submitted_by_role = '' OR submitted_by_role = 'contact_centre' OR submitted_by_role = 'contact' OR submitted_by_role = 'customer_rep' OR submitted_by_role = 'contact_rep')"; }
                $ps = $pdo->prepare("SELECT " . implode(',', $pCols) . " FROM payments WHERE " . implode(" AND ", $pWhere));
                $ps->execute($pParams);
                foreach ($ps->fetchAll(PDO::FETCH_ASSOC) ?: [] as $r) {
                    foreach (['user_id','client_id'] as $k) {
                        $cid = (int)($r[$k] ?? 0);
                        if ($cid > 0) { $ids[$cid] = true; }
                    }
                }
            }
        } catch (Throwable $ePay) {}
        try {
            if ($pdo->query("SHOW TABLES LIKE 'deals_submit'")->rowCount() > 0) {
                $cols = ['user_id'];
                if (function_exists('tableHasColumn') && tableHasColumn('deals_submit','submitted_by_user')) { $cols[] = 'submitted_by_user'; }
                if (function_exists('tableHasColumn') && tableHasColumn('deals_submit','marketer_id')) { $cols[] = 'marketer_id'; }
                $w = [];
                $p = [];
                if (function_exists('tableHasColumn') && tableHasColumn('deals_submit','submitted_by_user')) { $w[] = "submitted_by_user = ?"; $p[] = $userId; }
                if (function_exists('tableHasColumn') && tableHasColumn('deals_submit','marketer_id')) { $w[] = "marketer_id = ?"; $p[] = $userId; }
                if (empty($w)) { $w[] = "1=0"; }
                $where = "(" . implode(" OR ", $w) . ")";
                if ($companyId && function_exists('tableHasColumn') && tableHasColumn('deals_submit','company_id')) { $where .= " AND (company_id = ? OR company_id IS NULL)"; $p[] = $companyId; }
                $ds = $pdo->prepare("SELECT " . implode(',', $cols) . " FROM deals_submit WHERE " . $where);
                $ds->execute($p);
                foreach ($ds->fetchAll(PDO::FETCH_ASSOC) ?: [] as $r) {
                    $cid = (int)($r['user_id'] ?? 0);
                    if ($cid > 0) { $ids[$cid] = true; }
                }
            }
        } catch (Throwable $eDs) {}
        try {
            if ($pdo->query("SHOW TABLES LIKE 'deals'")->rowCount() > 0) {
                $cols = ['user_id'];
                if (function_exists('tableHasColumn') && tableHasColumn('deals','marketer_id')) { $cols[] = 'marketer_id'; }
                if (function_exists('tableHasColumn') && tableHasColumn('deals','submitted_by')) { $cols[] = 'submitted_by'; }
                $w = [];
                $p = [];
                if (function_exists('tableHasColumn') && tableHasColumn('deals','marketer_id')) { $w[] = "marketer_id = ?"; $p[] = $userId; }
                if (function_exists('tableHasColumn') && tableHasColumn('deals','submitted_by')) { $w[] = "submitted_by = ?"; $p[] = $userId; }
                if (empty($w)) { $w[] = "1=0"; }
                $where = "(" . implode(" OR ", $w) . ")";
                if ($companyId && function_exists('tableHasColumn') && tableHasColumn('deals','company_id')) { $where .= " AND (company_id = ? OR company_id IS NULL)"; $p[] = $companyId; }
                $dq = $pdo->prepare("SELECT " . implode(',', $cols) . " FROM deals WHERE " . $where);
                $dq->execute($p);
                foreach ($dq->fetchAll(PDO::FETCH_ASSOC) ?: [] as $r) {
                    $cid = (int)($r['user_id'] ?? 0);
                    if ($cid > 0) { $ids[$cid] = true; }
                }
            }
        } catch (Throwable $eD) {}

        $idList = array_keys($ids);
        if (!empty($idList)) {
            $place = implode(',', array_fill(0, count($idList), '?'));
            $sql = "SELECT id, {$nameCol} AS name, email FROM users WHERE role = 'client' AND id IN ($place)";
            $params = $idList;
            if ($companyId && function_exists('tableHasColumn') && tableHasColumn('users','company_id')) { $sql .= " AND (company_id = ? OR company_id IS NULL)"; $params[] = $companyId; }
            $sql .= " ORDER BY {$nameCol} ASC";
            $clq = $pdo->prepare($sql);
            $clq->execute($params);
            $clients = $clq->fetchAll(PDO::FETCH_ASSOC) ?: [];
        }
    }
} catch (Throwable $e) { $clients = []; }
?>
<div class="container-fluid px-4">
    <style>
        @media (max-width: 575.98px) {
            .deal-actions { width: 100%; }
            .deal-actions .btn { width: 100%; }
            .deal-footer > div { width: 100%; }
            .deal-footer .deal-footer-right { width: 100%; }
            .deal-footer .deal-footer-right .btn { flex: 1 1 0; }
            #dealPrevBtn { width: 100%; }
            #dealStepIndicator { width: 100%; text-align: center; }
            .deal-input-group, .deal-sqm-group { flex-wrap: wrap; }
            .deal-input-group > .form-control, .deal-sqm-group > .form-control { flex: 1 1 100%; width: 100%; }
            .deal-input-group > .btn { flex: 1 1 100%; width: 100%; }
            #propertyPickerModal .property-select-btn { width: 100%; }
        }
        .deal-footer{ position:relative; z-index:5000; }
        .deal-footer-right{ position:relative; z-index:5001; }
    </style>
    <div class="d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center gap-2 mt-4 mb-4 deal-page-header">
        <h1 class="h3 mb-0 text-gray-800">
            <i class="fa-solid fa-file-invoice-dollar me-2"></i>
            <?= $variant === 'contact' ? 'Contact Centre: Deal Submission' : 'Marketing: Deal Submission' ?>
        </h1>
        <div class="d-flex flex-column flex-sm-row align-items-stretch align-items-sm-center gap-2 deal-actions">
            <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#quickDealModal"><i class="fa-solid fa-plus me-2"></i>New Deal Submission</button>
            <?php if (in_array($role, ['finance','finance_officer','finance_manager'])): ?>
            <a href="finance-payment-queue.php" class="btn btn-outline-secondary"><i class="fa-solid fa-list-check me-2"></i>Payment Verification Queue</a>
            <?php endif; ?>
        </div>
    </div>
    <?php if (!empty($success_msg)): ?><div class="alert alert-success"><?= htmlspecialchars($success_msg) ?></div><?php endif; ?>
    <?php if (!empty($clientAccessSetup) && is_array($clientAccessSetup)): ?>
    <div class="alert alert-info">
        <div class="fw-bold mb-1">Client Login Details</div>
        <div class="small">Email: <?= htmlspecialchars((string)($clientAccessSetup['email'] ?? '')) ?></div>
        <div class="small">Password: <?= htmlspecialchars((string)($clientAccessSetup['password'] ?? '')) ?></div>
        <?php if (!empty($clientAccessSetup['otp_code'])): ?>
            <div class="small">One-time code: <?= htmlspecialchars((string)$clientAccessSetup['otp_code']) ?></div>
        <?php endif; ?>
        <div class="mt-2 d-flex flex-column flex-sm-row flex-wrap align-items-stretch align-items-sm-center gap-2">
            <a class="btn btn-sm btn-outline-primary" href="<?= htmlspecialchars((string)($clientAccessSetup['login_link'] ?? 'login.php')) ?>">Open Login</a>
            <button type="button" class="btn btn-sm btn-outline-secondary" onclick="navigator.clipboard.writeText('<?= htmlspecialchars((string)($clientAccessSetup['email'] ?? '')) ?>')">Copy Email</button>
            <button type="button" class="btn btn-sm btn-outline-secondary" onclick="navigator.clipboard.writeText('<?= htmlspecialchars((string)($clientAccessSetup['password'] ?? '')) ?>')">Copy Password</button>
            <button type="button" class="btn btn-sm btn-outline-secondary" onclick="navigator.clipboard.writeText('<?= htmlspecialchars((string)($clientAccessSetup['login_link'] ?? '')) ?>')">Copy Link</button>
        </div>
    </div>
    <?php endif; ?>
    <?php if (!empty($error_msg)): ?><div class="alert alert-danger"><?= htmlspecialchars($error_msg) ?></div><?php endif; ?>
    <form id="dealForm" method="post" enctype="multipart/form-data" class="card shadow-sm rounded-3 mb-4">
        <div class="card-header py-3 bg-navy text-white d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center gap-2">
            <h6 class="m-0 font-weight-bold">Deal Submission</h6>
            <div id="dealStatusSummary" class="small text-white-50"></div>
        </div>
        <div class="card-body">
            <input type="hidden" name="submit_deal" value="1">
            <input type="hidden" name="policy_acceptance" value="1">
            <div class="card shadow-sm mb-3">
                <div class="card-header bg-white"><strong>Client Details</strong></div>
                <div class="card-body">
                    <input type="hidden" name="existing_deal_id" id="existing_deal_id_hidden" value="0">
                    <div class="row g-3">
                        <div class="col-md-6">
                            <label class="form-label">Client</label>
                            <select name="client_id" id="client_id_select" class="form-select">
                                <option value="">Select client</option>
                                <?php foreach (($clients ?? []) as $c): ?>
                                    <option value="<?= (int)$c['id'] ?>"><?= htmlspecialchars(($c['name'] ?? 'Unknown').' — '.($c['email'] ?? '')) ?></option>
                                <?php endforeach; ?>
                            </select>
                        </div>
                        <div class="col-md-6">
                            <label class="form-label">Client’s Name (text)</label>
                            <input type="text" name="client_name" id="client_name_text" class="form-control" placeholder="e.g., Mr George hill">
                            <div class="form-text">Optional: type the client name exactly as provided.</div>
                        </div>
                        <div class="col-md-6">
                            <label class="form-label">Client Email (for dashboard)</label>
                            <input type="email" name="client_email" class="form-control" placeholder="e.g., client@example.com">
                        </div>
                    </div>
                </div>
            </div>
            <div class="card shadow-sm mb-3">
                <div class="card-header bg-white"><strong>Deal Details</strong></div>
                <div class="card-body">
                    <div class="row g-3">
                        <div class="col-md-6">
                            <?php if ($variant === 'contact'): ?>
                                <label class="form-label">Deal Source</label>
                                <input type="hidden" name="deal_source" value="Contact Centre">
                                <input type="text" class="form-control" value="Contact Centre" readonly>
                                <div class="form-text">This page is tailored for Contact Centre submissions.</div>
                            <?php else: ?>
                                <label class="form-label">Deal Source</label>
                                <select name="deal_source" class="form-select" required>
                                    <option <?= 'Marketer' ? 'selected' : '' ?>>Marketer</option>
                                    <option>Contact Centre</option>
                                    <option>Internal Staff</option>
                                    <option>Referral</option>
                                    <option>Direct Client</option>
                                </select>
                                <div class="form-text">Default is Marketer for Marketing submissions.</div>
                            <?php endif; ?>
                        </div>
                        <div class="col-md-6">
                            <label class="form-label"><?= $variant === 'contact' ? 'Contact Centre Rep Name' : 'Marketer Name' ?></label>
                            <input type="text" name="marketer_name" class="form-control" placeholder="<?= $variant === 'contact' ? 'e.g., Contact Rep Full Name' : 'e.g., Onyeugo Nkiruka Peace' ?>">
                        </div>
                        <div class="col-12">
                            <label class="form-label">Project / Property Description</label>
                            <div class="input-group deal-input-group">
                                <input type="text" name="project_desc" id="project_desc_input" class="form-control" placeholder="e.g., Half Hectare of 400sqm @ Hutu Royal">
                                <button type="button" class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#propertyPickerModal">Browse Properties</button>
                            </div>
                            <input type="hidden" name="property_id" id="property_id_input" value="">
                            <div id="projectHistoryMsg" class="small mt-1"></div>
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Payment Plan</label>
                            <select name="plan_type" id="plan_type" class="form-select">
                                <option value="full">Full Payment</option>
                                <option value="3_months">3 Months Plan</option>
                                <option value="6_months">6 Months Plan</option>
                                <option value="custom">Custom Months</option>
                            </select>
                        </div>
                        <div class="col-md-4" id="custom_months_group" style="display:none;">
                            <label class="form-label">Custom Duration (months)</label>
                            <input type="number" min="1" step="1" name="custom_months" id="custom_months" class="form-control" placeholder="e.g., 12">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Installment Start Date</label>
                            <input type="date" name="installment_start_date" id="installment_start_date" class="form-control">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">SQM</label>
                            <div class="input-group deal-sqm-group">
                                <input type="number" name="sqm" id="sqm_input" class="form-control" min="1" step="1" placeholder="e.g., 500">
                                <button type="button" class="btn btn-outline-secondary btn-sm" data-sqm-quick="250">250</button>
                                <button type="button" class="btn btn-outline-secondary btn-sm" data-sqm-quick="500">500</button>
                                <button type="button" class="btn btn-outline-secondary btn-sm" data-sqm-quick="1000">1000</button>
                            </div>
                            <div class="form-text">Type any SQM or tap a quick option.</div>
                            <div class="form-text" id="sqm_hectare_hint" style="display:none;"></div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="card shadow-sm mb-3">
                <div class="card-header bg-white"><strong>Payment & Notes</strong></div>
                <div class="card-body">
                    <div class="row g-3">
                        <div class="col-md-4">
                            <label class="form-label">Payment Type</label>
                            <select name="payment_type" id="payment_type" class="form-select">
                                <option value="land" selected>Land</option>
                                <option value="infrastructure">Infrastructure</option>
                                <option value="excavation">Excavation</option>
                            </select>
                            <div class="form-text">Marketer/Contact Centre do not choose accounts. Account is assigned automatically by property + payment type.</div>
                            <div class="alert alert-warning mt-2 py-2 px-3 small" id="accountWarning" style="display:none;"></div>
                        </div>
                        <div class="col-12">
                            <div class="border rounded p-2 bg-light" id="balanceBreakdown" style="display:none;">
                                <div class="fw-bold text-navy mb-1">Outstanding Summary</div>
                                <div class="row g-2 small">
                                    <div class="col-md-4"><span class="text-muted">Land:</span> <span id="bal_land">-</span></div>
                                    <div class="col-md-4"><span class="text-muted">Infrastructure:</span> <span id="bal_infra">-</span></div>
                                    <div class="col-md-4"><span class="text-muted">Excavation:</span> <span id="bal_excav">-</span></div>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-4" id="offered_group">
                            <label class="form-label">Amount Offered to Client (if installment)</label>
                            <input type="text" name="amount_offered" class="form-control comma-format">
                        </div>
                        <div class="col-md-4" id="sofar_group">
                            <label class="form-label">Amount Paid So Far</label>
                            <input type="text" name="amount_paid_so_far" id="amount_paid_so_far" class="form-control comma-format">
                            <div id="prevPaymentsBreakdown" class="mt-2 small" style="display:none;">
                                <div class="fw-bold text-navy mb-1">Previous Payments:</div>
                                <ul class="list-group list-group-flush border rounded-3 overflow-hidden" id="prevPaymentsList" style="max-height:150px; overflow-y:auto;">
                                </ul>
                            </div>
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Amount Paid Now</label>
                            <input type="text" name="amount_paid_now" id="amount_paid_now" class="form-control comma-format">
                        </div>
                        <div class="col-12">
                            <label class="form-label">Client Payment Status / Notes</label>
                            <textarea name="client_payment_status" class="form-control" rows="2" placeholder="e.g., Client is still making payment"></textarea>
                        </div>
                        <div class="col-12">
                            <label class="form-label">Transaction History</label>
                            <div id="txnList" class="border rounded p-2 bg-light">
                                <div class="row g-2 align-items-end mb-2">
                                    <div class="col-md-4"><input type="date" name="txn_date[]" class="form-control"></div>
                                    <div class="col-md-4"><input type="text" name="txn_amount[]" class="form-control comma-format" placeholder="Amount"></div>
                                    <div class="col-md-4"><button type="button" class="btn btn-outline-secondary btn-sm" onclick="addTxn()">Add Another</button></div>
                                </div>
                            </div>
                            <div class="form-text">Example: 20/1/2026 — 9M + 9M; 21/1/2026 — 1.86M + 9M; 23/1/2026 — 8.3M + 200k</div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="card shadow-sm mb-3">
                <div class="card-header bg-white"><strong>Discounts & Balance</strong></div>
                <div class="card-body">
                    <div class="row g-3">
                        <div class="col-md-4" id="discount_group">
                            <label class="form-label">Discount Amount</label>
                            <input type="text" name="discount_amount" id="discount_amount" class="form-control comma-format">
                        </div>
                        <div class="col-md-4" id="discount_by_group">
                            <label class="form-label">Discount Approved By</label>
                            <input type="text" name="discount_approved_by" class="form-control" placeholder="Chairman / Admin / HR / Management">
                        </div>
                        <div class="col-md-4" id="balance_group">
                            <label class="form-label">Balance Remaining</label>
                            <input type="text" name="balance_remaining" id="balance_remaining" class="form-control comma-format" readonly>
                        </div>
                    </div>
                </div>
            </div>
            <div class="card shadow-sm mb-3" id="commission_card">
                <div class="card-header bg-white"><strong>Commission</strong></div>
                <div class="card-body">
                    <div class="row g-3">
                        <div class="col-md-3">
                            <label class="form-label">Total Commission %</label>
                            <input type="number" inputmode="decimal" step="0.01" min="0" max="100" name="commission_pct" class="form-control" value="5.00" id="commission_total_display">
                        </div>
                        <div class="col-md-3">
                            <label class="form-label"><?= $variant === 'contact' ? 'Contact Centre %' : 'Marketer %' ?></label>
                            <input type="number" inputmode="decimal" step="0.01" min="0" max="100" name="marketer_pct" id="marketer_pct" class="form-control" value="3.00">
                            <div class="form-text">Auto-balances with Agent % to match Total Commission %</div>
                        </div>
                        <div class="col-md-3">
                            <label class="form-label">Agent %</label>
                            <input type="number" inputmode="decimal" step="0.01" min="0" max="100" name="agent_pct" id="agent_pct" class="form-control" value="2.00">
                        </div>
                        <div class="col-md-3 d-flex align-items-end">
                            <div class="btn-group w-100">
                                <button type="button" class="btn btn-outline-secondary" id="preset_3_2">3% / 2%</button>
                                <button type="button" class="btn btn-outline-secondary" id="preset_2_3">2% / 3%</button>
                            </div>
                        </div>
                        <div class="col-md-4">
                            <label class="form-label"><?= $variant === 'contact' ? 'Contact Centre Amount' : 'Marketer Amount' ?></label>
                            <input type="text" name="marketer_comm" id="marketer_comm" class="form-control comma-format" readonly>
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Agent Amount</label>
                            <input type="text" name="agent_comm" id="agent_comm" class="form-control comma-format" readonly>
                        </div>
                    </div>
                </div>
            </div>
            <div class="card shadow-sm mb-3">
                <div class="card-header bg-white"><strong>Bank Details</strong></div>
                <div class="card-body">
                    <div class="row g-3">
                        <div class="col-md-4">
                            <label class="form-label">Marketer Account Number</label>
                            <input type="text" name="mk_acc_no" class="form-control">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Marketer Bank Name</label>
                            <input type="text" name="mk_bank" class="form-control">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Marketer Account Name</label>
                            <input type="text" name="mk_acc_name" class="form-control">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Agent Account Number</label>
                            <input type="text" name="ag_acc_no" class="form-control">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Agent Bank Name</label>
                            <input type="text" name="ag_bank" class="form-control">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Agent Account Name</label>
                            <input type="text" name="ag_acc_name" class="form-control">
                        </div>
                    </div>
                </div>
            </div>
            <div class="card shadow-sm mb-3">
                <div class="card-header bg-white"><strong>Receipt Upload</strong></div>
                <div class="card-body">
                    <div class="row g-3">
                        <div class="col-md-6">
                            <label class="form-label">Upload Payment Receipt (Image/PDF)</label>
                            <input type="file" name="receipt" class="form-control" accept=".pdf,image/*" required>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="card-footer d-flex justify-content-between align-items-center flex-wrap gap-2 deal-footer">
            <div>
                <button type="button" class="btn btn-outline-secondary" id="dealPrevBtn">Back</button>
            </div>
            <div class="text-muted small fw-semibold text-center text-sm-start" id="dealStepIndicator" aria-live="polite">Step 1 of 7 — Client Details</div>
            <div class="d-flex gap-2 deal-footer-right">
                <button type="button" class="btn btn-primary" id="dealNextBtn">Next</button>
                <button type="button" class="btn btn-outline-primary" id="dealPreviewBtn" style="display:none;" data-bs-toggle="modal" data-bs-target="#dealPreviewModal">Preview</button>
                <button type="submit" class="btn btn-success" id="dealSubmitBtn" style="pointer-events:auto;position:relative;z-index:1002">Submit Deal</button>
            </div>
        </div>
    </form>
</div>
<!-- QUICK DEAL MODAL -->
<div class="modal fade" id="quickDealModal" tabindex="-1" aria-labelledby="quickDealLabel" aria-hidden="true">
    <div class="modal-dialog modal-dialog-centered modal-fullscreen-sm-down modal-dialog-scrollable">
        <form class="modal-content" method="post" enctype="multipart/form-data">
            <div class="modal-header">
                <h5 class="modal-title" id="quickDealLabel"><i class="fa-solid fa-file-invoice-dollar me-2"></i>New Deal Submission</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <input type="hidden" name="quick_deal" value="1">
                <div class="mb-2">
                    <label class="form-label">Client</label>
                    <select name="q_client_id" class="form-select" required>
                        <option value="">Select client</option>
                        <?php foreach (($clients ?? []) as $c): ?>
                            <option value="<?= (int)$c['id'] ?>"><?= htmlspecialchars(($c['name'] ?? 'Unknown').' — '.($c['email'] ?? '')) ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>
                <div class="mb-2">
                    <label class="form-label">Property / Estate</label>
                    <input type="text" name="q_property" class="form-control" required>
                </div>
                <div class="mb-2">
                    <label class="form-label">Amount Paid</label>
                    <input type="text" name="q_amount_paid" class="form-control comma-format" required>
                </div>
                <div class="mb-2">
                    <label class="form-label">Upload Payment Receipt</label>
                    <input type="file" name="q_receipt_file" class="form-control" accept=".pdf,image/*">
                </div>
                <div class="mb-2">
                    <label class="form-label">Payment Notes</label>
                    <textarea name="q_payment_notes" class="form-control" rows="3"></textarea>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
                <button type="submit" class="btn btn-primary">Submit</button>
            </div>
        </form>
    </div>
</div>
<?php if (isset($_GET['open']) && $_GET['open'] === 'quick_deal'): ?>
<script>document.addEventListener('DOMContentLoaded',function(){var m=new bootstrap.Modal(document.getElementById('quickDealModal'));m.show();});</script>
<?php endif; ?>
<script>
function addTxn(){
    var c = document.getElementById('txnList');
    var row = document.createElement('div');
    row.className = 'row g-2 align-items-end mb-2';
    row.innerHTML = `
        <div class="col-md-4"><input type="date" name="txn_date[]" class="form-control"></div>
        <div class="col-md-4"><input type="text" name="txn_amount[]" class="form-control comma-format" placeholder="Amount"></div>
        <div class="col-md-4"><button type="button" class="btn btn-outline-danger btn-sm" onclick="this.closest('div.row').remove()">Remove</button></div>
    `;
    c.appendChild(row);
    var newInp = row.querySelector('.comma-format');
    if(newInp) {
        newInp.addEventListener('input', function(e){
            var val = e.target.value.replace(/,/g, '');
            if(val !== '') {
                var parts = val.split('.');
                parts[0] = parts[0].replace(/\D/g, '').replace(/\B(?=(\d{3})+(?!\d))/g, ',');
                if(parts.length > 2) parts = [parts[0], parts[1]];
                e.target.value = parts.join('.');
            }
        });
    }
}
(function(){
    var paymentTypeSel = document.getElementById('payment_type');
    var totalPctEl = document.getElementById('commission_total_display');
    var statusSummary = document.getElementById('dealStatusSummary');
    function numDec(v){
        var s = String(v == null ? '' : v).trim().replace(',', '.');
        var n = parseFloat(s);
        return isFinite(n) ? n : 0;
    }
    function getTotalPct(){
        var v = numDec((totalPctEl && totalPctEl.value) ? totalPctEl.value : '0');
        if (!isFinite(v) || v < 0) v = 0;
        if (v > 100) v = 100;
        return Math.round(v * 100) / 100;
    }
    function recalc(){
        var payType = paymentTypeSel ? (paymentTypeSel.value || 'land') : 'land';
        var getVal = function(selector) {
            var el = document.querySelector(selector);
            return parseFloat(((el && el.value) ? el.value : '0').toString().replace(/,/g,''));
        };
        var offered = getVal('[name=amount_offered]');
        var paidSoFar = getVal('[name=amount_paid_so_far]');
        var paidNow = getVal('[name=amount_paid_now]');
        var discount = getVal('[name=discount_amount]');
        var plan = (document.getElementById('plan_type') && document.getElementById('plan_type').value) || 'installment';
        var txnTotal = 0;
        try {
            var txns = document.querySelectorAll('input[name="txn_amount[]"]');
            txns.forEach(function(inp){
                var v = parseFloat(((inp && inp.value) ? inp.value : '0').toString().replace(/,/g,''));
                if (isFinite(v) && v > 0) { txnTotal += v; }
            });
        } catch (e) {}
        if (plan === 'full') {
            paidSoFar = 0;
            discount = 0;
            offered = 0;
            var offEl = document.querySelector('[name=amount_offered]');
            if(offEl) offEl.value = '0.00';
            var psfEl = document.getElementById('amount_paid_so_far');
            if(psfEl) psfEl.value = '0.00';
        }
        var discounted = Math.max(offered - discount, 0);
        var balance = plan === 'full' ? 0 : Math.max(discounted - (paidSoFar + paidNow), 0);
        
        // Prevent negative balance display or accidental over-payment calculation
        if (balance < 0) balance = 0;

        var balEl = document.getElementById('balance_remaining');
        if (balEl) {
            balEl.value = formatWithCommas(balance.toFixed(2));
            if (balance === 0 && (paidSoFar + paidNow) >= discounted && discounted > 0) {
                balEl.classList.add('is-valid');
                balEl.classList.remove('is-invalid');
                if ((paidSoFar + paidNow) > discounted) {
                    balEl.classList.add('is-invalid');
                    if (statusSummary) {
                        statusSummary.innerHTML = '<span class="text-danger fw-bold"><i class="fa-solid fa-triangle-exclamation"></i> OVERPAYMENT: Amount exceeds offer balance!</span>';
                    }
                }
            } else {
                balEl.classList.remove('is-valid');
                balEl.classList.remove('is-invalid');
            }
        }
        var baseNow = paidNow;
        if (!isFinite(baseNow) || baseNow <= 0) {
            if (isFinite(txnTotal) && txnTotal > 0) { baseNow = txnTotal; }
            else if (isFinite(paidSoFar) && paidSoFar > 0) { baseNow = paidSoFar; }
            else if (isFinite(offered) && offered > 0) { baseNow = offered; }
            else { baseNow = 0; }
        }
        var mPctEl = document.getElementById('marketer_pct');
        var aPctEl = document.getElementById('agent_pct');
        var mCommEl = document.getElementById('marketer_comm');
        var aCommEl = document.getElementById('agent_comm');
        if (payType !== 'land') {
            if (totalPctEl) totalPctEl.value = '0.00';
            if (mPctEl) mPctEl.value = '0.00';
            if (aPctEl) aPctEl.value = '0.00';
            if (mCommEl) mCommEl.value = formatWithCommas('0.00');
            if (aCommEl) aCommEl.value = formatWithCommas('0.00');
            return;
        }

        var total = getTotalPct();
        var mPct = numDec(mPctEl ? (mPctEl.value || '0') : '0');
        var aPct = numDec(aPctEl ? (aPctEl.value || '0') : '0');
        if (mPct < 0) mPct = 0; if (mPct > total) mPct = total;
        if (aPct < 0) aPct = 0; if (aPct > total) aPct = total;
        var active = null;
        try { active = document.activeElement; } catch (e) { active = null; }
        if (mPctEl && active !== mPctEl) mPctEl.value = mPct.toFixed(2);
        if (aPctEl && active !== aPctEl) aPctEl.value = aPct.toFixed(2);
        if (mCommEl) mCommEl.value = formatWithCommas((baseNow * (mPct/100)).toFixed(2));
        if (aCommEl) aCommEl.value = formatWithCommas((baseNow * (aPct/100)).toFixed(2));
    }
    ['amount_offered','amount_paid_so_far','amount_paid_now','discount_amount','commission_pct'].forEach(function(n){
        var el = document.querySelector('[name='+n+']');
        if (el) el.addEventListener('input', recalc);
    });
    ['marketer_pct','agent_pct'].forEach(function(n){
        var el = document.querySelector('[name='+n+']');
        if (el) el.addEventListener('input', recalc);
    });
    var txnList = document.getElementById('txnList');
    if (txnList) {
        txnList.addEventListener('input', function(e){
            if (e && e.target && e.target.name === 'txn_amount[]') { recalc(); }
        });
    }
    var planSel = document.getElementById('plan_type');
    if (planSel) {
        planSel.addEventListener('change', function(){
            var plan = planSel.value;
            var soFar = document.getElementById('amount_paid_so_far');
            var offeredEl = document.querySelector('[name=amount_offered]');
            var discountEl = document.getElementById('discount_amount');
            var discByEl = document.querySelector('[name=discount_approved_by]');
            var offeredG = document.getElementById('offered_group');
            var sofarG = document.getElementById('sofar_group');
            var discountG = document.getElementById('discount_group');
            var discountByG = document.getElementById('discount_by_group');
            var balanceG = document.getElementById('balance_group');
            var customG = document.getElementById('custom_months_group');
            var customEl = document.getElementById('custom_months');
            if (soFar) {
                soFar.disabled = (plan === 'full');
            }
            if (offeredEl) offeredEl.disabled = (plan === 'full');
            if (discountEl) discountEl.disabled = (plan === 'full');
            if (discByEl) discByEl.disabled = (plan === 'full');
            if (offeredG) offeredG.style.display = (plan === 'full') ? 'none' : '';
            if (sofarG) sofarG.style.display = (plan === 'full') ? 'none' : '';
            if (discountG) discountG.style.display = (plan === 'full') ? 'none' : '';
            if (discountByG) discountByG.style.display = (plan === 'full') ? 'none' : '';
            if (balanceG) balanceG.style.display = (plan === 'full') ? 'none' : '';
            if (customG) customG.style.display = (plan === 'custom') ? '' : 'none';
            if (customEl) {
                customEl.disabled = (plan !== 'custom');
                if (plan !== 'custom') customEl.value = '';
            }
            var startDateEl = document.getElementById('installment_start_date');
            if (startDateEl) {
                startDateEl.disabled = (plan === 'full');
                var sdWrap = startDateEl.closest('.col-md-4');
                if (sdWrap) sdWrap.style.display = (plan === 'full') ? 'none' : '';
            }
            if (plan === 'full') {
                if (soFar) soFar.value = '0.00';
                if (offeredEl) offeredEl.value = '0.00';
                if (discountEl) discountEl.value = '0.00';
                document.getElementById('balance_remaining').value = '0.00';
            }
            recalc();
        });
        planSel.dispatchEvent(new Event('change'));
    }
    var mPctEl = document.getElementById('marketer_pct');
    var aPctEl = document.getElementById('agent_pct');
    function balanceSplit(changed){
        var payType = paymentTypeSel ? (paymentTypeSel.value || 'land') : 'land';
        if (payType !== 'land') {
            if (mPctEl) mPctEl.value = '0.00';
            if (aPctEl) aPctEl.value = '0.00';
            if (totalPctEl) totalPctEl.value = '0.00';
            recalc();
            return;
        }
        var total = getTotalPct();
        var m = numDec(mPctEl.value || '0'); var a = numDec(aPctEl.value || '0');
        if (m < 0) m = 0; if (m > total) m = total;
        if (a < 0) a = 0; if (a > total) a = total;
        if (changed === 'm') { a = total - m; }
        else if (changed === 'a') { m = total - a; }
        else { a = total - m; }
        mPctEl.value = m.toFixed(2);
        aPctEl.value = a.toFixed(2);
        recalc();
    }
    if (mPctEl) {
        mPctEl.addEventListener('change', function(){ balanceSplit('m'); });
        mPctEl.addEventListener('blur', function(){ balanceSplit('m'); });
    }
    if (aPctEl) {
        aPctEl.addEventListener('change', function(){ balanceSplit('a'); });
        aPctEl.addEventListener('blur', function(){ balanceSplit('a'); });
    }
    if (totalPctEl) {
        totalPctEl.addEventListener('change', function(){ balanceSplit('t'); });
        totalPctEl.addEventListener('blur', function(){ balanceSplit('t'); });
    }
    var p32 = document.getElementById('preset_3_2');
    var p23 = document.getElementById('preset_2_3');
    if (p32) p32.addEventListener('click', function(){ var t=getTotalPct(); var m=Math.min(3.00,t); mPctEl.value=m.toFixed(2); aPctEl.value=Math.max(0,t-m).toFixed(2); recalc(); });
    if (p23) p23.addEventListener('click', function(){ var t=getTotalPct(); var m=Math.min(2.00,t); mPctEl.value=m.toFixed(2); aPctEl.value=Math.max(0,t-m).toFixed(2); recalc(); });

    // Comma formatting logic
    function formatWithCommas(val) {
        if (!val && val !== 0) return '';
        var parts = val.toString().replace(/,/g, '').split('.');
        parts[0] = parts[0].replace(/\D/g, '').replace(/\B(?=(\d{3})+(?!\d))/g, ',');
        if (parts.length > 2) parts = [parts[0], parts[1]];
        return parts.join('.');
    }
    document.querySelectorAll('.comma-format').forEach(function(el) {
        el.addEventListener('input', function(e) {
            var start = e.target.selectionStart;
            var oldLen = e.target.value.length;
            e.target.value = formatWithCommas(e.target.value);
            var newLen = e.target.value.length;
            e.target.setSelectionRange(start + (newLen - oldLen), start + (newLen - oldLen));
        });
        // Initial format if has value
        if (el.value) el.value = formatWithCommas(el.value);
    });
    try {
        window.dealFormatWithCommas = formatWithCommas;
        window.dealRecalc = recalc;
    } catch (e) {}
})();
document.addEventListener('DOMContentLoaded', function(){
    var form = document.getElementById('dealForm');
    if (form) {
        var submitBtn = document.getElementById('dealSubmitBtn');
        var submitBtnDefaultText = submitBtn ? (submitBtn.textContent || 'Submit Deal') : 'Submit Deal';
        window.addEventListener('pageshow', function(ev){
            if (!submitBtn) return;
            if (ev && ev.persisted) {
                submitBtn.disabled = false;
                submitBtn.textContent = submitBtnDefaultText;
            }
        });
        var statusSummary = document.getElementById('dealStatusSummary');
        function validateStep(i){
            var ok = true;
            function req(name){ var el = form.querySelector('[name='+name+']'); if (!el) return true; var v = (el.value||'').trim(); var good = v!==''; if (!good) { el.classList.add('is-invalid'); ok=false; } else { el.classList.remove('is-invalid'); } return good; }
            if (i===0) { var a = form.querySelector('select[name=client_id]'); var b = form.querySelector('[name=client_name]'); var c = form.querySelector('[name=client_email]'); var has = (a && a.value.trim()!=='') || (b && b.value.trim()!=='') || (c && c.value.trim()!==''); if (!has) { ok=false; alert('Please select a client or provide client name/email.'); } }
            if (i===1) {
                req('marketer_name'); req('project_desc'); req('plan_type');
                var p = (form.querySelector('[name=plan_type]') || { value: '' }).value;
                if (p === 'custom') { req('custom_months'); }
                if (p !== 'full') { req('installment_start_date'); }
            }
            if (i===2) { req('amount_paid_now'); }
            if (i===4) {
                var pt = (typeof paymentTypeSel !== 'undefined' && paymentTypeSel) ? (paymentTypeSel.value || 'land') : 'land';
                if (pt !== 'land') { return ok; }
                var m = parseFloat((form.querySelector('[name=marketer_pct]')||{value:'0'}).value||'0');
                var a = parseFloat((form.querySelector('[name=agent_pct]')||{value:'0'}).value||'0');
                var t = parseFloat((form.querySelector('[name=commission_pct]')||{value:'0'}).value||'0');
                if (!isFinite(t) || t < 0) t = 0;
                if (t > 100) t = 100;
                var sum = (m + a).toFixed(2);
                if (sum !== t.toFixed(2)) { ok=false; alert('Commission split must sum to the Total Commission %.'); }
            }
            return ok;
        }
        function doAjaxSubmit(){
            var pt = paymentTypeSel ? (paymentTypeSel.value || 'land') : 'land';
            var existingId = existingDealIdInp ? Number(existingDealIdInp.value || '0') : 0;
            if (pt !== 'land' && (!existingId || existingId <= 0)) {
                var m0 = 'Please select an existing deal/property record before submitting an ' + pt + ' payment.';
                if (statusSummary) { statusSummary.textContent = m0; }
                alert(m0);
                return;
            }
            if (accountWarning && accountWarning.style.display !== 'none' && (accountWarning.textContent || '').trim() !== '') {
                var m1 = (accountWarning.textContent || 'Missing bank account configuration.');
                if (statusSummary) { statusSummary.textContent = m1; }
                alert(m1);
                return;
            }

            if (submitBtn) { submitBtn.disabled = true; submitBtn.textContent = 'Processing...'; }
            if (statusSummary) { statusSummary.textContent = 'Submitting...'; }

            var data = new FormData(form);
            data.append('xhr', '1');
            data.append('submit_deal', '1');

            var controller = null;
            try { controller = new AbortController(); } catch (err) { controller = null; }

            var timeoutMs = 45000;
            var timeoutId = setTimeout(function(){
                try { if (controller) controller.abort(); } catch (err) {}
            }, timeoutMs);

            fetch(form.getAttribute('action') || window.location.href, {
                method: 'POST',
                body: data,
                signal: controller ? controller.signal : undefined
            }).then(function(r){
                return r.text().then(function(txt){
                    var raw = (txt || '').trim();
                    var jsonText = raw;
                    var firstBrace = raw.indexOf('{');
                    if (firstBrace > 0) { jsonText = raw.slice(firstBrace); }
                    try {
                        var parsed = JSON.parse(jsonText);
                        if (parsed && typeof parsed === 'object') return parsed;
                    } catch (e) {}
                    var msg = 'Invalid server response.';
                    if (r && typeof r.status === 'number' && r.status > 0) { msg += ' HTTP ' + r.status + '.'; }
                    if (raw) { msg += ' ' + raw.slice(0, 180); }
                    return { success: false, error: msg };
                }).catch(function(){
                    return { success: false, error: 'Invalid server response.' };
                });
            }).then(function(res){
                if (!res) res = { success: false, error: 'No response.' };
                if (res.success) {
                    if (statusSummary) { statusSummary.textContent = res.message || 'Submitted.'; }
                    window.location.href = 'deal-submission.php?success=1';
                    return;
                }
                var msg = res.error || res.message || 'Submission failed.';
                if (statusSummary) { statusSummary.textContent = msg; }
                alert(msg);
                if (submitBtn) { submitBtn.disabled = false; submitBtn.textContent = submitBtnDefaultText; }
            }).catch(function(err){
                var msg = (err && err.name === 'AbortError') ? 'Submission timed out. Please try again.' : 'Network error. Please try again.';
                if (statusSummary) { statusSummary.textContent = msg; }
                alert(msg);
                if (submitBtn) { submitBtn.disabled = false; submitBtn.textContent = submitBtnDefaultText; }
            }).finally(function(){
                try { clearTimeout(timeoutId); } catch (err) {}
            });
        }
        function resolveExistingDealId(){
            var cid = cidSelect ? (cidSelect.value || '').trim() : '';
            var pid = propIdInp ? (propIdInp.value || '').trim() : '';
            var pdesc = (pDescInp ? pDescInp.value : '').trim();
            if (!cid || !pid) return Promise.resolve(0);
            var qs = 'client_id=' + encodeURIComponent(cid) + '&property_id=' + encodeURIComponent(pid);
            if (pdesc) { qs += '&project_desc=' + encodeURIComponent(pdesc); }
            return fetch('ajax_get_client_deal_status.php?' + qs).then(function(r){ return r.json(); }).then(function(res){
                var id = 0;
                try { id = res && res.success && res.data ? Number(res.data.parent_deal_id || 0) : 0; } catch (e) { id = 0; }
                if (!isFinite(id) || id < 0) id = 0;
                return id;
            }).catch(function(){ return 0; });
        }
        form.addEventListener('submit', function(e){
            if (!validateStep(0) || !validateStep(1) || !validateStep(2) || !validateStep(4)) {
                e.preventDefault();
                return;
            }
            var receiptEl = form.querySelector('[name="receipt"]');
            var hasReceipt = false;
            try { hasReceipt = !!(receiptEl && receiptEl.files && receiptEl.files.length > 0); } catch (err) { hasReceipt = false; }
            if (!hasReceipt) {
                e.preventDefault();
                var receiptIdx = -1;
                try {
                    if (Array.isArray(steps) && receiptEl) {
                        for (var si = 0; si < steps.length; si++) {
                            if (steps[si] && steps[si].contains && steps[si].contains(receiptEl)) { receiptIdx = si; break; }
                        }
                    }
                } catch (err2) { receiptIdx = -1; }
                if (receiptIdx >= 0) { idx = receiptIdx; show(idx); }
                if (statusSummary) { statusSummary.textContent = 'Please upload the payment receipt before submitting.'; }
                alert('Please upload the payment receipt before submitting.');
                try { if (receiptEl && receiptEl.scrollIntoView) receiptEl.scrollIntoView({behavior:'smooth', block:'center'}); } catch (err3) {}
                return;
            }
            e.preventDefault();
            var pt = paymentTypeSel ? (paymentTypeSel.value || 'land') : 'land';
            var existingId = existingDealIdInp ? Number(existingDealIdInp.value || '0') : 0;
            if (pt !== 'land' && (!existingId || existingId <= 0)) {
                if (statusSummary) { statusSummary.textContent = 'Checking existing land deal for this property...'; }
                resolveExistingDealId().then(function(id){
                    if (id > 0 && existingDealIdInp) { existingDealIdInp.value = String(id); }
                    if ((!id || id <= 0) && statusSummary) {
                        statusSummary.textContent = 'No existing land deal found for this client + property. Submit a Land payment first, then submit ' + pt + '.';
                    }
                    doAjaxSubmit();
                });
                return;
            }
            doAjaxSubmit();
        });
    }
    var steps = Array.prototype.slice.call(document.querySelectorAll('#dealForm .card.shadow-sm.mb-3'));
    if (steps.length === 0) { steps = Array.prototype.slice.call(document.querySelectorAll('#dealForm .card')); }
    if (steps.length === 0) { steps = Array.prototype.slice.call(document.querySelectorAll('#dealForm [data-step], #dealForm .step')); }
    var prev = document.getElementById('dealPrevBtn');
    var next = document.getElementById('dealNextBtn');
    var submit = document.getElementById('dealSubmitBtn');
    var stepIndicator = document.getElementById('dealStepIndicator');
    var idx = 0;

    // --- Dynamic Check for Existing Balance ---
    var cidSelect = document.getElementById('client_id_select');
    var pDescInp = document.getElementById('project_desc_input');
    var amtOfferedInp = document.querySelector('[name=amount_offered]');
    var amtSoFarInp = document.getElementById('amount_paid_so_far');
    var statusSummary = document.getElementById('dealStatusSummary');
    var historyMsg = document.getElementById('projectHistoryMsg');
    var prevBreakdown = document.getElementById('prevPaymentsBreakdown');
    var prevList = document.getElementById('prevPaymentsList');
    var existingDealIdInp = document.getElementById('existing_deal_id_hidden');
    var paymentTypeSel = document.getElementById('payment_type');
    var propIdInp = document.getElementById('property_id_input');
    var balWrap = document.getElementById('balanceBreakdown');
    var balLand = document.getElementById('bal_land');
    var balInfra = document.getElementById('bal_infra');
    var balExcav = document.getElementById('bal_excav');
    var accountWarning = document.getElementById('accountWarning');

    function fmtMoney(val) {
        var n = Number(val || 0);
        if (!isFinite(n)) n = 0;
        return '₦' + n.toLocaleString(undefined, {minimumFractionDigits:2, maximumFractionDigits:2});
    }
    var fmtCommas = (typeof window.dealFormatWithCommas === 'function') ? window.dealFormatWithCommas : function(val){
        if (!val && val !== 0) return '';
        var parts = val.toString().replace(/,/g, '').split('.');
        parts[0] = parts[0].replace(/\D/g, '').replace(/\B(?=(\d{3})+(?!\d))/g, ',');
        if (parts.length > 2) parts = [parts[0], parts[1]];
        return parts.join('.');
    };
    function safeRecalc(){
        try { if (typeof window.dealRecalc === 'function') window.dealRecalc(); } catch (e) {}
    }

    function refreshBalances() {
        var cid = cidSelect ? (cidSelect.value || '').trim() : '';
        var pid = propIdInp ? (propIdInp.value || '').trim() : '';
        if (!cid || !pid) {
            if (balWrap) balWrap.style.display = 'none';
            if (accountWarning) { accountWarning.style.display = 'none'; accountWarning.textContent = ''; }
            return;
        }
        fetch('deal-submission.php?action=balances&client_id=' + encodeURIComponent(cid) + '&property_id=' + encodeURIComponent(pid))
            .then(function(r){ return r.json(); })
            .then(function(res){
                if (!res || !res.ok) { if (balWrap) balWrap.style.display = 'none'; return; }
                if (balWrap) balWrap.style.display = '';
                if (balLand) balLand.textContent = fmtMoney((res.land && res.land.balance) ? res.land.balance : 0) + ' / ' + fmtMoney((res.land && res.land.total) ? res.land.total : 0);
                if (balInfra) balInfra.textContent = fmtMoney((res.infrastructure && res.infrastructure.balance) ? res.infrastructure.balance : 0) + ' / ' + fmtMoney((res.infrastructure && res.infrastructure.total) ? res.infrastructure.total : 0);
                if (balExcav) balExcav.textContent = fmtMoney((res.excavation && res.excavation.balance) ? res.excavation.balance : 0) + ' / ' + fmtMoney((res.excavation && res.excavation.total) ? res.excavation.total : 0);

                var t = paymentTypeSel ? (paymentTypeSel.value || 'land') : 'land';
                var ok = true;
                if (res.accounts && Object.prototype.hasOwnProperty.call(res.accounts, t)) { ok = !!res.accounts[t]; }
                if (!ok) {
                    if (accountWarning) {
                        accountWarning.textContent = 'No active ' + t + ' bank account configured for this property. Go to Finance → Property Bank Accounts and save the ' + t + ' account as Active.';
                        accountWarning.style.display = '';
                    }
                } else {
                    if (accountWarning) { accountWarning.style.display = 'none'; accountWarning.textContent = ''; }
                }
            })
            .catch(function(){ if (balWrap) balWrap.style.display = 'none'; if (accountWarning) { accountWarning.style.display = 'none'; accountWarning.textContent = ''; } });
    }

    function applyPaymentTypeUi() {
        var t = paymentTypeSel ? (paymentTypeSel.value || 'land') : 'land';
        var planSel = document.getElementById('plan_type');
        if (!planSel) return;
        if (t !== 'land') {
            planSel.value = 'full';
            planSel.disabled = true;
            planSel.dispatchEvent(new Event('change'));
        } else {
            planSel.disabled = false;
            planSel.dispatchEvent(new Event('change'));
        }
        var cc = document.getElementById('commission_card');
        if (cc) { cc.style.display = (t === 'land') ? '' : 'none'; }
        ['commission_pct','marketer_pct','agent_pct','marketer_comm','agent_comm'].forEach(function(n){
            var el = document.querySelector('[name='+n+']');
            if (!el) return;
            if (t === 'land') {
                el.disabled = false;
            } else {
                el.value = '0.00';
                el.disabled = true;
            }
        });
    }

    function checkClientStatus() {
        var cid = cidSelect ? cidSelect.value : '';
        var pdesc = (pDescInp ? pDescInp.value : '').trim();
        if (!cid) {
            if (statusSummary) statusSummary.textContent = '';
            if (historyMsg) historyMsg.innerHTML = '';
            if (prevBreakdown) prevBreakdown.style.display = 'none';
            if (existingDealIdInp) existingDealIdInp.value = '0';
            return;
        }
        
        var pid = (propIdInp ? (propIdInp.value || '').trim() : '');
        var qs = 'client_id=' + encodeURIComponent(cid);
        if (pid) { qs += '&property_id=' + encodeURIComponent(pid); }
        if (pdesc) { qs += '&project_desc=' + encodeURIComponent(pdesc); }
        fetch('ajax_get_client_deal_status.php?' + qs)
            .then(res => res.json())
            .then(res => {
                if (res.success && res.data) {
                    var d = res.data;
                    if (d.deals_count > 0) {
                        if (existingDealIdInp) existingDealIdInp.value = d.parent_deal_id || '0';
                        
                        var msg = "Client has " + d.deals_count + " record(s) matching this property. ";
                        if (d.total_paid > 0) {
                            msg += "Total Paid: ₦" + fmtCommas(d.total_paid.toFixed(2)) + ". ";
                        }
                        
                        if (d.total_offered > 0) {
                            if (amtOfferedInp && (!amtOfferedInp.value || amtOfferedInp.value == '0.00')) {
                                amtOfferedInp.value = fmtCommas(d.total_offered.toFixed(2));
                            }
                            if (amtSoFarInp) {
                                amtSoFarInp.value = fmtCommas(d.total_paid.toFixed(2));
                            }
                            
                            var rem = d.total_offered - d.total_paid;
                            if (rem <= 0 && d.total_offered > 0) {
                                historyMsg.innerHTML = '<span class="badge bg-success"><i class="fa-solid fa-check-circle me-1"></i> FULLY PAID</span>';
                            } else {
                                historyMsg.innerHTML = '<span class="text-info small"><i class="fa-solid fa-circle-info me-1"></i> Found matching property. Suggested remaining balance: ₦' + fmtCommas(rem.toFixed(2)) + '</span>';
                            }
                        }
                        
                        // Populate Breakdown List
                        if (prevList && res.raw_deals) {
                            prevList.innerHTML = '';
                            res.raw_deals.forEach(function(rd){
                                var li = document.createElement('li');
                                li.className = 'list-group-item d-flex justify-content-between align-items-center py-1';
                                li.innerHTML = '<span>' + (rd.project_name || rd.project_desc || 'Payment') + '</span>' +
                                               '<span class="fw-bold text-navy">₦' + fmtCommas(parseFloat(rd.amount_paid_so_far || 0).toFixed(2)) + '</span>';
                                prevList.appendChild(li);
                            });
                            if (prevBreakdown) prevBreakdown.style.display = '';
                        }
                        
                        if (statusSummary) statusSummary.textContent = msg;
                        safeRecalc();
                    refreshBalances();
                    } else {
                        if (statusSummary) statusSummary.textContent = pdesc ? 'No existing deal found for this property description.' : 'Select property to check balance.';
                        if (historyMsg) historyMsg.innerHTML = '';
                        if (prevBreakdown) prevBreakdown.style.display = 'none';
                    }
                }
            })
            .catch(err => console.error("Error checking client status", err));
    }

    if (cidSelect) cidSelect.addEventListener('change', checkClientStatus);
    if (pDescInp) pDescInp.addEventListener('blur', checkClientStatus);
    if (cidSelect) cidSelect.addEventListener('change', refreshBalances);
    if (propIdInp) propIdInp.addEventListener('change', refreshBalances);
    if (propIdInp) propIdInp.addEventListener('change', checkClientStatus);
    if (paymentTypeSel) paymentTypeSel.addEventListener('change', function(){ applyPaymentTypeUi(); refreshBalances(); checkClientStatus(); });
    applyPaymentTypeUi();

    var pickerModalEl = document.getElementById('propertyPickerModal');
    var propsTbodyEl = document.getElementById('pickerPropsTbody');
    var propSearchEl = document.getElementById('pickerPropSearch');

    function renderProperties(rows) {
        if (!propsTbodyEl) return;
        propsTbodyEl.innerHTML = '';
        if (!rows || !rows.length) {
            propsTbodyEl.innerHTML = '<tr><td colspan="6" class="text-center text-muted">No properties found.</td></tr>';
            return;
        }
        rows.forEach(function(p){
            var tr = document.createElement('tr');
            var id = p.id || '';
            var title = (p.title || '').toString();
            var location = (p.location || p.address || '').toString();
            var price = (p.price !== null && p.price !== undefined) ? parseFloat(p.price || 0) : null;
            var status = (p.status || '').toString();
            var sqmVal = (p.area_sqm || p.total_sqm || '').toString();

            var tdId = document.createElement('td'); tdId.textContent = String(id); tdId.setAttribute('data-label', 'ID');
            var tdTitle = document.createElement('td'); tdTitle.textContent = title; tdTitle.setAttribute('data-label', 'Title');
            var tdLoc = document.createElement('td'); tdLoc.textContent = location || '—'; tdLoc.setAttribute('data-label', 'Location');
            var tdPrice = document.createElement('td');
            tdPrice.textContent = (price !== null) ? ('₦' + price.toLocaleString(undefined, {minimumFractionDigits:2, maximumFractionDigits:2})) : '—';
            tdPrice.setAttribute('data-label', 'Price');
            var tdSt = document.createElement('td'); tdSt.textContent = status; tdSt.setAttribute('data-label', 'Status');
            var tdAct = document.createElement('td');
            tdAct.setAttribute('data-label', 'Action');
            var b = document.createElement('button');
            b.type = 'button';
            b.className = 'btn btn-sm btn-outline-primary property-select-btn';
            b.setAttribute('data-id', String(id));
            b.setAttribute('data-title', title);
            b.setAttribute('data-sqm', sqmVal);
            b.textContent = 'Use';
            tdAct.appendChild(b);

            tr.appendChild(tdId);
            tr.appendChild(tdTitle);
            tr.appendChild(tdLoc);
            tr.appendChild(tdPrice);
            tr.appendChild(tdSt);
            tr.appendChild(tdAct);
            propsTbodyEl.appendChild(tr);
        });
    }

    function fetchJson(url) {
        return fetch(url, { credentials: 'same-origin' }).then(function(r){ return r.json(); });
    }

    function loadProperties() {
        var q = propSearchEl ? (propSearchEl.value || '').trim() : '';
        var url = 'deal-submission.php?action=picker_properties&search=' + encodeURIComponent(q);
        return fetchJson(url)
            .then(function(res){
                if (!res || !res.ok) { renderProperties([]); return; }
                renderProperties(res.rows || []);
            })
            .catch(function(){ renderProperties([]); });
    }

    if (propSearchEl) {
        propSearchEl.addEventListener('input', function(){
            loadProperties();
        });
    }

    if (propsTbodyEl) {
        propsTbodyEl.addEventListener('click', function(e){
            var btn = e.target.closest('.property-select-btn');
            if (!btn) return;
            var id = btn.getAttribute('data-id') || '';
            var title = btn.getAttribute('data-title') || '';
            var sqmVal = btn.getAttribute('data-sqm') || '';
            var descInp = document.getElementById('project_desc_input');
            var propInp = document.getElementById('property_id_input');
            var sqmInp = document.getElementById('sqm_input');
            if (descInp && title) descInp.value = title;
            if (propInp) propInp.value = id;
            if (sqmInp && sqmVal && (!sqmInp.value || String(sqmInp.value).trim() === '')) sqmInp.value = sqmVal;
            if (pickerModalEl && typeof bootstrap !== 'undefined' && bootstrap.Modal) {
                var inst = bootstrap.Modal.getInstance(pickerModalEl) || new bootstrap.Modal(pickerModalEl);
                inst.hide();
            }
            checkClientStatus();
            refreshBalances();
        });
    }

    if (pickerModalEl) {
        pickerModalEl.addEventListener('shown.bs.modal', function(){
            loadProperties();
        });
    }
    var sqmQuick = document.querySelectorAll('[data-sqm-quick]');
    var sqmHint = document.getElementById('sqm_hectare_hint');
    function updateSqmHint(){
        var sqmInp = document.getElementById('sqm_input');
        if (!sqmInp || !sqmHint) return;
        var v = parseFloat(String(sqmInp.value || '').trim());
        if (!isFinite(v) || v <= 0 || v < 1000) {
            sqmHint.style.display = 'none';
            sqmHint.textContent = '';
            return;
        }
        var ha = v / 10000;
        var fmt = (Math.round(ha * 100) / 100).toFixed(2);
        sqmHint.textContent = 'Hectares: ' + fmt + ' ha';
        sqmHint.style.display = '';
    }
    sqmQuick.forEach(function(btn){
        btn.addEventListener('click', function(){
            var v = this.getAttribute('data-sqm-quick') || '';
            var sqmInp = document.getElementById('sqm_input');
            if (sqmInp && v) {
                sqmInp.value = v;
                sqmInp.focus();
                updateSqmHint();
            }
        });
    });
    var sqmInpLive = document.getElementById('sqm_input');
    if (sqmInpLive) sqmInpLive.addEventListener('input', updateSqmHint);
    updateSqmHint();

    function show(i){
        var total = steps.length;
        if (total === 0) {
            if (prev) prev.style.display = 'none';
            if (next) next.style.display = 'none';
            if (previewBtn) previewBtn.style.display = 'none';
            if (submit) submit.style.display = '';
            if (stepIndicator) stepIndicator.textContent = 'Single step form';
            return;
        }
        steps.forEach(function(c,k){ c.style.display = (k===i)? '' : 'none'; });
        if (prev) prev.disabled = (i===0);
        if (stepIndicator) {
            var stepTitle = '';
            var header = steps[i] ? steps[i].querySelector('.card-header strong, .card-header') : null;
            if (header) {
                stepTitle = (header.textContent || '').trim().replace(/\s+/g, ' ');
            }
            stepIndicator.textContent = 'Step ' + (i + 1) + ' of ' + total + (stepTitle ? ' — ' + stepTitle : '');
        }
        if (next) {
            next.style.display = (i < total-1) ? '' : 'none';
            next.textContent = 'Next';
        }
        if (previewBtn) {
            previewBtn.style.display = (i === total-1) ? '' : 'none';
        }
        if (submit) {
            submit.style.display = (i === total-1) ? '' : 'none';
            submit.disabled = false;
        }
        var top = form.querySelector('.card-header'); if (top) top.scrollIntoView({behavior:'smooth',block:'start'});
    }
    show(idx);
    if (next) next.addEventListener('click', function(){ if (idx < steps.length-1) { idx++; show(idx); } });
    if (prev) prev.addEventListener('click', function(){ if (idx > 0) { idx--; show(idx); } });

    var previewBtn = document.getElementById('dealPreviewBtn');
    var previewBody = document.getElementById('dealPreviewBody');
    var previewSubmitBtn = document.getElementById('dealPreviewSubmitBtn');
    var previewModalEl = document.getElementById('dealPreviewModal');
    var variant = <?= json_encode($variant) ?>;

    function escHtml(s){
        return String(s || '').replace(/[&<>"']/g, function(c){
            return ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]);
        });
    }
    function valSel(el){
        if (!el) return '';
        var tag = (el.tagName || '').toLowerCase();
        if (tag === 'select') {
            var opt = el.options && el.selectedIndex >= 0 ? el.options[el.selectedIndex] : null;
            return (opt && opt.textContent) ? String(opt.textContent).trim() : '';
        }
        if (el.type === 'checkbox') { return el.checked ? 'Yes' : 'No'; }
        return String(el.value || '').trim();
    }
    function getById(id){ return document.getElementById(id); }
    function getByName(name){ return form ? form.querySelector('[name="' + name + '"]') : null; }
    function row(label, value){
        if (!value) return '';
        return '<div class="d-flex justify-content-between gap-3 py-1 border-bottom">'
            + '<div class="text-muted small">' + escHtml(label) + '</div>'
            + '<div class="fw-semibold text-end" style="max-width: 65%; word-break: break-word;">' + escHtml(value) + '</div>'
            + '</div>';
    }
    function section(title, rowsHtml){
        if (!rowsHtml) return '';
        return '<div class="card shadow-sm mb-3">'
            + '<div class="card-header bg-white"><strong>' + escHtml(title) + '</strong></div>'
            + '<div class="card-body py-2">' + rowsHtml + '</div>'
            + '</div>';
    }
    function buildPreview(){
        if (!previewBody) return;
        var html = '';

        var clientName = valSel(getByName('client_name'));
        var clientEmail = valSel(getByName('client_email'));
        var clientSel = valSel(getById('client_id_select'));
        html += section('Client Details',
            row('Client', clientSel) +
            row('Client’s Name (text)', clientName) +
            row('Client Email', clientEmail)
        );

        var dealSource = valSel(getByName('deal_source'));
        var marketerLabel = (variant === 'contact') ? 'Contact Centre Rep Name' : 'Marketer Name';
        var marketerName = valSel(getByName('marketer_name'));
        var projectDesc = valSel(getById('project_desc_input'));
        var propertyId = valSel(getById('property_id_input'));
        var planType = valSel(getById('plan_type'));
        var customMonths = valSel(getById('custom_months'));
        var instStart = valSel(getById('installment_start_date'));
        var sqm = valSel(getById('sqm_input'));
        html += section('Deal Details',
            row('Deal Source', dealSource) +
            row(marketerLabel, marketerName) +
            row('Project / Property Description', projectDesc) +
            row('Property ID', propertyId) +
            row('Payment Plan', planType) +
            row('Custom Duration (months)', customMonths) +
            row('Installment Start Date', instStart) +
            row('SQM', sqm)
        );

        var paymentType = valSel(getById('payment_type'));
        var offered = valSel(getByName('amount_offered'));
        var paidSoFar = valSel(getByName('amount_paid_so_far'));
        var paidNow = valSel(getByName('amount_paid_now'));
        var notes = valSel(getByName('client_payment_status'));
        html += section('Payment & Notes',
            row('Payment Type', paymentType) +
            row('Amount Offered', offered) +
            row('Amount Paid So Far', paidSoFar) +
            row('Amount Paid Now', paidNow) +
            row('Notes', notes)
        );

        var txnDates = form ? form.querySelectorAll('input[name="txn_date[]"]') : [];
        var txnAmounts = form ? form.querySelectorAll('input[name="txn_amount[]"]') : [];
        var txnRows = '';
        var txnCount = Math.max(txnDates.length, txnAmounts.length);
        for (var i = 0; i < txnCount; i++) {
            var d = txnDates[i] ? String(txnDates[i].value || '').trim() : '';
            var a = txnAmounts[i] ? String(txnAmounts[i].value || '').trim() : '';
            if (!d && !a) continue;
            txnRows += '<tr>'
                + '<td data-label="Date" class="text-muted small">' + escHtml(d || '-') + '</td>'
                + '<td data-label="Amount" class="text-end fw-semibold">' + escHtml(a || '-') + '</td>'
                + '</tr>';
        }
        if (txnRows) {
            html += '<div class="card shadow-sm mb-3">'
                + '<div class="card-header bg-white"><strong>Transaction History</strong></div>'
                + '<div class="card-body p-0">'
                + '<div class="table-responsive">'
                + '<table class="table table-sm mb-0 table-stackable">'
                + '<thead class="table-light"><tr><th>Date</th><th class="text-end">Amount</th></tr></thead>'
                + '<tbody>' + txnRows + '</tbody>'
                + '</table>'
                + '</div>'
                + '</div>'
                + '</div>';
        }

        var discountAmt = valSel(getByName('discount_amount'));
        var discountBy = valSel(getByName('discount_approved_by'));
        var balance = valSel(getByName('balance_remaining'));
        html += section('Discounts & Balance',
            row('Discount Amount', discountAmt) +
            row('Discount Approved By', discountBy) +
            row('Balance Remaining', balance)
        );

        var commissionTotal = valSel(getById('commission_total_display'));
        var marketerPct = valSel(getById('marketer_pct'));
        var agentPct = valSel(getById('agent_pct'));
        var marketerComm = valSel(getById('marketer_comm'));
        var agentComm = valSel(getById('agent_comm'));
        html += section('Commission',
            row('Total Commission %', commissionTotal) +
            row((variant === 'contact') ? 'Contact Centre %' : 'Marketer %', marketerPct) +
            row('Agent %', agentPct) +
            row((variant === 'contact') ? 'Contact Centre Amount' : 'Marketer Amount', marketerComm) +
            row('Agent Amount', agentComm)
        );

        var mkAcc = valSel(getByName('mk_acc_no'));
        var mkBank = valSel(getByName('mk_bank'));
        var mkName = valSel(getByName('mk_acc_name'));
        var agAcc = valSel(getByName('ag_acc_no'));
        var agBank = valSel(getByName('ag_bank'));
        var agName = valSel(getByName('ag_acc_name'));
        html += section('Bank Details',
            row((variant === 'contact') ? 'Contact Centre Account Number' : 'Marketer Account Number', mkAcc) +
            row((variant === 'contact') ? 'Contact Centre Bank Name' : 'Marketer Bank Name', mkBank) +
            row((variant === 'contact') ? 'Contact Centre Account Name' : 'Marketer Account Name', mkName) +
            row('Agent Account Number', agAcc) +
            row('Agent Bank Name', agBank) +
            row('Agent Account Name', agName)
        );

        var receiptEl = getByName('receipt');
        var receiptName = '';
        try { receiptName = receiptEl && receiptEl.files && receiptEl.files[0] ? receiptEl.files[0].name : ''; } catch (e) { receiptName = ''; }
        html += section('Receipt Upload', row('Receipt File', receiptName || 'Not uploaded'));

        previewBody.innerHTML = html || '<div class="text-muted">Nothing to preview yet.</div>';
    }

    if (previewBtn && previewBody) {
        previewBtn.addEventListener('click', function(){
            buildPreview();
        });
    }
    if (previewSubmitBtn) {
        previewSubmitBtn.addEventListener('click', function(){
            var rEl = form ? form.querySelector('[name="receipt"]') : null;
            var okReceipt = false;
            try { okReceipt = !!(rEl && rEl.files && rEl.files.length > 0); } catch (err) { okReceipt = false; }
            if (!okReceipt) {
                try {
                    if (previewModalEl && typeof bootstrap !== 'undefined' && bootstrap.Modal) {
                        var inst0 = bootstrap.Modal.getInstance(previewModalEl) || bootstrap.Modal.getOrCreateInstance(previewModalEl);
                        inst0.hide();
                    }
                } catch (e0) {}
                var receiptIdx2 = -1;
                try {
                    if (Array.isArray(steps) && rEl) {
                        for (var sj = 0; sj < steps.length; sj++) {
                            if (steps[sj] && steps[sj].contains && steps[sj].contains(rEl)) { receiptIdx2 = sj; break; }
                        }
                    }
                } catch (e1) { receiptIdx2 = -1; }
                if (receiptIdx2 >= 0) { idx = receiptIdx2; show(idx); }
                if (statusSummary) { statusSummary.textContent = 'Please upload the payment receipt before submitting.'; }
                alert('Please upload the payment receipt before submitting.');
                try { if (rEl && rEl.scrollIntoView) rEl.scrollIntoView({behavior:'smooth', block:'center'}); } catch (e2) {}
                return;
            }
            try {
                if (previewModalEl && typeof bootstrap !== 'undefined' && bootstrap.Modal) {
                    var inst = bootstrap.Modal.getInstance(previewModalEl) || bootstrap.Modal.getOrCreateInstance(previewModalEl);
                    inst.hide();
                }
            } catch (e) {}
            if (submit) { submit.click(); return; }
            if (form && typeof form.requestSubmit === 'function') { form.requestSubmit(); return; }
            if (form) { form.submit(); }
        });
    }
});
</script>
<?php if (!$isAjax): ?>
<div class="modal fade" id="propertyPickerModal" tabindex="-1" aria-labelledby="propertyPickerLabel" aria-hidden="true">
    <div class="modal-dialog modal-xl modal-fullscreen-sm-down modal-dialog-scrollable">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="propertyPickerLabel">Select Property</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <div class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center gap-2 mb-2">
                    <div class="small text-muted">Source: Properties</div>
                    <div class="small text-muted">New properties added will appear here automatically.</div>
                </div>
                <div class="d-flex gap-2 mb-2">
                    <input type="text" class="form-control form-control-sm" id="pickerPropSearch" placeholder="Search properties...">
                </div>
                <div class="table-responsive">
                    <table class="table table-hover align-middle table-sm table-stackable">
                        <thead>
                            <tr>
                                <th>ID</th>
                                <th>Title</th>
                                <th>Location</th>
                                <th>Price</th>
                                <th>Status</th>
                                <th>Action</th>
                            </tr>
                        </thead>
                        <tbody id="pickerPropsTbody">
                            <tr><td colspan="6" class="text-center text-muted">Type to search or scroll to select.</td></tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>

<div class="modal fade" id="dealPreviewModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-lg modal-fullscreen-sm-down modal-dialog-scrollable">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title"><i class="fa-solid fa-eye me-2"></i>Deal Submission Preview</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <div class="alert alert-info py-2 px-3 small mb-3">
                    Review the details below before submitting.
                </div>
                <div id="dealPreviewBody"></div>
            </div>
            <div class="modal-footer d-flex justify-content-between gap-2">
                <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Back to Form</button>
                <button type="button" class="btn btn-success" id="dealPreviewSubmitBtn"><i class="fa-solid fa-paper-plane me-1"></i>Submit</button>
            </div>
        </div>
    </div>
</div>
<?php endif; ?>
<?php include __DIR__ . '/includes/footer.php'; ?>

Youez - 2016 - github.com/yon3zu
LinuXploit