update timezone

This commit is contained in:
Flatlogic Bot 2026-04-20 03:11:26 +00:00
parent 106c5dab28
commit 2d79f6ac5f
4 changed files with 307 additions and 3 deletions

View File

@ -12,7 +12,7 @@ if (!in_array($user['role'], ['owner', 'manager'])) {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$pdo = db();
$keys = [
'company_name_ar', 'company_name_en', 'vat_percentage',
'timezone', 'company_name_ar', 'company_name_en', 'vat_percentage',
'company_vat_number', 'company_phone', 'company_email', 'company_address',
'smtp_host', 'smtp_port', 'smtp_user', 'smtp_pass', 'smtp_secure', 'mail_from', 'mail_from_name'
];
@ -54,4 +54,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$referer = $_SERVER['HTTP_REFERER'] ?? '../index.php';
header('Location: ' . $referer);
exit;
}
}

View File

@ -7,7 +7,7 @@ if (session_status() !== PHP_SESSION_ACTIVE) {
require_once __DIR__ . '/../db/config.php';
date_default_timezone_set('UTC');
function get_settings(): array
{
@ -33,6 +33,15 @@ function get_setting(string $key, $default = '')
return $settings[$key] ?? $default;
}
$app_tz = get_setting('timezone', 'UTC');
if (empty($app_tz)) {
$app_tz = 'UTC';
}
date_default_timezone_set($app_tz);
try {
db()->exec("SET time_zone = '" . date('P') . "'");
} catch (Throwable $e) {}
function app_name(): string

View File

@ -10,6 +10,17 @@
</div>
<div class="modal-body">
<div class="row g-3">
<div class="col-md-12">
<label class="form-label"><?= h(tr('المنطقة الزمنية (Timezone)', 'Timezone')) ?></label>
<select class="form-select" name="timezone" required>
<?php
$zones = timezone_identifiers_list();
$current_tz = get_setting('timezone', 'UTC');
foreach($zones as $z): ?>
<option value="<?= h($z) ?>" <?= $z === $current_tz ? 'selected' : '' ?>><?= h($z) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label"><?= h(tr('اسم الشركة (عربي)', 'Company Name (AR)')) ?></label>
<input type="text" class="form-control" name="company_name_ar" value="<?= h(get_setting('company_name_ar')) ?>" required>

View File

@ -44,9 +44,14 @@ if ($tab === 'sales') {
}
$stmt->execute();
$followUpOrders = $stmt->fetchAll();
$onlineStmt = db()->query("SELECT * FROM online_orders WHERE status IN ('pending', 'accepted') ORDER BY created_at ASC");
$onlineOrders = $onlineStmt->fetchAll();
} catch(Throwable $e) {
$dbError = $e->getMessage();
$followUpOrders = [];
$onlineOrders = [];
}
} elseif ($tab === 'daily') {
$reportDate = $_GET['date'] ?? date('Y-m-d');
@ -92,6 +97,65 @@ if ($tab === 'sales') {
} catch(Throwable $e) {
$dbError = $e->getMessage();
}
} elseif ($tab === 'expenses') {
$dateFrom = $_GET['date_from'] ?? date('Y-m-01');
$dateTo = $_GET['date_to'] ?? date('Y-m-t');
$branchFilter = $_GET['branch'] ?? '';
$categoryFilter = $_GET['category_id'] ?? '';
$params = [];
$whereConditions = ["DATE(e.expense_date) >= :date_from", "DATE(e.expense_date) <= :date_to"];
$params[':date_from'] = $dateFrom;
$params[':date_to'] = $dateTo;
if ($user['role'] !== 'owner') {
$whereConditions[] = "(e.branch_code = :ubranch OR e.branch_code IS NULL)";
$params[':ubranch'] = $user['branch_code'];
if ($branchFilter && $branchFilter === $user['branch_code']) {
$whereConditions[] = "e.branch_code = :branch";
$params[':branch'] = $branchFilter;
} elseif ($branchFilter && $branchFilter === 'general') {
$whereConditions[] = "e.branch_code IS NULL";
}
} else {
if ($branchFilter) {
if ($branchFilter === 'general') {
$whereConditions[] = "e.branch_code IS NULL";
} else {
$whereConditions[] = "e.branch_code = :branch";
$params[':branch'] = $branchFilter;
}
}
}
if ($categoryFilter) {
$whereConditions[] = "e.category_id = :category_id";
$params[':category_id'] = $categoryFilter;
}
$where = " WHERE " . implode(" AND ", $whereConditions);
$sql = "SELECT e.*, c.name_ar as category_name_ar, c.name_en as category_name_en, u.username as created_by_name
FROM expenses e
LEFT JOIN expense_categories c ON e.category_id = c.id
LEFT JOIN users u ON e.created_by = u.id
" . $where . "
ORDER BY e.expense_date DESC";
try {
$stmt = db()->prepare($sql);
foreach ($params as $k => $v) {
$stmt->bindValue($k, $v);
}
$stmt->execute();
$expensesReport = $stmt->fetchAll();
$catStmt = db()->query("SELECT id, name_ar, name_en FROM expense_categories ORDER BY name_ar");
$expenseCategories = $catStmt->fetchAll();
} catch(Throwable $e) {
$dbError = $e->getMessage();
$expensesReport = [];
$expenseCategories = [];
}
} else {
$report = ['gross' => 0.0, 'branch_totals' => [], 'payment_totals' => [], 'product_totals' => [], 'sales_count' => 0];
try {
@ -123,6 +187,9 @@ require __DIR__ . '/includes/header.php';
<li class="nav-item">
<a class="nav-link <?= $tab === 'orders' ? 'active' : '' ?>" href="reports.php?tab=orders"><?= h(tr('طلبات للمتابعة', 'Follow-up Orders')) ?></a>
</li>
<li class="nav-item">
<a class="nav-link<?= $tab === 'expenses' ? 'active' : '' ?>" href="reports.php?tab=expenses"><?= h(tr('تقرير المصروفات', 'Expenses Report')) ?></a>
</li>
</ul>
<?php if ($dbError): ?>
@ -240,6 +307,176 @@ require __DIR__ . '/includes/header.php';
<?php endif; ?>
</div>
<?php elseif ($tab === 'expenses'): ?>
<style>
@media print {
body { font-size: 13pt !important; background: #fff; }
.table-bordered th, .table-bordered td { border: 1px solid #000 !important; padding: 6px; }
.table th { background-color: #f0f0f0 !important; -webkit-print-color-adjust: exact; color: #000; }
.d-print-none { display: none !important; }
.surface-card { box-shadow: none !important; border: none !important; padding: 0 !important; }
.print-header { display: block !important; margin-bottom: 30px; }
.page-break-inside-avoid { page-break-inside: avoid; }
}
.print-header { display: none; }
</style>
<!-- Filters (Hidden on Print) -->
<div class="card mb-4 d-print-none">
<div class="card-body">
<form method="GET" action="reports.php" class="row g-3 align-items-end">
<input type="hidden" name="tab" value="expenses">
<div class="col-md-3">
<label class="form-label"><?= h(tr('من تاريخ', 'From Date')) ?></label>
<input type="date" name="date_from" class="form-control" value="<?= h($dateFrom) ?>">
</div>
<div class="col-md-3">
<label class="form-label"><?= h(tr('إلى تاريخ', 'To Date')) ?></label>
<input type="date" name="date_to" class="form-control" value="<?= h($dateTo) ?>">
</div>
<div class="col-md-2">
<label class="form-label"><?= h(tr('التصنيف', 'Category')) ?></label>
<select name="category_id" class="form-select">
<option value=""><?= h(tr('الكل', 'All')) ?></option>
<?php foreach($expenseCategories as $cat):
if ($cat['id'] == $categoryFilter) {
$catName = $cat['name_ar'] . ' / ' . $cat['name_en'];
break;
}
?>
<option value="<?= $cat['id'] ?>" <?= $categoryFilter == $cat['id'] ? 'selected' : '' ?> >
<?= h($cat['name_ar'] . ' / ' . $cat['name_en']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2">
<label class="form-label"><?= h(tr('الفرع', 'Branch')) ?></label>
<select name="branch" class="form-select">
<option value=""><?= h(tr('جميع الفروع', 'All Branches')) ?></option>
<option value="general" <?= $branchFilter === 'general' ? 'selected' : '' ?>><?= h(tr('مصروفات عامة', 'General Expenses')) ?></option>
<?php
$availableBranches = $user['role'] === 'owner' ? branches() : [$user['branch_code'] => branches()[$user['branch_code']]];
foreach ($availableBranches as $code => $b):
?>
<option value="<?= h($code) ?>" <?= $branchFilter === $code ? 'selected' : '' ?>><?= h(branch_label($code)) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100"><?= h(tr('بحث', 'Search')) ?></button>
</div>
</form>
</div>
</div>
<!-- Formal Print Header -->
<div class="print-header">
<div class="text-center mb-4" style="border-bottom: 2px solid #000; padding-bottom: 15px;">
<h2 style="font-weight: bold; margin:0;"><?= h(tr('تقرير المصروفات التفصيلي', 'Detailed Expenses Report')) ?></h2>
<p style="margin: 5px 0 0; color: #555;"><?= h(tr('تاريخ الإصدار:', 'Generated on:')) ?> <?= date('Y-m-d H:i') ?></p>
</div>
<div class="row mb-4" style="border: 1px solid #000; padding: 15px; margin: 0;">
<div class="col-8">
<div style="margin-bottom: 5px;"><strong><?= h(tr('الفترة:', 'Period:')) ?></strong> <?= h($dateFrom) ?> <?= h(tr('إلى', 'to')) ?> <?= h($dateTo) ?></div>
<?php if ($categoryFilter):
$catName = '';
foreach ($expenseCategories as $c) {
if ($c['id'] == $categoryFilter) {
$catName = $c['name_ar'] . ' / ' . $c['name_en'];
break;
}
}
?>
<div style="margin-bottom: 5px;"><strong><?= h(tr('التصنيف:', 'Category:')) ?></strong> <?= h($catName) ?></div>
<?php endif; ?>
<div><strong><?= h(tr('الفرع:', 'Branch:')) ?></strong> <?= h($branchFilter ? ($branchFilter === 'general' ? tr('مصروفات عامة', 'General Expenses') : branch_label($branchFilter)) : tr('جميع الفروع', 'All Branches')) ?></div>
</div>
<div class="col-4 text-end">
<div><strong><?= h(tr('بواسطة:', 'Requested By:')) ?></strong> <?= h($user['username']) ?></div>
</div>
</div>
</div>
<!-- Results Table -->
<div class="surface-card">
<div class="d-flex justify-content-between align-items-center mb-3 d-print-none">
<h3 class="h5 mb-0"><?= h(tr('نتائج التقرير', 'Report Results')) ?></h3>
<button class="btn btn-outline-secondary btn-sm" onclick="window.print()"><i class="bi bi-printer"></i> <?= h(tr('طباعة رسمية', 'Formal Print')) ?></button>
</div>
<?php if(empty($expensesReport)): ?>
<p class="text-muted d-print-none"><?= h(tr('لا توجد مصروفات في هذه الفترة.', 'No expenses found in this period.')) ?></p>
<div class="print-header text-center py-5">
<h4><?= h(tr('لا توجد بيانات لهذه الفترة', 'No data for this period')) ?></h4>
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-bordered table-striped align-middle" style="width: 100%;">
<thead>
<tr>
<th><?= h(tr('التاريخ', 'Date')) ?></th>
<th><?= h(tr('الفرع', 'Branch')) ?></th>
<th><?= h(tr('التصنيف', 'Category')) ?></th>
<th><?= h(tr('الوصف', 'Description')) ?></th>
<th><?= h(tr('المسجل', 'Logged By')) ?></th>
<th class="text-end"><?= h(tr('المبلغ', 'Amount')) ?></th>
</tr>
</thead>
<tbody>
<?php
$totalSum = 0;
foreach($expensesReport as $exp):
$totalSum += (float) $exp['amount'];
?>
<tr>
<td><?= h(date('Y-m-d', strtotime((string)$exp['expense_date']))) ?></td>
<td>
<?php if (empty($exp['branch_code'])): ?>
<?= h(tr('عام', 'General')) ?>
<?php else:
echo h(branch_label((string)$exp['branch_code']));
endif; ?>
</td>
<td><?= h($exp['category_name_ar'] . ' / ' . $exp['category_name_en']) ?></td>
<td><?= h((string)$exp['description']) ?></td>
<td><?= h((string)$exp['created_by_name']) ?></td>
<td class="text-end fw-bold"><?= h(currency((float)$exp['amount'])) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot class="table-dark">
<tr>
<td colspan="5" class="text-end"><strong><?= h(tr('الإجمالي الكلي', 'Grand Total')) ?></strong></td>
<td class="text-end fw-bold fs-5"><strong><?= h(currency($totalSum)) ?></strong></td>
</tr>
</tfoot>
</table>
</div>
<!-- Signatures (Print Only) -->
<div class="print-header mt-5 pt-5 page-break-inside-avoid">
<div class="row text-center mt-5">
<div class="col-4">
<p><strong><?= h(tr('المحاسب / المُعد', 'Prepared by / Accountant')) ?></strong></p>
<hr style="width: 60%; margin: 40px auto 0; border-top: 1px solid #000;">
</div>
<div class="col-4">
<p><strong><?= h(tr('المراجع', 'Checked by')) ?></strong></p>
<hr style="width: 60%; margin: 40px auto 0; border-top: 1px solid #000;">
</div>
<div class="col-4">
<p><strong><?= h(tr('المدير العام', 'General Manager')) ?></strong></p>
<hr style="width: 60%; margin: 40px auto 0; border-top: 1px solid #000;">
</div>
</div>
</div>
<?php endif; ?>
</div>
<?php elseif ($tab === 'orders'): ?>
<div class="card mb-4 d-print-none">
@ -321,6 +558,53 @@ require __DIR__ . '/includes/header.php';
<?php endif; ?>
</div>
<!-- Online Orders Section -->
<div class="surface-card mt-4 mb-4">
<div class="d-flex justify-content-between align-items-center mb-3 d-print-none">
<h3 class="h5 mb-0"><i class="bi bi-globe me-2 text-primary"></i><?= h(tr('طلبات المتجر الإلكتروني (نشطة)', 'Active Online Store Orders')) ?></h3>
<a class="btn btn-outline-primary btn-sm" href="online_orders.php"><i class="bi bi-box-arrow-up-right"></i> <?= h(tr('إدارة الطلبات', 'Manage Orders')) ?></a>
</div>
<?php if(empty($onlineOrders)): ?>
<p class="text-muted"><?= h(tr('لا توجد طلبات متجر نشطة حالياً.', 'No active online orders currently.')) ?></p>
<?php else: ?>
<div class="table-responsive">
<table class="table table-bordered table-hover align-middle">
<thead class="table-light">
<tr>
<th><?= h(tr('التاريخ', 'Date')) ?></th>
<th><?= h(tr('رقم الطلب', 'Order ID')) ?></th>
<th><?= h(tr('العميل', 'Customer')) ?></th>
<th><?= h(tr('هاتف العميل', 'Customer Phone')) ?></th>
<th><?= h(tr('العنوان', 'Address')) ?></th>
<th><?= h(tr('الحالة', 'Status')) ?></th>
<th class="text-end"><?= h(tr('الإجمالي', 'Total')) ?></th>
</tr>
</thead>
<tbody>
<?php foreach($onlineOrders as $order): ?>
<tr>
<td><?= h(date('Y-m-d H:i', strtotime((string)$order['created_at']))) ?></td>
<td>#<?= h((string)$order['id']) ?></td>
<td><?= h((string)($order['customer_name'] ?: '-')) ?></td>
<td><?= h((string)($order['customer_phone'] ?: '-')) ?></td>
<td><?= h((string)($order['customer_address'] ?: '-')) ?></td>
<td>
<?php if ($order['status'] === 'pending'): ?>
<span class="badge bg-warning text-dark"><?= h(tr('قيد الانتظار', 'Pending')) ?></span>
<?php elseif ($order['status'] === 'accepted'): ?>
<span class="badge bg-info text-dark"><?= h(tr('مقبول', 'Accepted')) ?></span>
<?php endif; ?>
</td>
<td class="text-end fw-bold text-primary"><?= h(currency((float)$order['total_amount'])) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
<?php elseif ($tab === 'daily'): ?>
<div class="card mb-4 d-print-none">