<?php

declare(strict_types=1);

require DENTAL_ROOT . '/app/bootstrap.php';
require_login();
require_permission('reports.view', ['super_admin','clinic_admin','receptionist','staff','dentist','dental_assistant','inventory_officer']);
require DENTAL_ROOT . '/app/layout.php';
require DENTAL_ROOT . '/app/module_helpers.php';
require_once DENTAL_ROOT . '/app/revenue_integrity.php';
require_once DENTAL_ROOT . '/app/inventory_integrity.php';
require_once DENTAL_ROOT . '/app/owner_reports.php';
require_once DENTAL_ROOT . '/app/role_satisfaction.php';

$pdo = db();
$role = active_role();
$advanced = documentation_schema_ready();
$revenueReady = revenue_schema_ready();
$reportUser = current_user() ?? [];
$financeBranchId = superuser_primary_workspace() ? 0 : signed_user_branch_id();
$financeBranchClause = $financeBranchId > 0
    ? ' AND i.branch_id=' . $financeBranchId
    : (superuser_primary_workspace() ? '' : ' AND 1=0');
$paymentAdjustmentSelect = schema_column_exists(table('payments'), 'adjustment_total')
    ? 'COALESCE(py.adjustment_total,0)'
    : '0';
$paymentStatusSelect = schema_column_exists(table('payments'), 'status') ? 'py.status' : '"posted"';
$paymentSourceSelect = schema_column_exists(table('payments'), 'source_type') ? 'py.source_type' : '"patient"';

$loadPaymentMethodSummary = static function (string $sinceSql) use ($pdo, $financeBranchClause, $revenueReady): array {
    $received = $pdo->query(
        'SELECT py.method,COUNT(*) transactions,COALESCE(SUM(py.amount),0) gross '
        . 'FROM `' . table('payments') . '` py JOIN `' . table('invoices') . '` i ON i.id=py.invoice_id '
        . 'WHERE py.created_at>=' . $sinceSql . $financeBranchClause . ' GROUP BY py.method'
    )->fetchAll();
    $map = [];
    foreach ($received as $row) {
        $method = (string)$row['method'];
        $map[$method] = ['method'=>$method,'transactions'=>(int)$row['transactions'],'gross'=>(float)$row['gross'],'returned'=>0.0,'net'=>(float)$row['gross']];
    }
    if ($revenueReady) {
        $returned = $pdo->query(
            'SELECT pa.method,COUNT(*) return_transactions,COALESCE(SUM(pa.amount),0) returned '
            . 'FROM `' . table('payment_adjustments') . '` pa JOIN `' . table('invoices') . '` i ON i.id=pa.invoice_id '
            . 'WHERE pa.status="processed" AND pa.processed_at>=' . $sinceSql . $financeBranchClause . ' GROUP BY pa.method'
        )->fetchAll();
        foreach ($returned as $row) {
            $method = (string)$row['method'];
            if (!isset($map[$method])) $map[$method] = ['method'=>$method,'transactions'=>0,'gross'=>0.0,'returned'=>0.0,'net'=>0.0];
            $map[$method]['returned'] = (float)$row['returned'];
            $map[$method]['net'] = round((float)$map[$method]['gross'] - (float)$row['returned'], 2);
        }
    }
    usort($map, static fn(array $a,array $b): int => $b['net'] <=> $a['net']);
    return array_values($map);
};

if (in_array($role, ['receptionist','staff'], true)) {
    require_task_action('reports.frontdesk');
    $frontdesk = dental_frontdesk_report($pdo, signed_user_branch_id());
    render_header('Front Desk Reports'); ?>
    <div class="task-view-notice"><strong><?= $role==='staff'?'General Staff reception report.':'Reception scope only.' ?></strong> This report covers appointment requests, expected arrivals, check-ins, waitlist, and follow-up booking. <?= $role==='staff'?'Your cashier register, payment history, receipts, and drawer reconciliation remain in Billing.':'It does not show clinical notes or payment records.' ?></div>
    <section class="stats role-stats"><?php stat_card('Expected arrivals', $frontdesk['expected_arrivals'], 'Today'); stat_card('Checked in', $frontdesk['checked_in'], 'Today'); stat_card('Late / due now', $frontdesk['late_or_due'], 'Needs front-desk action'); stat_card('Unconfirmed', $frontdesk['unconfirmed'], 'Next 3 days'); stat_card('Open requests', $frontdesk['open_requests'], $frontdesk['aged_requests'] . ' older than 24h'); stat_card('Follow-ups to book', $frontdesk['followups_need_booking'], 'Due within 14 days'); ?></section>
    <div class="record-grid">
      <section class="card table-wrap"><h2>Expected arrivals today</h2><table><thead><tr><th>Time</th><th>Patient</th><th>Service</th><th>Status</th><th>Contact</th></tr></thead><tbody><?php foreach($frontdesk['expected_rows'] as $row):?><tr><td><?=e(date('g:i A',strtotime((string)$row['start_at'])))?></td><td><strong><?=e((string)$row['patient'])?></strong><br><small><?=e((string)$row['patient_no'])?></small></td><td><?=e((string)$row['service_name'])?></td><td><?=e(module_status((string)$row['status']))?></td><td><?=e((string)($row['mobile'] ?: '—'))?></td></tr><?php endforeach; if(!$frontdesk['expected_rows']):?><tr><td colspan="5" class="muted">No expected arrivals for today.</td></tr><?php endif;?></tbody></table></section>
      <section class="card table-wrap"><h2>Online requests needing action</h2><table><thead><tr><th>Submitted</th><th>Reference</th><th>Patient</th><th>Service</th><th>Status</th><th>Contact</th></tr></thead><tbody><?php foreach($frontdesk['request_rows'] as $row):?><tr><td><?=e(date('M j, g:i A',strtotime((string)$row['created_at'])))?></td><td><strong><?=e((string)$row['public_reference'])?></strong></td><td><?=e((string)$row['patient'])?></td><td><?=e((string)$row['service_name'])?></td><td><?=e(module_status((string)$row['status']))?></td><td><?=e((string)($row['mobile'] ?: '—'))?></td></tr><?php endforeach; if(!$frontdesk['request_rows']):?><tr><td colspan="6" class="muted">No online requests need action.</td></tr><?php endif;?></tbody></table></section>
    </div>
    <section class="card"><h2>Front-desk closeout checklist</h2><div class="module-card-grid reports"><article class="module-card"><h3>Before shift end</h3><ul><li>All arrived patients are checked in or marked no-show only after appointment time.</li><li>All clinic-decides requests are assigned or left with an assignment note.</li><li>All follow-ups due within 14 days are booked or documented as contacted.</li><li>Waitlist patients are reviewed against newly cancelled slots.</li></ul></article><article class="module-card"><h3>Escalate to Administrator</h3><ul><li>Provider or chair conflict</li><li>Patient identity mismatch</li><li>Repeated no-show / cancellation pattern</li><li><?= $role==='staff'?'Discount, refund, waiver, or disputed-charge approval':'Patient balance dispute or payment question' ?></li></ul></article></div></section>
    <?php render_footer(); exit;
}

if ($role === 'dental_assistant') {
    require_task_action('reports.assistant');
    $worklog = dental_assistant_worklog($pdo, signed_user_branch_id(), (int)(current_user()['id'] ?? 0));
    render_header('Dental Assistant Worklog'); ?>
    <div class="task-view-notice"><strong>Assistant scope only.</strong> This worklog shows chairside support, screenings, uploads, and sterilization handoff work. It does not allow diagnosis, prescription, or final clinical sign-off.</div>
    <section class="stats role-stats"><?php stat_card('Chairside patients', $worklog['chairside_patients'], 'Today'); stat_card('Vitals recorded', $worklog['vitals_recorded_today'], 'By you today'); stat_card('Drafts assisted', $worklog['drafts_assisted'], 'Today'); stat_card('Uploads made', $worklog['uploads_today'], 'Today'); stat_card('Unreturned packs', $worklog['unreturned_instruments'], 'Assigned to you'); ?></section>
    <div class="record-grid">
      <section class="card table-wrap"><h2>Chairside queue</h2><table><thead><tr><th>Queue</th><th>Patient</th><th>Service</th><th>Status</th><th>Chair</th><th>Checked in</th></tr></thead><tbody><?php foreach($worklog['queue_rows'] as $row):?><tr><td><strong><?=e((string)$row['queue_no'])?></strong></td><td><?=e((string)$row['patient'])?><br><small><?=e((string)$row['patient_no'])?></small></td><td><?=e((string)($row['service_name'] ?: '—'))?></td><td><?=e(module_status((string)$row['status']))?></td><td><?=e((string)($row['chair_name'] ?: '—'))?></td><td><?=e(date('g:i A',strtotime((string)$row['checked_in_at'])))?></td></tr><?php endforeach; if(!$worklog['queue_rows']):?><tr><td colspan="6" class="muted">No active chairside queue items.</td></tr><?php endif;?></tbody></table></section>
      <section class="card"><h2>Assistant handoff checklist</h2><ul><li>Dental safety alerts and indicated chairside observations recorded before Dentist review.</li><li>Chair and instrument set prepared before seating or treatment start.</li><li>X-ray/photo/document uploads are linked to the correct patient and encounter.</li><li>Used instrument packs are returned to sterilization and not left open.</li><li>Draft clinical entries are left for Dentist review, not finalized by assistant.</li></ul></section>
    </div>
    <?php render_footer(); exit;
}

if ($role === 'dentist') {
    require_task_action('reports.clinical');
    $isRealDentist = active_role_is('dentist');
    $dentists = $isRealDentist ? [] : dentist_options();
    $dentistId = $isRealDentist ? (int) current_user()['id'] : (int) ($_GET['dentist_id'] ?? $_SESSION['task_dentist_id'] ?? 0);
    if (!$isRealDentist && $dentistId <= 0) $dentistId = (int) ($dentists[0]['id'] ?? 0);
    if (!$isRealDentist && $dentistId > 0) $_SESSION['task_dentist_id'] = $dentistId;

    $stmt = $pdo->prepare('SELECT COUNT(*) FROM `' . table('appointments') . '` WHERE dentist_user_id=? AND DATE(start_at)=CURDATE()');
    $stmt->execute([$dentistId]);
    $todayAppointments = (int) $stmt->fetchColumn();
    $stmt = $pdo->prepare('SELECT COUNT(*) FROM `' . table('appointments') . '` WHERE dentist_user_id=? AND status="completed" AND start_at>=DATE_SUB(NOW(),INTERVAL 30 DAY)');
    $stmt->execute([$dentistId]);
    $completed30 = (int) $stmt->fetchColumn();
    $stmt = $pdo->prepare('SELECT COUNT(*) FROM `' . table('clinical_encounters') . '` WHERE dentist_user_id=? AND status IN ("draft","pending_review")');
    $stmt->execute([$dentistId]);
    $drafts = (int) $stmt->fetchColumn();
    $stmt = $pdo->prepare('SELECT COUNT(*) FROM `' . table('follow_ups') . '` WHERE dentist_user_id=? AND status IN ("pending","scheduled") AND recommended_date<=DATE_ADD(CURDATE(),INTERVAL 14 DAY)');
    $stmt->execute([$dentistId]);
    $followups = (int) $stmt->fetchColumn();
    $quality = dental_dentist_completion_report($pdo, $dentistId);
    $stmt = $pdo->prepare('SELECT DATE(a.start_at) day,COUNT(*) total,SUM(a.status="completed") completed,SUM(a.status="cancelled") cancelled,SUM(a.status="no_show") no_show FROM `' . table('appointments') . '` a WHERE a.dentist_user_id=? AND a.start_at>=DATE_SUB(CURDATE(),INTERVAL 13 DAY) GROUP BY DATE(a.start_at) ORDER BY day DESC');
    $stmt->execute([$dentistId]);
    $daily = $stmt->fetchAll();
    $stmt = $pdo->prepare('SELECT c.id,c.created_at,c.status,c.diagnosis,CONCAT(p.first_name," ",p.last_name) patient,p.patient_no FROM `' . table('clinical_encounters') . '` c JOIN `' . table('patients') . '` p ON p.id=c.patient_id WHERE c.dentist_user_id=? ORDER BY c.created_at DESC LIMIT 20');
    $stmt->execute([$dentistId]);
    $recentClinical = $stmt->fetchAll();

    render_header($isRealDentist ? 'My Clinical Reports' : 'Dentist Clinical Reports');
    if ($dentists): ?>
        <form class="card compact-filter" method="get"><label>Dentist<select name="dentist_id" onchange="this.form.submit()"><?php foreach ($dentists as $doctor): ?><option value="<?= (int)$doctor['id'] ?>" <?= $dentistId === (int)$doctor['id'] ? 'selected' : '' ?>><?= e((string)($doctor['display_name'] ?? $doctor['name'])) ?></option><?php endforeach; ?></select></label></form>
        <div class="task-view-notice"><strong>Clinical scope only.</strong> Financial collections, clinic-wide patients, and inventory reports are hidden in Dentist Task View.</div>
    <?php endif; ?>
    <section class="stats role-stats"><?php stat_card("Today's appointments", $todayAppointments, 'Selected dentist'); stat_card('Completed visits', $completed30, 'Last 30 days'); stat_card('Draft records', $quality['draft_records'], 'Need completion'); stat_card('Completion review', $quality['completion_needs_review'], 'Missing or needs review'); stat_card('Documents pending', $quality['documents_pending_review'], 'Need review'); stat_card('Follow-ups due', $quality['followups_due'], 'Within 14 days'); ?></section>
    <div class="record-grid">
        <section class="card table-wrap"><h2>Appointment activity · last 14 days</h2><table><thead><tr><th>Date</th><th>Total</th><th>Completed</th><th>Cancelled</th><th>No-show</th></tr></thead><tbody><?php foreach ($daily as $row): ?><tr><td><?= e(date('M j, Y', strtotime((string)$row['day']))) ?></td><td><?= e($row['total']) ?></td><td><?= e($row['completed']) ?></td><td><?= e($row['cancelled']) ?></td><td><?= e($row['no_show']) ?></td></tr><?php endforeach; if (!$daily): ?><tr><td colspan="5" class="muted">No appointment activity.</td></tr><?php endif; ?></tbody></table></section>
        <section class="card table-wrap"><h2>Recent clinical records</h2><table><thead><tr><th>Date</th><th>Patient</th><th>Diagnosis</th><th>Status</th></tr></thead><tbody><?php foreach ($recentClinical as $row): ?><tr><td><?= e(date('M j, Y', strtotime((string)$row['created_at']))) ?></td><td><strong><?= e($row['patient']) ?></strong><br><small><?= e($row['patient_no']) ?></small></td><td><?= e($row['diagnosis'] ?: '—') ?></td><td><?= e(module_status((string)$row['status'])) ?></td></tr><?php endforeach; if (!$recentClinical): ?><tr><td colspan="4" class="muted">No clinical records.</td></tr><?php endif; ?></tbody></table></section>
    </div>
    <?php render_footer(); exit;
}

if ($role === 'inventory_officer') {
    require_task_action('reports.inventory');
    $inventoryBranchId = signed_user_branch_id();
    if ($inventoryBranchId < 1) {
        access_denied('Assign this Inventory Officer to a clinic branch before opening inventory reports.');
    }
    $lowStock = [];
    if (schema_table_exists(table('inventory_branch_stocks'))) {
        $stmt=$pdo->prepare('SELECT i.sku,i.name,i.category,i.unit,bs.current_stock,bs.reorder_level,bs.last_reconciled_at FROM `' . table('inventory_branch_stocks') . '` bs JOIN `' . table('inventory_items') . '` i ON i.id=bs.item_id WHERE bs.branch_id=? AND i.status="active" AND bs.current_stock<=bs.reorder_level ORDER BY (bs.reorder_level-bs.current_stock) DESC,i.name LIMIT 100');
        $stmt->execute([$inventoryBranchId]);$lowStock=$stmt->fetchAll();
    }
    $stmt=$pdo->prepare('SELECT l.lot_number,l.expiry_date,l.quantity_remaining,l.status,i.sku,i.name,i.unit FROM `' . table('inventory_lots') . '` l JOIN `' . table('inventory_items') . '` i ON i.id=l.item_id WHERE l.branch_id=? AND l.quantity_remaining>0 AND l.status IN ("active","quarantined") AND l.expiry_date IS NOT NULL AND l.expiry_date<=DATE_ADD(CURDATE(),INTERVAL 90 DAY) ORDER BY l.expiry_date,i.name LIMIT 100');
    $stmt->execute([$inventoryBranchId]);$expiringLots=$stmt->fetchAll();
    $stmt=$pdo->prepare('SELECT d.document_no,d.document_type,d.status,d.reason,d.requested_at,u.name requester FROM `' . table('inventory_documents') . '` d LEFT JOIN `' . table('users') . '` u ON u.id=d.requested_by WHERE (d.branch_id=? OR d.source_branch_id=? OR d.destination_branch_id=?) AND d.status IN ("draft","submitted","approved","dispatched") ORDER BY d.requested_at DESC LIMIT 100');
    $stmt->execute([$inventoryBranchId,$inventoryBranchId,$inventoryBranchId]);$pendingDocuments=$stmt->fetchAll();
    $stmt=$pdo->prepare('SELECT cycle_no,load_no,sterilizer_name,cycle_started_at,cycle_status,release_status,chemical_indicator_result,biological_indicator_result FROM `' . table('sterilization_batches') . '` WHERE branch_id=? AND (cycle_status IN ("loaded","running","quarantined","failed") OR release_status IN ("pending","failed","quarantined")) ORDER BY cycle_started_at DESC LIMIT 100');
    $stmt->execute([$inventoryBranchId]);$sterilizationExceptions=$stmt->fetchAll();
    $lowStockCount=count($lowStock);$expiringCount=count($expiringLots);$pendingDocumentCount=count($pendingDocuments);$sterilizationExceptionCount=count($sterilizationExceptions);

    render_header('Inventory Reports'); ?>
    <div class="task-view-notice"><strong>Inventory scope only.</strong> Collections, patient diagnoses, and continuing-care metrics are hidden from Inventory Officer Task View.</div>
    <section class="stats role-stats"><?php stat_card('Low-stock items',$lowStockCount,'At or below reorder level');stat_card('Lots expiring',$expiringCount,'Within 90 days');stat_card('Open stock documents',$pendingDocumentCount,'Draft through dispatched');stat_card('Sterilization exceptions',$sterilizationExceptionCount,'Pending, failed, or quarantined'); ?></section>
    <div class="quick-actions"><a class="btn ghost" target="_blank" href="print_record.php?type=inventory_stock">Print current stock</a><a class="btn ghost" target="_blank" href="print_record.php?type=inventory_expiry">Print expiration report</a><a class="btn ghost" target="_blank" href="print_record.php?type=sterilization_log&amp;date=<?=e(date('Y-m-d'))?>">Print sterilization log</a><a class="btn primary" href="inventory.php">Open inventory</a></div>
    <div class="record-grid">
      <section class="card table-wrap"><h2>Low-stock items</h2><table><thead><tr><th>SKU / Item</th><th>Category</th><th>Stock</th><th>Reorder level</th><th>Last reconciled</th></tr></thead><tbody><?php foreach($lowStock as $row):?><tr><td><strong><?=e((string)$row['name'])?></strong><br><small><?=e((string)$row['sku'])?></small></td><td><?=e((string)($row['category']?:'—'))?></td><td><?=e((string)$row['current_stock'])?> <?=e((string)$row['unit'])?></td><td><?=e((string)$row['reorder_level'])?> <?=e((string)$row['unit'])?></td><td><?=!empty($row['last_reconciled_at'])?e(date('M j, Y g:i A',strtotime((string)$row['last_reconciled_at']))):'—'?></td></tr><?php endforeach;if(!$lowStock):?><tr><td colspan="5" class="muted">No low-stock item for this branch.</td></tr><?php endif;?></tbody></table></section>
      <section class="card table-wrap"><h2>Expiring and quarantined lots</h2><table><thead><tr><th>Item</th><th>Lot</th><th>Expiry</th><th>Remaining</th><th>Status</th></tr></thead><tbody><?php foreach($expiringLots as $row):?><tr><td><strong><?=e((string)$row['name'])?></strong><br><small><?=e((string)$row['sku'])?></small></td><td><?=e((string)($row['lot_number']?:'—'))?></td><td><?=e(date('M j, Y',strtotime((string)$row['expiry_date'])))?></td><td><?=e((string)$row['quantity_remaining'])?> <?=e((string)$row['unit'])?></td><td><?=e(module_status((string)$row['status']))?></td></tr><?php endforeach;if(!$expiringLots):?><tr><td colspan="5" class="muted">No lot expires within 90 days.</td></tr><?php endif;?></tbody></table></section>
      <section class="card table-wrap"><h2>Open inventory documents</h2><table><thead><tr><th>Requested</th><th>Document</th><th>Type</th><th>Status</th><th>Requester</th><th>Reason</th></tr></thead><tbody><?php foreach($pendingDocuments as $row):?><tr><td><?=e(date('M j, Y g:i A',strtotime((string)$row['requested_at'])))?></td><td><?=e((string)$row['document_no'])?></td><td><?=e(module_status((string)$row['document_type']))?></td><td><?=e(module_status((string)$row['status']))?></td><td><?=e((string)($row['requester']?:'—'))?></td><td><?=e((string)$row['reason'])?></td></tr><?php endforeach;if(!$pendingDocuments):?><tr><td colspan="6" class="muted">No open inventory document.</td></tr><?php endif;?></tbody></table></section>
      <section class="card table-wrap"><h2>Sterilization exceptions</h2><table><thead><tr><th>Started</th><th>Cycle / Load</th><th>Sterilizer</th><th>Cycle</th><th>Release</th><th>Indicators</th></tr></thead><tbody><?php foreach($sterilizationExceptions as $row):?><tr><td><?=e(date('M j, Y g:i A',strtotime((string)$row['cycle_started_at'])))?></td><td><?=e((string)($row['cycle_no']?:'—'))?> / <?=e((string)($row['load_no']?:'—'))?></td><td><?=e((string)$row['sterilizer_name'])?></td><td><?=e(module_status((string)$row['cycle_status']))?></td><td><?=e(module_status((string)$row['release_status']))?></td><td>Chemical: <?=e(module_status((string)$row['chemical_indicator_result']))?><br><small>Biological: <?=e(module_status((string)$row['biological_indicator_result']))?></small></td></tr><?php endforeach;if(!$sterilizationExceptions):?><tr><td colspan="6" class="muted">No active sterilization exception.</td></tr><?php endif;?></tbody></table></section>
    </div>
    <?php render_footer(); exit;
}

if ($role === 'cashier') {
    flash('info','Cashier payment summaries are inside Billing → Cashier Register.');
    header('Location: billing.php');
    exit;
}

if (false && $role === 'cashier') {
    require_task_action('reports.finance');
    $todayGross = (float)$pdo->query('SELECT COALESCE(SUM(py.amount),0) FROM `' . table('payments') . '` py JOIN `' . table('invoices') . '` i ON i.id=py.invoice_id WHERE DATE(py.created_at)=CURDATE()' . $financeBranchClause)->fetchColumn();
    $monthGross = (float)$pdo->query('SELECT COALESCE(SUM(py.amount),0) FROM `' . table('payments') . '` py JOIN `' . table('invoices') . '` i ON i.id=py.invoice_id WHERE YEAR(py.created_at)=YEAR(CURDATE()) AND MONTH(py.created_at)=MONTH(CURDATE())' . $financeBranchClause)->fetchColumn();
    $todayReturns = $revenueReady ? (float)$pdo->query('SELECT COALESCE(SUM(pa.amount),0) FROM `' . table('payment_adjustments') . '` pa JOIN `' . table('invoices') . '` i ON i.id=pa.invoice_id WHERE pa.status="processed" AND DATE(pa.processed_at)=CURDATE()' . $financeBranchClause)->fetchColumn() : 0.0;
    $monthReturns = $revenueReady ? (float)$pdo->query('SELECT COALESCE(SUM(pa.amount),0) FROM `' . table('payment_adjustments') . '` pa JOIN `' . table('invoices') . '` i ON i.id=pa.invoice_id WHERE pa.status="processed" AND YEAR(pa.processed_at)=YEAR(CURDATE()) AND MONTH(pa.processed_at)=MONTH(CURDATE())' . $financeBranchClause)->fetchColumn() : 0.0;
    $todayRevenue = round($todayGross - $todayReturns, 2);
    $monthRevenue = round($monthGross - $monthReturns, 2);
    $todayTransactions = (int)$pdo->query('SELECT COUNT(*) FROM `' . table('payments') . '` py JOIN `' . table('invoices') . '` i ON i.id=py.invoice_id WHERE DATE(py.created_at)=CURDATE()' . $financeBranchClause)->fetchColumn();
    $outstanding = (float)$pdo->query('SELECT COALESCE(SUM(GREATEST(i.amount-i.paid_amount,0)),0) FROM `' . table('invoices') . '` i WHERE i.status IN ("unpaid","partial")' . ($financeBranchId > 0 ? ' AND i.branch_id=' . $financeBranchId : (superuser_primary_workspace() ? '' : ' AND 1=0')))->fetchColumn();
    $payments = $loadPaymentMethodSummary('DATE_SUB(NOW(),INTERVAL 30 DAY)');
    $recent = $pdo->query(
        'SELECT py.created_at,py.amount,' . $paymentAdjustmentSelect . ' adjusted_amount,'
        . '(py.amount-' . $paymentAdjustmentSelect . ') net_amount,py.method,py.reference_no,'
        . $paymentStatusSelect . ' payment_status,' . $paymentSourceSelect . ' source_type,'
        . 'i.invoice_no,CONCAT(p.first_name," ",p.last_name) patient '
        . 'FROM `' . table('payments') . '` py JOIN `' . table('invoices') . '` i ON i.id=py.invoice_id '
        . 'JOIN `' . table('patients') . '` p ON p.id=i.patient_id WHERE 1=1' . $financeBranchClause
        . ' ORDER BY py.created_at DESC LIMIT 30'
    )->fetchAll();
    $adjustments = $revenueReady ? $pdo->query(
        'SELECT pa.*,i.invoice_no,CONCAT(p.first_name," ",p.last_name) patient,'
        . 'rq.name requester,ap.name approver,pr.name processor '
        . 'FROM `' . table('payment_adjustments') . '` pa JOIN `' . table('invoices') . '` i ON i.id=pa.invoice_id '
        . 'JOIN `' . table('patients') . '` p ON p.id=i.patient_id '
        . 'LEFT JOIN `' . table('users') . '` rq ON rq.id=pa.requested_by '
        . 'LEFT JOIN `' . table('users') . '` ap ON ap.id=pa.approved_by '
        . 'LEFT JOIN `' . table('users') . '` pr ON pr.id=pa.processed_by '
        . 'WHERE pa.status="processed"' . $financeBranchClause . ' ORDER BY pa.processed_at DESC LIMIT 30'
    )->fetchAll() : [];
    $sessionClause = $financeBranchId > 0 ? ' AND cs.branch_id=' . $financeBranchId : (superuser_primary_workspace() ? '' : ' AND 1=0');
    $sessions = $revenueReady ? $pdo->query(
        'SELECT cs.*,u.name cashier,rv.name reviewer FROM `' . table('cashier_sessions') . '` cs '
        . 'LEFT JOIN `' . table('users') . '` u ON u.id=cs.cashier_user_id LEFT JOIN `' . table('users') . '` rv ON rv.id=cs.reviewed_by '
        . 'WHERE cs.cashier_user_id=' . (int)($reportUser['id'] ?? 0) . $sessionClause . ' ORDER BY cs.opened_at DESC LIMIT 15'
    )->fetchAll() : [];
    render_header('Cashier Reports'); ?>
    <div class="task-view-notice"><strong>Finance scope only.</strong> Collections are reported by cash-movement date: payments received minus refunds and reversals processed in the same period.</div>
    <section class="stats role-stats"><?php stat_card("Today's net collections", '₱'.number_format($todayRevenue,2), 'Gross ₱'.number_format($todayGross,2)); stat_card('Monthly net collections', '₱'.number_format($monthRevenue,2), 'Gross ₱'.number_format($monthGross,2)); stat_card("Returns today", '₱'.number_format($todayReturns,2), 'Refunds and reversals'); stat_card("Today's transactions", $todayTransactions, 'Posted payments'); stat_card('Outstanding', '₱'.number_format($outstanding,2), 'Unpaid and partial invoices'); ?></section>
    <div class="record-grid">
      <section class="card table-wrap"><h2>Payment methods · last 30 days</h2><table><thead><tr><th>Method</th><th>Payments</th><th>Gross</th><th>Returned</th><th>Net</th></tr></thead><tbody><?php foreach ($payments as $row): ?><tr><td><?= e(module_status((string)$row['method'])) ?></td><td><?= e($row['transactions']) ?></td><td>₱<?= number_format((float)$row['gross'],2) ?></td><td>₱<?= number_format((float)$row['returned'],2) ?></td><td><strong>₱<?= number_format((float)$row['net'],2) ?></strong></td></tr><?php endforeach; if(!$payments):?><tr><td colspan="5" class="muted">No payment activity.</td></tr><?php endif;?></tbody></table></section>
      <section class="card table-wrap"><h2>Recent payments</h2><table><thead><tr><th>Date</th><th>Patient / Invoice</th><th>Method</th><th>Gross</th><th>Returned</th><th>Net</th><th>Status</th></tr></thead><tbody><?php foreach ($recent as $row): ?><tr><td><?= e(date('M j, g:i A', strtotime((string)$row['created_at']))) ?></td><td><strong><?= e($row['patient']) ?></strong><br><small><?= e($row['invoice_no']) ?> · <?=e(module_status((string)$row['source_type']))?></small></td><td><?= e(module_status((string)$row['method'])) ?><br><small><?=e((string)($row['reference_no'] ?: '—'))?></small></td><td>₱<?= number_format((float)$row['amount'],2) ?></td><td>₱<?= number_format((float)$row['adjusted_amount'],2) ?></td><td><strong>₱<?= number_format((float)$row['net_amount'],2) ?></strong></td><td><?=e(module_status((string)$row['payment_status']))?></td></tr><?php endforeach; if(!$recent):?><tr><td colspan="7" class="muted">No payments recorded.</td></tr><?php endif;?></tbody></table></section>
    </div>
    <?php if($revenueReady):?><div class="record-grid">
      <section class="card table-wrap"><h2>Processed refunds and reversals</h2><table><thead><tr><th>Processed</th><th>Patient / Invoice</th><th>Type</th><th>Method</th><th>Amount</th><th>Control trail</th><th>Reason</th></tr></thead><tbody><?php foreach($adjustments as $row):?><tr><td><?=e(date('M j, g:i A',strtotime((string)$row['processed_at'])))?></td><td><strong><?=e($row['patient'])?></strong><br><small><?=e($row['invoice_no'])?></small></td><td><?=e(module_status((string)$row['adjustment_type']))?></td><td><?=e(module_status((string)$row['method']))?><br><small><?=e((string)($row['reference_no']?:'—'))?></small></td><td>₱<?=number_format((float)$row['amount'],2)?></td><td><small>Requested: <?=e($row['requester']?:'—')?><br>Approved: <?=e($row['approver']?:'—')?><br>Processed: <?=e($row['processor']?:'—')?></small></td><td><?=e((string)$row['reason'])?></td></tr><?php endforeach; if(!$adjustments):?><tr><td colspan="7" class="muted">No processed returns.</td></tr><?php endif;?></tbody></table></section>
      <section class="card table-wrap"><h2>My cashier sessions</h2><table><thead><tr><th>Opened</th><th>Closed</th><th>Status</th><th>Opening</th><th>Expected</th><th>Counted</th><th>Variance</th><th>Reviewer</th></tr></thead><tbody><?php foreach($sessions as $row):?><tr><td><?=e(date('M j, g:i A',strtotime((string)$row['opened_at'])))?></td><td><?=!empty($row['closed_at'])?e(date('M j, g:i A',strtotime((string)$row['closed_at']))):'—'?></td><td><?=e(module_status((string)$row['status']))?></td><td>₱<?=number_format((float)$row['opening_cash'],2)?></td><td><?=isset($row['expected_cash'])?'₱'.number_format((float)$row['expected_cash'],2):'—'?></td><td><?=isset($row['counted_cash'])?'₱'.number_format((float)$row['counted_cash'],2):'—'?></td><td><?=isset($row['variance'])?'₱'.number_format((float)$row['variance'],2):'—'?></td><td><?=e($row['reviewer']?:'—')?></td></tr><?php endforeach; if(!$sessions):?><tr><td colspan="8" class="muted">No cashier sessions recorded.</td></tr><?php endif;?></tbody></table></section>
    </div><?php endif;?>
    <?php render_footer(); exit;
}

if ($role === 'inventory_officer') {
    require_task_action('reports.inventory');
    if(!inventory_schema_ready()){render_header('Inventory Reports');echo '<div class="alert danger">Apply Version 0.5.9.8 before opening reconciled inventory reports.</div>';render_footer();exit;}
    if (!inventory_schema_ready()) {
        render_header('Inventory Reports');
        echo '<div class="alert danger">Apply Version 0.5.9.8 before opening reconciled inventory reports.</div>';
        render_footer(); exit;
    }
    $invBranchId = superuser_primary_workspace() ? (int)($_GET['branch_id']??0) : signed_user_branch_id();
    $branchClause = $invBranchId>0 ? ' WHERE bs.branch_id=' . $invBranchId : (superuser_primary_workspace() ? '' : ' WHERE 1=0');
    $lotClause = $invBranchId>0 ? ' AND l.branch_id=' . $invBranchId : (superuser_primary_workspace() ? '' : ' AND 1=0');
    $txClause = $invBranchId>0 ? ' WHERE t.branch_id=' . $invBranchId : (superuser_primary_workspace() ? '' : ' WHERE 1=0');
    $docClause = $invBranchId>0 ? ' AND (branch_id=' . $invBranchId . ' OR destination_branch_id=' . $invBranchId . ')' : (superuser_primary_workspace() ? '' : ' AND 1=0');
    $totalItems = (int)$pdo->query('SELECT COUNT(*) FROM `' . table('inventory_branch_stocks') . '` bs JOIN `' . table('inventory_items') . '` i ON i.id=bs.item_id' . $branchClause . ($branchClause ? ' AND' : ' WHERE') . ' i.status="active"')->fetchColumn();
    $lowStock = (int)$pdo->query('SELECT COUNT(*) FROM `' . table('inventory_branch_stocks') . '` bs JOIN `' . table('inventory_items') . '` i ON i.id=bs.item_id' . $branchClause . ($branchClause ? ' AND' : ' WHERE') . ' i.status="active" AND bs.current_stock<=bs.reorder_level')->fetchColumn();
    $expiring = (int)$pdo->query('SELECT COUNT(DISTINCT l.id) FROM `' . table('inventory_lots') . '` l WHERE l.status="active" AND l.quantity_remaining>0 AND l.expiry_date BETWEEN CURDATE() AND DATE_ADD(CURDATE(),INTERVAL 60 DAY)' . $lotClause)->fetchColumn();
    $expired = (int)$pdo->query('SELECT COUNT(DISTINCT l.id) FROM `' . table('inventory_lots') . '` l WHERE l.quantity_remaining>0 AND l.expiry_date<CURDATE()' . $lotClause)->fetchColumn();
    $pendingDocs = (int)$pdo->query('SELECT COUNT(*) FROM `' . table('inventory_documents') . '` WHERE status IN ("submitted","approved","dispatched")' . $docClause)->fetchColumn();
    $items = $pdo->query('SELECT i.name,i.sku,bs.current_stock,bs.reorder_level,i.unit,b.name branch,(SELECT MIN(expiry_date) FROM `' . table('inventory_lots') . '` l WHERE l.item_id=i.id AND l.branch_id=bs.branch_id AND l.status="active" AND l.quantity_remaining>0) next_expiry FROM `' . table('inventory_branch_stocks') . '` bs JOIN `' . table('inventory_items') . '` i ON i.id=bs.item_id JOIN `' . table('branches') . '` b ON b.id=bs.branch_id' . $branchClause . ($branchClause ? ' AND' : ' WHERE') . ' i.status="active" AND (bs.current_stock<=bs.reorder_level OR EXISTS(SELECT 1 FROM `' . table('inventory_lots') . '` l2 WHERE l2.item_id=i.id AND l2.branch_id=bs.branch_id AND l2.status="active" AND l2.quantity_remaining>0 AND l2.expiry_date<=DATE_ADD(CURDATE(),INTERVAL 60 DAY))) ORDER BY bs.current_stock<=bs.reorder_level DESC,next_expiry LIMIT 50')->fetchAll();
    $recent = $pdo->query('SELECT t.created_at,t.movement_no,t.transaction_type,t.quantity,t.balance_after,i.name item,b.name branch,u.name user_name,d.document_no FROM `' . table('inventory_transactions') . '` t JOIN `' . table('inventory_items') . '` i ON i.id=t.item_id LEFT JOIN `' . table('branches') . '` b ON b.id=t.branch_id LEFT JOIN `' . table('users') . '` u ON u.id=t.user_id LEFT JOIN `' . table('inventory_documents') . '` d ON d.id=t.document_id' . $txClause . ' ORDER BY t.created_at DESC LIMIT 40')->fetchAll();
    render_header('Inventory Reports'); ?>
    <div class="task-view-notice"><strong>Inventory scope only.</strong> Figures are based on posted lot movements and branch reconciliation. Draft or approved-but-unposted documents do not change stock.</div>
    <section class="stats role-stats"><?php stat_card('Branch items',$totalItems,'Reconciled balances'); stat_card('Low stock',$lowStock,'At or below branch reorder'); stat_card('Expiring lots',$expiring,'Within 60 days'); stat_card('Expired lots',$expired,'Requires controlled expiry/disposal'); stat_card('Open documents',$pendingDocs,'Approval, posting, or transfer receipt'); ?></section>
    <div class="record-grid"><section class="card table-wrap"><h2>Stock requiring attention</h2><table><thead><tr><th>Item</th><th>Branch</th><th>Stock</th><th>Reorder</th><th>Next expiry</th></tr></thead><tbody><?php foreach ($items as $row): ?><tr><td><strong><?= e($row['name']) ?></strong><br><small><?= e($row['sku']) ?></small></td><td><?=e($row['branch'])?></td><td class="<?= (float)$row['current_stock'] <= (float)$row['reorder_level'] ? 'danger-text' : '' ?>"><?= e($row['current_stock']) ?> <?= e($row['unit']) ?></td><td><?= e($row['reorder_level']) ?></td><td><?= e($row['next_expiry'] ?: '—') ?></td></tr><?php endforeach; if (!$items): ?><tr><td colspan="5" class="muted">No immediate stock alerts.</td></tr><?php endif; ?></tbody></table></section><section class="card table-wrap"><h2>Posted movement ledger</h2><table><thead><tr><th>Date</th><th>Movement / Document</th><th>Item</th><th>Branch</th><th>Type</th><th>Quantity</th><th>Lot balance</th><th>User</th></tr></thead><tbody><?php foreach ($recent as $row): ?><tr><td><?= e(date('M j, g:i A', strtotime((string)$row['created_at']))) ?></td><td><?=e($row['movement_no']?:'Legacy')?><br><small><?=e($row['document_no']?:'—')?></small></td><td><?= e($row['item']) ?></td><td><?=e($row['branch']?:'—')?></td><td><?= e(module_status((string)$row['transaction_type'])) ?></td><td class="<?=(float)$row['quantity']<0?'danger-text':'ok'?>"><?= e($row['quantity']) ?></td><td><?=e($row['balance_after']??'—')?></td><td><?= e($row['user_name'] ?: 'System') ?></td></tr><?php endforeach; if(!$recent):?><tr><td colspan="8" class="muted">No posted movements.</td></tr><?php endif;?></tbody></table></section></div>
    <?php render_footer(); exit;
}

// Superuser and Administrator receive clinic-wide operational reports.
$todayGross=(float)$pdo->query('SELECT COALESCE(SUM(py.amount),0) FROM `' . table('payments') . '` py JOIN `' . table('invoices') . '` i ON i.id=py.invoice_id WHERE DATE(py.created_at)=CURDATE()' . $financeBranchClause)->fetchColumn();
$monthGross=(float)$pdo->query('SELECT COALESCE(SUM(py.amount),0) FROM `' . table('payments') . '` py JOIN `' . table('invoices') . '` i ON i.id=py.invoice_id WHERE YEAR(py.created_at)=YEAR(CURDATE()) AND MONTH(py.created_at)=MONTH(CURDATE())' . $financeBranchClause)->fetchColumn();
$todayReturns=$revenueReady?(float)$pdo->query('SELECT COALESCE(SUM(pa.amount),0) FROM `' . table('payment_adjustments') . '` pa JOIN `' . table('invoices') . '` i ON i.id=pa.invoice_id WHERE pa.status="processed" AND DATE(pa.processed_at)=CURDATE()' . $financeBranchClause)->fetchColumn():0.0;
$monthReturns=$revenueReady?(float)$pdo->query('SELECT COALESCE(SUM(pa.amount),0) FROM `' . table('payment_adjustments') . '` pa JOIN `' . table('invoices') . '` i ON i.id=pa.invoice_id WHERE pa.status="processed" AND YEAR(pa.processed_at)=YEAR(CURDATE()) AND MONTH(pa.processed_at)=MONTH(CURDATE())' . $financeBranchClause)->fetchColumn():0.0;
$todayRevenue=round($todayGross-$todayReturns,2);
$monthRevenue=round($monthGross-$monthReturns,2);
$patientBranchClause=$financeBranchId>0?' AND branch_id='.$financeBranchId:(superuser_primary_workspace()?'':' AND 1=0');
$appointmentBranchClause=$financeBranchId>0?' AND branch_id='.$financeBranchId:(superuser_primary_workspace()?'':' AND 1=0');
$newPatients=(int)$pdo->query('SELECT COUNT(*) FROM `' . table('patients') . '` WHERE YEAR(created_at)=YEAR(CURDATE()) AND MONTH(created_at)=MONTH(CURDATE())'.$patientBranchClause)->fetchColumn();
$completed=(int)$pdo->query('SELECT COUNT(*) FROM `' . table('appointments') . '` WHERE status="completed"'.$appointmentBranchClause)->fetchColumn();
$invoiceBranchOnly=$financeBranchId>0?' AND i.branch_id='.$financeBranchId:(superuser_primary_workspace()?'':' AND 1=0');
$metrics=['no_shows'=>(int)$pdo->query('SELECT COUNT(*) FROM `' . table('appointments') . '` WHERE status="no_show" AND start_at>=DATE_SUB(NOW(),INTERVAL 30 DAY)'.$appointmentBranchClause)->fetchColumn(),'cancelled'=>(int)$pdo->query('SELECT COUNT(*) FROM `' . table('appointments') . '` WHERE status="cancelled" AND start_at>=DATE_SUB(NOW(),INTERVAL 30 DAY)'.$appointmentBranchClause)->fetchColumn(),'outstanding'=>(float)$pdo->query('SELECT COALESCE(SUM(GREATEST(i.amount-i.paid_amount,0)),0) FROM `' . table('invoices') . '` i WHERE i.status IN ("unpaid","partial")'.$invoiceBranchOnly)->fetchColumn()];
if($advanced){
    $continuityBranch=$financeBranchId>0?' AND branch_id='.(int)$financeBranchId:(superuser_primary_workspace()?'':' AND 1=0');
    $patientJoinBranch=$financeBranchId>0?' AND p.branch_id='.(int)$financeBranchId:(superuser_primary_workspace()?'':' AND 1=0');
    $metrics['followups']=(int)$pdo->query('SELECT COUNT(*) FROM `' . table('follow_ups') . '` WHERE status="pending" AND recommended_date<=DATE_ADD(CURDATE(),INTERVAL 14 DAY)'.$continuityBranch)->fetchColumn();
    $metrics['recalls']=(int)$pdo->query('SELECT COUNT(*) FROM `' . table('recalls') . '` r JOIN `' . table('patients') . '` p ON p.id=r.patient_id WHERE r.status IN ("due_soon","due","overdue")'.$patientJoinBranch)->fetchColumn();
    if(schema_table_exists(table('inventory_branch_stocks'))){$reportBranch=signed_user_branch_id();$lowSql='SELECT COUNT(*) FROM `' . table('inventory_branch_stocks') . '` bs JOIN `' . table('inventory_items') . '` i ON i.id=bs.item_id WHERE i.status="active" AND bs.current_stock<=bs.reorder_level'.(superuser_primary_workspace()?'':($reportBranch>0?' AND bs.branch_id='.(int)$reportBranch:' AND 1=0'));$metrics['low_stock']=(int)$pdo->query($lowSql)->fetchColumn();}else{$metrics['low_stock']=(int)$pdo->query('SELECT COUNT(*) FROM `' . table('inventory_items') . '` WHERE status="active" AND current_stock<=reorder_level')->fetchColumn();}
    $metrics['lab_overdue']=(int)$pdo->query('SELECT COUNT(*) FROM `' . table('laboratory_cases') . '` l JOIN `' . table('patients') . '` p ON p.id=l.patient_id WHERE l.due_date<CURDATE() AND l.status NOT IN ("completed","cancelled")'.$patientJoinBranch)->fetchColumn();
}
$daily=$pdo->query('SELECT DATE(start_at) day,COUNT(*) total,SUM(status="completed") completed,SUM(status="cancelled") cancelled,SUM(status="no_show") no_show FROM `' . table('appointments') . '` WHERE start_at>=DATE_SUB(CURDATE(),INTERVAL 13 DAY)'.$appointmentBranchClause.' GROUP BY DATE(start_at) ORDER BY day DESC')->fetchAll();
$payments=$loadPaymentMethodSummary('DATE_SUB(NOW(),INTERVAL 30 DAY)');
$adjustments=$revenueReady?$pdo->query('SELECT pa.*,i.invoice_no,CONCAT(p.first_name," ",p.last_name) patient,rq.name requester,ap.name approver,pr.name processor FROM `' . table('payment_adjustments') . '` pa JOIN `' . table('invoices') . '` i ON i.id=pa.invoice_id JOIN `' . table('patients') . '` p ON p.id=i.patient_id LEFT JOIN `' . table('users') . '` rq ON rq.id=pa.requested_by LEFT JOIN `' . table('users') . '` ap ON ap.id=pa.approved_by LEFT JOIN `' . table('users') . '` pr ON pr.id=pa.processed_by WHERE pa.status="processed"'.$financeBranchClause.' ORDER BY pa.processed_at DESC LIMIT 30')->fetchAll():[];
$sessionClause=$financeBranchId>0?' WHERE cs.branch_id='.$financeBranchId:(superuser_primary_workspace()?'':' WHERE 1=0');
$sessions=$revenueReady?$pdo->query('SELECT cs.*,u.name cashier,rv.name reviewer FROM `' . table('cashier_sessions') . '` cs LEFT JOIN `' . table('users') . '` u ON u.id=cs.cashier_user_id LEFT JOIN `' . table('users') . '` rv ON rv.id=cs.reviewed_by'.$sessionClause.' ORDER BY cs.opened_at DESC LIMIT 30')->fetchAll():[];
$ownerReport = owner_report_snapshot($pdo, $financeBranchId);
$closeout = dental_admin_daily_closeout($pdo, $financeBranchId);
render_header('Clinic Reports'); ?>
<section class="stats"><?php stat_card("Today's net collections",'₱'.number_format($todayRevenue,2),'Gross ₱'.number_format($todayGross,2));stat_card('Monthly net collections','₱'.number_format($monthRevenue,2),'Returned ₱'.number_format($monthReturns,2));stat_card('Returns today','₱'.number_format($todayReturns,2),'Processed refunds/reversals');stat_card('New patients',$newPatients,'Current month');stat_card('Outstanding','₱'.number_format($metrics['outstanding'],2),'Unpaid and partial invoices');?></section>
<div class="module-card-grid reports"><article class="module-card"><h3>Appointment operations</h3><dl><dt>Completed</dt><dd><?=e($completed)?></dd><dt>No-shows (30d)</dt><dd><?=e($metrics['no_shows'])?></dd><dt>Cancelled (30d)</dt><dd><?=e($metrics['cancelled'])?></dd></dl></article><?php if($advanced):?><article class="module-card"><h3>Continuing care</h3><dl><dt>Follow-ups due</dt><dd><?=e($metrics['followups'])?></dd><dt>Recalls due</dt><dd><?=e($metrics['recalls'])?></dd><dt>Overdue lab cases</dt><dd><?=e($metrics['lab_overdue'])?></dd></dl><a href="followups.php">Open follow-ups and recalls</a></article><article class="module-card"><h3>Inventory control</h3><dl><dt>Low-stock items</dt><dd><?=e($metrics['low_stock'])?></dd></dl><a href="inventory.php">Open inventory</a></article><?php endif;?></div>
<section class="card owner-report-brief"><div class="card-head"><div><h2>Owner management dashboard</h2><p>Collections, production, balances, closeout exceptions, appointment conversion, and supply usage in one view.</p></div><a class="btn ghost" href="print_record.php?type=collection_report" target="_blank">Print collection report</a></div><div class="record-grid"><?php if(!empty($ownerReport['monthly_collections'])):?><section class="table-wrap"><h3>Monthly collections</h3><table><thead><tr><th>Month</th><th>Payments</th><th>Gross</th><th>Returns</th><th>Net</th></tr></thead><tbody><?php foreach($ownerReport['monthly_collections'] as $row):?><tr><td><?=e($row['label'])?></td><td><?=e((string)$row['payments'])?></td><td>₱<?=number_format((float)$row['gross'],2)?></td><td>₱<?=number_format((float)$row['returns'],2)?></td><td><strong>₱<?=number_format((float)$row['net'],2)?></strong></td></tr><?php endforeach;?></tbody></table></section><?php endif;?><?php if(!empty($ownerReport['provider_production'])):?><section class="table-wrap"><h3>Provider production · 30 days</h3><table><thead><tr><th>Provider</th><th>Invoices</th><th>Lines</th><th>Production</th></tr></thead><tbody><?php foreach($ownerReport['provider_production'] as $row):?><tr><td><?=e((string)$row['provider_name'])?></td><td><?=e((string)$row['invoices'])?></td><td><?=e((string)$row['billable_lines'])?></td><td><strong>₱<?=number_format((float)$row['production'],2)?></strong></td></tr><?php endforeach;?></tbody></table></section><?php endif;?></div><div class="record-grid"><?php if(!empty($ownerReport['balance_aging'])):?><section class="table-wrap"><h3>Patient balance aging</h3><table><thead><tr><th>Age</th><th>Invoices</th><th>Outstanding</th></tr></thead><tbody><?php foreach($ownerReport['balance_aging'] as $row):?><tr><td><?=e((string)$row['bucket'])?> days</td><td><?=e((string)$row['invoices'])?></td><td><strong>₱<?=number_format((float)$row['balance'],2)?></strong></td></tr><?php endforeach;?></tbody></table></section><?php endif;?><?php if(!empty($ownerReport['top_balances'])):?><section class="table-wrap"><h3>Largest open balances</h3><table><thead><tr><th>Patient</th><th>Open invoices</th><th>Oldest</th><th>Balance</th></tr></thead><tbody><?php foreach($ownerReport['top_balances'] as $row):?><tr><td><strong><?=e((string)$row['patient'])?></strong><br><small><?=e((string)$row['patient_no'])?></small></td><td><?=e((string)$row['open_invoices'])?></td><td><?=!empty($row['oldest_invoice'])?e(date('M j, Y',strtotime((string)$row['oldest_invoice']))):'—'?></td><td><strong>₱<?=number_format((float)$row['balance'],2)?></strong></td></tr><?php endforeach;?></tbody></table></section><?php endif;?></div><div class="record-grid"><?php if(!empty($ownerReport['appointment_conversion'])):?><section class="table-wrap"><h3>Appointment conversion · 30 days</h3><table><thead><tr><th>Status</th><th>Total</th></tr></thead><tbody><?php foreach($ownerReport['appointment_conversion'] as $row):?><tr><td><?=e(module_status((string)$row['status']))?></td><td><?=e((string)$row['total'])?></td></tr><?php endforeach;?></tbody></table></section><?php endif;?><?php if(!empty($ownerReport['no_show_watchlist'])):?><section class="table-wrap"><h3>No-show / cancellation watchlist</h3><table><thead><tr><th>Patient</th><th>No-shows</th><th>Cancelled</th><th>Last event</th></tr></thead><tbody><?php foreach($ownerReport['no_show_watchlist'] as $row):?><tr><td><strong><?=e((string)$row['patient'])?></strong><br><small><?=e((string)$row['patient_no'])?></small></td><td><?=e((string)$row['no_shows'])?></td><td><?=e((string)$row['cancellations'])?></td><td><?=!empty($row['last_event'])?e(date('M j, Y',strtotime((string)$row['last_event']))):'—'?></td></tr><?php endforeach;?></tbody></table></section><?php endif;?></div><div class="record-grid"><?php if(!empty($ownerReport['cashier_closeout_exceptions'])):?><section class="table-wrap"><h3>Cashier closeout exceptions</h3><table><thead><tr><th>Cashier</th><th>Status</th><th>Closed</th><th>Expected</th><th>Counted</th><th>Variance</th><th>Reviewer</th></tr></thead><tbody><?php foreach($ownerReport['cashier_closeout_exceptions'] as $row):?><tr><td><?=e((string)($row['cashier']?:'—'))?></td><td><?=e(module_status((string)$row['status']))?></td><td><?=!empty($row['closed_at'])?e(date('M j, g:i A',strtotime((string)$row['closed_at']))):'—'?></td><td><?=isset($row['expected_cash'])?'₱'.number_format((float)$row['expected_cash'],2):'—'?></td><td><?=isset($row['counted_cash'])?'₱'.number_format((float)$row['counted_cash'],2):'—'?></td><td><strong><?=isset($row['variance'])?'₱'.number_format((float)$row['variance'],2):'—'?></strong></td><td><?=e((string)($row['reviewer']?:'—'))?></td></tr><?php endforeach;?></tbody></table></section><?php endif;?><?php if(!empty($ownerReport['inventory_usage'])):?><section class="table-wrap"><h3>Clinical supply cost usage · 30 days</h3><table><thead><tr><th>Item</th><th>Category</th><th>Qty used</th><th>Estimated cost</th></tr></thead><tbody><?php foreach($ownerReport['inventory_usage'] as $row):?><tr><td><strong><?=e((string)$row['name'])?></strong><br><small><?=e((string)$row['sku'])?></small></td><td><?=e((string)($row['category']?:'—'))?></td><td><?=e(number_format((float)$row['quantity_used'],2))?> <?=e((string)$row['unit'])?></td><td><strong>₱<?=number_format((float)$row['estimated_cost'],2)?></strong></td></tr><?php endforeach;?></tbody></table></section><?php endif;?></div></section>
<div class="record-grid"><section class="card table-wrap"><h2>Appointment activity · last 14 days</h2><table><thead><tr><th>Date</th><th>Total</th><th>Completed</th><th>Cancelled</th><th>No-show</th></tr></thead><tbody><?php foreach($daily as $row):?><tr><td><?=e(date('M j, Y',strtotime((string)$row['day'])))?></td><td><?=e($row['total'])?></td><td><?=e($row['completed'])?></td><td><?=e($row['cancelled'])?></td><td><?=e($row['no_show'])?></td></tr><?php endforeach;?></tbody></table></section><section class="card table-wrap"><h2>Payment methods · last 30 days</h2><table><thead><tr><th>Method</th><th>Payments</th><th>Gross</th><th>Returned</th><th>Net</th></tr></thead><tbody><?php foreach($payments as $row):?><tr><td><?=e(module_status((string)$row['method']))?></td><td><?=e($row['transactions'])?></td><td>₱<?=number_format((float)$row['gross'],2)?></td><td>₱<?=number_format((float)$row['returned'],2)?></td><td><strong>₱<?=number_format((float)$row['net'],2)?></strong></td></tr><?php endforeach;?></tbody></table></section></div>
<?php if($revenueReady):?><div class="record-grid"><section class="card table-wrap"><h2>Processed refunds and reversals</h2><table><thead><tr><th>Processed</th><th>Patient / Invoice</th><th>Type</th><th>Method</th><th>Amount</th><th>Control trail</th><th>Reason</th></tr></thead><tbody><?php foreach($adjustments as $row):?><tr><td><?=e(date('M j, g:i A',strtotime((string)$row['processed_at'])))?></td><td><strong><?=e($row['patient'])?></strong><br><small><?=e($row['invoice_no'])?></small></td><td><?=e(module_status((string)$row['adjustment_type']))?></td><td><?=e(module_status((string)$row['method']))?><br><small><?=e((string)($row['reference_no']?:'—'))?></small></td><td>₱<?=number_format((float)$row['amount'],2)?></td><td><small>Requested: <?=e($row['requester']?:'—')?><br>Approved: <?=e($row['approver']?:'—')?><br>Processed: <?=e($row['processor']?:'—')?></small></td><td><?=e((string)$row['reason'])?></td></tr><?php endforeach;if(!$adjustments):?><tr><td colspan="7" class="muted">No processed returns.</td></tr><?php endif;?></tbody></table></section><section class="card table-wrap"><h2>Cashier session reconciliation</h2><table><thead><tr><th>Cashier</th><th>Opened</th><th>Closed</th><th>Status</th><th>Opening</th><th>Expected</th><th>Counted</th><th>Variance</th><th>Reviewer</th></tr></thead><tbody><?php foreach($sessions as $row):?><tr><td><?=e($row['cashier']?:'—')?></td><td><?=e(date('M j, g:i A',strtotime((string)$row['opened_at'])))?></td><td><?=!empty($row['closed_at'])?e(date('M j, g:i A',strtotime((string)$row['closed_at']))):'—'?></td><td><?=e(module_status((string)$row['status']))?></td><td>₱<?=number_format((float)$row['opening_cash'],2)?></td><td><?=isset($row['expected_cash'])?'₱'.number_format((float)$row['expected_cash'],2):'—'?></td><td><?=isset($row['counted_cash'])?'₱'.number_format((float)$row['counted_cash'],2):'—'?></td><td><?=isset($row['variance'])?'₱'.number_format((float)$row['variance'],2):'—'?></td><td><?=e($row['reviewer']?:'—')?></td></tr><?php endforeach;if(!$sessions):?><tr><td colspan="9" class="muted">No cashier sessions.</td></tr><?php endif;?></tbody></table></section></div><?php endif;?>
<?php render_footer();
