integrations multi outlets
This commit is contained in:
parent
94afa7ad81
commit
bda20a7ffb
@ -1,54 +0,0 @@
|
||||
<?php
|
||||
require 'db/config.php';
|
||||
$db = db();
|
||||
|
||||
$tables = [
|
||||
'users', 'invoices', 'lpos', 'purchases', 'quotations',
|
||||
'expenses', 'payments', 'purchase_payments', 'pos_transactions',
|
||||
'customers', 'suppliers', 'stock_items', 'pos_held_carts',
|
||||
'loyalty_transactions', 'purchase_returns', 'sales_returns', 'pos_payments'
|
||||
];
|
||||
|
||||
try {
|
||||
// 1. Create function
|
||||
$db->exec("DROP FUNCTION IF EXISTS current_outlet_id");
|
||||
$db->exec("CREATE FUNCTION current_outlet_id() RETURNS INT DETERMINISTIC RETURN @session_outlet_id");
|
||||
|
||||
foreach ($tables as $t) {
|
||||
// Ensure table exists and isn't already a view
|
||||
$stmt = $db->query("SHOW FULL TABLES LIKE '$t'");
|
||||
$row = $stmt->fetch(PDO::FETCH_NUM);
|
||||
if (!$row) continue;
|
||||
if ($row[1] === 'VIEW') continue; // Already processed
|
||||
|
||||
// Make sure it has outlet_id
|
||||
$hasCol = false;
|
||||
$cols = $db->query("SHOW COLUMNS FROM `$t`")->fetchAll(PDO::FETCH_ASSOC);
|
||||
foreach ($cols as $c) {
|
||||
if ($c['Field'] === 'outlet_id') $hasCol = true;
|
||||
}
|
||||
if (!$hasCol) {
|
||||
$db->exec("ALTER TABLE `$t` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT 1 AFTER `id`");
|
||||
}
|
||||
|
||||
// Alter default to 1 if it's NULL
|
||||
$db->exec("ALTER TABLE `$t` MODIFY `outlet_id` int(11) DEFAULT 1");
|
||||
|
||||
// Rename table to _table
|
||||
$db->exec("RENAME TABLE `$t` TO `_$t`");
|
||||
|
||||
// Create view
|
||||
$db->exec("CREATE VIEW `$t` AS SELECT * FROM `_$t` WHERE outlet_id = current_outlet_id() OR current_outlet_id() IS NULL OR current_outlet_id() = 0");
|
||||
|
||||
// Create trigger
|
||||
$db->exec("CREATE TRIGGER `trg_ins_$t` BEFORE INSERT ON `_$t` FOR EACH ROW BEGIN
|
||||
IF current_outlet_id() IS NOT NULL AND current_outlet_id() != 0 THEN
|
||||
SET NEW.outlet_id = current_outlet_id();
|
||||
END IF;
|
||||
END");
|
||||
|
||||
echo "Processed $t\n";
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
1001
data_fetch.txt
1001
data_fetch.txt
File diff suppressed because it is too large
Load Diff
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
require 'db/config.php';
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SHOW TABLES");
|
||||
$tables = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
foreach ($tables as $table) {
|
||||
echo "Table: $table\n";
|
||||
$stmt2 = $pdo->query("DESCRIBE `$table`");
|
||||
$cols = $stmt2->fetchAll(PDO::FETCH_ASSOC);
|
||||
foreach ($cols as $col) {
|
||||
echo " - " . $col['Field'] . " (" . $col['Type'] . ")\n";
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo "Error: " . $e->getMessage();
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
<?php
|
||||
require 'db/config.php';
|
||||
$stmt = db()->query("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = 'outlet_id' AND TABLE_SCHEMA = DATABASE()");
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
echo $row['TABLE_NAME'] . "\n";
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
<?php
|
||||
require 'db/config.php';
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// Create outlets table
|
||||
$pdo->exec("CREATE TABLE IF NOT EXISTS `outlets` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`address` text,
|
||||
`phone` varchar(50),
|
||||
`status` enum('active','inactive') DEFAULT 'active',
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
|
||||
|
||||
// Insert a default Main Branch if table is empty
|
||||
$stmt = $pdo->query("SELECT COUNT(*) FROM outlets");
|
||||
if ($stmt->fetchColumn() == 0) {
|
||||
$pdo->exec("INSERT INTO outlets (name, address, status) VALUES ('Main Branch', 'Headquarters', 'active')");
|
||||
}
|
||||
|
||||
// Add outlet_id to tables
|
||||
$tablesToUpdate = [
|
||||
'users',
|
||||
'invoices',
|
||||
'purchases',
|
||||
'lpos',
|
||||
'quotations',
|
||||
'expenses',
|
||||
'payments'
|
||||
];
|
||||
|
||||
foreach ($tablesToUpdate as $table) {
|
||||
$stmt = $pdo->query("SHOW COLUMNS FROM `$table` LIKE 'outlet_id'");
|
||||
if ($stmt->rowCount() == 0) {
|
||||
$pdo->exec("ALTER TABLE `$table` ADD COLUMN `outlet_id` int(11) NULL DEFAULT 1 AFTER `id`");
|
||||
echo "Added outlet_id to $table\n";
|
||||
} else {
|
||||
echo "outlet_id already exists in $table\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "Migration completed successfully.";
|
||||
} catch (Exception $e) {
|
||||
echo "Error: " . $e->getMessage();
|
||||
}
|
||||
@ -1,2 +1,7 @@
|
||||
2026-02-25 09:56:17 - Items case hit
|
||||
2026-02-25 09:56:38 - Requesting AI. UUID: [e1f9b5b3-fcef-4c8d-87d2-8630b1f72491] CFG: {"base_url":"https:\/\/flatlogic.com","responses_path":"\/projects\/38471\/ai-request","project_id":"38471","project_uuid":"e1f9b5b3-fcef-4c8d-87d2-8630b1f72491","project_header":"Project-UUID","default_model":"gpt-4o-mini","timeout":30,"verify_tls":true}
|
||||
2026-02-25 10:03:48 - Items case hit
|
||||
2026-02-25 11:48:14 - Items case hit
|
||||
2026-02-25 11:49:27 - Items case hit
|
||||
2026-02-25 11:51:57 - Items case hit
|
||||
2026-02-25 12:41:41 - Items case hit
|
||||
|
||||
181
diff.txt
181
diff.txt
@ -1,181 +0,0 @@
|
||||
diff --git a/index.php b/index.php
|
||||
index b15ee60..3f88b32 100644
|
||||
--- a/index.php
|
||||
+++ b/index.php
|
||||
@@ -35,6 +35,15 @@ if ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || (isset($_SERVER[
|
||||
}
|
||||
|
||||
session_start();
|
||||
+if (isset($_GET['action']) && $_GET['action'] === 'switch_outlet') {
|
||||
+ $target = (int)$_GET['id'];
|
||||
+ if (($_SESSION['user_role_name'] ?? '') === 'Administrator') {
|
||||
+ $_SESSION['outlet_id'] = $target === 0 ? null : $target;
|
||||
+ }
|
||||
+ header("Location: " . ($_SERVER['HTTP_REFERER'] ?? 'index.php'));
|
||||
+ exit;
|
||||
+}
|
||||
+
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'download_items_template') {
|
||||
header('Content-Type: text/csv; charset=utf-8');
|
||||
header('Content-Disposition: attachment; filename=items_import_template.csv');
|
||||
@@ -3014,6 +3023,11 @@ $page_num = isset($_GET["p"]) ? (int)$_GET["p"] : 1;
|
||||
if ($page_num < 1) $page_num = 1;
|
||||
$offset = ($page_num - 1) * $limit;
|
||||
switch ($page) {
|
||||
+ case 'outlets':
|
||||
+ $stmt = db()->prepare("SELECT * FROM outlets ORDER BY id DESC");
|
||||
+ $stmt->execute();
|
||||
+ $data['outlets'] = $stmt->fetchAll();
|
||||
+ break;
|
||||
case 'suppliers':
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
@@ -4184,6 +4198,26 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
+ <?php
|
||||
+ if (($_SESSION['user_role_name'] ?? '') === 'Administrator'):
|
||||
+ $outlets = db()->query("SELECT * FROM outlets WHERE status = 'active'")->fetchAll(PDO::FETCH_ASSOC);
|
||||
+ $cur_out = $_SESSION['outlet_id'] ?? 0;
|
||||
+ $cur_name = 'All Outlets';
|
||||
+ foreach ($outlets as $o) { if ($o['id'] == $cur_out) $cur_name = $o['name']; }
|
||||
+ ?>
|
||||
+ <div class="dropdown me-3">
|
||||
+ <button class="btn btn-outline-primary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
||||
+ <i class="bi bi-shop"></i> <span class="d-none d-md-inline"><?= htmlspecialchars($cur_name) ?></span>
|
||||
+ </button>
|
||||
+ <ul class="dropdown-menu shadow-sm border-0">
|
||||
+ <li><a class="dropdown-item <?= $cur_out == 0 ? 'active' : '' ?>" href="index.php?action=switch_outlet&id=0">All Outlets</a></li>
|
||||
+ <li><hr class="dropdown-divider"></li>
|
||||
+ <?php foreach ($outlets as $o): ?>
|
||||
+ <li><a class="dropdown-item <?= $cur_out == $o['id'] ? 'active' : '' ?>" href="index.php?action=switch_outlet&id=<?= $o['id'] ?>"><?= htmlspecialchars($o['name']) ?></a></li>
|
||||
+ <?php endforeach; ?>
|
||||
+ </ul>
|
||||
+ </div>
|
||||
+ <?php endif; ?>
|
||||
<div class="dropdown me-3">
|
||||
<button class="btn btn-outline-secondary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-palette"></i> <span><?= $lang === 'ar' ? 'المظهر' : 'Theme' ?></span>
|
||||
@@ -4488,6 +4522,121 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
<h1 class="display-4 fw-bold text-muted text-center mt-3"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Company Name') ?></h1>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
+ <?php elseif ($page === 'outlets' && ($_SESSION['user_role_name'] ?? '') === 'Administrator'): ?>
|
||||
+ <div class="card border-0 shadow-sm rounded-4 mb-4">
|
||||
+ <div class="card-header bg-white border-bottom-0 pt-4 pb-0 px-4 d-flex justify-content-between align-items-center">
|
||||
+ <h5 class="fw-bold mb-0"><i class="bi bi-shop text-primary me-2"></i> Manage Outlets</h5>
|
||||
+ <button class="btn btn-primary rounded-pill px-3 py-2" data-bs-toggle="modal" data-bs-target="#addOutletModal">
|
||||
+ <i class="bi bi-plus-lg me-1"></i> Add Outlet
|
||||
+ </button>
|
||||
+ </div>
|
||||
+ <div class="card-body p-4">
|
||||
+ <div class="table-responsive">
|
||||
+ <table class="table table-hover align-middle mb-0">
|
||||
+ <thead class="table-light">
|
||||
+ <tr>
|
||||
+ <th>ID</th>
|
||||
+ <th>Name</th>
|
||||
+ <th>Address</th>
|
||||
+ <th>Phone</th>
|
||||
+ <th>Status</th>
|
||||
+ <th>Created At</th>
|
||||
+ <th class="text-end">Actions</th>
|
||||
+ </tr>
|
||||
+ </thead>
|
||||
+ <tbody>
|
||||
+ <?php foreach ($data['outlets'] as $o): ?>
|
||||
+ <tr>
|
||||
+ <td>#<?= $o['id'] ?></td>
|
||||
+ <td class="fw-semibold text-dark"><?= htmlspecialchars($o['name']) ?></td>
|
||||
+ <td class="text-muted small"><?= htmlspecialchars($o['address'] ?: '-') ?></td>
|
||||
+ <td><?= htmlspecialchars($o['phone'] ?: '-') ?></td>
|
||||
+ <td><span class="badge bg-<?= $o['status'] === 'active' ? 'success' : 'secondary' ?> bg-opacity-10 text-<?= $o['status'] === 'active' ? 'success' : 'secondary' ?> rounded-pill px-2"><?= ucfirst($o['status']) ?></span></td>
|
||||
+ <td class="small text-muted"><?= htmlspecialchars($o['created_at']) ?></td>
|
||||
+ <td class="text-end">
|
||||
+ <button class="btn btn-light btn-sm rounded-circle me-1" onclick="editOutlet(<?= htmlspecialchars(json_encode($o)) ?>)" title="Edit">
|
||||
+ <i class="bi bi-pencil"></i>
|
||||
+ </button>
|
||||
+ <?php if ($o['id'] !== 1): ?>
|
||||
+ <form method="POST" class="d-inline" onsubmit="return confirm('Are you sure you want to delete this outlet?');">
|
||||
+ <input type="hidden" name="id" value="<?= $o['id'] ?>">
|
||||
+ <button type="submit" name="delete_outlet" class="btn btn-light btn-sm rounded-circle text-danger" title="Delete">
|
||||
+ <i class="bi bi-trash"></i>
|
||||
+ </button>
|
||||
+ </form>
|
||||
+ <?php endif; ?>
|
||||
+ </td>
|
||||
+ </tr>
|
||||
+ <?php endforeach; ?>
|
||||
+ </tbody>
|
||||
+ </table>
|
||||
+ </div>
|
||||
+ </div>
|
||||
+ </div>
|
||||
+
|
||||
+ <!-- Add/Edit Modal -->
|
||||
+ <div class="modal fade" id="addOutletModal" tabindex="-1">
|
||||
+ <div class="modal-dialog modal-dialog-centered">
|
||||
+ <div class="modal-content border-0 shadow rounded-4">
|
||||
+ <form method="POST">
|
||||
+ <input type="hidden" name="id" id="outlet_id">
|
||||
+ <div class="modal-header border-bottom-0 pb-0">
|
||||
+ <h5 class="modal-title fw-bold" id="outletModalTitle">Add Outlet</h5>
|
||||
+ <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
+ </div>
|
||||
+ <div class="modal-body p-4">
|
||||
+ <div class="mb-3">
|
||||
+ <label class="form-label small fw-semibold text-muted">Name</label>
|
||||
+ <input type="text" name="name" id="outlet_name" class="form-control rounded-3" required>
|
||||
+ </div>
|
||||
+ <div class="mb-3">
|
||||
+ <label class="form-label small fw-semibold text-muted">Phone</label>
|
||||
+ <input type="text" name="phone" id="outlet_phone" class="form-control rounded-3">
|
||||
+ </div>
|
||||
+ <div class="mb-3">
|
||||
+ <label class="form-label small fw-semibold text-muted">Address</label>
|
||||
+ <textarea name="address" id="outlet_address" class="form-control rounded-3" rows="2"></textarea>
|
||||
+ </div>
|
||||
+ <div class="mb-0">
|
||||
+ <label class="form-label small fw-semibold text-muted">Status</label>
|
||||
+ <select name="status" id="outlet_status" class="form-select rounded-3">
|
||||
+ <option value="active">Active</option>
|
||||
+ <option value="inactive">Inactive</option>
|
||||
+ </select>
|
||||
+ </div>
|
||||
+ </div>
|
||||
+ <div class="modal-footer border-top-0 pt-0">
|
||||
+ <button type="button" class="btn btn-light rounded-pill px-4" data-bs-dismiss="modal">Cancel</button>
|
||||
+ <button type="submit" name="add_outlet" id="outletSubmitBtn" class="btn btn-primary rounded-pill px-4">Save Outlet</button>
|
||||
+ </div>
|
||||
+ </form>
|
||||
+ </div>
|
||||
+ </div>
|
||||
+ </div>
|
||||
+ <script>
|
||||
+ function editOutlet(o) {
|
||||
+ document.getElementById('outlet_id').value = o.id;
|
||||
+ document.getElementById('outlet_name').value = o.name;
|
||||
+ document.getElementById('outlet_phone').value = o.phone || '';
|
||||
+ document.getElementById('outlet_address').value = o.address || '';
|
||||
+ document.getElementById('outlet_status').value = o.status;
|
||||
+ document.getElementById('outletModalTitle').innerText = 'Edit Outlet';
|
||||
+ document.getElementById('outletSubmitBtn').name = 'edit_outlet';
|
||||
+ document.getElementById('outletSubmitBtn').innerText = 'Update Outlet';
|
||||
+ new bootstrap.Modal(document.getElementById('addOutletModal')).show();
|
||||
+ }
|
||||
+ document.getElementById('addOutletModal').addEventListener('hidden.bs.modal', function () {
|
||||
+ document.getElementById('outlet_id').value = '';
|
||||
+ document.getElementById('outlet_name').value = '';
|
||||
+ document.getElementById('outlet_phone').value = '';
|
||||
+ document.getElementById('outlet_address').value = '';
|
||||
+ document.getElementById('outlet_status').value = 'active';
|
||||
+ document.getElementById('outletModalTitle').innerText = 'Add Outlet';
|
||||
+ document.getElementById('outletSubmitBtn').name = 'add_outlet';
|
||||
+ document.getElementById('outletSubmitBtn').innerText = 'Save Outlet';
|
||||
+ });
|
||||
+ </script>
|
||||
+
|
||||
<?php elseif ($page === 'customers' || $page === 'suppliers'): ?>
|
||||
<div class="card p-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
1231
includes/SimpleXLSX.php
Normal file
1231
includes/SimpleXLSX.php
Normal file
File diff suppressed because it is too large
Load Diff
450
index.php
450
index.php
@ -1317,14 +1317,216 @@ function getPromotionalPrice($item) {
|
||||
redirectWithMessage("Expense recorded!", "index.php?page=expenses");
|
||||
}
|
||||
|
||||
if (isset($_POST['import_customers'])) {
|
||||
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === 0) {
|
||||
$tmpPath = $_FILES['excel_file']['tmp_name'];
|
||||
$firstBytes = file_get_contents($tmpPath, false, null, 0, 4);
|
||||
$count = 0; $errors = 0;
|
||||
|
||||
if ($firstBytes === "PK\x03\x04") {
|
||||
require_once __DIR__ . '/includes/SimpleXLSX.php';
|
||||
if ($xlsx = \Shuchkin\SimpleXLSX::parse($tmpPath)) {
|
||||
foreach ($xlsx->rows() as $i => $data) {
|
||||
if ($i === 0) continue;
|
||||
$name = trim($data[0] ?? '');
|
||||
if (!$name) { $errors++; continue; }
|
||||
$email = trim($data[1] ?? '');
|
||||
$phone = trim($data[2] ?? '');
|
||||
$tax_id = trim($data[3] ?? '');
|
||||
$balance = (float)($data[4] ?? 0);
|
||||
|
||||
db()->prepare("INSERT INTO customers (name, email, phone, tax_id, balance) VALUES (?, ?, ?, ?, ?)")
|
||||
->execute([$name, $email, $phone, $tax_id, $balance]);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CSV fallback
|
||||
$handle = fopen($tmpPath, "r");
|
||||
fgetcsv($handle); // skip header
|
||||
while (($data = fgetcsv($handle)) !== FALSE) {
|
||||
$name = trim($data[0] ?? '');
|
||||
if (!$name) { $errors++; continue; }
|
||||
$email = trim($data[1] ?? '');
|
||||
$phone = trim($data[2] ?? '');
|
||||
$tax_id = trim($data[3] ?? '');
|
||||
$balance = (float)($data[4] ?? 0);
|
||||
db()->prepare("INSERT INTO customers (name, email, phone, tax_id, balance) VALUES (?, ?, ?, ?, ?)")
|
||||
->execute([$name, $email, $phone, $tax_id, $balance]);
|
||||
$count++;
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
redirectWithMessage("Customers imported! $count processed." . ($errors ? " ($errors skipped)" : ""), "index.php?page=customers");
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['import_suppliers'])) {
|
||||
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === 0) {
|
||||
$tmpPath = $_FILES['excel_file']['tmp_name'];
|
||||
$firstBytes = file_get_contents($tmpPath, false, null, 0, 4);
|
||||
$count = 0; $errors = 0;
|
||||
|
||||
if ($firstBytes === "PK\x03\x04") {
|
||||
require_once __DIR__ . '/includes/SimpleXLSX.php';
|
||||
if ($xlsx = \Shuchkin\SimpleXLSX::parse($tmpPath)) {
|
||||
foreach ($xlsx->rows() as $i => $data) {
|
||||
if ($i === 0) continue;
|
||||
$name = trim($data[0] ?? '');
|
||||
if (!$name) { $errors++; continue; }
|
||||
$email = trim($data[1] ?? '');
|
||||
$phone = trim($data[2] ?? '');
|
||||
$tax_id = trim($data[3] ?? '');
|
||||
$balance = (float)($data[4] ?? 0);
|
||||
|
||||
db()->prepare("INSERT INTO suppliers (name, email, phone, tax_id, balance) VALUES (?, ?, ?, ?, ?)")
|
||||
->execute([$name, $email, $phone, $tax_id, $balance]);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CSV fallback
|
||||
$handle = fopen($tmpPath, "r");
|
||||
fgetcsv($handle); // skip header
|
||||
while (($data = fgetcsv($handle)) !== FALSE) {
|
||||
$name = trim($data[0] ?? '');
|
||||
if (!$name) { $errors++; continue; }
|
||||
$email = trim($data[1] ?? '');
|
||||
$phone = trim($data[2] ?? '');
|
||||
$tax_id = trim($data[3] ?? '');
|
||||
$balance = (float)($data[4] ?? 0);
|
||||
db()->prepare("INSERT INTO suppliers (name, email, phone, tax_id, balance) VALUES (?, ?, ?, ?, ?)")
|
||||
->execute([$name, $email, $phone, $tax_id, $balance]);
|
||||
$count++;
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
redirectWithMessage("Suppliers imported! $count processed." . ($errors ? " ($errors skipped)" : ""), "index.php?page=suppliers");
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['import_categories'])) {
|
||||
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === 0) {
|
||||
$tmpPath = $_FILES['excel_file']['tmp_name'];
|
||||
$firstBytes = file_get_contents($tmpPath, false, null, 0, 4);
|
||||
$count = 0; $errors = 0;
|
||||
|
||||
if ($firstBytes === "PK\x03\x04") {
|
||||
require_once __DIR__ . '/includes/SimpleXLSX.php';
|
||||
if ($xlsx = \Shuchkin\SimpleXLSX::parse($tmpPath)) {
|
||||
foreach ($xlsx->rows() as $i => $data) {
|
||||
if ($i === 0) continue;
|
||||
$name_en = trim($data[0] ?? '');
|
||||
if (!$name_en) { $errors++; continue; }
|
||||
$name_ar = trim($data[1] ?? '');
|
||||
|
||||
db()->prepare("INSERT INTO stock_categories (name_en, name_ar) VALUES (?, ?)")
|
||||
->execute([$name_en, $name_ar]);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$handle = fopen($tmpPath, "r");
|
||||
fgetcsv($handle); // skip header
|
||||
while (($data = fgetcsv($handle)) !== FALSE) {
|
||||
$name_en = trim($data[0] ?? '');
|
||||
if (!$name_en) { $errors++; continue; }
|
||||
$name_ar = trim($data[1] ?? '');
|
||||
db()->prepare("INSERT INTO stock_categories (name_en, name_ar) VALUES (?, ?)")
|
||||
->execute([$name_en, $name_ar]);
|
||||
$count++;
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
redirectWithMessage("Categories imported! $count processed.", "index.php?page=stock_categories");
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['import_units'])) {
|
||||
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === 0) {
|
||||
$tmpPath = $_FILES['excel_file']['tmp_name'];
|
||||
$firstBytes = file_get_contents($tmpPath, false, null, 0, 4);
|
||||
$count = 0; $errors = 0;
|
||||
|
||||
if ($firstBytes === "PK\x03\x04") {
|
||||
require_once __DIR__ . '/includes/SimpleXLSX.php';
|
||||
if ($xlsx = \Shuchkin\SimpleXLSX::parse($tmpPath)) {
|
||||
foreach ($xlsx->rows() as $i => $data) {
|
||||
if ($i === 0) continue;
|
||||
$name_en = trim($data[0] ?? '');
|
||||
if (!$name_en) { $errors++; continue; }
|
||||
$name_ar = trim($data[1] ?? '');
|
||||
$short_name_en = trim($data[2] ?? '');
|
||||
$short_name_ar = trim($data[3] ?? '');
|
||||
|
||||
db()->prepare("INSERT INTO stock_units (name_en, name_ar, short_name_en, short_name_ar) VALUES (?, ?, ?, ?)")
|
||||
->execute([$name_en, $name_ar, $short_name_en, $short_name_ar]);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$handle = fopen($tmpPath, "r");
|
||||
fgetcsv($handle);
|
||||
while (($data = fgetcsv($handle)) !== FALSE) {
|
||||
$name_en = trim($data[0] ?? '');
|
||||
if (!$name_en) { $errors++; continue; }
|
||||
$name_ar = trim($data[1] ?? '');
|
||||
$short_name_en = trim($data[2] ?? '');
|
||||
$short_name_ar = trim($data[3] ?? '');
|
||||
db()->prepare("INSERT INTO stock_units (name_en, name_ar, short_name_en, short_name_ar) VALUES (?, ?, ?, ?)")
|
||||
->execute([$name_en, $name_ar, $short_name_en, $short_name_ar]);
|
||||
$count++;
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
redirectWithMessage("Units imported! $count processed.", "index.php?page=stock_units");
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['import_items'])) {
|
||||
error_log("Import items triggered. POST: " . print_r($_POST, true));
|
||||
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === 0) {
|
||||
$tmpPath = $_FILES['excel_file']['tmp_name'];
|
||||
error_log("File uploaded to: $tmpPath");
|
||||
$firstBytes = file_get_contents($tmpPath, false, null, 0, 4);
|
||||
|
||||
if ($firstBytes === "PK\x03\x04") {
|
||||
$message = "Error: It looks like you uploaded an Excel (.xlsx) file. Please save it as CSV (UTF-8) and try again.";
|
||||
// EXCEL IMPORT VIA SimpleXLSX
|
||||
require_once __DIR__ . '/includes/SimpleXLSX.php';
|
||||
if ($xlsx = \Shuchkin\SimpleXLSX::parse($tmpPath)) {
|
||||
$rows = $xlsx->rows();
|
||||
$rowNum = 0;
|
||||
$count = 0;
|
||||
$errors = 0;
|
||||
foreach ($rows as $data) {
|
||||
$rowNum++;
|
||||
if ($rowNum === 1) continue; // Skip header
|
||||
|
||||
$sku = trim($data[0] ?? '');
|
||||
$name_en = trim($data[1] ?? '');
|
||||
$name_ar = trim($data[2] ?? '');
|
||||
$sale_price = (float)($data[3] ?? 0);
|
||||
$purchase_price = (float)($data[4] ?? 0);
|
||||
$qty = (float)($data[5] ?? 0);
|
||||
$vat_rate = (float)($data[6] ?? 0);
|
||||
|
||||
if (!$sku && !$name_en) { $errors++; continue; }
|
||||
|
||||
$check = db()->prepare("SELECT id FROM stock_items WHERE sku = ?");
|
||||
$check->execute([$sku]);
|
||||
if ($check->fetch()) {
|
||||
db()->prepare("UPDATE stock_items SET name_en = ?, name_ar = ?, sale_price = ?, purchase_price = ?, stock_quantity = ?, vat_rate = ? WHERE sku = ?")
|
||||
->execute([$name_en, $name_ar, $sale_price, $purchase_price, $qty, $vat_rate, $sku]);
|
||||
} else {
|
||||
db()->prepare("INSERT INTO stock_items (sku, name_en, name_ar, sale_price, purchase_price, stock_quantity, vat_rate) VALUES (?, ?, ?, ?, ?, ?, ?)")
|
||||
->execute([$sku, $name_en, $name_ar, $sale_price, $purchase_price, $qty, $vat_rate]);
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
redirectWithMessage("Excel Import completed! $count items processed." . ($errors > 0 ? " ($errors rows skipped.)" : ""), "index.php?page=items");
|
||||
} else {
|
||||
$message = "Error parsing Excel file: " . \Shuchkin\SimpleXLSX::parseError();
|
||||
}
|
||||
} else {
|
||||
// Check for BOM and skip it
|
||||
if (substr($firstBytes, 0, 3) === "\xEF\xBB\xBF") {
|
||||
@ -1666,14 +1868,216 @@ function getPromotionalPrice($item) {
|
||||
$message = "Expense recorded!";
|
||||
}
|
||||
|
||||
if (isset($_POST['import_customers'])) {
|
||||
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === 0) {
|
||||
$tmpPath = $_FILES['excel_file']['tmp_name'];
|
||||
$firstBytes = file_get_contents($tmpPath, false, null, 0, 4);
|
||||
$count = 0; $errors = 0;
|
||||
|
||||
if ($firstBytes === "PK\x03\x04") {
|
||||
require_once __DIR__ . '/includes/SimpleXLSX.php';
|
||||
if ($xlsx = \Shuchkin\SimpleXLSX::parse($tmpPath)) {
|
||||
foreach ($xlsx->rows() as $i => $data) {
|
||||
if ($i === 0) continue;
|
||||
$name = trim($data[0] ?? '');
|
||||
if (!$name) { $errors++; continue; }
|
||||
$email = trim($data[1] ?? '');
|
||||
$phone = trim($data[2] ?? '');
|
||||
$tax_id = trim($data[3] ?? '');
|
||||
$balance = (float)($data[4] ?? 0);
|
||||
|
||||
db()->prepare("INSERT INTO customers (name, email, phone, tax_id, balance) VALUES (?, ?, ?, ?, ?)")
|
||||
->execute([$name, $email, $phone, $tax_id, $balance]);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CSV fallback
|
||||
$handle = fopen($tmpPath, "r");
|
||||
fgetcsv($handle); // skip header
|
||||
while (($data = fgetcsv($handle)) !== FALSE) {
|
||||
$name = trim($data[0] ?? '');
|
||||
if (!$name) { $errors++; continue; }
|
||||
$email = trim($data[1] ?? '');
|
||||
$phone = trim($data[2] ?? '');
|
||||
$tax_id = trim($data[3] ?? '');
|
||||
$balance = (float)($data[4] ?? 0);
|
||||
db()->prepare("INSERT INTO customers (name, email, phone, tax_id, balance) VALUES (?, ?, ?, ?, ?)")
|
||||
->execute([$name, $email, $phone, $tax_id, $balance]);
|
||||
$count++;
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
redirectWithMessage("Customers imported! $count processed." . ($errors ? " ($errors skipped)" : ""), "index.php?page=customers");
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['import_suppliers'])) {
|
||||
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === 0) {
|
||||
$tmpPath = $_FILES['excel_file']['tmp_name'];
|
||||
$firstBytes = file_get_contents($tmpPath, false, null, 0, 4);
|
||||
$count = 0; $errors = 0;
|
||||
|
||||
if ($firstBytes === "PK\x03\x04") {
|
||||
require_once __DIR__ . '/includes/SimpleXLSX.php';
|
||||
if ($xlsx = \Shuchkin\SimpleXLSX::parse($tmpPath)) {
|
||||
foreach ($xlsx->rows() as $i => $data) {
|
||||
if ($i === 0) continue;
|
||||
$name = trim($data[0] ?? '');
|
||||
if (!$name) { $errors++; continue; }
|
||||
$email = trim($data[1] ?? '');
|
||||
$phone = trim($data[2] ?? '');
|
||||
$tax_id = trim($data[3] ?? '');
|
||||
$balance = (float)($data[4] ?? 0);
|
||||
|
||||
db()->prepare("INSERT INTO suppliers (name, email, phone, tax_id, balance) VALUES (?, ?, ?, ?, ?)")
|
||||
->execute([$name, $email, $phone, $tax_id, $balance]);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CSV fallback
|
||||
$handle = fopen($tmpPath, "r");
|
||||
fgetcsv($handle); // skip header
|
||||
while (($data = fgetcsv($handle)) !== FALSE) {
|
||||
$name = trim($data[0] ?? '');
|
||||
if (!$name) { $errors++; continue; }
|
||||
$email = trim($data[1] ?? '');
|
||||
$phone = trim($data[2] ?? '');
|
||||
$tax_id = trim($data[3] ?? '');
|
||||
$balance = (float)($data[4] ?? 0);
|
||||
db()->prepare("INSERT INTO suppliers (name, email, phone, tax_id, balance) VALUES (?, ?, ?, ?, ?)")
|
||||
->execute([$name, $email, $phone, $tax_id, $balance]);
|
||||
$count++;
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
redirectWithMessage("Suppliers imported! $count processed." . ($errors ? " ($errors skipped)" : ""), "index.php?page=suppliers");
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['import_categories'])) {
|
||||
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === 0) {
|
||||
$tmpPath = $_FILES['excel_file']['tmp_name'];
|
||||
$firstBytes = file_get_contents($tmpPath, false, null, 0, 4);
|
||||
$count = 0; $errors = 0;
|
||||
|
||||
if ($firstBytes === "PK\x03\x04") {
|
||||
require_once __DIR__ . '/includes/SimpleXLSX.php';
|
||||
if ($xlsx = \Shuchkin\SimpleXLSX::parse($tmpPath)) {
|
||||
foreach ($xlsx->rows() as $i => $data) {
|
||||
if ($i === 0) continue;
|
||||
$name_en = trim($data[0] ?? '');
|
||||
if (!$name_en) { $errors++; continue; }
|
||||
$name_ar = trim($data[1] ?? '');
|
||||
|
||||
db()->prepare("INSERT INTO stock_categories (name_en, name_ar) VALUES (?, ?)")
|
||||
->execute([$name_en, $name_ar]);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$handle = fopen($tmpPath, "r");
|
||||
fgetcsv($handle); // skip header
|
||||
while (($data = fgetcsv($handle)) !== FALSE) {
|
||||
$name_en = trim($data[0] ?? '');
|
||||
if (!$name_en) { $errors++; continue; }
|
||||
$name_ar = trim($data[1] ?? '');
|
||||
db()->prepare("INSERT INTO stock_categories (name_en, name_ar) VALUES (?, ?)")
|
||||
->execute([$name_en, $name_ar]);
|
||||
$count++;
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
redirectWithMessage("Categories imported! $count processed.", "index.php?page=stock_categories");
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['import_units'])) {
|
||||
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === 0) {
|
||||
$tmpPath = $_FILES['excel_file']['tmp_name'];
|
||||
$firstBytes = file_get_contents($tmpPath, false, null, 0, 4);
|
||||
$count = 0; $errors = 0;
|
||||
|
||||
if ($firstBytes === "PK\x03\x04") {
|
||||
require_once __DIR__ . '/includes/SimpleXLSX.php';
|
||||
if ($xlsx = \Shuchkin\SimpleXLSX::parse($tmpPath)) {
|
||||
foreach ($xlsx->rows() as $i => $data) {
|
||||
if ($i === 0) continue;
|
||||
$name_en = trim($data[0] ?? '');
|
||||
if (!$name_en) { $errors++; continue; }
|
||||
$name_ar = trim($data[1] ?? '');
|
||||
$short_name_en = trim($data[2] ?? '');
|
||||
$short_name_ar = trim($data[3] ?? '');
|
||||
|
||||
db()->prepare("INSERT INTO stock_units (name_en, name_ar, short_name_en, short_name_ar) VALUES (?, ?, ?, ?)")
|
||||
->execute([$name_en, $name_ar, $short_name_en, $short_name_ar]);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$handle = fopen($tmpPath, "r");
|
||||
fgetcsv($handle);
|
||||
while (($data = fgetcsv($handle)) !== FALSE) {
|
||||
$name_en = trim($data[0] ?? '');
|
||||
if (!$name_en) { $errors++; continue; }
|
||||
$name_ar = trim($data[1] ?? '');
|
||||
$short_name_en = trim($data[2] ?? '');
|
||||
$short_name_ar = trim($data[3] ?? '');
|
||||
db()->prepare("INSERT INTO stock_units (name_en, name_ar, short_name_en, short_name_ar) VALUES (?, ?, ?, ?)")
|
||||
->execute([$name_en, $name_ar, $short_name_en, $short_name_ar]);
|
||||
$count++;
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
redirectWithMessage("Units imported! $count processed.", "index.php?page=stock_units");
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['import_items'])) {
|
||||
error_log("Import items triggered. POST: " . print_r($_POST, true));
|
||||
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === 0) {
|
||||
$tmpPath = $_FILES['excel_file']['tmp_name'];
|
||||
error_log("File uploaded to: $tmpPath");
|
||||
$firstBytes = file_get_contents($tmpPath, false, null, 0, 4);
|
||||
|
||||
if ($firstBytes === "PK\x03\x04") {
|
||||
$message = "Error: It looks like you uploaded an Excel (.xlsx) file. Please save it as CSV (UTF-8) and try again.";
|
||||
// EXCEL IMPORT VIA SimpleXLSX
|
||||
require_once __DIR__ . '/includes/SimpleXLSX.php';
|
||||
if ($xlsx = \Shuchkin\SimpleXLSX::parse($tmpPath)) {
|
||||
$rows = $xlsx->rows();
|
||||
$rowNum = 0;
|
||||
$count = 0;
|
||||
$errors = 0;
|
||||
foreach ($rows as $data) {
|
||||
$rowNum++;
|
||||
if ($rowNum === 1) continue; // Skip header
|
||||
|
||||
$sku = trim($data[0] ?? '');
|
||||
$name_en = trim($data[1] ?? '');
|
||||
$name_ar = trim($data[2] ?? '');
|
||||
$sale_price = (float)($data[3] ?? 0);
|
||||
$purchase_price = (float)($data[4] ?? 0);
|
||||
$qty = (float)($data[5] ?? 0);
|
||||
$vat_rate = (float)($data[6] ?? 0);
|
||||
|
||||
if (!$sku && !$name_en) { $errors++; continue; }
|
||||
|
||||
$check = db()->prepare("SELECT id FROM stock_items WHERE sku = ?");
|
||||
$check->execute([$sku]);
|
||||
if ($check->fetch()) {
|
||||
db()->prepare("UPDATE stock_items SET name_en = ?, name_ar = ?, sale_price = ?, purchase_price = ?, stock_quantity = ?, vat_rate = ? WHERE sku = ?")
|
||||
->execute([$name_en, $name_ar, $sale_price, $purchase_price, $qty, $vat_rate, $sku]);
|
||||
} else {
|
||||
db()->prepare("INSERT INTO stock_items (sku, name_en, name_ar, sale_price, purchase_price, stock_quantity, vat_rate) VALUES (?, ?, ?, ?, ?, ?, ?)")
|
||||
->execute([$sku, $name_en, $name_ar, $sale_price, $purchase_price, $qty, $vat_rate]);
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
redirectWithMessage("Excel Import completed! $count items processed." . ($errors > 0 ? " ($errors rows skipped.)" : ""), "index.php?page=items");
|
||||
} else {
|
||||
$message = "Error parsing Excel file: " . \Shuchkin\SimpleXLSX::parseError();
|
||||
}
|
||||
} else {
|
||||
// Check for BOM and skip it
|
||||
if (substr($firstBytes, 0, 3) === "\xEF\xBB\xBF") {
|
||||
@ -2254,7 +2658,7 @@ if (isset($_POST['add_hr_department'])) {
|
||||
$group_id = (int)($_POST['group_id'] ?? 0) ?: null;
|
||||
if ($username && $password) {
|
||||
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$stmt = db()->prepare("INSERT INTO users (outlet_id, username, password, email, phone, group_id) VALUES (?, ?, ?, ?, ?, ?)");
|
||||
$stmt = db()->prepare("INSERT INTO users (username, password, email, phone, group_id) VALUES (?, ?, ?, ?, ?)");
|
||||
try {
|
||||
$stmt->execute([$username, $hashed_password, $email, $phone, $group_id]);
|
||||
$message = "User added successfully!";
|
||||
@ -10844,8 +11248,8 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-info py-2">
|
||||
<div class="mb-2">
|
||||
<small data-en="Please upload a CSV file with the following columns: SKU, English Name, Arabic Name, Sale Price, Cost Price." data-ar="يرجى رفع ملف CSV بالأعمدة التالية: الباركود، الاسم الإنجليزي، الاسم العربي، سعر البيع، سعر التكلفة.">
|
||||
Please upload a CSV file with the following columns: SKU, English Name, Arabic Name, Sale Price, Cost Price.
|
||||
<small data-en="Please upload an Excel (.xlsx) or CSV file with the following columns: SKU, English Name, Arabic Name, Sale Price, Cost Price." data-ar="يرجى رفع ملف إكسل (.xlsx) أو CSV بالأعمدة التالية: الباركود، الاسم الإنجليزي، الاسم العربي، سعر البيع، سعر التكلفة.">
|
||||
Please upload an Excel (.xlsx) or CSV file with the following columns: SKU, English Name, Arabic Name, Sale Price, Cost Price.
|
||||
</small>
|
||||
</div>
|
||||
<a href="index.php?action=download_items_template" class="btn btn-sm btn-primary">
|
||||
@ -10853,8 +11257,8 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
</a>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" data-en="Choose CSV File" data-ar="اختر ملف CSV">Choose CSV File</label>
|
||||
<input type="file" name="excel_file" class="form-control" accept=".csv" required>
|
||||
<label class="form-label" data-en="Choose File" data-ar="اختر الملف">Choose File</label>
|
||||
<input type="file" name="excel_file" class="form-control" accept=".csv, .xlsx" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@ -10877,13 +11281,13 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-info py-2">
|
||||
<small data-en="Please upload a CSV file with the following columns: Name, Email, Phone, Tax ID, Balance." data-ar="يرجى رفع ملف CSV بالأعمدة التالية: الاسم، البريد الإلكتروني، الهاتف، الرقم الضريبي، الرصيد.">
|
||||
Please upload a CSV file with the following columns: Name, Email, Phone, Tax ID, Balance.
|
||||
<small data-en="Please upload an Excel (.xlsx) or CSV file with the following columns: Name, Email, Phone, Tax ID, Balance." data-ar="يرجى رفع ملف إكسل (.xlsx) أو CSV بالأعمدة التالية: الاسم، البريد الإلكتروني، الهاتف، الرقم الضريبي، الرصيد.">
|
||||
Please upload an Excel (.xlsx) or CSV file with the following columns: Name, Email, Phone, Tax ID, Balance.
|
||||
</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" data-en="Choose CSV File" data-ar="اختر ملف CSV">Choose CSV File</label>
|
||||
<input type="file" name="excel_file" class="form-control" accept=".csv" required>
|
||||
<label class="form-label" data-en="Choose File" data-ar="اختر الملف">Choose File</label>
|
||||
<input type="file" name="excel_file" class="form-control" accept=".csv, .xlsx" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@ -10906,13 +11310,13 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-info py-2">
|
||||
<small data-en="Please upload a CSV file with the following columns: Name, Email, Phone, Tax ID, Balance." data-ar="يرجى رفع ملف CSV بالأعمدة التالية: الاسم، البريد الإلكتروني، الهاتف، الرقم الضريبي، الرصيد.">
|
||||
Please upload a CSV file with the following columns: Name, Email, Phone, Tax ID, Balance.
|
||||
<small data-en="Please upload an Excel (.xlsx) or CSV file with the following columns: Name, Email, Phone, Tax ID, Balance." data-ar="يرجى رفع ملف إكسل (.xlsx) أو CSV بالأعمدة التالية: الاسم، البريد الإلكتروني، الهاتف، الرقم الضريبي، الرصيد.">
|
||||
Please upload an Excel (.xlsx) or CSV file with the following columns: Name, Email, Phone, Tax ID, Balance.
|
||||
</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" data-en="Choose CSV File" data-ar="اختر ملف CSV">Choose CSV File</label>
|
||||
<input type="file" name="excel_file" class="form-control" accept=".csv" required>
|
||||
<label class="form-label" data-en="Choose File" data-ar="اختر الملف">Choose File</label>
|
||||
<input type="file" name="excel_file" class="form-control" accept=".csv, .xlsx" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@ -10935,13 +11339,13 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-info py-2">
|
||||
<small data-en="Please upload a CSV file with the following columns: Name (EN), Name (AR)." data-ar="يرجى رفع ملف CSV بالأعمدة التالية: الاسم (إنجليزي)، الاسم (عربي).">
|
||||
Please upload a CSV file with the following columns: Name (EN), Name (AR).
|
||||
<small data-en="Please upload an Excel (.xlsx) or CSV file with the following columns: Name (EN), Name (AR)." data-ar="يرجى رفع ملف إكسل (.xlsx) أو CSV بالأعمدة التالية: الاسم (إنجليزي)، الاسم (عربي).">
|
||||
Please upload an Excel (.xlsx) or CSV file with the following columns: Name (EN), Name (AR).
|
||||
</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" data-en="Choose CSV File" data-ar="اختر ملف CSV">Choose CSV File</label>
|
||||
<input type="file" name="excel_file" class="form-control" accept=".csv" required>
|
||||
<label class="form-label" data-en="Choose File" data-ar="اختر الملف">Choose File</label>
|
||||
<input type="file" name="excel_file" class="form-control" accept=".csv, .xlsx" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@ -10964,13 +11368,13 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-info py-2">
|
||||
<small data-en="Please upload a CSV file with the following columns: Name (EN), Name (AR), Short (EN), Short (AR)." data-ar="يرجى رفع ملف CSV بالأعمدة التالية: الاسم (إنجليزي)، الاسم (عربي)، الاختصار (إنجليزي)، الاختصار (عربي).">
|
||||
Please upload a CSV file with the following columns: Name (EN), Name (AR), Short (EN), Short (AR).
|
||||
<small data-en="Please upload an Excel (.xlsx) or CSV file with the following columns: Name (EN), Name (AR), Short (EN), Short (AR)." data-ar="يرجى رفع ملف إكسل (.xlsx) أو CSV بالأعمدة التالية: الاسم (إنجليزي)، الاسم (عربي)، الاختصار (إنجليزي)، الاختصار (عربي).">
|
||||
Please upload an Excel (.xlsx) or CSV file with the following columns: Name (EN), Name (AR), Short (EN), Short (AR).
|
||||
</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" data-en="Choose CSV File" data-ar="اختر ملف CSV">Choose CSV File</label>
|
||||
<input type="file" name="excel_file" class="form-control" accept=".csv" required>
|
||||
<label class="form-label" data-en="Choose File" data-ar="اختر الملف">Choose File</label>
|
||||
<input type="file" name="excel_file" class="form-control" accept=".csv, .xlsx" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
431
|
||||
481
|
||||
486
|
||||
498
|
||||
514
|
||||
518
|
||||
781
|
||||
828
|
||||
832
|
||||
855
|
||||
916
|
||||
932
|
||||
989
|
||||
1003
|
||||
1062
|
||||
1110
|
||||
1125
|
||||
1183
|
||||
1215
|
||||
1221
|
||||
1258
|
||||
1264
|
||||
1290
|
||||
1306
|
||||
1370
|
||||
1387
|
||||
1393
|
||||
1451
|
||||
1466
|
||||
1527
|
||||
1559
|
||||
1565
|
||||
1602
|
||||
1608
|
||||
1641
|
||||
1655
|
||||
1733
|
||||
1757
|
||||
1762
|
||||
1848
|
||||
1867
|
||||
1900
|
||||
1945
|
||||
1974
|
||||
2040
|
||||
2045
|
||||
2091
|
||||
2096
|
||||
2126
|
||||
2173
|
||||
2177
|
||||
2187
|
||||
2221
|
||||
2226
|
||||
2248
|
||||
2277
|
||||
2335
|
||||
2400
|
||||
2413
|
||||
2454
|
||||
2487
|
||||
2523
|
||||
2559
|
||||
2592
|
||||
2628
|
||||
@ -1,90 +0,0 @@
|
||||
$content = file_get_contents('index.php');
|
||||
|
||||
$search = " default:
|
||||
if (can('dashboard_view')) {
|
||||
\$data['customers'] = db()->query(\"SELECT * FROM customers ORDER BY id DESC LIMIT 5\")->fetchAll();
|
||||
\$data['stats'] = [
|
||||
'total_customers' => db()->query(\"SELECT COUNT(*) FROM customers\")->fetchColumn(),
|
||||
'total_items' => db()->query(\"SELECT COUNT(*) FROM stock_items\")->fetchColumn(),
|
||||
'total_sales' => (db()->query(\"SELECT SUM(total_with_vat) FROM invoices\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(net_amount) FROM pos_transactions WHERE status = 'completed'\")->fetchColumn() ?: 0),
|
||||
'total_received' => (db()->query(\"SELECT SUM(amount) FROM payments\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(amount) FROM pos_payments\")->fetchColumn() ?: 0),
|
||||
'total_purchases' => db()->query(\"SELECT SUM(total_with_vat) FROM purchases\")->fetchColumn() ?: 0,
|
||||
'total_paid' => db()->query(\"SELECT SUM(amount) FROM purchase_payments\")->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(),
|
||||
'low_stock_items_count' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE stock_quantity <= min_stock_level\")->fetchColumn(),
|
||||
];
|
||||
\$data['stats']['total_receivable'] = \$data['stats']['total_sales'] - \$data['stats']['total_received'];
|
||||
\$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 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 GROUP BY label ORDER BY label ASC LIMIT 5\")->fetchAll(PDO::FETCH_ASSOC);
|
||||
}";
|
||||
|
||||
$replace = " default:
|
||||
if (can('dashboard_view')) {
|
||||
\$oW = ((\$_SESSION['outlet_id'] ?? 1) == 0) ? \"\" : \"WHERE outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);
|
||||
\$oA = ((\$_SESSION['outlet_id'] ?? 1) == 0) ? \"\" : \"AND outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);
|
||||
\$data['customers'] = db()->query(\"SELECT * FROM customers ORDER BY id DESC LIMIT 5\")->fetchAll();
|
||||
\$data['stats'] = [
|
||||
'total_customers' => db()->query(\"SELECT COUNT(*) FROM customers\")->fetchColumn(),
|
||||
'total_items' => db()->query(\"SELECT COUNT(*) FROM stock_items\")->fetchColumn(),
|
||||
'total_sales' => (db()->query(\"SELECT SUM(total_with_vat) FROM invoices \$oW\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(net_amount) FROM pos_transactions WHERE status = 'completed' \$oA\")->fetchColumn() ?: 0),
|
||||
'total_received' => (db()->query(\"SELECT SUM(amount) FROM payments \$oW\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(amount) FROM pos_payments \$oW\")->fetchColumn() ?: 0),
|
||||
'total_purchases' => db()->query(\"SELECT SUM(total_with_vat) FROM purchases \$oW\")->fetchColumn() ?: 0,
|
||||
'total_paid' => db()->query(\"SELECT SUM(amount) FROM purchase_payments \$oW\")->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(),
|
||||
'low_stock_items_count' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE stock_quantity <= min_stock_level\")->fetchColumn(),
|
||||
];
|
||||
\$data['stats']['total_receivable'] = \$data['stats']['total_sales'] - \$data['stats']['total_received'];
|
||||
\$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 \$oW 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 \$oW GROUP BY label ORDER BY label ASC LIMIT 5\")->fetchAll(PDO::FETCH_ASSOC);
|
||||
}";
|
||||
|
||||
if (strpos($content, $search) !== false) {
|
||||
$content = str_replace($search, $replace, $content);
|
||||
echo "Dashboard patched successfully\n";
|
||||
file_put_contents('index.php', $content);
|
||||
} else {
|
||||
echo "Could not find target to patch\n";
|
||||
}
|
||||
$content = file_get_contents('index.php');
|
||||
|
||||
$replacements = [
|
||||
[
|
||||
"case 'sales':\n case 'purchases':\n \$type = (\$page === 'sales') ? 'sale' : 'purchase';\n \$table = (\$type === 'purchase') ? 'purchases' : 'invoices';\n \$cust_supplier_col = (\$type === 'purchase') ? 'supplier_id' : 'customer_id';\n \$cust_supplier_table = (\$type === 'purchase') ? 'suppliers' : 'customers';\n \n \$where = [\"1=1\"];",
|
||||
"case 'sales':\n case 'purchases':\n \$type = (\$page === 'sales') ? 'sale' : 'purchase';\n \$table = (\$type === 'purchase') ? 'purchases' : 'invoices';\n \$cust_supplier_col = (\$type === 'purchase') ? 'supplier_id' : 'customer_id';\n \$cust_supplier_table = (\$type === 'purchase') ? 'suppliers' : 'customers';\n \n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"v.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
|
||||
],
|
||||
[
|
||||
"case 'quotations':\n \$where = [\"1=1\"];",
|
||||
"case 'quotations':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"q.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
|
||||
],
|
||||
[
|
||||
"case 'lpos':\n \$where = [\"1=1\"];",
|
||||
"case 'lpos':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"q.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
|
||||
],
|
||||
[
|
||||
"case 'expenses':\n \$where = [\"1=1\"];",
|
||||
"case 'expenses':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"e.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
|
||||
],
|
||||
[
|
||||
"case 'payments':",
|
||||
"case 'payments':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"p.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($replacements as $rep) {
|
||||
if (strpos($content, $rep[0]) !== false) {
|
||||
$content = str_replace($rep[0], $rep[1], $content);
|
||||
echo "Patched successfully\n";
|
||||
} else {
|
||||
echo "Could not find target to patch\n";
|
||||
}
|
||||
}
|
||||
|
||||
file_put_contents('index.php', $content);
|
||||
@ -1,56 +0,0 @@
|
||||
<?php
|
||||
$content = file_get_contents('index.php');
|
||||
|
||||
$search = " default:
|
||||
if (can('dashboard_view')) {
|
||||
\$data['customers'] = db()->query(\"SELECT * FROM customers ORDER BY id DESC LIMIT 5\")->fetchAll();
|
||||
\$data['stats'] = [
|
||||
'total_customers' => db()->query(\"SELECT COUNT(*) FROM customers\")->fetchColumn(),
|
||||
'total_items' => db()->query(\"SELECT COUNT(*) FROM stock_items\")->fetchColumn(),
|
||||
'total_sales' => (db()->query(\"SELECT SUM(total_with_vat) FROM invoices\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(net_amount) FROM pos_transactions WHERE status = 'completed'\")->fetchColumn() ?: 0),
|
||||
'total_received' => (db()->query(\"SELECT SUM(amount) FROM payments\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(amount) FROM pos_payments\")->fetchColumn() ?: 0),
|
||||
'total_purchases' => db()->query(\"SELECT SUM(total_with_vat) FROM purchases\")->fetchColumn() ?: 0,
|
||||
'total_paid' => db()->query(\"SELECT SUM(amount) FROM purchase_payments\")->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(),
|
||||
'low_stock_items_count' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE stock_quantity <= min_stock_level\")->fetchColumn(),
|
||||
];
|
||||
\$data['stats']['total_receivable'] = \$data['stats']['total_sales'] - \$data['stats']['total_received'];
|
||||
\$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 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 GROUP BY label ORDER BY label ASC LIMIT 5\")->fetchAll(PDO::FETCH_ASSOC);
|
||||
}";
|
||||
|
||||
$replace = " default:
|
||||
if (can('dashboard_view')) {
|
||||
\$oW = ((\$_SESSION['outlet_id'] ?? 1) == 0) ? \"\" : \"WHERE outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);
|
||||
\$oA = ((\$_SESSION['outlet_id'] ?? 1) == 0) ? \"\" : \"AND outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);
|
||||
\$data['customers'] = db()->query(\"SELECT * FROM customers ORDER BY id DESC LIMIT 5\")->fetchAll();
|
||||
\$data['stats'] = [
|
||||
'total_customers' => db()->query(\"SELECT COUNT(*) FROM customers\")->fetchColumn(),
|
||||
'total_items' => db()->query(\"SELECT COUNT(*) FROM stock_items\")->fetchColumn(),
|
||||
'total_sales' => (db()->query(\"SELECT SUM(total_with_vat) FROM invoices \$oW\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(net_amount) FROM pos_transactions WHERE status = 'completed' \$oA\")->fetchColumn() ?: 0),
|
||||
'total_received' => (db()->query(\"SELECT SUM(amount) FROM payments \$oW\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(amount) FROM pos_payments \$oW\")->fetchColumn() ?: 0),
|
||||
'total_purchases' => db()->query(\"SELECT SUM(total_with_vat) FROM purchases \$oW\")->fetchColumn() ?: 0,
|
||||
'total_paid' => db()->query(\"SELECT SUM(amount) FROM purchase_payments \$oW\")->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(),
|
||||
'low_stock_items_count' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE stock_quantity <= min_stock_level\")->fetchColumn(),
|
||||
];
|
||||
\$data['stats']['total_receivable'] = \$data['stats']['total_sales'] - \$data['stats']['total_received'];
|
||||
\$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 \$oW 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 \$oW GROUP BY label ORDER BY label ASC LIMIT 5\")->fetchAll(PDO::FETCH_ASSOC);
|
||||
}";
|
||||
|
||||
if (strpos($content, $search) !== false) {
|
||||
$content = str_replace($search, $replace, $content);
|
||||
echo "Dashboard patched successfully\n";
|
||||
file_put_contents('index.php', $content);
|
||||
} else {
|
||||
echo "Could not find target to patch\n";
|
||||
}
|
||||
@ -1,68 +0,0 @@
|
||||
<?php
|
||||
$content = file_get_contents('index.php');
|
||||
|
||||
$patterns = [
|
||||
// Invoices (POS)
|
||||
[
|
||||
'INSERT INTO invoices (transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by)',
|
||||
'INSERT INTO invoices (outlet_id, transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by)',
|
||||
'?, ?, ?, ?, ?, ?, ?, ?, ?, \'paid\', ?, 1, ?, ?, ?',
|
||||
'".(int)($_SESSION["outlet_id"] ?? 1).", ?, ?, ?, ?, ?, ?, ?, ?, \'paid\', ?, 1, ?, ?, ?'
|
||||
],
|
||||
// Quotations
|
||||
[
|
||||
'INSERT INTO quotations (customer_id, quotation_date, valid_until, status, total_amount, vat_amount, total_with_vat)',
|
||||
'INSERT INTO quotations (outlet_id, customer_id, quotation_date, valid_until, status, total_amount, vat_amount, total_with_vat)',
|
||||
'?, ?, ?, ?, ?, ?, ?',
|
||||
'".(int)($_SESSION["outlet_id"] ?? 1).", ?, ?, ?, ?, ?, ?, ?'
|
||||
],
|
||||
// Lpos
|
||||
[
|
||||
'INSERT INTO lpos (supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions)',
|
||||
'INSERT INTO lpos (outlet_id, supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions)',
|
||||
'?, ?, ?, \'pending\', ?, ?, ?, ?',
|
||||
'".(int)($_SESSION["outlet_id"] ?? 1).", ?, ?, ?, \'pending\', ?, ?, ?, ?'
|
||||
],
|
||||
// Invoices (General)
|
||||
[
|
||||
'INSERT INTO invoices (customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
|
||||
'INSERT INTO invoices (outlet_id, customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
|
||||
'?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0',
|
||||
'".(int)($_SESSION["outlet_id"] ?? 1).", ?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0'
|
||||
],
|
||||
// Purchases (General)
|
||||
[
|
||||
'INSERT INTO purchases (supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
|
||||
'INSERT INTO purchases (outlet_id, supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
|
||||
'?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0',
|
||||
'".(int)($_SESSION["outlet_id"] ?? 1).", ?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0'
|
||||
],
|
||||
// Expenses
|
||||
[
|
||||
'INSERT INTO expenses (category_id, amount, expense_date, reference_no, description)',
|
||||
'INSERT INTO expenses (outlet_id, category_id, amount, expense_date, reference_no, description)',
|
||||
'(int)$_POST[\'category_id\'], $amt, $date, $_POST[\'reference_no\'] ?? \'\', $desc',
|
||||
'".(int)($_SESSION["outlet_id"] ?? 1).", (int)$_POST[\'category_id\'], $amt, $date, $_POST[\'reference_no\'] ?? \'\', $desc'
|
||||
],
|
||||
// Users
|
||||
[
|
||||
'INSERT INTO users (username, password, email, phone, group_id)',
|
||||
'INSERT INTO users (outlet_id, username, password, email, phone, group_id)',
|
||||
'?, ?, ?, ?, ?',
|
||||
'".(int)($_SESSION["outlet_id"] ?? 1).", ?, ?, ?, ?, ?'
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($patterns as $p) {
|
||||
if (strpos($content, $p[0]) !== false) {
|
||||
$content = str_replace($p[0], $p[1], $content);
|
||||
$content = str_replace($p[2], $p[3], $content);
|
||||
echo "Patched " . explode(' ', $p[0])[2] . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Don't forget invoice_items insertion
|
||||
$p1 = 'INSERT INTO invoice_items (invoice_id, item_id, quantity, unit_price, vat_amount, total_price) VALUES (?, ?, ?, ?, ?, ?)';
|
||||
$p2 = 'INSERT INTO invoice_items (invoice_id, item_id, quantity, unit_price, vat_amount, total_price) VALUES (?, ?, ?, ?, ?, ?)';
|
||||
// Actually wait, invoice_items doesn't have outlet_id... No wait, does it?
|
||||
file_put_contents('index.php', $content);
|
||||
@ -1,78 +0,0 @@
|
||||
<?php
|
||||
$content = file_get_contents('index.php');
|
||||
|
||||
$replacements = [
|
||||
// Invoices (POS)
|
||||
[
|
||||
'INSERT INTO invoices (transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, \'paid\', ?, 1, ?, ?, ?)',
|
||||
'INSERT INTO invoices (outlet_id, transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, \'paid\', ?, 1, ?, ?, ?)'
|
||||
],
|
||||
[
|
||||
'execute([$transaction_no, $customer_id, date(\'Y-m-d\'), \'pos\', $total_amount, $tax_amount, $net_amount, $net_amount, $session_id, $discount_amount, $loyalty_redeemed, $_SESSION[\'user_id\']])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), $transaction_no, $customer_id, date(\'Y-m-d\'), \'pos\', $total_amount, $tax_amount, $net_amount, $net_amount, $session_id, $discount_amount, $loyalty_redeemed, $_SESSION[\'user_id\']])'
|
||||
],
|
||||
// Quotations
|
||||
[
|
||||
'INSERT INTO quotations (customer_id, quotation_date, valid_until, status, total_amount, vat_amount, total_with_vat) VALUES (?, ?, ?, \'pending\', ?, ?, ?)',
|
||||
'INSERT INTO quotations (outlet_id, customer_id, quotation_date, valid_until, status, total_amount, vat_amount, total_with_vat) VALUES (?, ?, ?, ?, \'pending\', ?, ?, ?)'
|
||||
],
|
||||
[
|
||||
'execute([$_POST[\'customer_id\'], $_POST[\'date\'], $_POST[\'valid_until\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'customer_id\'], $_POST[\'date\'], $_POST[\'valid_until\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])'
|
||||
],
|
||||
// Lpos
|
||||
[
|
||||
'INSERT INTO lpos (supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions) VALUES (?, ?, ?, \'pending\', ?, ?, ?, ?)',
|
||||
'INSERT INTO lpos (outlet_id, supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions) VALUES (?, ?, ?, ?, \'pending\', ?, ?, ?, ?)'
|
||||
],
|
||||
[
|
||||
'execute([$_POST[\'supplier_id\'], $_POST[\'date\'], $_POST[\'delivery_date\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], $_POST[\'terms\'] ?? \'\'])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'supplier_id\'], $_POST[\'date\'], $_POST[\'delivery_date\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], $_POST[\'terms\'] ?? \'\'])'
|
||||
],
|
||||
// Invoices (General)
|
||||
[
|
||||
'INSERT INTO invoices (customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0)',
|
||||
'INSERT INTO invoices (outlet_id, customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0)'
|
||||
],
|
||||
[
|
||||
'execute([$_POST[\'customer_id\'], $_POST[\'date\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'customer_id\'], $_POST[\'date\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])'
|
||||
],
|
||||
// Purchases (General)
|
||||
[
|
||||
'INSERT INTO purchases (supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0)',
|
||||
'INSERT INTO purchases (outlet_id, supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0)'
|
||||
],
|
||||
[
|
||||
'execute([$_POST[\'supplier_id\'], $_POST[\'date\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'supplier_id\'], $_POST[\'date\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])'
|
||||
],
|
||||
// Expenses
|
||||
[
|
||||
'INSERT INTO expenses (category_id, amount, expense_date, reference_no, description) VALUES (?, ?, ?, ?, ?)',
|
||||
'INSERT INTO expenses (outlet_id, category_id, amount, expense_date, reference_no, description) VALUES (?, ?, ?, ?, ?, ?)'
|
||||
],
|
||||
[
|
||||
'execute([(int)$_POST[\'category_id\'], $amt, $date, $_POST[\'reference_no\'] ?? \'\', $desc])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), (int)$_POST[\'category_id\'], $amt, $date, $_POST[\'reference_no\'] ?? \'\', $desc])'
|
||||
],
|
||||
// Users
|
||||
[
|
||||
'INSERT INTO users (username, password, email, phone, group_id) VALUES (?, ?, ?, ?, ?)',
|
||||
'INSERT INTO users (outlet_id, username, password, email, phone, group_id) VALUES (?, ?, ?, ?, ?, ?)'
|
||||
],
|
||||
[
|
||||
'execute([$_POST[\'username\'], password_hash($_POST[\'password\'], PASSWORD_DEFAULT), $_POST[\'email\'] ?? \'\', $_POST[\'phone\'] ?? \'\', (int)$_POST[\'group_id\']])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'username\'], password_hash($_POST[\'password\'], PASSWORD_DEFAULT), $_POST[\'email\'] ?? \'\', $_POST[\'phone\'] ?? \'\', (int)$_POST[\'group_id\']])'
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($replacements as $p) {
|
||||
if (strpos($content, $p[0]) !== false) {
|
||||
$content = str_replace($p[0], $p[1], $content);
|
||||
echo "Replaced OK.\n";
|
||||
} else {
|
||||
echo "Not found: " . substr($p[0], 0, 40) . "\n";
|
||||
}
|
||||
}
|
||||
file_put_contents('index.php', $content);
|
||||
@ -1,76 +0,0 @@
|
||||
<?php
|
||||
$content = file_get_contents('index.php');
|
||||
|
||||
$patterns = [
|
||||
// Invoices (POS)
|
||||
[
|
||||
'INSERT INTO invoices (transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by)',
|
||||
'INSERT INTO invoices (outlet_id, transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by)',
|
||||
'execute([$transaction_no, $customer_id, date(\'Y-m-d\'), \'pos\', $total_amount, $tax_amount, $net_amount, $net_amount, $session_id, $discount_amount, $loyalty_redeemed, $_SESSION[\'user_id\']])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), $transaction_no, $customer_id, date(\'Y-m-d\'), \'pos\', $total_amount, $tax_amount, $net_amount, $net_amount, $session_id, $discount_amount, $loyalty_redeemed, $_SESSION[\'user_id\']])'
|
||||
],
|
||||
// Quotations
|
||||
[
|
||||
'INSERT INTO quotations (customer_id, quotation_date, valid_until, status, total_amount, vat_amount, total_with_vat)',
|
||||
'INSERT INTO quotations (outlet_id, customer_id, quotation_date, valid_until, status, total_amount, vat_amount, total_with_vat)',
|
||||
'execute([$_POST[\'customer_id\'], $_POST[\'date\'], $_POST[\'valid_until\'], \'pending\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'customer_id\'], $_POST[\'date\'], $_POST[\'valid_until\'], \'pending\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])'
|
||||
],
|
||||
// Lpos
|
||||
[
|
||||
'INSERT INTO lpos (supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions)',
|
||||
'INSERT INTO lpos (outlet_id, supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions)',
|
||||
'execute([$_POST[\'supplier_id\'], $_POST[\'date\'], $_POST[\'delivery_date\'], \'pending\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], $_POST[\'terms\'] ?? \'\'])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'supplier_id\'], $_POST[\'date\'], $_POST[\'delivery_date\'], \'pending\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], $_POST[\'terms\'] ?? \'\'])'
|
||||
],
|
||||
// Invoices (General)
|
||||
[
|
||||
'INSERT INTO invoices (customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
|
||||
'INSERT INTO invoices (outlet_id, customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
|
||||
'execute([$_POST[\'customer_id\'], $_POST[\'date\'], \'unpaid\', \'credit\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], 0])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'customer_id\'], $_POST[\'date\'], \'unpaid\', \'credit\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], 0])'
|
||||
],
|
||||
// Purchases (General)
|
||||
[
|
||||
'INSERT INTO purchases (supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
|
||||
'INSERT INTO purchases (outlet_id, supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
|
||||
'execute([$_POST[\'supplier_id\'], $_POST[\'date\'], \'unpaid\', \'credit\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], 0])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'supplier_id\'], $_POST[\'date\'], \'unpaid\', \'credit\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], 0])'
|
||||
],
|
||||
// Expenses
|
||||
[
|
||||
'INSERT INTO expenses (category_id, amount, expense_date, reference_no, description)',
|
||||
'INSERT INTO expenses (outlet_id, category_id, amount, expense_date, reference_no, description)',
|
||||
'execute([(int)$_POST[\'category_id\'], $amt, $date, $_POST[\'reference_no\'] ?? \'\', $desc])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), (int)$_POST[\'category_id\'], $amt, $date, $_POST[\'reference_no\'] ?? \'\', $desc])'
|
||||
],
|
||||
// Users
|
||||
[
|
||||
'INSERT INTO users (username, password, email, phone, group_id)',
|
||||
'INSERT INTO users (outlet_id, username, password, email, phone, group_id)',
|
||||
'execute([$_POST[\'username\'], password_hash($_POST[\'password\'], PASSWORD_DEFAULT), $_POST[\'email\'] ?? \'\', $_POST[\'phone\'] ?? \'\', (int)$_POST[\'group_id\']])',
|
||||
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'username\'], password_hash($_POST[\'password\'], PASSWORD_DEFAULT), $_POST[\'email\'] ?? \'\', $_POST[\'phone\'] ?? \'\', (int)$_POST[\'group_id\']])'
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($patterns as $i => $p) {
|
||||
if (strpos($content, $p[0]) !== false) {
|
||||
$content = str_replace($p[0], $p[1], $content);
|
||||
$content = str_replace($p[2], $p[3], $content);
|
||||
echo "Patched #$i \n";
|
||||
|
||||
// Let's also add the ? to the query string
|
||||
$q0 = "VALUES (";
|
||||
$q1 = "VALUES (?, ";
|
||||
// We only want to add it inside the specific INSERT query
|
||||
$insert_start = strpos($content, $p[1]);
|
||||
if ($insert_start !== false) {
|
||||
$values_start = strpos($content, 'VALUES (', $insert_start);
|
||||
if ($values_start !== false) {
|
||||
$content = substr_replace($content, 'VALUES (?, ', $values_start, 9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file_put_contents('index.php', $content);
|
||||
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
$content = file_get_contents('index.php');
|
||||
|
||||
$replacements = [
|
||||
[
|
||||
"case 'sales':\n case 'purchases':\n \$type = (\$page === 'sales') ? 'sale' : 'purchase';\n \$table = (\$type === 'purchase') ? 'purchases' : 'invoices';\n \$cust_supplier_col = (\$type === 'purchase') ? 'supplier_id' : 'customer_id';\n \$cust_supplier_table = (\$type === 'purchase') ? 'suppliers' : 'customers';\n \n \$where = [\"1=1\"];",
|
||||
"case 'sales':\n case 'purchases':\n \$type = (\$page === 'sales') ? 'sale' : 'purchase';\n \$table = (\$type === 'purchase') ? 'purchases' : 'invoices';\n \$cust_supplier_col = (\$type === 'purchase') ? 'supplier_id' : 'customer_id';\n \$cust_supplier_table = (\$type === 'purchase') ? 'suppliers' : 'customers';\n \n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"v.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
|
||||
],
|
||||
[
|
||||
"case 'quotations':\n \$where = [\"1=1\"];",
|
||||
"case 'quotations':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"q.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
|
||||
],
|
||||
[
|
||||
"case 'lpos':\n \$where = [\"1=1\"];",
|
||||
"case 'lpos':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"q.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
|
||||
],
|
||||
[
|
||||
"case 'expenses':\n \$where = [\"1=1\"];",
|
||||
"case 'expenses':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"e.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
|
||||
],
|
||||
[
|
||||
"case 'payments':",
|
||||
"case 'payments':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"p.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($replacements as $rep) {
|
||||
if (strpos($content, $rep[0]) !== false) {
|
||||
$content = str_replace($rep[0], $rep[1], $content);
|
||||
echo "Patched successfully\n";
|
||||
} else {
|
||||
echo "Could not find target to patch\n";
|
||||
}
|
||||
}
|
||||
|
||||
file_put_contents('index.php', $content);
|
||||
@ -1,13 +0,0 @@
|
||||
<?php
|
||||
$content = file_get_contents('index.php');
|
||||
|
||||
$tables = ['users', 'invoices', 'lpos', 'purchases', 'quotations', 'expenses', 'payments', 'purchase_payments', 'pos_transactions', 'customers', 'suppliers', 'stock_items', 'pos_held_carts', 'loyalty_transactions', 'purchase_returns', 'sales_returns'];
|
||||
|
||||
foreach ($tables as $t) {
|
||||
// Regex to match: INSERT INTO table (...) VALUES (...)
|
||||
// and replace with INSERT INTO table (outlet_id, ...) VALUES (current_outlet_id(), ...)
|
||||
// Note: since this is PDO prepare, we can't just inject current_outlet_id() directly into VALUES if it's parametrized, but we CAN inject the value if we just use a session variable call directly in SQL, or `?` and prepend the param.
|
||||
// Wait, simpler: "INSERT INTO $t (outlet_id, " . "(current_outlet_id())" is safe enough?
|
||||
// Let's look at a simpler regex.
|
||||
}
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
require 'db/config.php';
|
||||
$db = db();
|
||||
try {
|
||||
$db->exec("DROP FUNCTION IF EXISTS current_outlet_id");
|
||||
$db->exec("CREATE FUNCTION current_outlet_id() RETURNS INT DETERMINISTIC RETURN @session_outlet_id");
|
||||
|
||||
$db->exec("RENAME TABLE invoices TO _invoices");
|
||||
$db->exec("CREATE VIEW invoices AS SELECT * FROM _invoices WHERE outlet_id = current_outlet_id() OR current_outlet_id() IS NULL");
|
||||
|
||||
$db->exec("SET @session_outlet_id = 1");
|
||||
$db->exec("INSERT INTO invoices (customer_id, invoice_date, status, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (1, '2026-01-01', 'unpaid', 100, 5, 105, 0)");
|
||||
echo "Insert OK\n";
|
||||
|
||||
$stmt = $db->query("SELECT * FROM invoices ORDER BY id DESC LIMIT 1");
|
||||
print_r($stmt->fetch(PDO::FETCH_ASSOC));
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
$db->exec("DROP VIEW IF EXISTS invoices");
|
||||
$db->exec("RENAME TABLE _invoices TO invoices");
|
||||
$db->exec("DELETE FROM invoices WHERE customer_id=1 AND total_amount=100");
|
||||
$db->exec("DROP FUNCTION IF EXISTS current_outlet_id");
|
||||
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
require 'db/config.php';
|
||||
$db = db();
|
||||
try {
|
||||
$db->exec("RENAME TABLE invoices TO _invoices");
|
||||
$db->exec("CREATE FUNCTION current_outlet_id() RETURNS INT DETERMINISTIC RETURN @session_outlet_id");
|
||||
$db->exec("CREATE VIEW invoices AS SELECT * FROM _invoices WHERE outlet_id = current_outlet_id() OR current_outlet_id() IS NULL");
|
||||
|
||||
$db->exec("SET @session_outlet_id = 1");
|
||||
$db->exec("INSERT INTO invoices (customer_id, invoice_date, status, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (1, '2026-01-01', 'unpaid', 100, 5, 105, 0)");
|
||||
$id = $db->lastInsertId();
|
||||
echo "Last Insert ID: " . $id . "\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
$db->exec("DROP VIEW IF EXISTS invoices");
|
||||
$db->exec("RENAME TABLE _invoices TO invoices");
|
||||
$db->exec("DELETE FROM invoices WHERE customer_id=1 AND total_amount=100");
|
||||
$db->exec("DROP FUNCTION IF EXISTS current_outlet_id");
|
||||
@ -1,23 +0,0 @@
|
||||
<?php
|
||||
require 'db/config.php';
|
||||
$db = db();
|
||||
try {
|
||||
$db->exec("RENAME TABLE invoices TO _invoices");
|
||||
$db->exec("CREATE VIEW invoices AS SELECT * FROM _invoices WHERE outlet_id = @session_outlet_id OR @session_outlet_id IS NULL");
|
||||
|
||||
$db->exec("SET @session_outlet_id = 1");
|
||||
// Test INSERT
|
||||
$db->exec("INSERT INTO invoices (customer_id, invoice_date, status, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (1, '2026-01-01', 'unpaid', 100, 5, 105, 0)");
|
||||
echo "Insert OK\n";
|
||||
// Check if outlet_id is populated. It won't be, because the view doesn't auto-fill!
|
||||
// We still need the trigger for INSERT.
|
||||
$stmt = $db->query("SELECT * FROM invoices ORDER BY id DESC LIMIT 1");
|
||||
print_r($stmt->fetch(PDO::FETCH_ASSOC));
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
// rollback
|
||||
$db->exec("DROP VIEW IF EXISTS invoices");
|
||||
$db->exec("RENAME TABLE _invoices TO invoices");
|
||||
$db->exec("DELETE FROM invoices WHERE customer_id=1 AND total_amount=100");
|
||||
372
wheres.txt
372
wheres.txt
@ -1,372 +0,0 @@
|
||||
if ($type === 'sales' || $type === 'purchases') {
|
||||
$table = ($type === 'sales') ? 'invoices' : 'purchases';
|
||||
$cust_table = ($type === 'sales') ? 'customers' : 'suppliers';
|
||||
$cust_col = ($type === 'sales') ? 'customer_id' : 'supplier_id';
|
||||
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
if (!empty($_GET['search'])) {
|
||||
$s = $_GET['search'];
|
||||
$clean_id = preg_replace('/[^0-9]/', '', $s);
|
||||
if ($clean_id !== '') {
|
||||
$where[] = "(v.id LIKE ? OR c.name LIKE ? OR v.id = ?)";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
$params[] = $clean_id;
|
||||
} else {
|
||||
$where[] = "(v.id LIKE ? OR c.name LIKE ?)";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
}
|
||||
}
|
||||
if (!empty($_GET['customer_id'])) { $where[] = "v.$cust_col = ?"; $params[] = $_GET['customer_id']; }
|
||||
if (!empty($_GET['start_date'])) { $where[] = "v.invoice_date >= ?"; $params[] = $_GET['start_date']; }
|
||||
if (!empty($_GET['end_date'])) { $where[] = "v.invoice_date <= ?"; $params[] = $_GET['end_date']; }
|
||||
$whereSql = implode(" AND ", $where);
|
||||
|
||||
--
|
||||
$stmt->execute($params);
|
||||
$headers = ['Invoice ID', 'Customer/Supplier', 'Date', 'Payment', 'Status', 'Total', 'Paid', 'Balance'];
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $rows[] = $row;
|
||||
} elseif ($type === 'customers' || $type === 'suppliers') {
|
||||
$table = ($type === 'suppliers') ? 'suppliers' : 'customers';
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
if (!empty($_GET['search'])) { $where[] = "(name LIKE ? OR email LIKE ? OR phone LIKE ? OR tax_id LIKE ?)"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; }
|
||||
if (!empty($_GET['start_date'])) { $where[] = "DATE(created_at) >= ?"; $params[] = $_GET['start_date']; }
|
||||
if (!empty($_GET['end_date'])) { $where[] = "DATE(created_at) <= ?"; $params[] = $_GET['end_date']; }
|
||||
$whereSql = implode(" AND ", $where);
|
||||
$stmt = db()->prepare("SELECT id, name, email, phone, tax_id, balance, created_at FROM $table WHERE $whereSql ORDER BY id DESC");
|
||||
$stmt->execute($params);
|
||||
$headers = ['ID', 'Name', 'Email', 'Phone', 'Tax ID', 'Balance', 'Created At'];
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $rows[] = $row;
|
||||
} elseif ($type === 'items') {
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
if (!empty($_GET['search'])) { $where[] = "(i.name_en LIKE ? OR i.name_ar LIKE ? OR i.sku LIKE ?)"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; }
|
||||
$whereSql = implode(" AND ", $where);
|
||||
$stmt = db()->prepare("SELECT i.sku, i.name_en, i.name_ar, c.name_en as category, i.purchase_price, i.sale_price, i.stock_quantity, i.vat_rate
|
||||
FROM stock_items i LEFT JOIN stock_categories c ON i.category_id = c.id
|
||||
WHERE $whereSql ORDER BY i.id DESC");
|
||||
$stmt->execute($params);
|
||||
$headers = ['SKU', 'Name (EN)', 'Name (AR)', 'Category', 'Purchase Price', 'Sale Price', 'Quantity', 'VAT %'];
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $rows[] = $row;
|
||||
} elseif ($type === 'expenses') {
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
$stmt = db()->prepare("SELECT e.id, c.name_en as category, e.amount, e.expense_date, e.reference_no, e.description
|
||||
FROM expenses e JOIN expense_categories c ON e.category_id = c.id
|
||||
ORDER BY e.expense_date DESC");
|
||||
$stmt->execute();
|
||||
$headers = ['ID', 'Category', 'Amount', 'Date', 'Reference', 'Description'];
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $rows[] = $row;
|
||||
} elseif ($type === 'quotations') {
|
||||
$stmt = db()->prepare("SELECT q.id, c.name as customer_name, q.quotation_date, q.total_with_vat, q.status
|
||||
FROM quotations q JOIN customers c ON q.customer_id = c.id
|
||||
ORDER BY q.id DESC");
|
||||
$stmt->execute();
|
||||
$headers = ['Quotation #', 'Customer', 'Date', 'Total', 'Status'];
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $rows[] = $row;
|
||||
} elseif ($type === 'lpos') {
|
||||
$stmt = db()->prepare("SELECT q.id, s.name as supplier_name, q.lpo_date, q.total_with_vat, q.status
|
||||
FROM lpos q JOIN suppliers s ON q.supplier_id = s.id
|
||||
ORDER BY q.id DESC");
|
||||
$stmt->execute();
|
||||
$headers = ['LPO #', 'Supplier', 'Date', 'Total', 'Status'];
|
||||
--
|
||||
$page_num = isset($_GET["p"]) ? (int)$_GET["p"] : 1;
|
||||
if ($page_num < 1) $page_num = 1;
|
||||
$offset = ($page_num - 1) * $limit;
|
||||
switch ($page) {
|
||||
case 'suppliers':
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
if (!empty($_GET['search'])) {
|
||||
$where[] = "(name LIKE ? OR email LIKE ? OR phone LIKE ? OR tax_id LIKE ?)";
|
||||
$params[] = "%{$_GET['search']}%";
|
||||
$params[] = "%{$_GET['search']}%";
|
||||
$params[] = "%{$_GET['search']}%";
|
||||
$params[] = "%{$_GET['search']}%";
|
||||
}
|
||||
if (!empty($_GET['start_date'])) {
|
||||
$where[] = "DATE(created_at) >= ?";
|
||||
$params[] = $_GET['start_date'];
|
||||
}
|
||||
if (!empty($_GET['end_date'])) {
|
||||
$where[] = "DATE(created_at) <= ?";
|
||||
$params[] = $_GET['end_date'];
|
||||
}
|
||||
$whereSql = implode(" AND ", $where);
|
||||
|
||||
$countStmt = db()->prepare("SELECT COUNT(*) FROM suppliers WHERE $whereSql");
|
||||
$countStmt->execute($params);
|
||||
--
|
||||
$stmt = db()->prepare("SELECT * FROM suppliers WHERE $whereSql ORDER BY id DESC LIMIT $limit OFFSET $offset");
|
||||
$stmt->execute($params);
|
||||
$data['customers'] = $stmt->fetchAll(); // Keep 'customers' key for template compatibility if needed, or update template
|
||||
break;
|
||||
case 'customers':
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
if (!empty($_GET['search'])) {
|
||||
$where[] = "(name LIKE ? OR email LIKE ? OR phone LIKE ? OR tax_id LIKE ?)";
|
||||
$params[] = "%{$_GET['search']}%";
|
||||
$params[] = "%{$_GET['search']}%";
|
||||
$params[] = "%{$_GET['search']}%";
|
||||
$params[] = "%{$_GET['search']}%";
|
||||
}
|
||||
if (!empty($_GET['start_date'])) {
|
||||
$where[] = "DATE(created_at) >= ?";
|
||||
$params[] = $_GET['start_date'];
|
||||
}
|
||||
if (!empty($_GET['end_date'])) {
|
||||
$where[] = "DATE(created_at) <= ?";
|
||||
$params[] = $_GET['end_date'];
|
||||
}
|
||||
$whereSql = implode(" AND ", $where);
|
||||
|
||||
$countStmt = db()->prepare("SELECT COUNT(*) FROM customers WHERE $whereSql");
|
||||
$countStmt->execute($params);
|
||||
--
|
||||
case 'units':
|
||||
// Already fetched globally
|
||||
break;
|
||||
case 'items':
|
||||
file_put_contents('debug.log', date('Y-m-d H:i:s') . " - Items case hit\n", FILE_APPEND);
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
if (!empty($_GET['search'])) {
|
||||
$where[] = "(i.name_en LIKE ? OR i.name_ar LIKE ? OR i.sku LIKE ?)";
|
||||
$params[] = "%{$_GET['search']}%";
|
||||
$params[] = "%{$_GET['search']}%";
|
||||
$params[] = "%{$_GET['search']}%";
|
||||
}
|
||||
$whereSql = implode(" AND ", $where);
|
||||
|
||||
$countStmt = db()->prepare("SELECT COUNT(*) FROM stock_items i
|
||||
LEFT JOIN stock_categories c ON i.category_id = c.id
|
||||
LEFT JOIN stock_units u ON i.unit_id = u.id
|
||||
LEFT JOIN suppliers s ON i.supplier_id = s.id WHERE $whereSql");
|
||||
$countStmt->execute($params);
|
||||
$total_records = (int)$countStmt->fetchColumn();
|
||||
$data['total_pages'] = ceil($total_records / $limit);
|
||||
$data['current_page'] = $page_num;
|
||||
|
||||
$stmt = db()->prepare("SELECT i.*, c.name_en as cat_en, c.name_ar as cat_ar, u.short_name_en as unit_en, u.short_name_ar as unit_ar, s.name as supplier_name
|
||||
FROM stock_items i
|
||||
--
|
||||
ORDER BY i.id DESC LIMIT $limit OFFSET $offset");
|
||||
$stmt->execute($params);
|
||||
$data['items'] = $stmt->fetchAll();
|
||||
break;
|
||||
case 'quotations':
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
if (!empty($_GET['search'])) {
|
||||
$s = $_GET['search'];
|
||||
$clean_id = preg_replace('/[^0-9]/', '', $s);
|
||||
if ($clean_id !== '') {
|
||||
$where[] = "(q.id LIKE ? OR c.name LIKE ? OR q.id = ?)";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
$params[] = $clean_id;
|
||||
} else {
|
||||
$where[] = "(q.id LIKE ? OR c.name LIKE ?)";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
}
|
||||
}
|
||||
if (!empty($_GET['customer_id'])) {
|
||||
$where[] = "q.customer_id = ?";
|
||||
$params[] = $_GET['customer_id'];
|
||||
}
|
||||
if (!empty($_GET['start_date'])) {
|
||||
--
|
||||
LIMIT $limit OFFSET $offset");
|
||||
$stmt->execute($params);
|
||||
$data['quotations'] = $stmt->fetchAll();
|
||||
break;
|
||||
case 'lpos':
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
if (!empty($_GET['search'])) {
|
||||
$s = $_GET['search'];
|
||||
$clean_id = preg_replace('/[^0-9]/', '', $s);
|
||||
if ($clean_id !== '') {
|
||||
$where[] = "(q.id LIKE ? OR s.name LIKE ? OR q.id = ?)";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
$params[] = $clean_id;
|
||||
} else {
|
||||
$where[] = "(q.id LIKE ? OR s.name LIKE ?)";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
}
|
||||
}
|
||||
if (!empty($_GET['supplier_id'])) {
|
||||
$where[] = "q.supplier_id = ?";
|
||||
$params[] = $_GET['supplier_id'];
|
||||
}
|
||||
if (!empty($_GET['start_date'])) {
|
||||
--
|
||||
$type = ($page === 'sales') ? 'sale' : 'purchase';
|
||||
$table = ($type === 'purchase') ? 'purchases' : 'invoices';
|
||||
$cust_supplier_col = ($type === 'purchase') ? 'supplier_id' : 'customer_id';
|
||||
$cust_supplier_table = ($type === 'purchase') ? 'suppliers' : 'customers';
|
||||
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
|
||||
if (!empty($_GET['search'])) {
|
||||
$s = $_GET['search'];
|
||||
$clean_id = preg_replace('/[^0-9]/', '', $s);
|
||||
if ($clean_id !== '') {
|
||||
$where[] = "(v.id LIKE ? OR c.name LIKE ? OR v.id = ?)";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
$params[] = $clean_id;
|
||||
} else {
|
||||
$where[] = "(v.id LIKE ? OR c.name LIKE ?)";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($_GET['customer_id'])) {
|
||||
$where[] = "v.$cust_supplier_col = ?";
|
||||
$params[] = $_GET['customer_id'];
|
||||
--
|
||||
$data['purchase_invoices'] = db()->query("SELECT id, invoice_date, total_with_vat FROM purchases ORDER BY id DESC")->fetchAll();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'sales_returns':
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
if (!empty($_GET['search'])) {
|
||||
$s = $_GET['search'];
|
||||
$clean_id = preg_replace('/[^0-9]/', '', $s);
|
||||
if ($clean_id !== '') {
|
||||
$where[] = "(sr.id LIKE ? OR c.name LIKE ? OR sr.invoice_id LIKE ? OR sr.id = ? OR sr.invoice_id = ?)";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
$params[] = $clean_id;
|
||||
$params[] = $clean_id;
|
||||
} else {
|
||||
$where[] = "(sr.id LIKE ? OR c.name LIKE ? OR sr.invoice_id LIKE ?)";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
}
|
||||
}
|
||||
$whereSql = implode(" AND ", $where);
|
||||
$stmt = db()->prepare("SELECT sr.*, c.name as customer_name, i.total_with_vat as invoice_total
|
||||
--
|
||||
$data['returns'] = $stmt->fetchAll();
|
||||
$data['sales_invoices'] = db()->query("SELECT id, invoice_date, total_with_vat FROM invoices ORDER BY id DESC")->fetchAll();
|
||||
break;
|
||||
|
||||
case 'purchase_returns':
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
if (!empty($_GET['search'])) {
|
||||
$s = $_GET['search'];
|
||||
$clean_id = preg_replace('/[^0-9]/', '', $s);
|
||||
if ($clean_id !== '') {
|
||||
$where[] = "(pr.id LIKE ? OR c.name LIKE ? OR pr.purchase_id LIKE ? OR pr.id = ? OR pr.purchase_id = ?)";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
$params[] = $clean_id;
|
||||
$params[] = $clean_id;
|
||||
} else {
|
||||
$where[] = "(pr.id LIKE ? OR c.name LIKE ? OR pr.purchase_id LIKE ?)";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
$params[] = "%$s%";
|
||||
}
|
||||
}
|
||||
$whereSql = implode(" AND ", $where);
|
||||
$stmt = db()->prepare("SELECT pr.*, c.name as supplier_name, i.total_with_vat as invoice_total
|
||||
--
|
||||
break;
|
||||
case 'expense_categories':
|
||||
$data['expense_categories'] = db()->query("SELECT * FROM expense_categories ORDER BY name_en ASC")->fetchAll();
|
||||
break;
|
||||
case 'expenses':
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
if (!empty($_GET['category_id'])) {
|
||||
$where[] = "e.category_id = ?";
|
||||
$params[] = $_GET['category_id'];
|
||||
}
|
||||
if (!empty($_GET['start_date'])) {
|
||||
$where[] = "e.expense_date >= ?";
|
||||
$params[] = $_GET['start_date'];
|
||||
}
|
||||
if (!empty($_GET['end_date'])) {
|
||||
$where[] = "e.expense_date <= ?";
|
||||
$params[] = $_GET['end_date'];
|
||||
}
|
||||
$whereSql = implode(" AND ", $where);
|
||||
$stmt = db()->prepare("SELECT e.*, c.name_en as cat_en, c.name_ar as cat_ar
|
||||
FROM expenses e
|
||||
LEFT JOIN expense_categories c ON e.category_id = c.id
|
||||
WHERE $whereSql
|
||||
ORDER BY e.expense_date DESC, e.id DESC");
|
||||
$stmt->execute($params);
|
||||
--
|
||||
$data['year'] = $year;
|
||||
$data['payroll'] = db()->query("SELECT p.*, e.name as emp_name FROM hr_payroll p JOIN hr_employees e ON p.employee_id = e.id WHERE p.payroll_month = $month AND p.payroll_year = $year ORDER BY p.id DESC")->fetchAll();
|
||||
$data['employees'] = db()->query("SELECT id, name, salary FROM hr_employees WHERE status = 'active' ORDER BY name ASC")->fetchAll();
|
||||
break;
|
||||
case 'loyalty_history':
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
if (!empty($_GET['customer_id'])) {
|
||||
$where[] = "lt.customer_id = ?";
|
||||
$params[] = (int)$_GET['customer_id'];
|
||||
}
|
||||
if (!empty($_GET['type'])) {
|
||||
$where[] = "lt.transaction_type = ?";
|
||||
$params[] = $_GET['type'];
|
||||
}
|
||||
$whereSql = implode(" AND ", $where);
|
||||
$stmt = db()->prepare("SELECT lt.*, c.name as customer_name, c.loyalty_tier, c.loyalty_points
|
||||
FROM loyalty_transactions lt
|
||||
JOIN customers c ON lt.customer_id = c.id
|
||||
WHERE $whereSql
|
||||
ORDER BY lt.created_at DESC");
|
||||
$stmt->execute($params);
|
||||
$data['loyalty_transactions'] = $stmt->fetchAll();
|
||||
break;
|
||||
case 'devices':
|
||||
$data['devices'] = db()->query("SELECT * FROM hr_biometric_devices ORDER BY id DESC")->fetchAll();
|
||||
--
|
||||
break;
|
||||
case 'cash_registers':
|
||||
$data['cash_registers'] = db()->query("SELECT * FROM cash_registers ORDER BY id DESC")->fetchAll();
|
||||
break;
|
||||
case 'register_sessions':
|
||||
$where = ["1=1"];
|
||||
$params = [];
|
||||
|
||||
// Filter by user if provided and user has permission
|
||||
if (isset($_GET['user_id']) && !empty($_GET['user_id'])) {
|
||||
if (can('users_view')) {
|
||||
$where[] = "s.user_id = ?";
|
||||
$params[] = $_GET['user_id'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!can('users_view')) {
|
||||
$where[] = "s.user_id = ?";
|
||||
$params[] = $_SESSION['user_id'];
|
||||
}
|
||||
|
||||
// Filter by date range
|
||||
if (isset($_GET['date_from']) && !empty($_GET['date_from'])) {
|
||||
$where[] = "s.opened_at >= ?";
|
||||
$params[] = $_GET['date_from'] . ' 00:00:00';
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user