add reports
This commit is contained in:
parent
4b01726905
commit
eeb8d0977c
254
admin_reports_shippers.php
Normal file
254
admin_reports_shippers.php
Normal file
@ -0,0 +1,254 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/includes/layout.php';
|
||||
|
||||
// Check permission
|
||||
if (!has_permission('view_reports') && !has_permission('manage_shippers')) {
|
||||
render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippers');
|
||||
echo '<div class="container py-5"><div class="alert alert-danger">Access Denied. You do not have permission to view reports.</div></div>';
|
||||
render_footer();
|
||||
exit;
|
||||
}
|
||||
|
||||
$shipperId = (int)($_GET['shipper_id'] ?? 0);
|
||||
$startDate = $_GET['start_date'] ?? '';
|
||||
$endDate = $_GET['end_date'] ?? '';
|
||||
|
||||
$shipper = null;
|
||||
$shipments = [];
|
||||
$totalAmount = 0.00;
|
||||
|
||||
// Fetch all shippers for the dropdown
|
||||
$allShippers = db()->query("
|
||||
SELECT u.id, u.full_name, p.company_name
|
||||
FROM users u
|
||||
LEFT JOIN shipper_profiles p ON u.id = p.user_id
|
||||
WHERE u.role = 'shipper'
|
||||
ORDER BY u.full_name ASC
|
||||
")->fetchAll();
|
||||
|
||||
if ($shipperId) {
|
||||
// Fetch selected shipper details
|
||||
$stmt = db()->prepare("
|
||||
SELECT u.id, u.full_name, u.email, p.company_name, p.phone, p.address_line,
|
||||
c.name_en as country, ci.name_en as city
|
||||
FROM users u
|
||||
LEFT JOIN shipper_profiles p ON u.id = p.user_id
|
||||
LEFT JOIN countries c ON p.country_id = c.id
|
||||
LEFT JOIN cities ci ON p.city_id = ci.id
|
||||
WHERE u.id = ? AND u.role = 'shipper'
|
||||
");
|
||||
$stmt->execute([$shipperId]);
|
||||
$shipper = $stmt->fetch();
|
||||
|
||||
if ($shipper) {
|
||||
// Build Query with Date Filter
|
||||
$sql = "SELECT *
|
||||
FROM shipments
|
||||
WHERE shipper_id = ?
|
||||
AND status IN ('confirmed', 'in_transit', 'delivered')";
|
||||
$params = [$shipperId];
|
||||
|
||||
if (!empty($startDate)) {
|
||||
$sql .= " AND created_at >= ?";
|
||||
$params[] = $startDate . ' 00:00:00';
|
||||
}
|
||||
|
||||
if (!empty($endDate)) {
|
||||
$sql .= " AND created_at <= ?";
|
||||
$params[] = $endDate . ' 23:59:59';
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY created_at DESC";
|
||||
|
||||
$stmt = db()->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$shipments = $stmt->fetchAll();
|
||||
|
||||
foreach ($shipments as $s) {
|
||||
$totalAmount += (float)($s['total_price'] ?? 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippers', true);
|
||||
?>
|
||||
|
||||
<style>
|
||||
@media print {
|
||||
@page { size: A4; margin: 2cm; }
|
||||
body { background: white !important; font-family: 'Times New Roman', serif; -webkit-print-color-adjust: exact; }
|
||||
.no-print, .admin-sidebar, nav, footer, .btn, form.filter-form { display: none !important; }
|
||||
.col-md-2 { display: none !important; }
|
||||
.col-md-10 { width: 100% !important; flex: 0 0 100% !important; max-width: 100% !important; padding: 0 !important; margin: 0 !important; }
|
||||
.row { display: block !important; margin: 0 !important; }
|
||||
.panel { border: none !important; box-shadow: none !important; padding: 0 !important; }
|
||||
.print-header { display: block !important; margin-bottom: 30px; border-bottom: 2px solid #000; padding-bottom: 20px; }
|
||||
.print-header h1 { font-size: 24pt; font-weight: bold; margin-bottom: 5px; text-transform: uppercase; }
|
||||
.print-header p { margin: 0; font-size: 10pt; color: #555; }
|
||||
.statement-info { margin-bottom: 30px; display: flex; justify-content: space-between; border-bottom: 1px solid #ddd; padding-bottom: 20px; }
|
||||
.statement-info div { width: 48%; }
|
||||
.table-responsive { overflow: visible !important; }
|
||||
table { width: 100% !important; border-collapse: collapse !important; font-size: 10pt; }
|
||||
th, td { border: 1px solid #ddd !important; padding: 8px 12px !important; text-align: left; }
|
||||
th { background-color: #f8f9fa !important; font-weight: bold; text-transform: uppercase; color: #000 !important; }
|
||||
.text-end { text-align: right !important; }
|
||||
.total-row td { background-color: #eee !important; font-weight: bold; font-size: 12pt; border-top: 2px solid #000 !important; }
|
||||
.print-footer { display: block !important; margin-top: 50px; text-align: center; font-size: 9pt; color: #777; border-top: 1px solid #ddd; padding-top: 10px; }
|
||||
|
||||
/* Arabic Support */
|
||||
[dir="rtl"] body { font-family: 'Traditional Arabic', serif; }
|
||||
[dir="rtl"] th, [dir="rtl"] td { text-align: right; }
|
||||
[dir="rtl"] .text-end { text-align: left !important; }
|
||||
}
|
||||
.print-header, .print-footer { display: none; }
|
||||
</style>
|
||||
|
||||
<div class="row g-0">
|
||||
<div class="col-md-2 bg-white border-end min-vh-100 no-print">
|
||||
<?php render_admin_sidebar('reports_shippers'); ?>
|
||||
</div>
|
||||
<div class="col-md-10 p-4">
|
||||
<!-- Screen Only Header -->
|
||||
<div class="page-intro d-flex justify-content-between align-items-center mb-4 no-print">
|
||||
<div>
|
||||
<h1 class="section-title mb-1">Shipper Statements</h1>
|
||||
<p class="muted mb-0">View and print financial statements for shippers.</p>
|
||||
</div>
|
||||
<?php if ($shipper): ?>
|
||||
<button onclick="window.print()" class="btn btn-dark">
|
||||
<i class="bi bi-printer me-2"></i>Print Formal Statement
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Filter Form -->
|
||||
<div class="panel p-4 mb-4 no-print filter-form">
|
||||
<form method="get" class="row g-3 align-items-end">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small text-muted">Select Shipper</label>
|
||||
<select name="shipper_id" class="form-select" onchange="this.form.submit()">
|
||||
<option value="">-- Choose a Shipper --</option>
|
||||
<?php foreach ($allShippers as $s): ?>
|
||||
<option value="<?= $s['id'] ?>" <?= $shipperId == $s['id'] ? 'selected' : '' ?>>
|
||||
<?= e($s['full_name']) ?> (<?= e($s['company_name'] ?: 'No Company') ?>)
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small text-muted">Start Date</label>
|
||||
<input type="date" name="start_date" class="form-control" value="<?= e($startDate) ?>">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small text-muted">End Date</label>
|
||||
<input type="date" name="end_date" class="form-control" value="<?= e($endDate) ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="submit" class="btn btn-primary w-100">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php if ($shipperId && !$shipper): ?>
|
||||
<div class="alert alert-warning">Shipper not found.</div>
|
||||
<?php elseif ($shipper): ?>
|
||||
<div class="panel p-5 bg-white">
|
||||
<!-- Print Header -->
|
||||
<div class="print-header text-center">
|
||||
<h1>Statement of Account</h1>
|
||||
<h2 style="font-size: 18pt; margin: 0; font-weight: normal;">كشف حساب</h2>
|
||||
<p class="mt-2"><?= e(get_setting('company_name', 'Logistics Platform')) ?></p>
|
||||
<p><?= date('F j, Y') ?></p>
|
||||
</div>
|
||||
|
||||
<!-- Info Section -->
|
||||
<div class="statement-info row mb-4">
|
||||
<div class="col-6">
|
||||
<h5 class="fw-bold text-uppercase text-muted small mb-2">Billed To / إلى السيد</h5>
|
||||
<h4 class="fw-bold mb-1"><?= e($shipper['full_name']) ?></h4>
|
||||
<div class="text-muted"><?= e($shipper['company_name'] ?: '-') ?></div>
|
||||
<div class="small text-muted mt-1">
|
||||
<?= e($shipper['address_line'] ?: '') ?><br>
|
||||
<?= e($shipper['city'] ?: '') ?>, <?= e($shipper['country'] ?: '') ?><br>
|
||||
<?= e($shipper['phone'] ?: '') ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 text-end">
|
||||
<h5 class="fw-bold text-uppercase text-muted small mb-2">Summary / ملخص</h5>
|
||||
<div class="mb-1"><strong>Statement Date:</strong> <?= date('Y-m-d') ?></div>
|
||||
<?php if ($startDate || $endDate): ?>
|
||||
<div class="mb-1"><strong>Period:</strong> <?= e($startDate ?: 'Start') ?> to <?= e($endDate ?: 'Now') ?></div>
|
||||
<?php else: ?>
|
||||
<div class="mb-1"><strong>Period:</strong> All Time</div>
|
||||
<?php endif; ?>
|
||||
<div class="mb-1"><strong>Total Shipments:</strong> <?= count($shipments) ?></div>
|
||||
<div class="fs-4 fw-bold text-primary mt-2">
|
||||
<?= number_format($totalAmount, 2) ?> OMR
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Table -->
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered align-middle">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Date <br> <span class="fw-normal text-muted">التاريخ</span></th>
|
||||
<th>Ref # <br> <span class="fw-normal text-muted">رقم الشحنة</span></th>
|
||||
<th>Route <br> <span class="fw-normal text-muted">المسار</span></th>
|
||||
<th>Status <br> <span class="fw-normal text-muted">الحالة</span></th>
|
||||
<th class="text-end">Amount (OMR) <br> <span class="fw-normal text-muted">المبلغ</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($shipments)): ?>
|
||||
<tr><td colspan="5" class="text-center py-4 text-muted">No completed shipments found for this period.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($shipments as $row): ?>
|
||||
<tr>
|
||||
<td><?= date('Y-m-d', strtotime($row['created_at'])) ?></td>
|
||||
<td><span class="font-monospace">#<?= $row['id'] ?></span></td>
|
||||
<td>
|
||||
<?= e($row['origin_city']) ?> <i class="bi bi-arrow-right small text-muted mx-1"></i> <?= e($row['destination_city']) ?>
|
||||
<div class="small text-muted"><?= e($row['cargo_description']) ?></div>
|
||||
</td>
|
||||
<td>
|
||||
<?= e(ucfirst(str_replace('_', ' ', $row['status']))) ?>
|
||||
</td>
|
||||
<td class="text-end fw-bold">
|
||||
<?= number_format((float)$row['total_price'], 2) ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="total-row table-active">
|
||||
<td colspan="4" class="text-end text-uppercase">Total Balance / الإجمالي</td>
|
||||
<td class="text-end text-dark"><?= number_format($totalAmount, 2) ?> OMR</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Print Footer -->
|
||||
<div class="print-footer">
|
||||
<div class="row">
|
||||
<div class="col-6 text-start">
|
||||
Authorized Signature<br>
|
||||
_______________________
|
||||
</div>
|
||||
<div class="col-6 text-end">
|
||||
Printed on <?= date('Y-m-d H:i') ?><br>
|
||||
This is a computer-generated document.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php render_footer(); ?>
|
||||
254
admin_reports_truck_owners.php
Normal file
254
admin_reports_truck_owners.php
Normal file
@ -0,0 +1,254 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/includes/layout.php';
|
||||
|
||||
// Check permission
|
||||
if (!has_permission('view_reports') && !has_permission('manage_truck_owners')) {
|
||||
render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports_truck_owners');
|
||||
echo '<div class="container py-5"><div class="alert alert-danger">Access Denied. You do not have permission to view reports.</div></div>';
|
||||
render_footer();
|
||||
exit;
|
||||
}
|
||||
|
||||
$ownerId = (int)($_GET['owner_id'] ?? 0);
|
||||
$startDate = $_GET['start_date'] ?? '';
|
||||
$endDate = $_GET['end_date'] ?? '';
|
||||
|
||||
$owner = null;
|
||||
$shipments = [];
|
||||
$totalEarnings = 0.00;
|
||||
|
||||
// Fetch all truck owners for the dropdown
|
||||
$allOwners = db()->query("
|
||||
SELECT u.id, u.full_name, p.plate_no
|
||||
FROM users u
|
||||
LEFT JOIN truck_owner_profiles p ON u.id = p.user_id
|
||||
WHERE u.role = 'truck_owner'
|
||||
ORDER BY u.full_name ASC
|
||||
")->fetchAll();
|
||||
|
||||
if ($ownerId) {
|
||||
// Fetch selected owner details
|
||||
$stmt = db()->prepare("
|
||||
SELECT u.id, u.full_name, u.email, p.phone, p.plate_no, p.truck_type,
|
||||
c.name_en as country, ci.name_en as city
|
||||
FROM users u
|
||||
LEFT JOIN truck_owner_profiles p ON u.id = p.user_id
|
||||
LEFT JOIN countries c ON p.country_id = c.id
|
||||
LEFT JOIN cities ci ON p.city_id = ci.id
|
||||
WHERE u.id = ? AND u.role = 'truck_owner'
|
||||
");
|
||||
$stmt->execute([$ownerId]);
|
||||
$owner = $stmt->fetch();
|
||||
|
||||
if ($owner) {
|
||||
// Build Query with Date Filter
|
||||
$sql = "SELECT *
|
||||
FROM shipments
|
||||
WHERE truck_owner_id = ?
|
||||
AND status IN ('confirmed', 'in_transit', 'delivered')";
|
||||
$params = [$ownerId];
|
||||
|
||||
if (!empty($startDate)) {
|
||||
$sql .= " AND created_at >= ?";
|
||||
$params[] = $startDate . ' 00:00:00';
|
||||
}
|
||||
|
||||
if (!empty($endDate)) {
|
||||
$sql .= " AND created_at <= ?";
|
||||
$params[] = $endDate . ' 23:59:59';
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY created_at DESC";
|
||||
|
||||
$stmt = db()->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$shipments = $stmt->fetchAll();
|
||||
|
||||
foreach ($shipments as $s) {
|
||||
$totalEarnings += (float)($s['offer_price'] ?? 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports_truck_owners', true);
|
||||
?>
|
||||
|
||||
<style>
|
||||
@media print {
|
||||
@page { size: A4; margin: 2cm; }
|
||||
body { background: white !important; font-family: 'Times New Roman', serif; -webkit-print-color-adjust: exact; }
|
||||
.no-print, .admin-sidebar, nav, footer, .btn, form.filter-form { display: none !important; }
|
||||
.col-md-2 { display: none !important; }
|
||||
.col-md-10 { width: 100% !important; flex: 0 0 100% !important; max-width: 100% !important; padding: 0 !important; margin: 0 !important; }
|
||||
.row { display: block !important; margin: 0 !important; }
|
||||
.panel { border: none !important; box-shadow: none !important; padding: 0 !important; }
|
||||
.print-header { display: block !important; margin-bottom: 30px; border-bottom: 2px solid #000; padding-bottom: 20px; }
|
||||
.print-header h1 { font-size: 24pt; font-weight: bold; margin-bottom: 5px; text-transform: uppercase; }
|
||||
.print-header p { margin: 0; font-size: 10pt; color: #555; }
|
||||
.statement-info { margin-bottom: 30px; display: flex; justify-content: space-between; border-bottom: 1px solid #ddd; padding-bottom: 20px; }
|
||||
.statement-info div { width: 48%; }
|
||||
.table-responsive { overflow: visible !important; }
|
||||
table { width: 100% !important; border-collapse: collapse !important; font-size: 10pt; }
|
||||
th, td { border: 1px solid #ddd !important; padding: 8px 12px !important; text-align: left; }
|
||||
th { background-color: #f8f9fa !important; font-weight: bold; text-transform: uppercase; color: #000 !important; }
|
||||
.text-end { text-align: right !important; }
|
||||
.total-row td { background-color: #eee !important; font-weight: bold; font-size: 12pt; border-top: 2px solid #000 !important; }
|
||||
.print-footer { display: block !important; margin-top: 50px; text-align: center; font-size: 9pt; color: #777; border-top: 1px solid #ddd; padding-top: 10px; }
|
||||
|
||||
/* Arabic Support */
|
||||
[dir="rtl"] body { font-family: 'Traditional Arabic', serif; }
|
||||
[dir="rtl"] th, [dir="rtl"] td { text-align: right; }
|
||||
[dir="rtl"] .text-end { text-align: left !important; }
|
||||
}
|
||||
.print-header, .print-footer { display: none; }
|
||||
</style>
|
||||
|
||||
<div class="row g-0">
|
||||
<div class="col-md-2 bg-white border-end min-vh-100 no-print">
|
||||
<?php render_admin_sidebar('reports_truck_owners'); ?>
|
||||
</div>
|
||||
<div class="col-md-10 p-4">
|
||||
<!-- Screen Only Header -->
|
||||
<div class="page-intro d-flex justify-content-between align-items-center mb-4 no-print">
|
||||
<div>
|
||||
<h1 class="section-title mb-1">Truck Owner Statements</h1>
|
||||
<p class="muted mb-0">View and print financial statements for truck owners.</p>
|
||||
</div>
|
||||
<?php if ($owner): ?>
|
||||
<button onclick="window.print()" class="btn btn-dark">
|
||||
<i class="bi bi-printer me-2"></i>Print Formal Statement
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Filter Form -->
|
||||
<div class="panel p-4 mb-4 no-print filter-form">
|
||||
<form method="get" class="row g-3 align-items-end">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small text-muted">Select Truck Owner</label>
|
||||
<select name="owner_id" class="form-select" onchange="this.form.submit()">
|
||||
<option value="">-- Choose a Truck Owner --</option>
|
||||
<?php foreach ($allOwners as $o): ?>
|
||||
<option value="<?= $o['id'] ?>" <?= $ownerId == $o['id'] ? 'selected' : '' ?>>
|
||||
<?= e($o['full_name']) ?> (Plate: <?= e($o['plate_no'] ?: '-') ?>)
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small text-muted">Start Date</label>
|
||||
<input type="date" name="start_date" class="form-control" value="<?= e($startDate) ?>">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small text-muted">End Date</label>
|
||||
<input type="date" name="end_date" class="form-control" value="<?= e($endDate) ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="submit" class="btn btn-primary w-100">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php if ($ownerId && !$owner): ?>
|
||||
<div class="alert alert-warning">Truck Owner not found.</div>
|
||||
<?php elseif ($owner): ?>
|
||||
<div class="panel p-5 bg-white">
|
||||
<!-- Print Header -->
|
||||
<div class="print-header text-center">
|
||||
<h1>Payment Statement</h1>
|
||||
<h2 style="font-size: 18pt; margin: 0; font-weight: normal;">كشف مدفوعات</h2>
|
||||
<p class="mt-2"><?= e(get_setting('company_name', 'Logistics Platform')) ?></p>
|
||||
<p><?= date('F j, Y') ?></p>
|
||||
</div>
|
||||
|
||||
<!-- Info Section -->
|
||||
<div class="statement-info row mb-4">
|
||||
<div class="col-6">
|
||||
<h5 class="fw-bold text-uppercase text-muted small mb-2">Pay To / إلى السيد</h5>
|
||||
<h4 class="fw-bold mb-1"><?= e($owner['full_name']) ?></h4>
|
||||
<div class="text-muted">Truck Plate: <?= e($owner['plate_no'] ?: '-') ?></div>
|
||||
<div class="small text-muted mt-1">
|
||||
<?= e($owner['truck_type'] ?: '') ?><br>
|
||||
<?= e($owner['city'] ?: '') ?>, <?= e($owner['country'] ?: '') ?><br>
|
||||
<?= e($owner['phone'] ?: '') ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 text-end">
|
||||
<h5 class="fw-bold text-uppercase text-muted small mb-2">Summary / ملخص</h5>
|
||||
<div class="mb-1"><strong>Statement Date:</strong> <?= date('Y-m-d') ?></div>
|
||||
<?php if ($startDate || $endDate): ?>
|
||||
<div class="mb-1"><strong>Period:</strong> <?= e($startDate ?: 'Start') ?> to <?= e($endDate ?: 'Now') ?></div>
|
||||
<?php else: ?>
|
||||
<div class="mb-1"><strong>Period:</strong> All Time</div>
|
||||
<?php endif; ?>
|
||||
<div class="mb-1"><strong>Total Trips:</strong> <?= count($shipments) ?></div>
|
||||
<div class="fs-4 fw-bold text-primary mt-2">
|
||||
<?= number_format($totalEarnings, 2) ?> OMR
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Table -->
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered align-middle">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Date <br> <span class="fw-normal text-muted">التاريخ</span></th>
|
||||
<th>Ref # <br> <span class="fw-normal text-muted">رقم الشحنة</span></th>
|
||||
<th>Route <br> <span class="fw-normal text-muted">المسار</span></th>
|
||||
<th>Status <br> <span class="fw-normal text-muted">الحالة</span></th>
|
||||
<th class="text-end">Earnings (OMR) <br> <span class="fw-normal text-muted">المبلغ</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($shipments)): ?>
|
||||
<tr><td colspan="5" class="text-center py-4 text-muted">No completed shipments found for this period.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($shipments as $row): ?>
|
||||
<tr>
|
||||
<td><?= date('Y-m-d', strtotime($row['created_at'])) ?></td>
|
||||
<td><span class="font-monospace">#<?= $row['id'] ?></span></td>
|
||||
<td>
|
||||
<?= e($row['origin_city']) ?> <i class="bi bi-arrow-right small text-muted mx-1"></i> <?= e($row['destination_city']) ?>
|
||||
<div class="small text-muted"><?= e($row['cargo_description']) ?></div>
|
||||
</td>
|
||||
<td>
|
||||
<?= e(ucfirst(str_replace('_', ' ', $row['status']))) ?>
|
||||
</td>
|
||||
<td class="text-end fw-bold">
|
||||
<?= number_format((float)$row['offer_price'], 2) ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="total-row table-active">
|
||||
<td colspan="4" class="text-end text-uppercase">Total Earnings / الإجمالي</td>
|
||||
<td class="text-end text-dark"><?= number_format($totalEarnings, 2) ?> OMR</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Print Footer -->
|
||||
<div class="print-footer">
|
||||
<div class="row">
|
||||
<div class="col-6 text-start">
|
||||
Authorized Signature<br>
|
||||
_______________________
|
||||
</div>
|
||||
<div class="col-6 text-end">
|
||||
Printed on <?= date('Y-m-d H:i') ?><br>
|
||||
This is a computer-generated document.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php render_footer(); ?>
|
||||
@ -20,6 +20,67 @@
|
||||
--sidebar-border: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
/* Theme: Dark */
|
||||
[data-theme="dark"] {
|
||||
--bg: #0f172a;
|
||||
--surface: #1e293b;
|
||||
--text: #f1f5f9;
|
||||
--muted: #94a3b8;
|
||||
--border: #334155;
|
||||
--primary: #60a5fa;
|
||||
--primary-hover: #3b82f6;
|
||||
--accent: #38bdf8;
|
||||
--shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||||
|
||||
--sidebar-bg: #0f172a;
|
||||
--sidebar-text: #e2e8f0;
|
||||
--sidebar-text-hover: #ffffff;
|
||||
--sidebar-active-bg: #334155;
|
||||
--sidebar-border: #334155;
|
||||
}
|
||||
|
||||
/* Theme: Blue (Corporate) */
|
||||
[data-theme="blue"] {
|
||||
--primary: #2563eb;
|
||||
--primary-hover: #1d4ed8;
|
||||
--sidebar-bg: #1e3a8a;
|
||||
}
|
||||
|
||||
/* Theme: Green (Nature) */
|
||||
[data-theme="green"] {
|
||||
--primary: #10b981;
|
||||
--primary-hover: #059669;
|
||||
--sidebar-bg: #064e3b;
|
||||
}
|
||||
|
||||
/* Theme: Purple (Creative) */
|
||||
[data-theme="purple"] {
|
||||
--primary: #8b5cf6;
|
||||
--primary-hover: #7c3aed;
|
||||
--sidebar-bg: #4c1d95;
|
||||
}
|
||||
|
||||
/* Theme: Red (Bold) */
|
||||
[data-theme="red"] {
|
||||
--primary: #ef4444;
|
||||
--primary-hover: #dc2626;
|
||||
--sidebar-bg: #7f1d1d;
|
||||
}
|
||||
|
||||
/* Theme: Orange (Warm) */
|
||||
[data-theme="orange"] {
|
||||
--primary: #f97316;
|
||||
--primary-hover: #ea580c;
|
||||
--sidebar-bg: #7c2d12;
|
||||
}
|
||||
|
||||
/* Theme: Teal (Calm) */
|
||||
[data-theme="teal"] {
|
||||
--primary: #14b8a6;
|
||||
--primary-hover: #0d9488;
|
||||
--sidebar-bg: #134e4a;
|
||||
}
|
||||
|
||||
body.app-body {
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(59, 130, 246, 0.05), transparent 40%),
|
||||
@ -31,6 +92,66 @@ body.app-body {
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* Dark mode specific adjustments */
|
||||
[data-theme="dark"] body.app-body {
|
||||
background: var(--bg); /* Simplify background for dark mode */
|
||||
}
|
||||
|
||||
[data-theme="dark"] .navbar {
|
||||
background: rgba(30, 41, 59, 0.85) !important;
|
||||
border-bottom: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .navbar-brand {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .navbar-light .navbar-nav .nav-link {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .navbar-light .navbar-nav .nav-link.active,
|
||||
[data-theme="dark"] .navbar-light .navbar-nav .nav-link:hover {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .bg-white {
|
||||
background-color: var(--surface) !important;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .text-dark {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .text-muted {
|
||||
color: var(--muted) !important;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .form-control,
|
||||
[data-theme="dark"] .form-select {
|
||||
background-color: #0f172a;
|
||||
color: var(--text);
|
||||
border-color: var(--border);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .form-control:focus,
|
||||
[data-theme="dark"] .form-select:focus {
|
||||
background-color: #1e293b;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .dropdown-menu {
|
||||
background-color: var(--surface);
|
||||
border-color: var(--border);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .dropdown-item {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .dropdown-item:hover {
|
||||
background-color: var(--border);
|
||||
}
|
||||
|
||||
.navbar {
|
||||
backdrop-filter: blur(10px);
|
||||
background: rgba(255, 255, 255, 0.85) !important;
|
||||
@ -195,10 +316,23 @@ body.app-body {
|
||||
border-bottom: 1px solid #f8fafc;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .table tbody td {
|
||||
border-bottom-color: var(--border);
|
||||
}
|
||||
|
||||
.table tbody tr:hover {
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .table tbody tr:hover {
|
||||
background: #334155;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .table {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.form-select {
|
||||
border-radius: 12px;
|
||||
@ -220,6 +354,10 @@ body.app-body {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .form-label {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--primary);
|
||||
border-color: var(--primary);
|
||||
@ -252,6 +390,16 @@ body.app-body {
|
||||
border-color: #cbd5e1;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .btn-outline-dark {
|
||||
color: var(--text);
|
||||
border-color: var(--border);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .btn-outline-dark:hover {
|
||||
background-color: var(--border);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
@ -370,4 +518,4 @@ body.app-body {
|
||||
overflow-y: visible;
|
||||
background-color: var(--sidebar-bg); /* Keep dark on mobile too */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
db/migrations/update_report_permission_description.php
Normal file
16
db/migrations/update_report_permission_description.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../db/config.php';
|
||||
|
||||
$pdo = db();
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("UPDATE permissions SET description = ? WHERE slug = ?");
|
||||
$stmt->execute([
|
||||
'Access to all reports, including Shipper and Truck Owner statements.',
|
||||
'view_reports'
|
||||
]);
|
||||
|
||||
echo "Updated 'view_reports' permission description.";
|
||||
} catch (PDOException $e) {
|
||||
echo "Error updating permission: " . $e->getMessage();
|
||||
}
|
||||
@ -19,6 +19,12 @@ function render_header(string $title, string $active = '', bool $isFluid = false
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title><?= e($title) ?> | <?= e($appName) ?></title>
|
||||
<script>
|
||||
(function() {
|
||||
const savedTheme = localStorage.getItem('theme') || 'light';
|
||||
document.documentElement.setAttribute('data-theme', savedTheme);
|
||||
})();
|
||||
</script>
|
||||
<?php if ($faviconPath): ?>
|
||||
<link rel="icon" href="<?= e($faviconPath) ?>">
|
||||
<?php endif; ?>
|
||||
@ -70,6 +76,24 @@ function render_header(string $title, string $active = '', bool $isFluid = false
|
||||
</li>
|
||||
</ul>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
|
||||
<!-- Theme Switcher -->
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-sm btn-outline-dark rounded-pill px-3 fw-bold dropdown-toggle" type="button" id="themeDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-palette-fill me-1"></i> Theme
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end shadow-sm border-0 mt-3" aria-labelledby="themeDropdown" style="border-radius: 12px;">
|
||||
<li><button class="dropdown-item py-2" onclick="setTheme('light')"><span class="d-inline-block rounded-circle me-2" style="width:12px;height:12px;background:#f4f7f6;border:1px solid #ccc;"></span>Default</button></li>
|
||||
<li><button class="dropdown-item py-2" onclick="setTheme('dark')"><span class="d-inline-block rounded-circle me-2" style="width:12px;height:12px;background:#0f172a;"></span>Dark</button></li>
|
||||
<li><button class="dropdown-item py-2" onclick="setTheme('blue')"><span class="d-inline-block rounded-circle me-2" style="width:12px;height:12px;background:#2563eb;"></span>Blue</button></li>
|
||||
<li><button class="dropdown-item py-2" onclick="setTheme('green')"><span class="d-inline-block rounded-circle me-2" style="width:12px;height:12px;background:#10b981;"></span>Green</button></li>
|
||||
<li><button class="dropdown-item py-2" onclick="setTheme('purple')"><span class="d-inline-block rounded-circle me-2" style="width:12px;height:12px;background:#8b5cf6;"></span>Purple</button></li>
|
||||
<li><button class="dropdown-item py-2" onclick="setTheme('red')"><span class="d-inline-block rounded-circle me-2" style="width:12px;height:12px;background:#ef4444;"></span>Red</button></li>
|
||||
<li><button class="dropdown-item py-2" onclick="setTheme('orange')"><span class="d-inline-block rounded-circle me-2" style="width:12px;height:12px;background:#f97316;"></span>Orange</button></li>
|
||||
<li><button class="dropdown-item py-2" onclick="setTheme('teal')"><span class="d-inline-block rounded-circle me-2" style="width:12px;height:12px;background:#14b8a6;"></span>Teal</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="dropdown">
|
||||
<?php if (isset($_SESSION['user_id'])): ?>
|
||||
<a class="text-decoration-none text-muted fw-semibold dropdown-toggle" href="#" id="loginDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
@ -208,6 +232,12 @@ function render_footer(bool $showFooter = true): void
|
||||
</footer>
|
||||
<?php endif; ?>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
function setTheme(theme) {
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
localStorage.setItem('theme', theme);
|
||||
}
|
||||
</script>
|
||||
<script src="/assets/js/main.js?v=<?= time() ?>"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -220,6 +250,7 @@ function render_admin_sidebar(string $active = 'dashboard'): void
|
||||
$locationsActive = in_array($active, ['countries', 'cities']);
|
||||
$usersActive = in_array($active, ['shippers', 'truck_owners', 'register', 'platform_users']);
|
||||
$pagesActive = in_array($active, ['faqs', 'landing_pages']);
|
||||
$reportsActive = in_array($active, ['reports_shippers', 'reports_truck_owners']);
|
||||
?>
|
||||
<aside class="admin-sidebar d-flex flex-column h-100 py-4 px-3">
|
||||
<h2 class="h5 fw-bold mb-4 px-2"><i class="bi bi-shield-lock me-2 text-primary"></i><?= e(t('nav_admin')) ?></h2>
|
||||
@ -231,6 +262,21 @@ function render_admin_sidebar(string $active = 'dashboard'): void
|
||||
<i class="bi bi-box2-fill me-2"></i><?= e(t('shipments') ?: 'Shipments') ?>
|
||||
</a>
|
||||
|
||||
<a class="nav-link fw-bold text-muted text-uppercase mt-2 d-flex justify-content-between align-items-center p-2 rounded" style="cursor: pointer; font-size: 0.85rem;" data-bs-toggle="collapse" data-bs-target="#collapseReports" aria-expanded="<?= $reportsActive ? 'true' : 'false' ?>">
|
||||
<span><i class="bi bi-file-earmark-bar-graph-fill me-2"></i><?= e(t('reports') ?: 'Reports') ?></span>
|
||||
<i class="bi bi-chevron-down small"></i>
|
||||
</a>
|
||||
<div class="collapse <?= $reportsActive ? 'show' : '' ?>" id="collapseReports">
|
||||
<div class="nav flex-column gap-1 ms-3 border-start ps-2 border-2">
|
||||
<a class="admin-nav-link <?= $active === 'reports_shippers' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_reports_shippers.php')) ?>">
|
||||
<i class="bi bi-people me-2"></i><?= e(t('shippers_statements') ?: 'Shippers Statements') ?>
|
||||
</a>
|
||||
<a class="admin-nav-link <?= $active === 'reports_truck_owners' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_reports_truck_owners.php')) ?>">
|
||||
<i class="bi bi-truck me-2"></i><?= e(t('truck_owners_statements') ?: 'Truck Owner Statements') ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a class="nav-link fw-bold text-muted text-uppercase mt-2 d-flex justify-content-between align-items-center p-2 rounded" style="cursor: pointer; font-size: 0.85rem;" data-bs-toggle="collapse" data-bs-target="#collapseSettings" aria-expanded="<?= $settingsActive ? 'true' : 'false' ?>">
|
||||
<span><i class="bi bi-gear-fill me-2"></i><?= e(t('settings')) ?></span>
|
||||
<i class="bi bi-chevron-down small"></i>
|
||||
@ -309,4 +355,4 @@ function render_admin_sidebar(string $active = 'dashboard'): void
|
||||
</div>
|
||||
</aside>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user