add expired items
This commit is contained in:
parent
01b6fa4c64
commit
ea63a5146b
@ -235,6 +235,10 @@ body {
|
|||||||
border-bottom: 2px solid var(--border);
|
border-bottom: 2px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.op-50 {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
/* RTL Adjustments */
|
/* RTL Adjustments */
|
||||||
[dir="rtl"] .ms-auto {
|
[dir="rtl"] .ms-auto {
|
||||||
margin-right: auto !important;
|
margin-right: auto !important;
|
||||||
|
|||||||
@ -20,7 +20,30 @@ function setLanguage(lang) {
|
|||||||
|
|
||||||
// Update UI text
|
// Update UI text
|
||||||
document.querySelectorAll('[data-en]').forEach(el => {
|
document.querySelectorAll('[data-en]').forEach(el => {
|
||||||
el.textContent = el.getAttribute(`data-${lang}`);
|
const text = el.getAttribute(`data-${lang}`);
|
||||||
|
if (text) {
|
||||||
|
// If it's a simple element with only text, update it
|
||||||
|
// If it has children, we should only update the text node parts
|
||||||
|
// But for simplicity in this app, we'll check if it has any children
|
||||||
|
if (el.children.length === 0) {
|
||||||
|
el.textContent = text;
|
||||||
|
} else {
|
||||||
|
// If it has children (like icons), we try to find a text node to update
|
||||||
|
// or just update the first text node child
|
||||||
|
let found = false;
|
||||||
|
for (let node of el.childNodes) {
|
||||||
|
if (node.nodeType === 3) { // Text node
|
||||||
|
node.textContent = text;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
// Fallback: append text if no text node exists
|
||||||
|
el.appendChild(document.createTextNode(text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update buttons/inputs
|
// Update buttons/inputs
|
||||||
|
|||||||
23
db/migrations/20260217_sales_returns.sql
Normal file
23
db/migrations/20260217_sales_returns.sql
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
-- Migration: Add Sales Returns tables
|
||||||
|
CREATE TABLE IF NOT EXISTS sales_returns (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
invoice_id INT NOT NULL,
|
||||||
|
customer_id INT NULL,
|
||||||
|
return_date DATE NOT NULL,
|
||||||
|
total_amount DECIMAL(15, 3) NOT NULL DEFAULT 0,
|
||||||
|
notes TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (invoice_id) REFERENCES invoices(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS sales_return_items (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
return_id INT NOT NULL,
|
||||||
|
item_id INT NOT NULL,
|
||||||
|
quantity DECIMAL(15, 2) NOT NULL,
|
||||||
|
unit_price DECIMAL(15, 3) NOT NULL,
|
||||||
|
total_price DECIMAL(15, 3) NOT NULL,
|
||||||
|
FOREIGN KEY (return_id) REFERENCES sales_returns(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (item_id) REFERENCES stock_items(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
725
index.php
725
index.php
@ -104,6 +104,17 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action'])) {
|
|||||||
echo json_encode(['success' => true, 'points' => (float)$points]);
|
echo json_encode(['success' => true, 'points' => (float)$points]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
if ($_GET['action'] === 'get_invoice_items') {
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
$invoice_id = (int)$_GET['invoice_id'];
|
||||||
|
$stmt = db()->prepare("SELECT ii.*, i.name_en, i.name_ar, i.sku
|
||||||
|
FROM invoice_items ii
|
||||||
|
JOIN stock_items i ON ii.item_id = i.id
|
||||||
|
WHERE ii.invoice_id = ?");
|
||||||
|
$stmt->execute([$invoice_id]);
|
||||||
|
echo json_encode($stmt->fetchAll());
|
||||||
|
exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
@ -1046,6 +1057,72 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($_POST['add_sales_return'])) {
|
||||||
|
$invoice_id = (int)$_POST['invoice_id'];
|
||||||
|
$return_date = $_POST['return_date'] ?: date('Y-m-d');
|
||||||
|
$notes = $_POST['notes'] ?? '';
|
||||||
|
$item_ids = $_POST['item_ids'] ?? [];
|
||||||
|
$quantities = $_POST['quantities'] ?? [];
|
||||||
|
$prices = $_POST['prices'] ?? [];
|
||||||
|
|
||||||
|
if ($invoice_id && !empty($item_ids)) {
|
||||||
|
$db = db();
|
||||||
|
$db->beginTransaction();
|
||||||
|
try {
|
||||||
|
// Get customer ID from invoice
|
||||||
|
$stmt = $db->prepare("SELECT customer_id FROM invoices WHERE id = ?");
|
||||||
|
$stmt->execute([$invoice_id]);
|
||||||
|
$customer_id = $stmt->fetchColumn();
|
||||||
|
|
||||||
|
$total_return_amount = 0;
|
||||||
|
$items_data = [];
|
||||||
|
foreach ($item_ids as $index => $item_id) {
|
||||||
|
$qty = (float)$quantities[$index];
|
||||||
|
$price = (float)$prices[$index];
|
||||||
|
if ($qty <= 0) continue;
|
||||||
|
|
||||||
|
$line_total = $qty * $price;
|
||||||
|
$total_return_amount += $line_total;
|
||||||
|
|
||||||
|
$items_data[] = [
|
||||||
|
'id' => $item_id,
|
||||||
|
'qty' => $qty,
|
||||||
|
'price' => $price,
|
||||||
|
'total' => $line_total
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($items_data)) throw new Exception("No items to return");
|
||||||
|
|
||||||
|
// Create Sales Return record
|
||||||
|
$stmt = $db->prepare("INSERT INTO sales_returns (invoice_id, customer_id, return_date, total_amount, notes) VALUES (?, ?, ?, ?, ?)");
|
||||||
|
$stmt->execute([$invoice_id, $customer_id, $return_date, $total_return_amount, $notes]);
|
||||||
|
$return_id = $db->lastInsertId();
|
||||||
|
|
||||||
|
foreach ($items_data as $item) {
|
||||||
|
$stmt = $db->prepare("INSERT INTO sales_return_items (return_id, item_id, quantity, unit_price, total_price) VALUES (?, ?, ?, ?, ?)");
|
||||||
|
$stmt->execute([$return_id, $item['id'], $item['qty'], $item['price'], $item['total']]);
|
||||||
|
|
||||||
|
// Restore stock
|
||||||
|
$stmt = $db->prepare("UPDATE stock_items SET stock_quantity = stock_quantity + ? WHERE id = ?");
|
||||||
|
$stmt->execute([$item['qty'], $item['id']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it was a credit sale, we might want to reduce the customer balance.
|
||||||
|
if ($customer_id) {
|
||||||
|
$stmt = $db->prepare("UPDATE customers SET balance = balance + ? WHERE id = ?");
|
||||||
|
$stmt->execute([$total_return_amount, $customer_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->commit();
|
||||||
|
$message = "Sales Return #$return_id processed successfully!";
|
||||||
|
} catch (Exception $e) {
|
||||||
|
if (isset($db)) $db->rollBack();
|
||||||
|
$message = "Error: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1252,6 +1329,27 @@ switch ($page) {
|
|||||||
$data['customers_list'] = db()->query("SELECT id, name FROM customers WHERE type = '" . ($type === 'sale' ? 'customer' : 'supplier') . "' ORDER BY name ASC")->fetchAll();
|
$data['customers_list'] = db()->query("SELECT id, name FROM customers WHERE type = '" . ($type === 'sale' ? 'customer' : 'supplier') . "' ORDER BY name ASC")->fetchAll();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'sales_returns':
|
||||||
|
$where = ["1=1"];
|
||||||
|
$params = [];
|
||||||
|
if (!empty($_GET['search'])) {
|
||||||
|
$where[] = "(sr.id LIKE ? OR c.name LIKE ? OR sr.invoice_id LIKE ?)";
|
||||||
|
$params[] = "%{$_GET['search']}%";
|
||||||
|
$params[] = "%{$_GET['search']}%";
|
||||||
|
$params[] = "%{$_GET['search']}%";
|
||||||
|
}
|
||||||
|
$whereSql = implode(" AND ", $where);
|
||||||
|
$stmt = db()->prepare("SELECT sr.*, c.name as customer_name, i.total_with_vat as invoice_total
|
||||||
|
FROM sales_returns sr
|
||||||
|
LEFT JOIN customers c ON sr.customer_id = c.id
|
||||||
|
LEFT JOIN invoices i ON sr.invoice_id = i.id
|
||||||
|
WHERE $whereSql
|
||||||
|
ORDER BY sr.id DESC");
|
||||||
|
$stmt->execute($params);
|
||||||
|
$data['returns'] = $stmt->fetchAll();
|
||||||
|
$data['sales_invoices'] = db()->query("SELECT id, invoice_date, total_with_vat FROM invoices WHERE type = 'sale' ORDER BY id DESC")->fetchAll();
|
||||||
|
break;
|
||||||
|
|
||||||
case 'customer_statement':
|
case 'customer_statement':
|
||||||
case 'supplier_statement':
|
case 'supplier_statement':
|
||||||
$type = ($page === 'customer_statement') ? 'customer' : 'supplier';
|
$type = ($page === 'customer_statement') ? 'customer' : 'supplier';
|
||||||
@ -1335,6 +1433,25 @@ switch ($page) {
|
|||||||
$stmt->execute([$start_date, $end_date]);
|
$stmt->execute([$start_date, $end_date]);
|
||||||
$data['total_expenses'] = $stmt->fetchColumn() ?: 0;
|
$data['total_expenses'] = $stmt->fetchColumn() ?: 0;
|
||||||
break;
|
break;
|
||||||
|
case 'expiry_report':
|
||||||
|
$where = ["expiry_date IS NOT NULL"];
|
||||||
|
$params = [];
|
||||||
|
$filter = $_GET['filter'] ?? 'all';
|
||||||
|
if ($filter === 'expired') {
|
||||||
|
$where[] = "expiry_date <= CURDATE()";
|
||||||
|
} elseif ($filter === 'near_expiry') {
|
||||||
|
$where[] = "expiry_date > CURDATE() AND expiry_date <= DATE_ADD(CURDATE(), INTERVAL 30 DAY)";
|
||||||
|
}
|
||||||
|
|
||||||
|
$whereSql = implode(" AND ", $where);
|
||||||
|
$stmt = db()->prepare("SELECT i.*, c.name_en as cat_en, c.name_ar as cat_ar
|
||||||
|
FROM stock_items i
|
||||||
|
LEFT JOIN stock_categories c ON i.category_id = c.id
|
||||||
|
WHERE $whereSql
|
||||||
|
ORDER BY i.expiry_date ASC");
|
||||||
|
$stmt->execute($params);
|
||||||
|
$data['expiry_items'] = $stmt->fetchAll();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
$data['customers'] = db()->query("SELECT * FROM customers WHERE type = 'customer' ORDER BY id DESC LIMIT 5")->fetchAll();
|
$data['customers'] = db()->query("SELECT * FROM customers WHERE type = 'customer' ORDER BY id DESC LIMIT 5")->fetchAll();
|
||||||
// Dashboard stats
|
// Dashboard stats
|
||||||
@ -1345,9 +1462,15 @@ switch ($page) {
|
|||||||
'total_received' => db()->query("SELECT SUM(amount) FROM payments p JOIN invoices i ON p.invoice_id = i.id WHERE i.type = 'sale'")->fetchColumn() ?: 0,
|
'total_received' => db()->query("SELECT SUM(amount) FROM payments p JOIN invoices i ON p.invoice_id = i.id WHERE i.type = 'sale'")->fetchColumn() ?: 0,
|
||||||
'total_purchases' => db()->query("SELECT SUM(total_with_vat) FROM invoices WHERE type = 'purchase'")->fetchColumn() ?: 0,
|
'total_purchases' => db()->query("SELECT SUM(total_with_vat) FROM invoices WHERE type = 'purchase'")->fetchColumn() ?: 0,
|
||||||
'total_paid' => db()->query("SELECT SUM(amount) FROM payments p JOIN invoices i ON p.invoice_id = i.id WHERE i.type = 'purchase'")->fetchColumn() ?: 0,
|
'total_paid' => db()->query("SELECT SUM(amount) FROM payments p JOIN invoices i ON p.invoice_id = i.id WHERE i.type = 'purchase'")->fetchColumn() ?: 0,
|
||||||
|
'expired_items' => db()->query("SELECT COUNT(*) FROM stock_items WHERE expiry_date IS NOT NULL AND expiry_date <= CURDATE()")->fetchColumn(),
|
||||||
|
'near_expiry_items' => db()->query("SELECT COUNT(*) FROM stock_items WHERE expiry_date IS NOT NULL AND expiry_date > CURDATE() AND expiry_date <= DATE_ADD(CURDATE(), INTERVAL 30 DAY)")->fetchColumn(),
|
||||||
];
|
];
|
||||||
$data['stats']['total_receivable'] = $data['stats']['total_sales'] - $data['stats']['total_received'];
|
$data['stats']['total_receivable'] = $data['stats']['total_sales'] - $data['stats']['total_received'];
|
||||||
$data['stats']['total_payable'] = $data['stats']['total_purchases'] - $data['stats']['total_paid'];
|
$data['stats']['total_payable'] = $data['stats']['total_purchases'] - $data['stats']['total_paid'];
|
||||||
|
|
||||||
|
// Sales Chart Data
|
||||||
|
$data['monthly_sales'] = db()->query("SELECT DATE_FORMAT(invoice_date, '%M %Y') as label, SUM(total_with_vat) as total FROM invoices WHERE type = 'sale' GROUP BY DATE_FORMAT(invoice_date, '%Y-%m') ORDER BY invoice_date ASC LIMIT 12")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
$data['yearly_sales'] = db()->query("SELECT YEAR(invoice_date) as label, SUM(total_with_vat) as total FROM invoices WHERE type = 'sale' GROUP BY label ORDER BY label ASC LIMIT 5")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1368,9 +1491,11 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.5/dist/JsBarcode.all.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.5/dist/JsBarcode.all.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||||
<style>
|
<style>
|
||||||
@ -1402,6 +1527,9 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
<a href="index.php?page=sales" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'sales' ? 'active' : '' ?>">
|
<a href="index.php?page=sales" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'sales' ? 'active' : '' ?>">
|
||||||
<i class="bi bi-cart"></i> <span data-en="Sales Tax Invoices" data-ar="فواتير المبيعات الضريبية">Sales Tax Invoices</span>
|
<i class="bi bi-cart"></i> <span data-en="Sales Tax Invoices" data-ar="فواتير المبيعات الضريبية">Sales Tax Invoices</span>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="index.php?page=sales_returns" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'sales_returns' ? 'active' : '' ?>">
|
||||||
|
<i class="bi bi-arrow-return-left"></i> <span data-en="Sales Returns" data-ar="مرتجع المبيعات">Sales Returns</span>
|
||||||
|
</a>
|
||||||
<a href="index.php?page=purchases" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'purchases' ? 'active' : '' ?>">
|
<a href="index.php?page=purchases" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'purchases' ? 'active' : '' ?>">
|
||||||
<i class="bi bi-bag"></i> <span data-en="Purchase Tax Invoices" data-ar="فواتير المشتريات الضريبية">Purchase Tax Invoices</span>
|
<i class="bi bi-bag"></i> <span data-en="Purchase Tax Invoices" data-ar="فواتير المشتريات الضريبية">Purchase Tax Invoices</span>
|
||||||
</a>
|
</a>
|
||||||
@ -1470,6 +1598,9 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
<a href="index.php?page=supplier_statement" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'supplier_statement' ? 'active' : '' ?>">
|
<a href="index.php?page=supplier_statement" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'supplier_statement' ? 'active' : '' ?>">
|
||||||
<i class="bi bi-file-earmark-medical"></i> <span data-en="Supplier Statement" data-ar="كشف حساب مورد">Supplier Statement</span>
|
<i class="bi bi-file-earmark-medical"></i> <span data-en="Supplier Statement" data-ar="كشف حساب مورد">Supplier Statement</span>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="index.php?page=expiry_report" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'expiry_report' ? 'active' : '' ?>">
|
||||||
|
<i class="bi bi-calendar-x"></i> <span data-en="Expiry Report" data-ar="تقرير الانتهاء">Expiry Report</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Configuration Section -->
|
<!-- Configuration Section -->
|
||||||
@ -1507,8 +1638,10 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
'payment_methods' => ['en' => 'Payment Methods', 'ar' => 'طرق الدفع'],
|
'payment_methods' => ['en' => 'Payment Methods', 'ar' => 'طرق الدفع'],
|
||||||
'sales' => ['en' => 'Sales Tax Invoices', 'ar' => 'فواتير المبيعات الضريبية'],
|
'sales' => ['en' => 'Sales Tax Invoices', 'ar' => 'فواتير المبيعات الضريبية'],
|
||||||
'purchases' => ['en' => 'Purchase Tax Invoices', 'ar' => 'فواتير المشتريات الضريبية'],
|
'purchases' => ['en' => 'Purchase Tax Invoices', 'ar' => 'فواتير المشتريات الضريبية'],
|
||||||
|
'sales_returns' => ['en' => 'Sales Returns', 'ar' => 'مرتجع المبيعات'],
|
||||||
'customer_statement' => ['en' => 'Customer Statement', 'ar' => 'كشف حساب عميل'],
|
'customer_statement' => ['en' => 'Customer Statement', 'ar' => 'كشف حساب عميل'],
|
||||||
'supplier_statement' => ['en' => 'Supplier Statement', 'ar' => 'كشف حساب مورد'],
|
'supplier_statement' => ['en' => 'Supplier Statement', 'ar' => 'كشف حساب مورد'],
|
||||||
|
'expiry_report' => ['en' => 'Expiry Report', 'ar' => 'تقرير انتهاء الصلاحية'],
|
||||||
'settings' => ['en' => 'Company Profile', 'ar' => 'ملف الشركة'],
|
'settings' => ['en' => 'Company Profile', 'ar' => 'ملف الشركة'],
|
||||||
];
|
];
|
||||||
$currTitle = $titles[$page] ?? $titles['dashboard'];
|
$currTitle = $titles[$page] ?? $titles['dashboard'];
|
||||||
@ -1557,59 +1690,150 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if ($page === 'dashboard'): ?>
|
<?php if ($page === 'dashboard'): ?>
|
||||||
|
|
||||||
|
<?php if ($data['stats']['expired_items'] > 0 || $data['stats']['near_expiry_items'] > 0): ?>
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="alert alert-warning border-0 shadow-sm d-flex align-items-center mb-0">
|
||||||
|
<i class="bi bi-exclamation-triangle-fill h4 mb-0 me-3 text-warning"></i>
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<span data-en="Inventory Alert:" data-ar="تنبيه المخزون:"><strong>Inventory Alert:</strong></span>
|
||||||
|
<?php if ($data['stats']['expired_items'] > 0): ?>
|
||||||
|
<span data-en="<?= $data['stats']['expired_items'] ?> items have expired." data-ar="هنالك <?= $data['stats']['expired_items'] ?> صنف منتهي الصلاحية."><?= $data['stats']['expired_items'] ?> items have expired.</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($data['stats']['near_expiry_items'] > 0): ?>
|
||||||
|
<span data-en="<?= $data['stats']['near_expiry_items'] ?> items are expiring soon (within 30 days)." data-ar="هنالك <?= $data['stats']['near_expiry_items'] ?> صنف ستنتهي صلاحيتها قريباً (خلال 30 يوم)."><?= $data['stats']['near_expiry_items'] ?> items are expiring soon (within 30 days).</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<a href="index.php?page=expiry_report" class="btn btn-warning btn-sm" data-en="View Report" data-ar="عرض التقرير">View Report</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="row g-4 mb-4">
|
<div class="row g-4 mb-4">
|
||||||
<div class="col">
|
<div class="col-md-3">
|
||||||
<div class="card p-3 border-start border-primary border-4 h-100">
|
<div class="card p-3 border-start border-primary border-4 h-100">
|
||||||
<div class="text-muted small" data-en="Total Sales" data-ar="إجمالي المبيعات">Total Sales</div>
|
<div class="d-flex align-items-center">
|
||||||
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_sales'] ?? 0), 3) ?></div>
|
<div class="flex-grow-1">
|
||||||
|
<div class="text-muted small" data-en="Total Sales" data-ar="إجمالي المبيعات">Total Sales</div>
|
||||||
|
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_sales'] ?? 0), 3) ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-3">
|
||||||
|
<i class="bi bi-cart h2 text-primary op-50"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col-md-3">
|
||||||
<div class="card p-3 border-start border-warning border-4 h-100">
|
<div class="card p-3 border-start border-warning border-4 h-100">
|
||||||
<div class="text-muted small" data-en="Total Received" data-ar="إجمالي المبالغ المحصلة">Total Received</div>
|
<div class="d-flex align-items-center">
|
||||||
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_received'] ?? 0), 3) ?></div>
|
<div class="flex-grow-1">
|
||||||
|
<div class="text-muted small" data-en="Total Received" data-ar="إجمالي المبالغ المحصلة">Total Received</div>
|
||||||
|
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_received'] ?? 0), 3) ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-3">
|
||||||
|
<i class="bi bi-cash-stack h2 text-warning op-50"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col-md-3">
|
||||||
<div class="card p-3 border-start border-danger border-4 h-100">
|
<div class="card p-3 border-start border-danger border-4 h-100">
|
||||||
<div class="text-muted small" data-en="Total Receivable" data-ar="إجمالي المبالغ المتبقية">Total Receivable</div>
|
<div class="d-flex align-items-center">
|
||||||
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_receivable'] ?? 0), 3) ?></div>
|
<div class="flex-grow-1">
|
||||||
|
<div class="text-muted small" data-en="Customer Due" data-ar="مستحقات العملاء">Customer Due</div>
|
||||||
|
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_receivable'] ?? 0), 3) ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-3">
|
||||||
|
<i class="bi bi-person-exclamation h2 text-danger op-50"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="col-md-3">
|
||||||
|
|
||||||
<div class="row g-4 mb-4">
|
|
||||||
<div class="col">
|
|
||||||
<div class="card p-3 border-start border-dark border-4 h-100 bg-light">
|
<div class="card p-3 border-start border-dark border-4 h-100 bg-light">
|
||||||
<div class="text-muted small" data-en="Total Purchases" data-ar="إجمالي المشتريات">Total Purchases</div>
|
<div class="d-flex align-items-center">
|
||||||
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_purchases'] ?? 0), 3) ?></div>
|
<div class="flex-grow-1">
|
||||||
</div>
|
<div class="text-muted small" data-en="Total Purchases" data-ar="إجمالي المشتريات">Total Purchases</div>
|
||||||
</div>
|
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_purchases'] ?? 0), 3) ?></div>
|
||||||
<div class="col">
|
</div>
|
||||||
<div class="card p-3 border-start border-info border-4 h-100 bg-light">
|
<div class="ms-3">
|
||||||
<div class="text-muted small" data-en="Total Paid to Suppliers" data-ar="إجمالي المدفوع للموردين">Total Paid to Suppliers</div>
|
<i class="bi bi-bag h2 text-dark op-50"></i>
|
||||||
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_paid'] ?? 0), 3) ?></div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<div class="card p-3 border-start border-secondary border-4 h-100 bg-light">
|
|
||||||
<div class="text-muted small" data-en="Total Payable" data-ar="إجمالي الذمم الدائنة">Total Payable</div>
|
|
||||||
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_payable'] ?? 0), 3) ?></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row g-4 mb-4">
|
<div class="row g-4 mb-4">
|
||||||
<div class="col">
|
<div class="col-md-3">
|
||||||
<div class="card p-3 border-start border-success border-4 h-100">
|
<div class="card p-3 border-start border-info border-4 h-100 bg-light">
|
||||||
<div class="text-muted small" data-en="Total Customers" data-ar="إجمالي العملاء">Total Customers</div>
|
<div class="d-flex align-items-center">
|
||||||
<div class="h4 m-0"><?= (int)($data['stats']['total_customers'] ?? 0) ?></div>
|
<div class="flex-grow-1">
|
||||||
|
<div class="text-muted small" data-en="Total Paid" data-ar="إجمالي المدفوع">Total Paid</div>
|
||||||
|
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_paid'] ?? 0), 3) ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-3">
|
||||||
|
<i class="bi bi-wallet2 h2 text-info op-50"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col-md-3">
|
||||||
|
<div class="card p-3 border-start border-secondary border-4 h-100 bg-light">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<div class="text-muted small" data-en="Supplier Due" data-ar="مستحقات الموردين">Supplier Due</div>
|
||||||
|
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_payable'] ?? 0), 3) ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-3">
|
||||||
|
<i class="bi bi-truck h2 text-secondary op-50"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card p-3 border-start border-success border-4 h-100">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<div class="text-muted small" data-en="Total Customers" data-ar="إجمالي العملاء">Total Customers</div>
|
||||||
|
<div class="h4 m-0"><?= (int)($data['stats']['total_customers'] ?? 0) ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-3">
|
||||||
|
<i class="bi bi-people h2 text-success op-50"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
<div class="card p-3 border-start border-info border-4 h-100">
|
<div class="card p-3 border-start border-info border-4 h-100">
|
||||||
<div class="text-muted small" data-en="Total Items" data-ar="إجمالي الأصناف">Total Items</div>
|
<div class="d-flex align-items-center">
|
||||||
<div class="h4 m-0"><?= (int)($data['stats']['total_items'] ?? 0) ?></div>
|
<div class="flex-grow-1">
|
||||||
|
<div class="text-muted small" data-en="Total Items" data-ar="إجمالي الأصناف">Total Items</div>
|
||||||
|
<div class="h4 m-0"><?= (int)($data['stats']['total_items'] ?? 0) ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-3">
|
||||||
|
<i class="bi bi-box-seam h2 text-info op-50"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-4 mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="card p-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h5 class="m-0" data-en="Sales Performance" data-ar="أداء المبيعات">Sales Performance</h5>
|
||||||
|
<div class="btn-group btn-group-sm">
|
||||||
|
<button type="button" class="btn btn-outline-primary active" id="btnMonthly" data-en="Monthly" data-ar="شهري">Monthly</button>
|
||||||
|
<button type="button" class="btn btn-outline-primary" id="btnYearly" data-en="Yearly" data-ar="سنوي">Yearly</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="height: 300px;">
|
||||||
|
<canvas id="salesChart"></canvas>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1977,7 +2201,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
<div class="bg-light rounded d-flex align-items-center justify-content-center mx-auto" style="width: 150px; height: 150px;">
|
<div class="bg-light rounded d-flex align-items-center justify-content-center mx-auto" style="width: 150px; height: 150px;">
|
||||||
<i class="bi bi-image text-muted" style="font-size: 3rem;"></i>
|
<i class="bi bi-image text-muted" style="font-size: 3rem;"></i>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-sm">
|
<table class="table table-sm">
|
||||||
<tr><th class="text-muted">SKU</th><td><?= htmlspecialchars($item['sku']) ?></td></tr>
|
<tr><th class="text-muted">SKU</th><td><?= htmlspecialchars($item['sku']) ?></td></tr>
|
||||||
@ -2089,6 +2313,64 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?php elseif ($page === 'expiry_report'): ?>
|
||||||
|
<div class="card p-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h5 class="m-0" data-en="Expiry Report" data-ar="تقرير انتهاء الصلاحية">Expiry Report</h5>
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<a href="index.php?page=expiry_report&filter=all" class="btn btn-sm <?= !isset($_GET['filter']) || $_GET['filter'] === 'all' ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="All" data-ar="الكل">All</a>
|
||||||
|
<a href="index.php?page=expiry_report&filter=expired" class="btn btn-sm <?= isset($_GET['filter']) && $_GET['filter'] === 'expired' ? 'btn-danger' : 'btn-outline-danger' ?>" data-en="Expired" data-ar="منتهي">Expired</a>
|
||||||
|
<a href="index.php?page=expiry_report&filter=near_expiry" class="btn btn-sm <?= isset($_GET['filter']) && $_GET['filter'] === 'near_expiry' ? 'btn-warning' : 'btn-outline-warning' ?>" data-en="Near Expiry" data-ar="قريب الانتهاء">Near Expiry</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th data-en="SKU" data-ar="الباركود">SKU</th>
|
||||||
|
<th data-en="Item Name" data-ar="اسم الصنف">Item Name</th>
|
||||||
|
<th data-en="Category" data-ar="الفئة">Category</th>
|
||||||
|
<th data-en="Stock Level" data-ar="المخزون">Stock Level</th>
|
||||||
|
<th data-en="Expiry Date" data-ar="تاريخ الانتهاء">Expiry Date</th>
|
||||||
|
<th data-en="Status" data-ar="الحالة">Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if (empty($data['expiry_items'])): ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="text-center text-muted p-4" data-en="No items found." data-ar="لا توجد أصناف.">No items found.</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php foreach ($data['expiry_items'] as $item): ?>
|
||||||
|
<?php
|
||||||
|
$is_expired = strtotime($item['expiry_date']) <= strtotime(date('Y-m-d'));
|
||||||
|
$is_near = !$is_expired && strtotime($item['expiry_date']) <= strtotime(date('Y-m-d', strtotime('+30 days')));
|
||||||
|
?>
|
||||||
|
<tr class="<?= $is_expired ? 'table-danger' : ($is_near ? 'table-warning' : '') ?>">
|
||||||
|
<td><?= htmlspecialchars($item['sku']) ?></td>
|
||||||
|
<td>
|
||||||
|
<div class="fw-bold"><?= htmlspecialchars($item['name_en']) ?></div>
|
||||||
|
<div class="small text-muted"><?= htmlspecialchars($item['name_ar']) ?></div>
|
||||||
|
</td>
|
||||||
|
<td><?= htmlspecialchars($item['cat_en'] ?? '---') ?></td>
|
||||||
|
<td><?= number_format((float)$item['stock_quantity'], 3) ?></td>
|
||||||
|
<td><?= htmlspecialchars($item['expiry_date']) ?></td>
|
||||||
|
<td>
|
||||||
|
<?php if ($is_expired): ?>
|
||||||
|
<span class="badge bg-danger" data-en="Expired" data-ar="منتهي">Expired</span>
|
||||||
|
<?php elseif ($is_near): ?>
|
||||||
|
<span class="badge bg-warning text-dark" data-en="Near Expiry" data-ar="قريب الانتهاء">Near Expiry</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="badge bg-success" data-en="Good" data-ar="صالح">Good</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php elseif ($page === 'pos'): ?>
|
<?php elseif ($page === 'pos'): ?>
|
||||||
<?php
|
<?php
|
||||||
$products = db()->query("SELECT * FROM stock_items WHERE stock_quantity > 0 ORDER BY name_en ASC")->fetchAll(PDO::FETCH_ASSOC);
|
$products = db()->query("SELECT * FROM stock_items WHERE stock_quantity > 0 ORDER BY name_en ASC")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
@ -3073,7 +3355,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
<input type="hidden" name="page" value="<?= $page ?>">
|
<input type="hidden" name="page" value="<?= $page ?>">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<label class="form-label small fw-bold" data-en="Select <?= $page === 'customer_statement' ? 'Customer' : 'Supplier' ?>" data-ar="اختر <?= $page === 'customer_statement' ? 'العميل' : 'المورد' ?>">Select <?= $page === 'customer_statement' ? 'Customer' : 'Supplier' ?></label>
|
<label class="form-label small fw-bold" data-en="Select <?= $page === 'customer_statement' ? 'Customer' : 'Supplier' ?>" data-ar="اختر <?= $page === 'customer_statement' ? 'العميل' : 'المورد' ?>">Select <?= $page === 'customer_statement' ? 'Customer' : 'Supplier' ?></label>
|
||||||
<select name="entity_id" class="form-select" required>
|
<select name="entity_id" class="form-select select2" required>
|
||||||
<option value="">---</option>
|
<option value="">---</option>
|
||||||
<?php foreach ($data['entities'] as $e): ?>
|
<?php foreach ($data['entities'] as $e): ?>
|
||||||
<option value="<?= $e['id'] ?>" <?= (($_GET['entity_id'] ?? '') == $e['id']) ? 'selected' : '' ?>><?= htmlspecialchars($e['name']) ?></option>
|
<option value="<?= $e['id'] ?>" <?= (($_GET['entity_id'] ?? '') == $e['id']) ? 'selected' : '' ?>><?= htmlspecialchars($e['name']) ?></option>
|
||||||
@ -3398,7 +3680,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Category</label>
|
<label class="form-label">Category</label>
|
||||||
<select name="category_id" class="form-select" required>
|
<select name="category_id" class="form-select select2" required>
|
||||||
<?php foreach ($data['expense_categories'] as $c): ?>
|
<?php foreach ($data['expense_categories'] as $c): ?>
|
||||||
<option value="<?= $c['id'] ?>" <?= $c['id'] == $exp['category_id'] ? 'selected' : '' ?>><?= htmlspecialchars($c['name_en']) ?></option>
|
<option value="<?= $c['id'] ?>" <?= $c['id'] == $exp['category_id'] ? 'selected' : '' ?>><?= htmlspecialchars($c['name_en']) ?></option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
@ -3551,6 +3833,123 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?php elseif ($page === 'sales_returns'): ?>
|
||||||
|
<div class="card p-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h5 class="m-0" data-en="Sales Returns" data-ar="مرتجع المبيعات">Sales Returns</h5>
|
||||||
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addSalesReturnModal" id="createSalesReturnBtn">
|
||||||
|
<i class="bi bi-plus-lg"></i> <span data-en="Create New Return" data-ar="إنشاء مرتجع جديد">Create New Return</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-light p-3 rounded mb-4">
|
||||||
|
<form method="GET" class="row g-3">
|
||||||
|
<input type="hidden" name="page" value="sales_returns">
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" name="search" class="form-control form-control-sm" value="<?= htmlspecialchars($_GET['search'] ?? '') ?>" placeholder="Search by Return ID, Customer or Invoice ID...">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<button type="submit" class="btn btn-primary btn-sm w-100">Filter</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th data-en="Return #" data-ar="رقم المرتجع">Return #</th>
|
||||||
|
<th data-en="Date" data-ar="التاريخ">Date</th>
|
||||||
|
<th data-en="Invoice #" data-ar="رقم الفاتورة">Invoice #</th>
|
||||||
|
<th data-en="Customer" data-ar="العميل">Customer</th>
|
||||||
|
<th data-en="Total Amount" data-ar="إجمالي المرتجع" class="text-end">Total Amount</th>
|
||||||
|
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($data['returns'] as $ret): ?>
|
||||||
|
<tr>
|
||||||
|
<td>RET-<?= str_pad((string)$ret['id'], 5, '0', STR_PAD_LEFT) ?></td>
|
||||||
|
<td><?= $ret['return_date'] ?></td>
|
||||||
|
<td>INV-<?= str_pad((string)$ret['invoice_id'], 5, '0', STR_PAD_LEFT) ?></td>
|
||||||
|
<td><?= htmlspecialchars($ret['customer_name'] ?? 'Walk-in') ?></td>
|
||||||
|
<td class="text-end fw-bold text-danger">OMR <?= number_format((float)$ret['total_amount'], 3) ?></td>
|
||||||
|
<td class="text-end">
|
||||||
|
<div class="btn-group btn-group-sm">
|
||||||
|
<button class="btn btn-outline-info view-return-btn" data-id="<?= $ret['id'] ?>"><i class="bi bi-eye"></i></button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php if (empty($data['returns'])): ?>
|
||||||
|
<tr><td colspan="6" class="text-center py-4 text-muted">No returns found</td></tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php elseif ($page === 'settings'): ?>
|
||||||
|
<div class="card p-4">
|
||||||
|
<h5 class="mb-4" data-en="Company Profile" data-ar="ملف الشركة">Company Profile</h5>
|
||||||
|
<form method="POST" enctype="multipart/form-data">
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label" data-en="Company Name" data-ar="اسم الشركة">Company Name</label>
|
||||||
|
<input type="text" name="settings[company_name]" class="form-control" value="<?= htmlspecialchars($data['settings']['company_name'] ?? '') ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label" data-en="Phone" data-ar="الهاتف">Phone</label>
|
||||||
|
<input type="text" name="settings[company_phone]" class="form-control" value="<?= htmlspecialchars($data['settings']['company_phone'] ?? '') ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label" data-en="Email" data-ar="البريد الإلكتروني">Email</label>
|
||||||
|
<input type="email" name="settings[company_email]" class="form-control" value="<?= htmlspecialchars($data['settings']['company_email'] ?? '') ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label" data-en="VAT Number" data-ar="الرقم الضريبي">VAT Number</label>
|
||||||
|
<input type="text" name="settings[vat_number]" class="form-control" value="<?= htmlspecialchars($data['settings']['vat_number'] ?? '') ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<label class="form-label" data-en="Address" data-ar="العنوان">Address</label>
|
||||||
|
<textarea name="settings[company_address]" class="form-control" rows="3"><?= htmlspecialchars($data['settings']['company_address'] ?? '') ?></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label" data-en="Company Logo" data-ar="شعار الشركة">Company Logo</label>
|
||||||
|
<input type="file" name="company_logo" class="form-control" accept="image/*">
|
||||||
|
<?php if (!empty($data['settings']['company_logo'])): ?>
|
||||||
|
<div class="mt-2">
|
||||||
|
<img src="<?= htmlspecialchars($data['settings']['company_logo']) ?>?v=<?= time() ?>" alt="Logo" class="img-thumbnail" style="max-height: 80px;">
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label" data-en="Favicon" data-ar="أيقونة الموقع">Favicon</label>
|
||||||
|
<input type="file" name="favicon" class="form-control" accept="image/*">
|
||||||
|
<?php if (!empty($data['settings']['favicon'])): ?>
|
||||||
|
<div class="mt-2">
|
||||||
|
<img src="<?= htmlspecialchars($data['settings']['favicon']) ?>?v=<?= time() ?>" alt="Favicon" class="img-thumbnail" style="max-height: 32px;">
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label" data-en="Manager Signature" data-ar="توقيع المدير">Manager Signature</label>
|
||||||
|
<input type="file" name="manager_signature" class="form-control" accept="image/*">
|
||||||
|
<?php if (!empty($data['settings']['manager_signature'])): ?>
|
||||||
|
<div class="mt-2">
|
||||||
|
<img src="<?= htmlspecialchars($data['settings']['manager_signature']) ?>?v=<?= time() ?>" alt="Signature" class="img-thumbnail" style="max-height: 80px;">
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12 mt-4">
|
||||||
|
<button type="submit" name="update_settings" class="btn btn-primary">
|
||||||
|
<i class="bi bi-save"></i> <span data-en="Save Changes" data-ar="حفظ التغييرات">Save Changes</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -3912,7 +4311,17 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
const hasExpiryToggle = document.getElementById('hasExpiryToggle');
|
console.log("DOM Content Loaded - Accounting System");
|
||||||
|
try {
|
||||||
|
// Initialize Select2 for all searchable dropdowns
|
||||||
|
$('.select2').each(function() {
|
||||||
|
$(this).select2({
|
||||||
|
width: '100%',
|
||||||
|
dropdownParent: $(this).closest('.modal').length ? $(this).closest('.modal') : $(document.body)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const hasExpiryToggle = document.getElementById('hasExpiryToggle');
|
||||||
const expiryDateContainer = document.getElementById('expiryDateContainer');
|
const expiryDateContainer = document.getElementById('expiryDateContainer');
|
||||||
const suggestSkuBtn = document.getElementById('suggestSkuBtn');
|
const suggestSkuBtn = document.getElementById('suggestSkuBtn');
|
||||||
const skuInput = document.getElementById('skuInput');
|
const skuInput = document.getElementById('skuInput');
|
||||||
@ -3972,10 +4381,14 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
$rid = (int)$_SESSION['show_receipt_id'];
|
$rid = (int)$_SESSION['show_receipt_id'];
|
||||||
unset($_SESSION['trigger_receipt_modal']);
|
unset($_SESSION['trigger_receipt_modal']);
|
||||||
?>
|
?>
|
||||||
showReceipt(<?= $rid ?>);
|
if (typeof showReceipt === 'function') {
|
||||||
|
showReceipt(<?= $rid ?>);
|
||||||
|
} else {
|
||||||
|
setTimeout(() => { if (typeof showReceipt === 'function') showReceipt(<?= $rid ?>); }, 500);
|
||||||
|
}
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
window.showReceipt = function(paymentId) {
|
function showReceipt(paymentId) {
|
||||||
fetch(`index.php?action=get_payment_details&payment_id=${paymentId}`)
|
fetch(`index.php?action=get_payment_details&payment_id=${paymentId}`)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
@ -4493,9 +4906,174 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Sales Return Logic
|
||||||
|
const returnInvoiceSelect = document.getElementById('return_invoice_select');
|
||||||
|
|
||||||
|
if (returnInvoiceSelect) {
|
||||||
|
const calculateReturnTotal = function() {
|
||||||
|
let total = 0;
|
||||||
|
document.querySelectorAll('#return_items_tbody tr').forEach(row => {
|
||||||
|
const qtyInput = row.querySelector('.return-qty-input');
|
||||||
|
if (!qtyInput) return;
|
||||||
|
const qty = parseFloat(qtyInput.value) || 0;
|
||||||
|
const price = parseFloat(qtyInput.dataset.price) || 0;
|
||||||
|
const lineTotal = qty * price;
|
||||||
|
const lineTotalDisplay = row.querySelector('.line-total');
|
||||||
|
if (lineTotalDisplay) {
|
||||||
|
lineTotalDisplay.innerText = lineTotal.toFixed(3);
|
||||||
|
}
|
||||||
|
total += lineTotal;
|
||||||
|
});
|
||||||
|
const totalDisplay = document.getElementById('return_total_display');
|
||||||
|
if (totalDisplay) {
|
||||||
|
totalDisplay.innerText = 'OMR ' + total.toFixed(3);
|
||||||
|
}
|
||||||
|
const submitBtn = document.getElementById('submit_return_btn');
|
||||||
|
if (submitBtn) {
|
||||||
|
submitBtn.disabled = total <= 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
returnInvoiceSelect.addEventListener('change', async function() {
|
||||||
|
const invoiceId = this.value;
|
||||||
|
const container = document.getElementById('return_items_container');
|
||||||
|
const tbody = document.getElementById('return_items_tbody');
|
||||||
|
const submitBtn = document.getElementById('submit_return_btn');
|
||||||
|
|
||||||
|
if (!invoiceId) {
|
||||||
|
if (container) container.style.display = 'none';
|
||||||
|
if (submitBtn) submitBtn.disabled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tbody) {
|
||||||
|
tbody.innerHTML = '<tr><td colspan="5" class="text-center"><div class="spinner-border spinner-border-sm text-primary"></div> Loading items...</td></tr>';
|
||||||
|
}
|
||||||
|
if (container) container.style.display = 'block';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resp = await fetch(`index.php?action=get_invoice_items&invoice_id=${invoiceId}`);
|
||||||
|
const items = await resp.json();
|
||||||
|
|
||||||
|
if (tbody) {
|
||||||
|
tbody.innerHTML = '';
|
||||||
|
if (items.length === 0) {
|
||||||
|
tbody.innerHTML = '<tr><td colspan="5" class="text-center text-muted">No items found for this invoice.</td></tr>';
|
||||||
|
} else {
|
||||||
|
let html = '';
|
||||||
|
items.forEach(item => {
|
||||||
|
html += `
|
||||||
|
<tr>
|
||||||
|
<td>${item.name_en}<br><small class="text-muted">${item.sku}</small></td>
|
||||||
|
<td>${parseFloat(item.quantity).toFixed(2)}</td>
|
||||||
|
<td>
|
||||||
|
<input type="number" name="quantities[]" class="form-control form-control-sm return-qty-input"
|
||||||
|
step="0.01" min="0" max="${item.quantity}" value="0"
|
||||||
|
data-price="${item.unit_price}">
|
||||||
|
<input type="hidden" name="item_ids[]" value="${item.item_id}">
|
||||||
|
<input type="hidden" name="prices[]" value="${item.unit_price}">
|
||||||
|
</td>
|
||||||
|
<td class="text-end">${parseFloat(item.unit_price).toFixed(3)}</td>
|
||||||
|
<td class="text-end line-total">0.000</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
tbody.innerHTML = html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (submitBtn) submitBtn.disabled = true;
|
||||||
|
|
||||||
|
// Add event listeners for qty changes
|
||||||
|
tbody.querySelectorAll('.return-qty-input').forEach(input => {
|
||||||
|
input.addEventListener('input', calculateReturnTotal);
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
Swal.fire('Error', 'Failed to fetch invoice items', 'error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// View Return Logic
|
||||||
|
document.querySelectorAll('.view-return-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', function() {
|
||||||
|
Swal.fire('Info', 'View Return Details functionality is coming soon!', 'info');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (e) { console.error("JS Error in DOMContentLoaded:", e); }
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<?php if ($page === 'sales_returns'): ?>
|
||||||
|
<!-- Add Sales Return Modal -->
|
||||||
|
<div class="modal fade" id="addSalesReturnModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content text-start border-0 shadow">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Process Sales Return</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<form method="POST">
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row g-3 mb-4 text-start">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label" data-en="Select Invoice" data-ar="اختر الفاتورة">Select Invoice</label>
|
||||||
|
<select name="invoice_id" id="return_invoice_select" class="form-select select2" required>
|
||||||
|
<option value="">Choose Invoice...</option>
|
||||||
|
<?php if (!empty($data['sales_invoices'])): ?>
|
||||||
|
<?php foreach ($data['sales_invoices'] as $inv): ?>
|
||||||
|
<option value="<?= $inv['id'] ?>">INV-<?= str_pad((string)$inv['id'], 5, '0', STR_PAD_LEFT) ?> (<?= $inv['invoice_date'] ?>) - OMR <?= number_format($inv['total_with_vat'], 3) ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label">Return Date</label>
|
||||||
|
<input type="date" name="return_date" class="form-control" value="<?= date('Y-m-d') ?>" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="return_items_container" style="display:none;" class="text-start">
|
||||||
|
<h6>Items for Return</h6>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-sm table-bordered">
|
||||||
|
<thead class="bg-light">
|
||||||
|
<tr>
|
||||||
|
<th>Item</th>
|
||||||
|
<th>Sold Qty</th>
|
||||||
|
<th>Return Qty</th>
|
||||||
|
<th>Price</th>
|
||||||
|
<th>Total</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="return_items_tbody"></tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<th colspan="4" class="text-end">Total Return Amount:</th>
|
||||||
|
<th class="text-end" id="return_total_display">OMR 0.000</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Notes / Reason for Return</label>
|
||||||
|
<textarea name="notes" class="form-control" rows="2"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="submit" name="add_sales_return" class="btn btn-danger" id="submit_return_btn" disabled>Process Return</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||||
|
|
||||||
<!-- View Invoice Modal -->
|
<!-- View Invoice Modal -->
|
||||||
@ -4513,7 +5091,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
<div class="row g-3 mb-4">
|
<div class="row g-3 mb-4">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<label class="form-label fw-bold" data-en="<?= $page === 'sales' ? 'Customer' : 'Supplier' ?>" data-ar="<?= $page === 'sales' ? 'العميل' : 'المورد' ?>"><?= $page === 'sales' ? 'Customer' : 'Supplier' ?></label>
|
<label class="form-label fw-bold" data-en="<?= $page === 'sales' ? 'Customer' : 'Supplier' ?>" data-ar="<?= $page === 'sales' ? 'العميل' : 'المورد' ?>"><?= $page === 'sales' ? 'Customer' : 'Supplier' ?></label>
|
||||||
<select name="customer_id" class="form-select" required>
|
<select name="customer_id" class="form-select select2" required>
|
||||||
<option value="">---</option>
|
<option value="">---</option>
|
||||||
<?php foreach ($data['customers_list'] as $c): ?>
|
<?php foreach ($data['customers_list'] as $c): ?>
|
||||||
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name']) ?></option>
|
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name']) ?></option>
|
||||||
@ -4613,7 +5191,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
<div class="row g-3 mb-4">
|
<div class="row g-3 mb-4">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<label class="form-label fw-bold" data-en="<?= $page === 'sales' ? 'Customer' : 'Supplier' ?>" data-ar="<?= $page === 'sales' ? 'العميل' : 'المورد' ?>"><?= $page === 'sales' ? 'Customer' : 'Supplier' ?></label>
|
<label class="form-label fw-bold" data-en="<?= $page === 'sales' ? 'Customer' : 'Supplier' ?>" data-ar="<?= $page === 'sales' ? 'العميل' : 'المورد' ?>"><?= $page === 'sales' ? 'Customer' : 'Supplier' ?></label>
|
||||||
<select name="customer_id" id="edit_customer_id" class="form-select" required>
|
<select name="customer_id" id="edit_customer_id" class="form-select select2" required>
|
||||||
<option value="">---</option>
|
<option value="">---</option>
|
||||||
<?php foreach ($data['customers_list'] as $c): ?>
|
<?php foreach ($data['customers_list'] as $c): ?>
|
||||||
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name']) ?></option>
|
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name']) ?></option>
|
||||||
@ -4712,7 +5290,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
<div class="row g-3 mb-4">
|
<div class="row g-3 mb-4">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<label class="form-label fw-bold" data-en="Customer" data-ar="العميل">Customer</label>
|
<label class="form-label fw-bold" data-en="Customer" data-ar="العميل">Customer</label>
|
||||||
<select name="customer_id" class="form-select" required>
|
<select name="customer_id" class="form-select select2" required>
|
||||||
<option value="">---</option>
|
<option value="">---</option>
|
||||||
<?php foreach ($data['customers_list'] as $c): ?>
|
<?php foreach ($data['customers_list'] as $c): ?>
|
||||||
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name']) ?></option>
|
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name']) ?></option>
|
||||||
@ -4792,7 +5370,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
<div class="row g-3 mb-4">
|
<div class="row g-3 mb-4">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label class="form-label fw-bold" data-en="Customer" data-ar="العميل">Customer</label>
|
<label class="form-label fw-bold" data-en="Customer" data-ar="العميل">Customer</label>
|
||||||
<select name="customer_id" id="edit_quot_customer_id" class="form-select" required>
|
<select name="customer_id" id="edit_quot_customer_id" class="form-select select2" required>
|
||||||
<option value="">---</option>
|
<option value="">---</option>
|
||||||
<?php foreach ($data['customers_list'] as $c): ?>
|
<?php foreach ($data['customers_list'] as $c): ?>
|
||||||
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name']) ?></option>
|
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name']) ?></option>
|
||||||
@ -5112,7 +5690,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label fw-bold" data-en="Payment Method" data-ar="طريقة الدفع">Payment Method</label>
|
<label class="form-label fw-bold" data-en="Payment Method" data-ar="طريقة الدفع">Payment Method</label>
|
||||||
<select name="payment_method" class="form-select" required>
|
<select name="payment_method" class="form-select select2" required>
|
||||||
<option value="Cash">Cash</option>
|
<option value="Cash">Cash</option>
|
||||||
<option value="Card">Card</option>
|
<option value="Card">Card</option>
|
||||||
<option value="Bank Transfer">Bank Transfer</option>
|
<option value="Bank Transfer">Bank Transfer</option>
|
||||||
@ -5218,7 +5796,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
</div>
|
</div>
|
||||||
<div id="creditCustomerSection" class="mt-2 pt-2 border-top" style="display:none;">
|
<div id="creditCustomerSection" class="mt-2 pt-2 border-top" style="display:none;">
|
||||||
<label class="form-label smaller fw-bold mb-1">Select Credit Customer</label>
|
<label class="form-label smaller fw-bold mb-1">Select Credit Customer</label>
|
||||||
<select id="paymentCreditCustomer" class="form-select form-select-sm" onchange="cart.syncCustomer(this.value)">
|
<select id="paymentCreditCustomer" class="form-select form-select-sm select2" onchange="cart.syncCustomer(this.value)">
|
||||||
<option value="">--- Select Customer ---</option>
|
<option value="">--- Select Customer ---</option>
|
||||||
<?php foreach ($customers as $c): ?>
|
<?php foreach ($customers as $c): ?>
|
||||||
<option value="<?= $c['id'] ?>" data-search="<?= htmlspecialchars(strtolower($c['name'] . ' ' . ($c['phone'] ?? ''))) ?>"><?= htmlspecialchars($c['name']) ?> (<?= htmlspecialchars($c['phone'] ?? '') ?>)</option>
|
<option value="<?= $c['id'] ?>" data-search="<?= htmlspecialchars(strtolower($c['name'] . ' ' . ($c['phone'] ?? ''))) ?>"><?= htmlspecialchars($c['name']) ?> (<?= htmlspecialchars($c['phone'] ?? '') ?>)</option>
|
||||||
@ -5901,6 +6479,59 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
document.body.classList.remove('printing-receipt');
|
document.body.classList.remove('printing-receipt');
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<?php if ($page === 'dashboard'): ?>
|
||||||
|
const monthlyData = <?= json_encode($data['monthly_sales']) ?>;
|
||||||
|
const yearlyData = <?= json_encode($data['yearly_sales']) ?>;
|
||||||
|
|
||||||
|
const ctx = document.getElementById('salesChart').getContext('2d');
|
||||||
|
let salesChart = new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: monthlyData.map(d => d.label),
|
||||||
|
datasets: [{
|
||||||
|
label: 'Sales (OMR)',
|
||||||
|
data: monthlyData.map(d => d.total),
|
||||||
|
borderColor: '#0d6efd',
|
||||||
|
backgroundColor: 'rgba(13, 110, 253, 0.1)',
|
||||||
|
fill: true,
|
||||||
|
tension: 0.4
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
plugins: {
|
||||||
|
legend: { display: false }
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true,
|
||||||
|
ticks: {
|
||||||
|
callback: function(value) { return 'OMR ' + value.toFixed(3); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('btnMonthly').addEventListener('click', function() {
|
||||||
|
this.classList.add('active');
|
||||||
|
document.getElementById('btnYearly').classList.remove('active');
|
||||||
|
salesChart.data.labels = monthlyData.map(d => d.label);
|
||||||
|
salesChart.data.datasets[0].data = monthlyData.map(d => d.total);
|
||||||
|
salesChart.update();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('btnYearly').addEventListener('click', function() {
|
||||||
|
this.classList.add('active');
|
||||||
|
document.getElementById('btnMonthly').classList.remove('active');
|
||||||
|
salesChart.data.labels = yearlyData.map(d => d.label);
|
||||||
|
salesChart.data.datasets[0].data = yearlyData.map(d => d.total);
|
||||||
|
salesChart.update();
|
||||||
|
});
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user