From 038a4de94de715c19471fe41c35d51b682c961db Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 18 Feb 2026 12:01:04 +0000 Subject: [PATCH] adding cash register --- db/migrations/20260218_pos_payments.sql | 12 + index.php | 845 +++++++++++++++++++++++ lib/LicenseService.php | 55 +- license_manager/config.php | 21 + license_manager/database.sql | 26 + license_manager/index.php | 115 +++ licensing_server_sample.php | 53 -- post_debug.log | 4 + sessions/sess_lh615g4etelsak5v2rj9mcn1eb | 2 +- 9 files changed, 1055 insertions(+), 78 deletions(-) create mode 100644 db/migrations/20260218_pos_payments.sql create mode 100644 license_manager/config.php create mode 100644 license_manager/database.sql create mode 100644 license_manager/index.php delete mode 100644 licensing_server_sample.php diff --git a/db/migrations/20260218_pos_payments.sql b/db/migrations/20260218_pos_payments.sql new file mode 100644 index 0000000..40a22c5 --- /dev/null +++ b/db/migrations/20260218_pos_payments.sql @@ -0,0 +1,12 @@ +-- Create pos_payments table to support split payments and detailed reporting +CREATE TABLE IF NOT EXISTS pos_payments ( + id INT AUTO_INCREMENT PRIMARY KEY, + transaction_id INT NOT NULL, + payment_method VARCHAR(50) NOT NULL, + amount DECIMAL(15, 3) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (transaction_id) REFERENCES pos_transactions(id) ON DELETE CASCADE +); + +-- Add register_session_id to pos_transactions if missing (already exists but for idempotency) +-- ALTER TABLE pos_transactions ADD COLUMN IF NOT EXISTS register_session_id INT NULL; diff --git a/index.php b/index.php index 6875128..8823d98 100644 --- a/index.php +++ b/index.php @@ -137,6 +137,121 @@ if (isset($_GET['action']) && $_GET['action'] === 'logout') { exit; } +// --- POS AJAX Handlers --- +if (isset($_GET['action']) || isset($_POST['action'])) { + $action = $_GET['action'] ?? $_POST['action'] ?? ''; + + if ($action === 'validate_discount') { + header('Content-Type: application/json'); + $code = $_GET['code'] ?? ''; + $stmt = db()->prepare("SELECT * FROM discount_codes WHERE code = ? AND status = 'active' AND (expiry_date IS NULL OR expiry_date >= CURDATE())"); + $stmt->execute([$code]); + $discount = $stmt->fetch(PDO::FETCH_ASSOC); + if ($discount) { + echo json_encode(['success' => true, 'discount' => $discount]); + } else { + echo json_encode(['success' => false, 'error' => 'Invalid or expired discount code']); + } + exit; + } + + if ($action === 'get_held_carts') { + header('Content-Type: application/json'); + $stmt = db()->query("SELECT h.*, c.name as customer_name FROM pos_held_carts h LEFT JOIN customers c ON h.customer_id = c.id ORDER BY h.created_at DESC"); + echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC)); + exit; + } + + if ($action === 'hold_pos_cart') { + header('Content-Type: application/json'); + $name = $_POST['cart_name'] ?? 'Untitled Cart'; + $items = $_POST['items'] ?? '[]'; + $customer_id = !empty($_POST['customer_id']) ? (int)$_POST['customer_id'] : null; + $stmt = db()->prepare("INSERT INTO pos_held_carts (cart_name, items_json, customer_id) VALUES (?, ?, ?)"); + $stmt->execute([$name, $items, $customer_id]); + echo json_encode(['success' => true]); + exit; + } + + if ($action === 'delete_held_cart') { + header('Content-Type: application/json'); + $id = (int)$_POST['id']; + $stmt = db()->prepare("DELETE FROM pos_held_carts WHERE id = ?"); + $stmt->execute([$id]); + echo json_encode(['success' => true]); + exit; + } + + if ($action === 'save_pos_transaction') { + header('Content-Type: application/json'); + $db = db(); + try { + $db->beginTransaction(); + + $customer_id = !empty($_POST['customer_id']) ? (int)$_POST['customer_id'] : null; + $payments = json_decode($_POST['payments'] ?? '[]', true); + $items = json_decode($_POST['items'] ?? '[]', true); + $total_amount = (float)($_POST['total_amount'] ?? 0); + $discount_code_id = !empty($_POST['discount_code_id']) ? (int)$_POST['discount_code_id'] : null; + $discount_amount = (float)($_POST['discount_amount'] ?? 0); + $loyalty_redeemed = (float)($_POST['loyalty_redeemed'] ?? 0); + $net_amount = $total_amount - $discount_amount - $loyalty_redeemed; + + $transaction_no = 'POS-' . time() . rand(10, 99); + $session_id = $_SESSION['register_session_id'] ?? null; + + // Insert Transaction + $stmt = $db->prepare("INSERT INTO pos_transactions (transaction_no, customer_id, total_amount, discount_code_id, discount_amount, loyalty_points_redeemed, net_amount, register_session_id, created_by, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'completed')"); + $stmt->execute([$transaction_no, $customer_id, $total_amount, $discount_code_id, $discount_amount, $loyalty_redeemed, $net_amount, $session_id, $_SESSION['user_id']]); + $transaction_id = (int)$db->lastInsertId(); + + // Insert Items & Update Stock + $stmtItem = $db->prepare("INSERT INTO pos_items (transaction_id, product_id, quantity, unit_price, subtotal) VALUES (?, ?, ?, ?, ?)"); + $stmtStock = $db->prepare("UPDATE stock_items SET stock_quantity = stock_quantity - ? WHERE id = ?"); + + foreach ($items as $item) { + $sub = (float)$item['price'] * (float)$item['qty']; + $stmtItem->execute([$transaction_id, $item['id'], $item['qty'], $item['price'], $sub]); + $stmtStock->execute([$item['qty'], $item['id']]); + } + + // Insert Payments + $stmtPay = $db->prepare("INSERT INTO pos_payments (transaction_id, payment_method, amount) VALUES (?, ?, ?)"); + foreach ($payments as $p) { + $stmtPay->execute([$transaction_id, $p['method'], $p['amount']]); + } + + // Update Loyalty Points if customer exists + if ($customer_id) { + // Earn points + $points_earned = floor($net_amount); + $stmtPoints = $db->prepare("UPDATE customers SET loyalty_points = loyalty_points - ? + ? WHERE id = ?"); + $stmtPoints->execute([$loyalty_redeemed * 100, $points_earned, $customer_id]); + + // Record transactions + if ($points_earned > 0) { + $db->prepare("INSERT INTO loyalty_transactions (customer_id, transaction_id, points_change, transaction_type, description) VALUES (?, ?, ?, 'earned', ?)") + ->execute([$customer_id, $transaction_id, $points_earned, "Earned from POS order #$transaction_no"]); + } + if ($loyalty_redeemed > 0) { + $db->prepare("INSERT INTO loyalty_transactions (customer_id, transaction_id, points_change, transaction_type, description) VALUES (?, ?, ?, 'redeemed', ?)") + ->execute([$customer_id, $transaction_id, -$loyalty_redeemed * 100, "Redeemed for POS order #$transaction_no"]); + } + + // Update transaction with points earned + $db->prepare("UPDATE pos_transactions SET loyalty_points_earned = ? WHERE id = ?")->execute([$points_earned, $transaction_id]); + } + + $db->commit(); + echo json_encode(['success' => true, 'invoice_id' => $transaction_id, 'transaction_no' => $transaction_no]); + } catch (Exception $e) { + $db->rollBack(); + echo json_encode(['success' => false, 'error' => $e->getMessage()]); + } + exit; + } +} + // Redirect to login if not authenticated if (!isset($_SESSION['user_id'])) { ?> @@ -535,6 +650,44 @@ if (isset($_POST['add_hr_department'])) { } } + // --- POS Devices Handlers --- + if (isset($_POST['add_pos_device'])) { + $name = $_POST['device_name'] ?? ''; + $type = $_POST['device_type'] ?? 'scale'; + $conn = $_POST['connection_type'] ?? 'usb'; + $ip = $_POST['ip_address'] ?? ''; + $port = $_POST['port'] ? (int)$_POST['port'] : null; + $baud = $_POST['baud_rate'] ? (int)$_POST['baud_rate'] : null; + if ($name) { + $stmt = db()->prepare("INSERT INTO pos_devices (device_name, device_type, connection_type, ip_address, port, baud_rate) VALUES (?, ?, ?, ?, ?, ?)"); + $stmt->execute([$name, $type, $conn, $ip, $port, $baud]); + $message = "Device added successfully!"; + } + } + if (isset($_POST['edit_pos_device'])) { + $id = (int)$_POST['id']; + $name = $_POST['device_name'] ?? ''; + $type = $_POST['device_type'] ?? 'scale'; + $conn = $_POST['connection_type'] ?? 'usb'; + $ip = $_POST['ip_address'] ?? ''; + $port = $_POST['port'] ? (int)$_POST['port'] : null; + $baud = $_POST['baud_rate'] ? (int)$_POST['baud_rate'] : null; + $status = $_POST['status'] ?? 'active'; + if ($id && $name) { + $stmt = db()->prepare("UPDATE pos_devices SET device_name = ?, device_type = ?, connection_type = ?, ip_address = ?, port = ?, baud_rate = ?, status = ? WHERE id = ?"); + $stmt->execute([$name, $type, $conn, $ip, $port, $baud, $status, $id]); + $message = "Device updated successfully!"; + } + } + if (isset($_POST['delete_pos_device'])) { + $id = (int)$_POST['id']; + if ($id) { + $stmt = db()->prepare("DELETE FROM pos_devices WHERE id = ?"); + $stmt->execute([$id]); + $message = "Device deleted successfully!"; + } + } + if (isset($_POST['update_profile'])) { $id = $_SESSION['user_id']; $username = $_POST['username'] ?? ''; @@ -606,6 +759,76 @@ if (isset($_POST['add_hr_department'])) { } } + // --- Cash Register & Session Handlers --- + if (isset($_POST['add_cash_register'])) { + $name = $_POST['name'] ?? ''; + if ($name) { + $stmt = db()->prepare("INSERT INTO cash_registers (name) VALUES (?)"); + $stmt->execute([$name]); + $message = "Cash Register added successfully!"; + } + } + if (isset($_POST['edit_cash_register'])) { + $id = (int)$_POST['id']; + $name = $_POST['name'] ?? ''; + $status = $_POST['status'] ?? 'active'; + if ($id && $name) { + $stmt = db()->prepare("UPDATE cash_registers SET name = ?, status = ? WHERE id = ?"); + $stmt->execute([$name, $status, $id]); + $message = "Cash Register updated successfully!"; + } + } + if (isset($_POST['delete_cash_register'])) { + $id = (int)$_POST['id']; + if ($id) { + $stmt = db()->prepare("DELETE FROM cash_registers WHERE id = ?"); + $stmt->execute([$id]); + $message = "Cash Register deleted successfully!"; + } + } + + if (isset($_POST['open_register'])) { + $register_id = (int)$_POST['register_id']; + $user_id = $_SESSION['user_id']; + $opening_balance = (float)$_POST['opening_balance']; + + // Check if user already has an open session + $check = db()->prepare("SELECT id FROM register_sessions WHERE user_id = ? AND status = 'open'"); + $check->execute([$user_id]); + if ($check->fetch()) { + $message = "Error: You already have an open register session."; + } else { + $stmt = db()->prepare("INSERT INTO register_sessions (register_id, user_id, opening_balance, status) VALUES (?, ?, ?, 'open')"); + $stmt->execute([$register_id, $user_id, $opening_balance]); + $_SESSION['register_session_id'] = db()->lastInsertId(); + $message = "Register opened successfully!"; + } + } + + if (isset($_POST['close_register'])) { + $session_id = (int)$_POST['session_id']; + $cash_in_hand = (float)$_POST['cash_in_hand']; + $notes = $_POST['notes'] ?? ''; + + // Calculate expected closing balance + // Opening + Sum of POS Transactions (Cash) - Any cash outflows (if any) + $session = db()->prepare("SELECT opening_balance FROM register_sessions WHERE id = ?"); + $session->execute([$session_id]); + $opening = (float)$session->fetchColumn(); + + $sales = db()->prepare("SELECT SUM(p.amount) FROM pos_payments p JOIN pos_transactions t ON p.transaction_id = t.id WHERE t.register_session_id = ? AND t.status = 'completed' AND p.payment_method = 'cash'"); + $sales->execute([$session_id]); + $cash_sales = (float)$sales->fetchColumn(); + + $expected = $opening + $cash_sales; + + $stmt = db()->prepare("UPDATE register_sessions SET closing_balance = ?, cash_in_hand = ?, closed_at = CURRENT_TIMESTAMP, status = 'closed', notes = ? WHERE id = ?"); + $stmt->execute([$expected, $cash_in_hand, $notes, $session_id]); + + unset($_SESSION['register_session_id']); + $message = "Register closed successfully!"; + } + // Routing & Data Fetching $page = $_GET['page'] ?? 'dashboard'; @@ -642,8 +865,11 @@ $page_permissions = [ 'hr_payroll' => 'hr_view', 'role_groups' => 'users_view', 'users' => 'users_view', + 'scale_devices' => 'users_view', 'backups' => 'users_view', 'logs' => 'users_view', + 'cash_registers' => 'users_view', + 'register_sessions' => 'pos_view', ]; if (isset($page_permissions[$page]) && !can($page_permissions[$page])) { @@ -1189,6 +1415,30 @@ switch ($page) { case 'devices': $data['devices'] = db()->query("SELECT * FROM hr_biometric_devices ORDER BY id DESC")->fetchAll(); break; + case 'scale_devices': + $data['scale_devices'] = db()->query("SELECT * FROM pos_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 = []; + if (!can('users_view')) { + $where[] = "s.user_id = ?"; + $params[] = $_SESSION['user_id']; + } + $whereSql = implode(" AND ", $where); + $stmt = db()->prepare("SELECT s.*, r.name as register_name, u.username + FROM register_sessions s + JOIN cash_registers r ON s.register_id = r.id + JOIN users u ON s.user_id = u.id + WHERE $whereSql + ORDER BY s.id DESC"); + $stmt->execute($params); + $data['sessions'] = $stmt->fetchAll(); + $data['cash_registers'] = db()->query("SELECT * FROM cash_registers WHERE status = 'active'")->fetchAll(); + break; default: $data['customers'] = db()->query("SELECT * FROM customers WHERE type = 'customer' ORDER BY id DESC LIMIT 5")->fetchAll(); // Dashboard stats @@ -1465,6 +1715,15 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System'; Users + + Cash Registers + + + Register Sessions + + + Devices + Backups @@ -1521,6 +1780,9 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System'; 'users' => ['en' => 'User Management', 'ar' => 'إدارة المستخدمين'], 'backups' => ['en' => 'Database Backups', 'ar' => 'نسخ قاعدة البيانات'], 'role_groups' => ['en' => 'Role Groups', 'ar' => 'مجموعات الأدوار'], + 'scale_devices' => ['en' => 'POS Devices', 'ar' => 'أجهزة نقاط البيع'], + 'cash_registers' => ['en' => 'Cash Registers', 'ar' => 'خزائن الكاشير'], + 'register_sessions' => ['en' => 'Register Sessions', 'ar' => 'جلسات الكاشير'], ]; $currTitle = $titles[$page] ?? $titles['dashboard']; ?> @@ -5174,6 +5436,188 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System'; + +
+
+
POS Devices
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Device NameTypeConnectionDetailsStatusActions
+
+
+ + + + + + : + + Baud: + + USB Interface + + + + + +
+ + +
+
+
+
+ + + +
@@ -5660,6 +6104,407 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
+ +
+
+
+
Cash Registers Management
+

Define your shop counters and registers.

+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
IDNameStatusCreated AtActions
# + + + + + +
+ + +
+ + + +
+
+
+ + + + + +
+
+
+
Register Sessions
+

Manage daily opening and closing of cash registers.

+
+
+ prepare("SELECT s.*, r.name as register_name FROM register_sessions s JOIN cash_registers r ON s.register_id = r.id WHERE s.user_id = ? AND s.status = 'open'"); + $active_session->execute([$_SESSION['user_id']]); + $session = $active_session->fetch(); + ?> + + + + + +
+
+ + +
+
+ + Current Open Register: | + Opened At: | + Opening Balance: OMR +
+
+ Go to POS +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RegisterCashierOpened AtClosed AtOpening Bal.Expected Bal.Cash in HandDifferenceStatusReport
OMR OMR OMR + 0 ? 'text-info' : 'text-danger'); + ?> + OMR + --- + + + + + + + + + +
+
+
+ + + + + + + + +
diff --git a/lib/LicenseService.php b/lib/LicenseService.php index e7da6a4..f174845 100644 --- a/lib/LicenseService.php +++ b/lib/LicenseService.php @@ -90,41 +90,48 @@ class LicenseService { * Remote API Caller */ private static function callRemoteApi($endpoint, $params) { - // In a real production environment, this would hit your licensing server. - // For this demonstration, we simulate the request logic. - $url = self::$remote_api_url . $endpoint; - /* - // Real implementation would look like this: + // Check if we are in local development / simulation mode + // If the URL is still the default placeholder, we use simulation + if (strpos(self::$remote_api_url, 'your-domain.com') !== false) { + return self::simulateApi($endpoint, $params); + } + $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params)); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); $resp = curl_exec($ch); + $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); - $data = json_decode($resp, true); - return $data; - */ - // SIMULATION: If the key starts with 'FLAT-' (case-insensitive), we treat it as valid. - $clean_key = strtoupper(trim($params['license_key'] ?? '')); - if (strpos($clean_key, 'FLAT-') === 0) { - // Check if it's a verification request - if ($endpoint === '/verify') { - return ['success' => true]; - } - - return [ - 'success' => true, - 'activation_token' => hash('sha256', $params['license_key'] . $params['fingerprint'] . 'SECRET_SALT') - ]; + if ($http_code !== 200) { + return ['success' => false, 'error' => "Remote server returned error code $http_code."]; } - return [ - 'success' => false, - 'error' => 'License key invalid or expired. Please contact support.' - ]; + $data = json_decode($resp, true); + if (!$data) { + return ['success' => false, 'error' => "Invalid response from remote server."]; + } + + return $data; + } + + /** + * Local Simulation for development purposes + */ + private static function simulateApi($endpoint, $params) { + $clean_key = strtoupper(trim($params['license_key'] ?? '')); + if (strpos($clean_key, 'FLAT-') === 0) { + if ($endpoint === '/verify') return ['success' => true]; + return [ + 'success' => true, + 'activation_token' => hash('sha256', $params['license_key'] . $params['fingerprint'] . 'DEBUG_SALT') + ]; + } + return ['success' => false, 'error' => 'License key invalid or expired (Simulation Mode).']; } } diff --git a/license_manager/config.php b/license_manager/config.php new file mode 100644 index 0000000..fee83f1 --- /dev/null +++ b/license_manager/config.php @@ -0,0 +1,21 @@ + PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + ]); + } + return $pdo; +} diff --git a/license_manager/database.sql b/license_manager/database.sql new file mode 100644 index 0000000..37a8578 --- /dev/null +++ b/license_manager/database.sql @@ -0,0 +1,26 @@ +-- SQL for the License Manager Database +-- Create a new database called 'license_manager_db' and run this script. + +CREATE TABLE IF NOT EXISTS licenses ( + id INT AUTO_INCREMENT PRIMARY KEY, + license_key VARCHAR(255) UNIQUE NOT NULL, + max_activations INT DEFAULT 1, + status ENUM('active', 'suspended', 'expired') DEFAULT 'active', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS activations ( + id INT AUTO_INCREMENT PRIMARY KEY, + license_id INT NOT NULL, + fingerprint VARCHAR(255) NOT NULL, + domain VARCHAR(255), + product VARCHAR(255), + activated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (license_id) REFERENCES licenses(id) ON DELETE CASCADE, + UNIQUE KEY (license_id, fingerprint) +) ENGINE=InnoDB; + +-- Seed some test data +INSERT INTO licenses (license_key, max_activations) VALUES ('FLAT-8822-1192-3301', 1); +INSERT INTO licenses (license_key, max_activations) VALUES ('FLAT-TEST-KEY-0001', 5); +INSERT INTO licenses (license_key, max_activations) VALUES ('FLAT-DEV-UNLIMITED', 999); diff --git a/license_manager/index.php b/license_manager/index.php new file mode 100644 index 0000000..6611aa7 --- /dev/null +++ b/license_manager/index.php @@ -0,0 +1,115 @@ + false, 'error' => 'Database connection failed.']); + exit; +} + +if ($endpoint === 'activate') { + $key = strtoupper(trim($input['license_key'] ?? '')); + $fingerprint = $input['fingerprint'] ?? ''; + $domain = $input['domain'] ?? ''; + $product = $input['product'] ?? ''; + + if (empty($key) || empty($fingerprint)) { + echo json_encode(['success' => false, 'error' => 'Missing required parameters.']); + exit; + } + + // 1. Find License + $stmt = $pdo->prepare("SELECT * FROM licenses WHERE license_key = ? LIMIT 1"); + $stmt->execute([$key]); + $license = $stmt->fetch(); + + if (!$license) { + echo json_encode(['success' => false, 'error' => 'Invalid license key.']); + exit; + } + + if ($license['status'] !== 'active') { + echo json_encode(['success' => false, 'error' => 'License is ' . $license['status'] . '.']); + exit; + } + + // 2. Check current activations + $stmt = $pdo->prepare("SELECT COUNT(*) FROM activations WHERE license_id = ?"); + $stmt->execute([$license['id']]); + $current_activations = $stmt->fetchColumn(); + + // 3. Check if this machine is already activated + $stmt = $pdo->prepare("SELECT * FROM activations WHERE license_id = ? AND fingerprint = ?"); + $stmt->execute([$license['id'], $fingerprint]); + $existing = $stmt->fetch(); + + if (!$existing) { + if ($current_activations >= $license['max_activations']) { + echo json_encode(['success' => false, 'error' => 'Maximum activation limit reached.']); + exit; + } + + // Record new activation + $stmt = $pdo->prepare("INSERT INTO activations (license_id, fingerprint, domain, product) VALUES (?, ?, ?, ?)"); + $stmt->execute([$license['id'], $fingerprint, $domain, $product]); + } + + // Success: Return signed token + $token = hash_hmac('sha256', $key . $fingerprint, SERVER_SECRET); + echo json_encode([ + 'success' => true, + 'activation_token' => $token + ]); + exit; +} + +if ($endpoint === 'verify') { + $key = strtoupper(trim($input['license_key'] ?? '')); + $fingerprint = $input['fingerprint'] ?? ''; + $token = $input['token'] ?? ''; + + // Simple validation: re-calculate token and check DB status + $expected_token = hash_hmac('sha256', $key . $fingerprint, SERVER_SECRET); + + if ($token !== $expected_token) { + echo json_encode(['success' => false, 'error' => 'Invalid activation token.']); + exit; + } + + $stmt = $pdo->prepare("SELECT status FROM licenses WHERE license_key = ?"); + $stmt->execute([$key]); + $status = $stmt->fetchColumn(); + + if ($status === 'active') { + echo json_encode(['success' => true]); + } else { + echo json_encode(['success' => false, 'error' => 'License is no longer active.']); + } + exit; +} + +echo json_encode(['success' => false, 'error' => 'Invalid endpoint.']); diff --git a/licensing_server_sample.php b/licensing_server_sample.php deleted file mode 100644 index 48dd8fb..0000000 --- a/licensing_server_sample.php +++ /dev/null @@ -1,53 +0,0 @@ - ['status' => 'active', 'max_activations' => 1], - 'FLAT-TEST-KEY-0001' => ['status' => 'active', 'max_activations' => 3], -]; - -// 2. Mock Database of current activations (Key => Fingerprint) -$activations = [ - // 'FLAT-8822-1192-3301' => 'hash_from_client' -]; - -$input = json_decode(file_get_contents('php://input'), true); -$endpoint = $_SERVER['PATH_INFO'] ?? ''; - -if ($endpoint === '/activate') { - $key = strtoupper(trim($input['license_key'] ?? '')); - $fingerprint = $input['fingerprint'] ?? ''; - - if (!isset($valid_keys[$key])) { - echo json_encode(['success' => false, 'error' => 'Invalid license key.']); - exit; - } - - if ($valid_keys[$key]['status'] !== 'active') { - echo json_encode(['success' => false, 'error' => 'License is expired or suspended.']); - exit; - } - - // Check if already activated on another machine - if (isset($activations[$key]) && $activations[$key] !== $fingerprint) { - echo json_encode(['success' => false, 'error' => 'License already in use on another server.']); - exit; - } - - // Success: Return a signed token - echo json_encode([ - 'success' => true, - 'activation_token' => hash_hmac('sha256', $key . $fingerprint, 'YOUR_SECRET_SERVER_SALT') - ]); -} - -if ($endpoint === '/verify') { - // Similar logic to check if the token is still valid or if the key was revoked - echo json_encode(['success' => true]); -} diff --git a/post_debug.log b/post_debug.log index cd1e1c7..f46927e 100644 --- a/post_debug.log +++ b/post_debug.log @@ -9,3 +9,7 @@ 2026-02-18 10:46:04 - POST: {"license_key":"Flat-8822-1192-3301","activate":""} 2026-02-18 10:46:14 - POST: {"license_key":": FLAT-8822-1192-3301","activate":""} 2026-02-18 10:48:04 - POST: {"license_key":" FLAT-8822-1192-3301","activate":""} +2026-02-18 11:33:56 - POST: {"name":"Counter 1","add_cash_register":""} +2026-02-18 11:34:15 - POST: {"name":"Counter 2","add_cash_register":""} +2026-02-18 11:43:14 - POST: {"register_id":"1","opening_balance":"0.000","open_register":""} +2026-02-18 11:50:03 - POST: {"register_id":"1","opening_balance":"0.000","open_register":""} diff --git a/sessions/sess_lh615g4etelsak5v2rj9mcn1eb b/sessions/sess_lh615g4etelsak5v2rj9mcn1eb index a7e827f..23bc6c0 100644 --- a/sessions/sess_lh615g4etelsak5v2rj9mcn1eb +++ b/sessions/sess_lh615g4etelsak5v2rj9mcn1eb @@ -1 +1 @@ -user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";profile_pic|s:32:"uploads/profile_1_1771401598.png"; \ No newline at end of file +user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";profile_pic|s:32:"uploads/profile_1_1771401598.png";register_session_id|s:1:"1"; \ No newline at end of file