add expired items

This commit is contained in:
Flatlogic Bot 2026-02-17 16:12:25 +00:00
parent 01b6fa4c64
commit ea63a5146b
4 changed files with 729 additions and 48 deletions

View File

@ -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;

View File

@ -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

View 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
View File

@ -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>