ZEZO AI POS Database Spec
ZEZO AI POS — Database Specification v1
نظرة عامة
هذا المستند يحوّل الـ Blueprint إلى Database Specification كامل قابل للتنفيذ المباشر، بحيث يصبح لديك أساس جاهز لكتابة كود PHP/Laravel.
1. ERD المختصر (Logical)
text
┌─────────────────────────────────────────────────────────────────────────────┐
│ ZEZO AI POS — ERD │
└─────────────────────────────────────────────────────────────────────────────┘
┌──────────────┐
│ STORES │
└──────┬───────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ BRANCHES │ │ USERS │ │TERMINALS │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────┐
│ SHIFTS │
└────┬──────────────┬──────────────┬──────┘
│ │ │
▼ ▼ ▼
┌────────┐ ┌──────────┐ ┌──────────────┐
│ SALES │ │ CASH │ │ CARDS │
└───┬────┘ │TRANSACT. │ │ TRANSACTIONS │
│ └──────────┘ └──────────────┘
▼
┌──────────┐
│SALE_ITEMS│
└────┬─────┘
│
▼
┌──────────┐ ┌──────────────┐
│ PRODUCTS │◄───────│ CATEGORIES │
└────┬─────┘ └──────────────┘
│ ┌──────────────┐
│◄─────────────│ BRANDS │
│ └──────────────┘
│
┌────────┼────────┬──────────────┐
▼ ▼ ▼ ▼
┌────────┐┌────────┐┌──────────────┐┌──────────────┐
│STOCK_ ││PURCHASE││PRODUCT_ ││PRODUCT_ │
│MOVEM. ││_ITEMS ││PRICES ││BARCODES │
└────────┘└───┬────┘└──────────────┘└──────────────┘
│
▼
┌──────────┐
│PURCHASES │
└────┬─────┘
│
▼
┌──────────┐
│SUPPLIERS │
└──────────┘
┌──────────────┐
│ AI_EVENTS │
└──────┬───────┘
▼
┌──────────────────┐
│AI_RECOMMENDATIONS│
└──────┬───────────┘
▼
┌──────────────┐
│ AI_ACTIONS │
└──────────────┘
┌──────────────┐
│ AUDIT_LOGS │
└──────────────┘
2. Database Schema — CREATE TABLE
ملاحظات عامة:
- كل الجداول تستخدم
InnoDB+utf8mb4_unicode_ci- كل الجداول الأساسية تحتوي
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY- كل الجداول التشغيلية تحتوي
store_idللعزل المنطقي (Multi-Tenant)- كل الجداول الحساسة تحتوي
created_at,updated_at, ويفضّلdeleted_at(Soft Delete)- المفاتيح الأجنبية
FOREIGN KEY ... ON DELETE RESTRICT ON UPDATE CASCADE
2.1 جداول الهوية والصلاحيات
sql
-- ============================================================
-- USERS
-- ============================================================
CREATE TABLE users (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
branch_id BIGINT UNSIGNED NULL,
username VARCHAR(80) NOT NULL,
email VARCHAR(150) NOT NULL,
phone VARCHAR(30) NULL,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(150) NOT NULL,
avatar_path VARCHAR(255) NULL,
locale VARCHAR(10) NOT NULL DEFAULT 'ar',
is_active TINYINT(1) NOT NULL DEFAULT 1,
last_login_at DATETIME NULL,
last_login_ip VARCHAR(45) NULL,
failed_attempts INT UNSIGNED NOT NULL DEFAULT 0,
locked_until DATETIME NULL,
remember_token VARCHAR(100) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at DATETIME NULL,
UNIQUE KEY uq_users_email (email),
UNIQUE KEY uq_users_username (username),
KEY idx_users_store (store_id),
KEY idx_users_branch (branch_id),
KEY idx_users_active (is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- ROLES
-- ============================================================
CREATE TABLE roles (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NULL, -- NULL = دور نظامي عام
name VARCHAR(80) NOT NULL, -- super_admin, owner, manager, cashier...
name_ar VARCHAR(120) NOT NULL,
description TEXT NULL,
is_system TINYINT(1) NOT NULL DEFAULT 0, -- لا يمكن حذفه
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uq_roles_store_name (store_id, name),
KEY idx_roles_store (store_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- PERMISSIONS
-- ============================================================
CREATE TABLE permissions (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
module VARCHAR(60) NOT NULL, -- products, sales, cash, cards, ai...
action VARCHAR(60) NOT NULL, -- view, create, update, delete, approve...
name VARCHAR(150) NOT NULL, -- products.create
name_ar VARCHAR(180) NOT NULL,
description TEXT NULL,
is_sensitive TINYINT(1) NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uq_permissions_name (name),
KEY idx_permissions_module (module)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- ROLE_PERMISSIONS
-- ============================================================
CREATE TABLE role_permissions (
role_id BIGINT UNSIGNED NOT NULL,
permission_id BIGINT UNSIGNED NOT NULL,
granted_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (role_id, permission_id),
CONSTRAINT fk_rp_role FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
CONSTRAINT fk_rp_perm FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- USER_ROLES
-- ============================================================
CREATE TABLE user_roles (
user_id BIGINT UNSIGNED NOT NULL,
role_id BIGINT UNSIGNED NOT NULL,
assigned_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, role_id),
CONSTRAINT fk_ur_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
CONSTRAINT fk_ur_role FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.2 جداول المتجر والفروع
sql
-- ============================================================
-- STORES
-- ============================================================
CREATE TABLE stores (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(150) NOT NULL,
name_ar VARCHAR(180) NOT NULL,
legal_name VARCHAR(200) NULL,
tax_number VARCHAR(60) NULL,
currency VARCHAR(10) NOT NULL DEFAULT 'SAR',
timezone VARCHAR(60) NOT NULL DEFAULT 'Asia/Riyadh',
locale VARCHAR(10) NOT NULL DEFAULT 'ar',
logo_path VARCHAR(255) NULL,
subscription_id BIGINT UNSIGNED NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at DATETIME NULL,
KEY idx_stores_active (is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- BRANCHES
-- ============================================================
CREATE TABLE branches (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
code VARCHAR(30) NOT NULL,
name VARCHAR(150) NOT NULL,
name_ar VARCHAR(180) NOT NULL,
address TEXT NULL,
phone VARCHAR(30) NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uq_branches_store_code (store_id, code),
CONSTRAINT fk_branches_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- TERMINALS
-- ============================================================
CREATE TABLE terminals (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
branch_id BIGINT UNSIGNED NOT NULL,
code VARCHAR(30) NOT NULL,
name VARCHAR(150) NOT NULL,
device_token VARCHAR(120) NULL,
last_seen_at DATETIME NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uq_terminals_code (store_id, code),
CONSTRAINT fk_terminals_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_terminals_branch FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.3 جداول المنتجات
sql
-- ============================================================
-- CATEGORIES
-- ============================================================
CREATE TABLE categories (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
parent_id BIGINT UNSIGNED NULL,
name VARCHAR(120) NOT NULL,
name_ar VARCHAR(150) NOT NULL,
sort_order INT NOT NULL DEFAULT 0,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY idx_categories_store (store_id),
KEY idx_categories_parent (parent_id),
CONSTRAINT fk_categories_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_categories_parent FOREIGN KEY (parent_id) REFERENCES categories(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- BRANDS
-- ============================================================
CREATE TABLE brands (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
name VARCHAR(120) NOT NULL,
name_ar VARCHAR(150) NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY idx_brands_store (store_id),
CONSTRAINT fk_brands_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- PRODUCTS
-- ============================================================
CREATE TABLE products (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
category_id BIGINT UNSIGNED NULL,
brand_id BIGINT UNSIGNED NULL,
sku VARCHAR(60) NOT NULL,
name VARCHAR(180) NOT NULL,
name_ar VARCHAR(200) NULL,
name_en VARCHAR(200) NULL,
description TEXT NULL,
image_path VARCHAR(255) NULL,
unit VARCHAR(30) NOT NULL DEFAULT 'piece',
purchase_price DECIMAL(12,3) NOT NULL DEFAULT 0.000,
selling_price DECIMAL(12,3) NOT NULL DEFAULT 0.000,
tax_rate DECIMAL(6,3) NOT NULL DEFAULT 0.000,
stock_quantity DECIMAL(14,3) NOT NULL DEFAULT 0.000,
minimum_stock DECIMAL(14,3) NOT NULL DEFAULT 0.000,
maximum_stock DECIMAL(14,3) NULL,
track_stock TINYINT(1) NOT NULL DEFAULT 1,
allow_negative TINYINT(1) NOT NULL DEFAULT 0,
status ENUM('active','inactive','archived') NOT NULL DEFAULT 'active',
created_by BIGINT UNSIGNED NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at DATETIME NULL,
UNIQUE KEY uq_products_store_sku (store_id, sku),
KEY idx_products_store_status (store_id, status),
KEY idx_products_category (category_id),
KEY idx_products_brand (brand_id),
KEY idx_products_lowstock (store_id, stock_quantity, minimum_stock),
FULLTEXT KEY ft_products_search (name, name_ar, name_en),
CONSTRAINT fk_products_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_products_category FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL,
CONSTRAINT fk_products_brand FOREIGN KEY (brand_id) REFERENCES brands(id) ON DELETE SET NULL,
CONSTRAINT fk_products_creator FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- PRODUCT_BARCODES
-- ============================================================
CREATE TABLE product_barcodes (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
product_id BIGINT UNSIGNED NOT NULL,
barcode VARCHAR(80) NOT NULL,
barcode_type VARCHAR(30) NOT NULL DEFAULT 'EAN13',
is_primary TINYINT(1) NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uq_barcodes_barcode (barcode),
KEY idx_barcodes_product (product_id),
CONSTRAINT fk_barcodes_product FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- PRODUCT_PRICES (تاريخ الأسعار — Price History)
-- ============================================================
CREATE TABLE product_prices (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
product_id BIGINT UNSIGNED NOT NULL,
price_type ENUM('purchase','selling','wholesale','minimum') NOT NULL,
price DECIMAL(12,3) NOT NULL,
effective_from DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
effective_to DATETIME NULL,
changed_by BIGINT UNSIGNED NULL,
reason VARCHAR(255) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_prices_product_type (product_id, price_type, effective_from),
CONSTRAINT fk_prices_product FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE,
CONSTRAINT fk_prices_user FOREIGN KEY (changed_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.4 جداول المخزون
sql
-- ============================================================
-- STOCK_MOVEMENTS (المصدر الوحيد للحقيقة بشأن المخزون)
-- ============================================================
CREATE TABLE stock_movements (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
product_id BIGINT UNSIGNED NOT NULL,
type ENUM(
'OPENING_BALANCE',
'PURCHASE',
'SALE',
'RETURN',
'ADJUSTMENT',
'DAMAGE',
'TRANSFER_IN',
'TRANSFER_OUT'
) NOT NULL,
quantity DECIMAL(14,3) NOT NULL, -- موجب للداخل، سالب للخارج
before_quantity DECIMAL(14,3) NOT NULL,
after_quantity DECIMAL(14,3) NOT NULL,
unit_cost DECIMAL(12,3) NULL,
total_cost DECIMAL(14,3) NULL,
reference_type VARCHAR(60) NULL, -- Sale, Purchase, Adjustment...
reference_id BIGINT UNSIGNED NULL,
user_id BIGINT UNSIGNED NULL,
shift_id BIGINT UNSIGNED NULL,
notes VARCHAR(500) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_sm_product_date (product_id, created_at),
KEY idx_sm_store_date (store_id, created_at),
KEY idx_sm_type (type),
KEY idx_sm_reference (reference_type, reference_id),
CONSTRAINT fk_sm_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_sm_product FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE RESTRICT,
CONSTRAINT fk_sm_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- INVENTORY_ADJUSTMENTS
-- ============================================================
CREATE TABLE inventory_adjustments (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
product_id BIGINT UNSIGNED NOT NULL,
movement_id BIGINT UNSIGNED NOT NULL,
reason ENUM('COUNT','DAMAGE','LOSS','EXPIRY','CORRECTION','OTHER') NOT NULL,
old_quantity DECIMAL(14,3) NOT NULL,
new_quantity DECIMAL(14,3) NOT NULL,
difference DECIMAL(14,3) NOT NULL,
notes TEXT NULL,
approved_by BIGINT UNSIGNED NULL,
user_id BIGINT UNSIGNED NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_adj_store_date (store_id, created_at),
KEY idx_adj_product (product_id),
CONSTRAINT fk_adj_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_adj_product FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE RESTRICT,
CONSTRAINT fk_adj_movement FOREIGN KEY (movement_id) REFERENCES stock_movements(id) ON DELETE RESTRICT,
CONSTRAINT fk_adj_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT,
CONSTRAINT fk_adj_approver FOREIGN KEY (approved_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.5 جداول الموردين والمشتريات
sql
-- ============================================================
-- SUPPLIERS
-- ============================================================
CREATE TABLE suppliers (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
code VARCHAR(40) NOT NULL,
name VARCHAR(180) NOT NULL,
name_ar VARCHAR(200) NULL,
phone VARCHAR(30) NULL,
email VARCHAR(150) NULL,
address TEXT NULL,
tax_number VARCHAR(60) NULL,
balance DECIMAL(14,3) NOT NULL DEFAULT 0.000,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at DATETIME NULL,
UNIQUE KEY uq_suppliers_store_code (store_id, code),
CONSTRAINT fk_suppliers_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- PURCHASES
-- ============================================================
CREATE TABLE purchases (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
branch_id BIGINT UNSIGNED NULL,
supplier_id BIGINT UNSIGNED NULL,
invoice_number VARCHAR(80) NULL,
invoice_date DATE NOT NULL,
subtotal DECIMAL(14,3) NOT NULL DEFAULT 0.000,
tax_amount DECIMAL(14,3) NOT NULL DEFAULT 0.000,
discount_amount DECIMAL(14,3) NOT NULL DEFAULT 0.000,
total_amount DECIMAL(14,3) NOT NULL DEFAULT 0.000,
paid_amount DECIMAL(14,3) NOT NULL DEFAULT 0.000,
due_amount DECIMAL(14,3) NOT NULL DEFAULT 0.000,
status ENUM('draft','pending','received','partial','cancelled') NOT NULL DEFAULT 'draft',
notes TEXT NULL,
created_by BIGINT UNSIGNED NOT NULL,
received_by BIGINT UNSIGNED NULL,
received_at DATETIME NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY idx_purchases_store_date (store_id, invoice_date),
KEY idx_purchases_supplier (supplier_id),
KEY idx_purchases_status (status),
CONSTRAINT fk_purchases_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_purchases_branch FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE SET NULL,
CONSTRAINT fk_purchases_supplier FOREIGN KEY (supplier_id) REFERENCES suppliers(id) ON DELETE SET NULL,
CONSTRAINT fk_purchases_creator FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE RESTRICT,
CONSTRAINT fk_purchases_receiver FOREIGN KEY (received_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- PURCHASE_ITEMS
-- ============================================================
CREATE TABLE purchase_items (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
purchase_id BIGINT UNSIGNED NOT NULL,
product_id BIGINT UNSIGNED NOT NULL,
quantity DECIMAL(14,3) NOT NULL,
received_qty DECIMAL(14,3) NOT NULL DEFAULT 0.000,
unit_cost DECIMAL(12,3) NOT NULL,
tax_rate DECIMAL(6,3) NOT NULL DEFAULT 0.000,
discount DECIMAL(12,3) NOT NULL DEFAULT 0.000,
line_total DECIMAL(14,3) NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_pi_purchase (purchase_id),
KEY idx_pi_product (product_id),
CONSTRAINT fk_pi_purchase FOREIGN KEY (purchase_id) REFERENCES purchases(id) ON DELETE CASCADE,
CONSTRAINT fk_pi_product FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.6 جداول المبيعات
sql
-- ============================================================
-- SALES
-- ============================================================
CREATE TABLE sales (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
branch_id BIGINT UNSIGNED NOT NULL,
terminal_id BIGINT UNSIGNED NULL,
shift_id BIGINT UNSIGNED NULL,
user_id BIGINT UNSIGNED NOT NULL,
customer_id BIGINT UNSIGNED NULL,
invoice_number VARCHAR(60) NOT NULL,
sale_type ENUM('sale','return','exchange') NOT NULL DEFAULT 'sale',
subtotal DECIMAL(14,3) NOT NULL DEFAULT 0.000,
discount_amount DECIMAL(14,3) NOT NULL DEFAULT 0.000,
tax_amount DECIMAL(14,3) NOT NULL DEFAULT 0.000,
total_amount DECIMAL(14,3) NOT NULL DEFAULT 0.000,
paid_amount DECIMAL(14,3) NOT NULL DEFAULT 0.000,
change_amount DECIMAL(14,3) NOT NULL DEFAULT 0.000,
due_amount DECIMAL(14,3) NOT NULL DEFAULT 0.000,
item_count INT UNSIGNED NOT NULL DEFAULT 0,
status ENUM('draft','held','completed','refunded','partially_refunded','voided') NOT NULL DEFAULT 'draft',
notes TEXT NULL,
completed_at DATETIME NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uq_sales_invoice (store_id, invoice_number),
KEY idx_sales_store_date (store_id, created_at),
KEY idx_sales_branch_date (branch_id, created_at),
KEY idx_sales_shift (shift_id),
KEY idx_sales_user (user_id),
KEY idx_sales_status (status),
CONSTRAINT fk_sales_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_sales_branch FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE RESTRICT,
CONSTRAINT fk_sales_terminal FOREIGN KEY (terminal_id) REFERENCES terminals(id) ON DELETE SET NULL,
CONSTRAINT fk_sales_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- SALE_ITEMS
-- ============================================================
CREATE TABLE sale_items (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
sale_id BIGINT UNSIGNED NOT NULL,
product_id BIGINT UNSIGNED NOT NULL,
product_name VARCHAR(200) NOT NULL, -- Snapshot للاسم وقت البيع
quantity DECIMAL(14,3) NOT NULL,
unit_price DECIMAL(12,3) NOT NULL, -- Snapshot
unit_cost DECIMAL(12,3) NULL, -- Snapshot للتكلفة (لحساب الربح)
tax_rate DECIMAL(6,3) NOT NULL DEFAULT 0.000,
discount DECIMAL(12,3) NOT NULL DEFAULT 0.000,
line_subtotal DECIMAL(14,3) NOT NULL,
line_total DECIMAL(14,3) NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_si_sale (sale_id),
KEY idx_si_product (product_id),
CONSTRAINT fk_si_sale FOREIGN KEY (sale_id) REFERENCES sales(id) ON DELETE CASCADE,
CONSTRAINT fk_si_product FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- SALE_RETURNS
-- ============================================================
CREATE TABLE sale_returns (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
sale_id BIGINT UNSIGNED NOT NULL,
shift_id BIGINT UNSIGNED NULL,
user_id BIGINT UNSIGNED NOT NULL,
return_number VARCHAR(60) NOT NULL,
reason VARCHAR(255) NULL,
total_amount DECIMAL(14,3) NOT NULL DEFAULT 0.000,
refund_method ENUM('cash','card','store_credit') NOT NULL DEFAULT 'cash',
status ENUM('pending','approved','rejected','completed') NOT NULL DEFAULT 'pending',
approved_by BIGINT UNSIGNED NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
completed_at DATETIME NULL,
UNIQUE KEY uq_returns_number (store_id, return_number),
KEY idx_returns_sale (sale_id),
KEY idx_returns_store_date (store_id, created_at),
CONSTRAINT fk_returns_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_returns_sale FOREIGN KEY (sale_id) REFERENCES sales(id) ON DELETE RESTRICT,
CONSTRAINT fk_returns_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT,
CONSTRAINT fk_returns_approver FOREIGN KEY (approved_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- SALE_RETURN_ITEMS
-- ============================================================
CREATE TABLE sale_return_items (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
return_id BIGINT UNSIGNED NOT NULL,
sale_item_id BIGINT UNSIGNED NOT NULL,
product_id BIGINT UNSIGNED NOT NULL,
quantity DECIMAL(14,3) NOT NULL,
unit_price DECIMAL(12,3) NOT NULL,
line_total DECIMAL(14,3) NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_sri_return (return_id),
KEY idx_sri_product (product_id),
CONSTRAINT fk_sri_return FOREIGN KEY (return_id) REFERENCES sale_returns(id) ON DELETE CASCADE,
CONSTRAINT fk_sri_saleitem FOREIGN KEY (sale_item_id) REFERENCES sale_items(id) ON DELETE RESTRICT,
CONSTRAINT fk_sri_product FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.7 جداول الدفع
sql
-- ============================================================
-- PAYMENT_METHODS
-- ============================================================
CREATE TABLE payment_methods (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
code VARCHAR(40) NOT NULL, -- cash, card, visa, mojana, mixed
name VARCHAR(100) NOT NULL,
name_ar VARCHAR(120) NOT NULL,
type ENUM('cash','card','wallet','credit','other') NOT NULL,
requires_ref TINYINT(1) NOT NULL DEFAULT 0,
is_active TINYINT(1) NOT NULL DEFAULT 1,
sort_order INT NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uq_pm_store_code (store_id, code),
CONSTRAINT fk_pm_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- PAYMENTS
-- ============================================================
CREATE TABLE payments (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
sale_id BIGINT UNSIGNED NOT NULL,
payment_method_id BIGINT UNSIGNED NOT NULL,
card_machine_id BIGINT UNSIGNED NULL,
amount DECIMAL(14,3) NOT NULL,
reference_number VARCHAR(120) NULL,
status ENUM('pending','completed','failed','refunded') NOT NULL DEFAULT 'completed',
paid_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
user_id BIGINT UNSIGNED NULL,
notes VARCHAR(500) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_payments_sale (sale_id),
KEY idx_payments_method (payment_method_id),
KEY idx_payments_date (store_id, paid_at),
CONSTRAINT fk_payments_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_payments_sale FOREIGN KEY (sale_id) REFERENCES sales(id) ON DELETE CASCADE,
CONSTRAINT fk_payments_method FOREIGN KEY (payment_method_id) REFERENCES payment_methods(id) ON DELETE RESTRICT,
CONSTRAINT fk_payments_machine FOREIGN KEY (card_machine_id) REFERENCES card_machines(id) ON DELETE SET NULL,
CONSTRAINT fk_payments_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.8 جداول الورديات والنقد
sql
-- ============================================================
-- SHIFTS
-- ============================================================
CREATE TABLE shifts (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
branch_id BIGINT UNSIGNED NOT NULL,
terminal_id BIGINT UNSIGNED NULL,
user_id BIGINT UNSIGNED NOT NULL, -- من فتح الوردية
closed_by BIGINT UNSIGNED NULL,
shift_number VARCHAR(60) NOT NULL,
opening_cash DECIMAL(14,3) NOT NULL DEFAULT 0.000,
expected_cash DECIMAL(14,3) NOT NULL DEFAULT 0.000,
actual_cash DECIMAL(14,3) NOT NULL DEFAULT 0.000,
cash_difference DECIMAL(14,3) NOT NULL DEFAULT 0.000,
expected_card DECIMAL(14,3) NOT NULL DEFAULT 0.000,
actual_card DECIMAL(14,3) NOT NULL DEFAULT 0.000,
card_difference DECIMAL(14,3) NOT NULL DEFAULT 0.000,
total_sales DECIMAL(14,3) NOT NULL DEFAULT 0.000,
total_returns DECIMAL(14,3) NOT NULL DEFAULT 0.000,
total_expenses DECIMAL(14,3) NOT NULL DEFAULT 0.000,
status ENUM('open','closed','reconciled') NOT NULL DEFAULT 'open',
opened_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
closed_at DATETIME NULL,
notes TEXT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uq_shifts_number (store_id, shift_number),
KEY idx_shifts_store_date (store_id, opened_at),
KEY idx_shifts_status (status),
KEY idx_shifts_user (user_id),
CONSTRAINT fk_shifts_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_shifts_branch FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE RESTRICT,
CONSTRAINT fk_shifts_terminal FOREIGN KEY (terminal_id) REFERENCES terminals(id) ON DELETE SET NULL,
CONSTRAINT fk_shifts_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT,
CONSTRAINT fk_shifts_closer FOREIGN KEY (closed_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- CASH_TRANSACTIONS
-- ============================================================
CREATE TABLE cash_transactions (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
branch_id BIGINT UNSIGNED NOT NULL,
shift_id BIGINT UNSIGNED NULL,
user_id BIGINT UNSIGNED NOT NULL,
type ENUM(
'OPENING',
'SALE',
'REFUND',
'EXPENSE',
'DEPOSIT',
'WITHDRAWAL',
'ADJUSTMENT',
'CLOSING'
) NOT NULL,
direction ENUM('in','out') NOT NULL,
amount DECIMAL(14,3) NOT NULL,
balance_after DECIMAL(14,3) NOT NULL,
description VARCHAR(500) NULL,
reference_type VARCHAR(60) NULL,
reference_id BIGINT UNSIGNED NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_cash_shift (shift_id),
KEY idx_cash_store_date (store_id, created_at),
KEY idx_cash_type (type),
KEY idx_cash_reference (reference_type, reference_id),
CONSTRAINT fk_cash_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_cash_branch FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE RESTRICT,
CONSTRAINT fk_cash_shift FOREIGN KEY (shift_id) REFERENCES shifts(id) ON DELETE SET NULL,
CONSTRAINT fk_cash_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.9 جداول البطاقات
sql
-- ============================================================
-- CARD_MACHINES
-- ============================================================
CREATE TABLE card_machines (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
branch_id BIGINT UNSIGNED NOT NULL,
code VARCHAR(30) NOT NULL, -- CARDS_1, CARDS_2, CARDS_3
name VARCHAR(120) NOT NULL, -- Cards No.1
bank_name VARCHAR(120) NULL,
terminal_id VARCHAR(80) NULL, -- رقم ماكينة البنك
commission_rate DECIMAL(6,3) NOT NULL DEFAULT 0.000,
is_active TINYINT(1) NOT NULL DEFAULT 1,
sort_order INT NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uq_cm_store_code (store_id, code),
KEY idx_cm_branch (branch_id),
CONSTRAINT fk_cm_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_cm_branch FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- CARD_TRANSACTIONS
-- ============================================================
CREATE TABLE card_transactions (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
branch_id BIGINT UNSIGNED NOT NULL,
card_machine_id BIGINT UNSIGNED NOT NULL,
shift_id BIGINT UNSIGNED NULL,
user_id BIGINT UNSIGNED NULL,
type ENUM('OPENING','SALE','ADD','WITHDRAWAL','COMMISSION','CLOSING','ADJUSTMENT') NOT NULL,
start_balance DECIMAL(14,3) NULL,
end_balance DECIMAL(14,3) NULL,
amount DECIMAL(14,3) NOT NULL DEFAULT 0.000,
commission DECIMAL(14,3) NOT NULL DEFAULT 0.000,
difference DECIMAL(14,3) NOT NULL DEFAULT 0.000,
reference_type VARCHAR(60) NULL,
reference_id BIGINT UNSIGNED NULL,
notes VARCHAR(500) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_ct_machine_date (card_machine_id, created_at),
KEY idx_ct_shift (shift_id),
KEY idx_ct_store_date (store_id, created_at),
KEY idx_ct_reference (reference_type, reference_id),
CONSTRAINT fk_ct_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_ct_branch FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE RESTRICT,
CONSTRAINT fk_ct_machine FOREIGN KEY (card_machine_id) REFERENCES card_machines(id) ON DELETE RESTRICT,
CONSTRAINT fk_ct_shift FOREIGN KEY (shift_id) REFERENCES shifts(id) ON DELETE SET NULL,
CONSTRAINT fk_ct_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.10 جداول المصروفات والعملاء
sql
-- ============================================================
-- EXPENSES
-- ============================================================
CREATE TABLE expenses (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
branch_id BIGINT UNSIGNED NOT NULL,
shift_id BIGINT UNSIGNED NULL,
category VARCHAR(80) NOT NULL,
description VARCHAR(500) NOT NULL,
amount DECIMAL(14,3) NOT NULL,
payment_method_id BIGINT UNSIGNED NULL,
reference_no VARCHAR(80) NULL,
user_id BIGINT UNSIGNED NOT NULL,
approved_by BIGINT UNSIGNED NULL,
expense_date DATE NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_expenses_store_date (store_id, expense_date),
KEY idx_expenses_shift (shift_id),
CONSTRAINT fk_expenses_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_expenses_branch FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE RESTRICT,
CONSTRAINT fk_expenses_shift FOREIGN KEY (shift_id) REFERENCES shifts(id) ON DELETE SET NULL,
CONSTRAINT fk_expenses_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT,
CONSTRAINT fk_expenses_method FOREIGN KEY (payment_method_id) REFERENCES payment_methods(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- CUSTOMERS
-- ============================================================
CREATE TABLE customers (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
code VARCHAR(40) NULL,
name VARCHAR(180) NOT NULL,
phone VARCHAR(30) NULL,
email VARCHAR(150) NULL,
address TEXT NULL,
balance DECIMAL(14,3) NOT NULL DEFAULT 0.000,
loyalty_points INT UNSIGNED NOT NULL DEFAULT 0,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY idx_customers_store (store_id),
KEY idx_customers_phone (store_id, phone),
CONSTRAINT fk_customers_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- RECEIPTS
-- ============================================================
CREATE TABLE receipts (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
sale_id BIGINT UNSIGNED NOT NULL,
receipt_no VARCHAR(60) NOT NULL,
format ENUM('thermal','a4','pdf','email') NOT NULL DEFAULT 'thermal',
file_path VARCHAR(255) NULL,
printed_at DATETIME NULL,
print_count INT UNSIGNED NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uq_receipts_no (store_id, receipt_no),
KEY idx_receipts_sale (sale_id),
CONSTRAINT fk_receipts_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_receipts_sale FOREIGN KEY (sale_id) REFERENCES sales(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.11 جداول الذكاء الاصطناعي
sql
-- ============================================================
-- AI_EVENTS
-- ============================================================
CREATE TABLE ai_events (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
user_id BIGINT UNSIGNED NULL,
event_type ENUM('USER_QUERY','SYSTEM_SCAN','SCHEDULED_ANALYSIS','ALERT','ACTION_RESULT') NOT NULL,
intent VARCHAR(120) NULL,
input_text TEXT NULL,
context_json JSON NULL,
tool_calls JSON NULL,
response_text TEXT NULL,
response_json JSON NULL,
tokens_used INT UNSIGNED NULL,
latency_ms INT UNSIGNED NULL,
status ENUM('success','failed','partial') NOT NULL DEFAULT 'success',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_ai_events_store_date (store_id, created_at),
KEY idx_ai_events_user (user_id),
KEY idx_ai_events_type (event_type),
CONSTRAINT fk_ai_events_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_ai_events_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- AI_RECOMMENDATIONS
-- ============================================================
CREATE TABLE ai_recommendations (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
event_id BIGINT UNSIGNED NULL,
category ENUM(
'LOW_STOCK',
'SALES_TREND',
'SLOW_MOVING',
'HIGH_MOVING',
'CASH_DIFFERENCE',
'CARD_DIFFERENCE',
'UNUSUAL_TRANSACTION',
'INVENTORY_RISK',
'OPERATIONAL_ALERT',
'FORECAST'
) NOT NULL,
severity ENUM('info','warning','critical') NOT NULL DEFAULT 'info',
title VARCHAR(200) NOT NULL,
title_ar VARCHAR(220) NOT NULL,
body TEXT NOT NULL,
body_ar TEXT NOT NULL,
entity_type VARCHAR(60) NULL,
entity_id BIGINT UNSIGNED NULL,
data_json JSON NULL,
status ENUM('new','seen','approved','rejected','expired') NOT NULL DEFAULT 'new',
expires_at DATETIME NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_ai_rec_store_status (store_id, status),
KEY idx_ai_rec_category (category),
KEY idx_ai_rec_severity (severity),
CONSTRAINT fk_ai_rec_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_ai_rec_event FOREIGN KEY (event_id) REFERENCES ai_events(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- AI_ACTIONS
-- ============================================================
CREATE TABLE ai_actions (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
recommendation_id BIGINT UNSIGNED NULL,
event_id BIGINT UNSIGNED NULL,
tool_name VARCHAR(120) NOT NULL, -- inventory.adjust, product.update...
tool_args_json JSON NOT NULL,
status ENUM('proposed','pending_approval','approved','rejected','executed','failed','rolled_back') NOT NULL DEFAULT 'proposed',
requires_approval TINYINT(1) NOT NULL DEFAULT 1,
approved_by BIGINT UNSIGNED NULL,
approved_at DATETIME NULL,
executed_by BIGINT UNSIGNED NULL,
executed_at DATETIME NULL,
result_json JSON NULL,
error_message TEXT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_ai_actions_store_status (store_id, status),
KEY idx_ai_actions_tool (tool_name),
CONSTRAINT fk_ai_actions_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_ai_actions_rec FOREIGN KEY (recommendation_id) REFERENCES ai_recommendations(id) ON DELETE SET NULL,
CONSTRAINT fk_ai_actions_event FOREIGN KEY (event_id) REFERENCES ai_events(id) ON DELETE SET NULL,
CONSTRAINT fk_ai_actions_approver FOREIGN KEY (approved_by) REFERENCES users(id) ON DELETE SET NULL,
CONSTRAINT fk_ai_actions_executor FOREIGN KEY (executed_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.12 جداول السجلات والإعدادات
sql
-- ============================================================
-- AUDIT_LOGS
-- ============================================================
CREATE TABLE audit_logs (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NULL,
user_id BIGINT UNSIGNED NULL,
action VARCHAR(80) NOT NULL, -- CREATE, UPDATE, DELETE, PRICE_CHANGE...
entity_type VARCHAR(80) NOT NULL,
entity_id BIGINT UNSIGNED NULL,
before_json JSON NULL,
after_json JSON NULL,
ip_address VARCHAR(45) NULL,
user_agent VARCHAR(255) NULL,
request_id CHAR(36) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_audit_store_date (store_id, created_at),
KEY idx_audit_user (user_id),
KEY idx_audit_entity (entity_type, entity_id),
KEY idx_audit_action (action)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- SETTINGS
-- ============================================================
CREATE TABLE settings (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NULL, -- NULL = إعداد عام للنظام
group_key VARCHAR(80) NOT NULL, -- pos, receipt, tax, ai...
setting_key VARCHAR(120) NOT NULL,
setting_value TEXT NULL,
value_type ENUM('string','int','decimal','bool','json') NOT NULL DEFAULT 'string',
is_public TINYINT(1) NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uq_settings (store_id, group_key, setting_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- NOTIFICATIONS
-- ============================================================
CREATE TABLE notifications (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
user_id BIGINT UNSIGNED NULL,
type VARCHAR(80) NOT NULL,
title VARCHAR(200) NOT NULL,
body TEXT NULL,
data_json JSON NULL,
is_read TINYINT(1) NOT NULL DEFAULT 0,
read_at DATETIME NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_notif_user_read (user_id, is_read),
KEY idx_notif_store_date (store_id, created_at),
CONSTRAINT fk_notif_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_notif_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.13 جداول الاشتراكات (SaaS)
sql
-- ============================================================
-- SUBSCRIPTION_PLANS
-- ============================================================
CREATE TABLE subscription_plans (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
code VARCHAR(40) NOT NULL, -- starter, pro, ai_business, enterprise
name VARCHAR(150) NOT NULL,
name_ar VARCHAR(180) NOT NULL,
description TEXT NULL,
price_monthly DECIMAL(12,3) NOT NULL DEFAULT 0.000,
price_yearly DECIMAL(12,3) NOT NULL DEFAULT 0.000,
max_stores INT UNSIGNED NOT NULL DEFAULT 1,
max_branches INT UNSIGNED NOT NULL DEFAULT 1,
max_terminals INT UNSIGNED NOT NULL DEFAULT 1,
max_users INT UNSIGNED NOT NULL DEFAULT 1,
max_products INT UNSIGNED NOT NULL DEFAULT 500,
features_json JSON NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
sort_order INT NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uq_plans_code (code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- SUBSCRIPTIONS
-- ============================================================
CREATE TABLE subscriptions (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
store_id BIGINT UNSIGNED NOT NULL,
plan_id BIGINT UNSIGNED NOT NULL,
status ENUM('trial','active','past_due','cancelled','expired') NOT NULL DEFAULT 'trial',
billing_cycle ENUM('monthly','yearly') NOT NULL DEFAULT 'monthly',
started_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
current_period_start DATETIME NOT NULL,
current_period_end DATETIME NOT NULL,
trial_ends_at DATETIME NULL,
cancelled_at DATETIME NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY idx_subs_store_status (store_id, status),
KEY idx_subs_period_end (current_period_end),
CONSTRAINT fk_subs_store FOREIGN KEY (store_id) REFERENCES stores(id) ON DELETE RESTRICT,
CONSTRAINT fk_subs_plan FOREIGN KEY (plan_id) REFERENCES subscription_plans(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ملاحظة FK:
payments.card_machine_idيشير إلىcard_machines— يجب إنشاء جدولcard_machinesقبلpayments، أو تأجيل الـ FK بعد الإنشاء. في تنفيذ Laravel migrations سيتم الترتيب تلقائيًا.
3. Seed Data — الأصناف الـ 26
sql
-- ============================================================
-- SEED: STORE + BRANCH + TERMINAL + USER + ROLES
-- ============================================================
INSERT INTO stores (id, name, name_ar, currency, timezone, locale)
VALUES (1, 'Twist Taste', 'تويست تيست', 'SAR', 'Asia/Riyadh', 'ar');
INSERT INTO branches (id, store_id, code, name, name_ar)
VALUES (1, 1, 'MAIN', 'Main Branch', 'الفرع الرئيسي');
INSERT INTO terminals (id, store_id, branch_id, code, name)
VALUES (1, 1, 1, 'POS-01', 'Terminal 1');
-- ============================================================
-- SEED: CATEGORIES
-- ============================================================
INSERT INTO categories (id, store_id, name, name_ar, sort_order) VALUES
(1, 1, 'Cigarettes', 'سجائر', 1),
(2, 1, 'Beverages', 'مشروبات', 2),
(3, 1, 'Cards', 'بطاقات', 3),
(4, 1, 'Shisha', 'شيشة', 4),
(5, 1, 'Accessories','مستلزمات', 5);
-- ============================================================
-- SEED: PRODUCTS (26 items) — الأسماء كما في المصدر
-- ============================================================
INSERT INTO products
(store_id, category_id, sku, name, name_ar, name_en,
purchase_price, selling_price, stock_quantity, minimum_stock, tax_rate, unit, status)
VALUES
(1, 1, 'WINSTON', 'WINSTON', 'وينستون', 'WINSTON', 16.000, 20.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'PALLMALL', 'PALLMALL', 'بال مال', 'PALLMALL', 15.000, 19.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'CHESTER', 'CHESTER', 'تشيستر', 'CHESTER', 15.000, 19.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'WEST', 'WEST', 'ويست', 'WEST', 15.000, 19.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'GOLDLEAF18', 'GOLDLEAF 18', 'جولدليف 18', 'GOLDLEAF 18', 14.000, 18.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'MONTECARLO', 'MONTE CARLO', 'مونت كارلو', 'MONTE CARLO', 14.000, 18.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'DAVIDOFFSH', 'DAVIDOFF SH', 'دافيدوف ش', 'DAVIDOFF SH', 16.000, 20.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'PANLIAMANT', 'PANLIAMANT', 'بان ليامانت', 'PANLIAMANT', 16.000, 20.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'LM', 'L&M', 'إل أند إم', 'L&M', 18.000, 22.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'ROTHMANS', 'ROTHMANS', 'روثمانز', 'ROTHMANS', 17.000, 21.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'MARLBORO', 'MARLBORO', 'مارلبورو', 'MARLBORO', 21.000, 25.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'DAVIDOFFL', 'DAVIDOFF L', 'دافيدوف إل', 'DAVIDOFF L', 25.000, 29.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'KENT', 'KENT', 'كينت', 'KENT', 17.000, 21.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'DINHIL', 'DINHIL', 'دنهل', 'DINHIL', 16.000, 20.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'MARLBOROS', 'MARLBORO S', 'مارلبورو إس', 'MARLBORO S', 20.000, 24.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'WINSTONTALL19', 'WINSTON TALL 19', 'وينستون تال 19', 'WINSTON TALL 19',15.000, 19.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'WESTTALL18', 'WEST TALL 18', 'ويست تال 18', 'WEST TALL 18', 15.000, 18.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'BENSON', 'BENSON', 'بنسون', 'BENSON', 21.000, 25.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'GOLDLEAF16', 'GOLDLEAF 16', 'جولدليف 16', 'GOLDLEAF 16', 13.000, 16.000, 0, 5, 0, 'piece', 'active'),
(1, 5, 'LIGHTER1SR', 'LIGHTER 1SR', 'ولاعة 1 ريال', 'LIGHTER 1SR', 0.500, 1.000, 0, 10, 0, 'piece', 'active'),
(1, 1, 'WINSTONDMAX', 'WINSTON DU MAX', 'وينستون ديماكس', 'WINSTON DU MAX', 17.000, 21.000, 0, 5, 0, 'piece', 'active'),
(1, 4, 'SHISHA15', 'SHISHA 15', 'شيشة 15', 'SHISHA 15', 12.000, 15.000, 0, 5, 0, 'piece', 'active'),
(1, 4, 'SHISHA20', 'SHISHA 20', 'شيشة 20', 'SHISHA 20', 16.000, 20.000, 0, 5, 0, 'piece', 'active'),
(1, 4, 'SHISHA80', 'SHISHA 80', 'شيشة 80', 'SHISHA 80', 65.000, 80.000, 0, 3, 0, 'piece', 'active'),
(1, 1, 'LM18', 'L&M 18', 'إل أند إم 18', 'L&M 18', 15.000, 19.000, 0, 5, 0, 'piece', 'active'),
(1, 1, 'PALLMALL16', 'PALLMALL 16', 'بال مال 16', 'PALLMALL 16', 13.000, 16.000, 0, 5, 0, 'piece', 'active');
-- ============================================================
-- SEED: PAYMENT METHODS
-- ============================================================
INSERT INTO payment_methods (store_id, code, name, name_ar, type, requires_ref, sort_order) VALUES
(1, 'cash', 'Cash', 'نقد', 'cash', 0, 1),
(1, 'card', 'Card', 'شبكة', 'card', 1, 2),
(1, 'visa', 'Visa', 'فيزا', 'card', 1, 3),
(1, 'mojana', 'Mojana', 'مجانة', 'wallet', 1, 4),
(1, 'mixed', 'Mixed', 'مختلط', 'other', 0, 5);
-- ============================================================
-- SEED: CARD MACHINES (Cards No.1 / No.2 / No.3)
-- ============================================================
INSERT INTO card_machines (store_id, branch_id, code, name, sort_order) VALUES
(1, 1, 'CARDS_1', 'Cards No.1', 1),
(1, 1, 'CARDS_2', 'Cards No.2', 2),
(1, 1, 'CARDS_3', 'Cards No.3', 3);
-- ============================================================
-- SEED: ROLES
-- ============================================================
INSERT INTO roles (store_id, name, name_ar, is_system) VALUES
(NULL, 'super_admin', 'مدير النظام', 1),
(1, 'owner', 'مالك', 1),
(1, 'manager', 'مدير', 1),
(1, 'cashier', 'كاشير', 1),
(1, 'inventory_manager', 'مدير مخزون', 1),
(1, 'accountant', 'محاسب', 1),
(1, 'ai_operator', 'مشغل الذكاء', 1);
-- ============================================================
-- SEED: PERMISSIONS
-- ============================================================
INSERT INTO permissions (module, action, name, name_ar, is_sensitive) VALUES
('dashboard', 'view', 'dashboard.view', 'عرض لوحة القيادة', 0),
('pos', 'access', 'pos.access', 'استخدام الكاشير', 0),
('pos', 'refund', 'pos.refund', 'استرجاع من الكاشير',1),
('products', 'view', 'products.view', 'عرض المنتجات', 0),
('products', 'create', 'products.create', 'إضافة منتج', 0),
('products', 'update', 'products.update', 'تعديل منتج', 0),
('products', 'delete', 'products.delete', 'حذف منتج', 1),
('products', 'price_change', 'products.price_change', 'تغيير السعر', 1),
('inventory', 'view', 'inventory.view', 'عرض المخزون', 0),
('inventory', 'adjust', 'inventory.adjust', 'تسوية المخزون', 1),
('purchases', 'view', 'purchases.view', 'عرض المشتريات', 0),
('purchases', 'create', 'purchases.create', 'إضافة مشتريات', 0),
('purchases', 'approve','purchases.approve','اعتماد المشتريات', 1),
('sales', 'view', 'sales.view', 'عرض المبيعات', 0),
('sales', 'create', 'sales.create', 'إنشاء عملية بيع', 0),
('sales', 'void', 'sales.void', 'إلغاء عملية بيع', 1),
('cash', 'view', 'cash.view', 'عرض النقد', 0),
('cash', 'manage', 'cash.manage', 'إدارة النقد', 1),
('cash', 'reconcile', 'cash.reconcile','تسوية النقد', 1),
('cards', 'view', 'cards.view', 'عرض البطاقات', 0),
('cards', 'manage', 'cards.manage', 'إدارة البطاقات', 1),
('cards', 'reconcile', 'cards.reconcile','تسوية البطاقات', 1),
('shifts', 'open', 'shifts.open', 'فتح وردية', 0),
('shifts', 'close', 'shifts.close', 'إغلاق وردية', 0),
('shifts', 'view', 'shifts.view', 'عرض الورديات', 0),
('reports', 'view', 'reports.view', 'عرض التقارير', 0),
('reports', 'export', 'reports.export', 'تصدير التقارير', 0),
('users', 'view', 'users.view', 'عرض المستخدمين', 0),
('users', 'manage', 'users.manage', 'إدارة المستخدمين', 1),
('settings', 'view', 'settings.view', 'عرض الإعدادات', 0),
('settings', 'manage', 'settings.manage', 'إدارة الإعدادات', 1),
('ai', 'chat', 'ai.chat', 'محادثة الذكاء', 0),
('ai', 'analyze','ai.analyze', 'تحليل بالذكاء', 0),
('ai', 'execute','ai.execute', 'تنفيذ إجراء AI', 1),
('audit', 'view', 'audit.view', 'عرض سجل التدقيق', 1);
-- ============================================================
-- SEED: SUBSCRIPTION PLANS
-- ============================================================
INSERT INTO subscription_plans
(code, name, name_ar, price_monthly, price_yearly, max_stores, max_branches, max_terminals, max_users, max_products, sort_order)
VALUES
('starter', 'Starter', 'المبتدئ', 49.000, 490.000, 1, 1, 1, 2, 500, 1),
('pro', 'Pro', 'الاحترافي',149.000, 1490.000, 1, 3, 5, 15, 5000, 2),
('ai_business','AI Business','ذكاء أعمال',349.000,3490.000, 5, 10,20, 50, 50000,3),
('enterprise', 'Enterprise', 'المؤسسات', 0.000, 0.000, 0, 0, 0, 0, 0, 4);
ملاحظة:
purchase_priceتم تقديرها منطقيًا (سعر البيع ناقص هامش). عدّلها حسب بياناتك الفعلية.stock_quantityابدأت بـ 0 لأن المصدر لم يحدد كميات فعلية — ستُدخل عبرOPENING_BALANCEأوPURCHASE.
4. Permission Matrix
| Permission | Super Admin | Owner | Manager | Cashier | Inventory Mgr | Accountant | AI Operator |
|---|---|---|---|---|---|---|---|
| dashboard.view | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| pos.access | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| pos.refund | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| products.view | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| products.create | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ |
| products.update | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ |
| products.delete | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| products.price_change | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| inventory.view | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
| inventory.adjust | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ |
| purchases.view | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
| purchases.create | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ |
| purchases.approve | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| sales.view | ✅ | ✅ | ✅ | ✅ (own) | ❌ | ✅ | ✅ |
| sales.create | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| sales.void | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| cash.view | ✅ | ✅ | ✅ | ✅ (shift) | ❌ | ✅ | ✅ |
| cash.manage | ✅ | ✅ | ✅ | ✅ (shift) | ❌ | ❌ | ❌ |
| cash.reconcile | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ |
| cards.view | ✅ | ✅ | ✅ | ✅ (shift) | ❌ | ✅ | ✅ |
| cards.manage | ✅ | ✅ | ✅ | ✅ (shift) | ❌ | ❌ | ❌ |
| cards.reconcile | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ |
| shifts.open | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| shifts.close | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| shifts.view | ✅ | ✅ | ✅ | ✅ (own) | ✅ | ✅ | ✅ |
| reports.view | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
| reports.export | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
| users.view | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| users.manage | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| settings.view | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| settings.manage | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| ai.chat | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| ai.analyze | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
| ai.execute | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
| audit.view | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ |
5. API Contracts
5.1 Authentication
text
POST /api/auth/login POST /api/auth/logout POST /api/auth/refresh GET /api/auth/me POST /api/auth/forgot-password POST /api/auth/reset-password
POST /api/auth/login
json
{
"username": "cashier01",
"password": "secret",
"device_name": "POS-01"
}
Response 200:
json
{
"token": "eyJ...",
"user": { "id": 5, "full_name": "...", "roles": ["cashier"] },
"permissions": ["pos.access", "sales.create", "..."],
"store": { "id": 1, "name": "Twist Taste", "currency": "SAR" }
}
5.2 Products
text
GET /api/products?search=&category_id=&status=&page=&per_page=
POST /api/products
GET /api/products/{id}
PUT /api/products/{id}
DELETE /api/products/{id}
GET /api/products/low-stock
POST /api/products/{id}/barcodes
DELETE /api/products/{id}/barcodes/{barcodeId}
GET /api/products/{id}/price-history
POST /api/products
json
{
"sku": "WINSTON",
"name": "WINSTON",
"name_ar": "وينستون",
"category_id": 1,
"purchase_price": 16,
"selling_price": 20,
"minimum_stock": 5,
"unit": "piece",
"barcodes": ["6291234567890"]
}
5.3 Inventory
text
GET /api/inventory GET /api/inventory/movements?product_id=&type=&from=&to= POST /api/inventory/adjustment GET /api/inventory/valuation
POST /api/inventory/adjustment
json
{
"product_id": 1,
"new_quantity": 120,
"reason": "COUNT",
"notes": "جرد دوري"
}
5.4 Sales (POS)
text
POST /api/sales # إنشاء بيع
GET /api/sales
GET /api/sales/{id}
POST /api/sales/{id}/void
POST /api/sales/{id}/refund
POST /api/sales/hold
GET /api/sales/held
POST /api/sales/{id}/resume
POST /api/sales
json
{
"terminal_id": 1,
"shift_id": 10,
"items": [
{ "product_id": 1, "quantity": 2, "unit_price": 20 },
{ "product_id": 3, "quantity": 1, "unit_price": 19 }
],
"discount_amount": 0,
"payments": [
{ "payment_method_id": 1, "amount": 40 },
{ "payment_method_id": 2, "amount": 19, "card_machine_id": 1, "reference_number": "TX123" }
]
}
Response 201:
json
{
"sale_id": 1001,
"invoice_number": "INV-2026-0001001",
"total_amount": 59,
"paid_amount": 59,
"change_amount": 0,
"receipt_url": "/api/receipts/1001"
}
العملية ذرّية (Atomic): Sale + Sale Items + Payments + Stock Movements + Cash/Card Transactions + Audit Log — كلها داخل Transaction واحد. إذا فشل أي جزء → Rollback كامل.
5.5 Payments
text
GET /api/payment-methods POST /api/payments GET /api/payments?sale_id=
5.6 Cash
text
GET /api/cash/transactions?shift_id=&type=&from=&to= POST /api/cash/transactions POST /api/cash/reconcile GET /api/cash/balance
POST /api/cash/transactions
json
{
"shift_id": 10,
"type": "EXPENSE",
"direction": "out",
"amount": 50,
"description": "كهرباء"
}
5.7 Cards
text
GET /api/card-machines GET /api/cards/transactions?machine_id=&shift_id=&from=&to= POST /api/cards/transactions POST /api/cards/reconcile
POST /api/cards/reconcile
json
{
"shift_id": 10,
"machine_id": 2,
"start_balance": 1000,
"added_amount": 500,
"sales_amount": 1840,
"commission": 12,
"end_balance": 3328
}
Response:
json
{
"expected": 3328,
"actual": 3328,
"difference": 0,
"status": "matched"
}
5.8 Shifts
text
POST /api/shifts/open
GET /api/shifts/current
GET /api/shifts/{id}
POST /api/shifts/{id}/close
GET /api/shifts/{id}/report
POST /api/shifts/open
json
{ "terminal_id": 1, "opening_cash": 500 }
POST /api/shifts/{id}/close
json
{
"actual_cash": 2940,
"actual_card": 1910,
"notes": ""
}
5.9 Reports
text
GET /api/reports/daily?date=
GET /api/reports/monthly?month=&year=
GET /api/reports/products?from=&to=
GET /api/reports/inventory
GET /api/reports/cash?shift_id=
GET /api/reports/cards?shift_id=
GET /api/reports/shifts/{id}
GET /api/reports/profit?from=&to=
GET /api/reports/returns?from=&to=
GET /api/reports/expenses?from=&to=
5.10 AI
text
POST /api/ai/chat
POST /api/ai/analyze
GET /api/ai/recommendations?status=&category=
POST /api/ai/recommendations/{id}/approve
POST /api/ai/recommendations/{id}/reject
GET /api/ai/actions?status=
POST /api/ai/actions/{id}/approve
POST /api/ai/actions/{id}/execute
GET /api/ai/events?from=&to=
POST /api/ai/chat
json
{
"message": "ما المنتجات التي تحتاج إعادة طلب؟",
"context": { "shift_id": 10 }
}
Response 200:
json
{
"event_id": 501,
"intent": "LOW_STOCK_ANALYSIS",
"response": "لديك 5 منتجات وصلت للحد الأدنى:\n- WINSTON (متبقي 3)\n- ...",
"tools_used": ["inventory.get_low_stock"],
"recommendations": [
{ "id": 77, "category": "LOW_STOCK", "severity": "warning", "title": "..." }
]
}
مبدأ أساسي: أي Tool يغيّر البيانات يمر بـ: Permission Check → Validation → Business Rules → DB Transaction → Audit Log → Verification → Response. لا وصول مباشر من AI إلى MySQL.
6. AI Tool Registry
| Tool Name | Module | يغيّر البيانات؟ | يتطلب صلاحية | يتطلب موافقة |
|---|---|---|---|---|
sales.get_today | sales | ❌ | sales.view | ❌ |
sales.get_report | sales | ❌ | reports.view | ❌ |
sales.create | sales | ✅ | sales.create | ❌ |
products.get | products | ❌ | products.view | ❌ |
products.search | products | ❌ | products.view | ❌ |
products.create | products | ✅ | products.create | ✅ |
products.update | products | ✅ | products.update | ✅ |
products.change_price | products | ✅ | products.price_change | ✅ |
inventory.get | inventory | ❌ | inventory.view | ❌ |
inventory.get_low_stock | inventory | ❌ | inventory.view | ❌ |
inventory.adjust | inventory | ✅ | inventory.adjust | ✅ |
purchases.create | purchases | ✅ | purchases.create | ✅ |
cash.get_balance | cash | ❌ | cash.view | ❌ |
cash.reconcile | cash | ✅ | cash.reconcile | ✅ |
cards.reconcile | cards | ✅ | cards.reconcile | ✅ |
shifts.get | shifts | ❌ | shifts.view | ❌ |
shifts.report | shifts | ❌ | shifts.view | ❌ |
reports.daily | reports | ❌ | reports.view | ❌ |
reports.generate | reports | ❌ | reports.view | ❌ |
7. Migration Plan (Laravel)
ترتيب الـ migrations الإلزامي (لاحترام الـ Foreign Keys):
text
001_create_stores_table 002_create_branches_table 003_create_terminals_table 004_create_roles_table 005_create_permissions_table 006_create_users_table 007_create_role_permissions_table 008_create_user_roles_table 009_create_categories_table 010_create_brands_table 011_create_products_table 012_create_product_barcodes_table 013_create_product_prices_table 014_create_suppliers_table 015_create_purchases_table 016_create_purchase_items_table 017_create_card_machines_table 018_create_payment_methods_table 019_create_shifts_table 020_create_sales_table 021_create_sale_items_table 022_create_payments_table 023_create_stock_movements_table 024_create_inventory_adjustments_table 025_create_cash_transactions_table 026_create_card_transactions_table 027_create_sale_returns_table 028_create_sale_return_items_table 029_create_expenses_table 030_create_customers_table 031_create_receipts_table 032_create_subscription_plans_table 033_create_subscriptions_table 034_create_ai_events_table 035_create_ai_recommendations_table 036_create_ai_actions_table 037_create_audit_logs_table 038_create_settings_table 039_create_notifications_table
Seeders:
text
DatabaseSeeder ├── StoreSeeder ├── BranchSeeder ├── TerminalSeeder ├── RoleSeeder ├── PermissionSeeder ├── RolePermissionSeeder ├── UserSeeder ├── CategorySeeder ├── ProductSeeder ← الـ 26 صنف ├── PaymentMethodSeeder ├── CardMachineSeeder └── SubscriptionPlanSeeder
8. Business Rules (قواعد العمل الحرجة)
- البيع الذرّي: لا يُعتمد بيع إلا إذا نجح: Sale + Sale Items + Payments + Stock Movements + Cash/Card Transactions + Audit Log. أي فشل → Rollback كامل.
- المخزون لا يُعدّل مباشرة: كل تغيير في
products.stock_quantityيجب أن يسبقهstock_movementsمعbefore_quantityوafter_quantity. - منع البيع بالسالب: إذا
allow_negative = 0ولا يوجد رصيد كافٍ → رفض العملية مع رسالة واضحة. - إغلاق الوردية: لا يُسمح إلا إذا:
- لا توجد فواتير معلقة (
held) في الوردية. - تم إدخال
actual_cashوactual_card. - تم حساب
differenceتلقائيًا.
- لا توجد فواتير معلقة (
- تسوية البطاقات:
Start + Add + Sales - Commission - Withdrawal = Expected End. الفرق يُسجّل فيcard_transactions.difference. - تغيير السعر: يُسجّل في
product_prices(تاريخ) +audit_logs(before/after) + يتطلب صلاحيةproducts.price_change. - الاسترجاع: لا يُسمح إلا إذا:
- الفاتورة الأصلية موجودة وغير ملغاة.
- الكمية المرتجعة ≤ الكمية المبيعة.
- يتطلب صلاحية
pos.refundأوsales.void.
- الوردية المفتوحة: لا يمكن للمستخدم فتح وردية جديدة إذا كانت لديه وردية مفتوحة على نفس الجهاز.
- AI لا ينفذ تلقائيًا: أي Tool يغيّر البيانات يتطلب
ai.execute+ موافقة صريحة (ai_actions.status = approved). - Audit Log إلزامي: كل عملية حساسة (بيع، استرجاع، تسوية، تغيير سعر، حذف) تُسجّل في
audit_logsمع before/after.
9. Implementation Roadmap (محدّث)
| Phase | المخرج | المدة التقديرية |
|---|---|---|
| 1 | Architecture Blueprint + ERD | ✅ مكتمل (هذا المستند) |
| 2 | Migrations + Models + Relations | 3–4 أيام |
| 3 | Auth + RBAC + Seeders | 2–3 أيام |
| 4 | Products + Categories + Barcodes | 2–3 أيام |
| 5 | Inventory + Stock Movements | 3–4 أيام |
| 6 | Purchases + Suppliers | 3 أيام |
| 7 | POS Screen + Sales | 5–7 أيام |
| 8 | Payments (Cash/Card/Mixed) | 2–3 أيام |
| 9 | Cash Ledger + Reconciliation | 2–3 أيام |
| 10 | Card Machines + Reconciliation | 2–3 أيام |
| 11 | Shifts + Close/Reconcile | 3 أيام |
| 12 | Reports (Daily/Monthly/Shift) | 4–5 أيام |
| 13 | AI Layer + Tool Registry + Chat | 5–7 أيام |
| 14 | Subscriptions (SaaS) | 3–4 أيام |
| 15 | Security Hardening + Audit | 2–3 أيام |
| 16 | Testing (Unit + Feature) | 4–5 أيام |
| 17 | Deployment + Monitoring | 2–3 أيام |
الإجمالي التقديري: 50–65 يوم عمل لمطور واحد متمكن.
10. الخطوة التالية
هذا المستند هو Database Specification v1. الخطوة المنطقية التالية هي:
- اختيار الإطار: Laravel 11 (موصى به) أم PHP MVC مخصص؟
- توليد Migrations فعلية: تحويل كل
CREATE TABLEإلى ملف Laravel Migration. - توليد Models + Relations:
Product,Sale,Shift,StockMovement… مع العلاقات. - بناء Seeders: تشغيلها على بيئة
pos3.twisttaste.comلتأكيد صحة المخطط. - بناء Auth + RBAC: JWT أو Sanctum + Permission Engine.
- بناء POS Screen: أول شاشة تشغيلية فعلية.
توصية هندسية: ابدأ بـ Phase 2 (Database) و Phase 3 (Auth) بالتوازي، ثم Phase 4 (Products) لأنهما أساس كل شيء. لا تبدأ POS قبل أن يكون المخزون والمنتجات مستقرين.
هل تريد أن أُكمل الآن بـ:
- (أ) توليد ملفات Laravel Migrations الفعلية (كود PHP كامل)؟
- (ب) توليد Models + Relations كاملة؟
- (ج) توليد Seeders جاهزة للتشغيل؟
- (د) تصميم POS Screen (HTML/CSS/JS) كواجهة أولى
ZEZO AI POS — التعريف الجديد الكامل للمنصة + قاعدة البيانات + Prompt الاحترافي
الجزء الأول: التعريف الجديد للمنصة
1. الهوية الرسمية
text
╔══════════════════════════════════════════════════════════════════╗ ║ ║ ║ ZEZO AI BUILD PLATFORM POS AI ║ ║ ║ ║ AI-Powered Point of Sale & Business Operating ║ ║ Platform ║ ║ ║ ║ منصة تشغيل ذكية لإدارة المتجر ║ ║ ║ ╚══════════════════════════════════════════════════════════════════╝
الاسم الكامل: ZEZO AI BUILD PLATFORM POS AI
الاسم المختصر: ZEZO AI POS
النوع: منصة تشغيل أعمال + نظام نقاط بيع + طبقة ذكاء اصطناعي
اللغة الأساسية: PHP + MySQL + JavaScript
الاستضافة: pos3.twisttaste.com (Cloud Professional Hosting)
الجمهور المستهدف: المتاجر الصغيرة والمتوسطة، محلات السجائر، البقالات، الصيدليات، المطاعم السريعة
2. المشكلة التي يحلها النظام
النموذج الورقي الحالي (المصدر الأصلي) يعاني من:
| المشكلة | التأثير |
|---|---|
حقول Start / Buy / End / Sell فارغة | لا يوجد تتبع حقيقي للمخزون |
Total Amount فارغ | لا توجد معرفة بالكميات المبيعة |
Total in CASH فارغ | لا توجد تسوية نقدية |
Cards No.1/2/3 بدون بيانات | لا توجد تسوية بطاقات |
| لا يوجد تتبع للورديات | لا يمكن معرفة أداء كل كاشير |
| لا يوجد audit trail | لا يمكن اكتشاف الأخطاء أو التلاعب |
| لا توجد تقارير | لا يمكن اتخاذ قرارات |
الحل: تحويل كل خانة ورقية إلى كيان رقمي مترابط قابل للتحليل والتنفيذ الآلي.
3. الفلسفة المعمارية
text
DATA → TRANSACTION → EVENT → ANALYSIS → INSIGHT → RECOMMENDATION → ACTION → VERIFICATION
كل عملية بيع أو شراء أو جرد أو حركة نقدية تتحول إلى حدث رقمي يمكن تتبعه ومراجعته وتحليله.
المبدأ الأساسي: النظام ليس CRUD — بل Business Operating System.
4. الوحدات الرئيسية (13 وحدة)
text
┌─────────────────────────────────────────────────────────────┐ │ ZEZO AI POS MODULES │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 01. Dashboard لوحة القيادة │ │ 02. POS نقطة البيع │ │ 03. Products المنتجات │ │ 04. Inventory المخزون │ │ 05. Purchases المشتريات │ │ 06. Sales المبيعات │ │ 07. Cash النقد │ │ 08. Cards البطاقات │ │ 09. Shifts الورديات │ │ 10. Reports التقارير │ │ 11. AI Assistant مساعد الذكاء الاصطناعي │ │ 12. Users & Roles المستخدمون والصلاحيات │ │ 13. Settings الإعدادات │ │ │ └─────────────────────────────────────────────────────────────┘
الجزء الثاني: شرح كل شاشة بالتفصيل
الشاشة 01 — Login (تسجيل الدخول)
الوظيفة: بوابة الدخول الآمنة للنظام.
العناصر:
- شعار ZEZO AI POS
- حقل
Email / Username - حقل
Password - زر
Login - رابط
نسيت كلمة المرور - اختيار اللغة (AR/EN)
السلوك:
- بعد 5 محاولات فاشلة → قفل الحساب 15 دقيقة
- تسجيل
last_login_atوlast_login_ip - إصدار Token (JWT أو Sanctum)
- توجيه حسب الدور:
Cashier→ POS مباشرةManager/Owner→ DashboardInventory Manager→ Inventory
الشاشة 02 — Dashboard (لوحة القيادة)
الوظيفة: نظرة شاملة على أداء المتجر في الوقت الفعلي.
البطاقات العلوية:
text
┌──────────────┬──────────────┬──────────────┬──────────────┐ │ مبيعات اليوم │ العمليات │ النقد │ الشبكة │ │ 4,850 SAR │ 187 │ 2,940 SAR │ 1,910 SAR │ └──────────────┴──────────────┴──────────────┴──────────────┘
البطاقات الوسطى:
- قيمة المخزون الإجمالية
- المنتجات منخفضة المخزون (5 منتجات)
- المنتجات التي تحتاج إعادة طلب (3 منتجات)
- الوردية الحالية (مفتوحة منذ 8:00 صباحًا)
الرسوم البيانية:
- مبيعات آخر 7 أيام (Line Chart)
- توزيع طرق الدفع (Pie Chart)
- أعلى 5 منتجات مبيعًا (Bar Chart)
قسم AI Insights:
text
┌────────────────────────────────────────────────────────────┐ │ ZEZO AI INSIGHT │ │ ──────────────────────────────────────────────────────── │ │ 📈 منتج WINSTON ارتفعت مبيعاته 22% خلال آخر 7 أيام │ │ ⚠️ منتج SHISHA 80 وصل إلى الحد الأدنى (3 وحدات) │ │ 💰 يوجد فرق 15 SAR بين النقد المتوقع والفعلي في الوردية │ │ 🎯 3 منتجات لم تتحرك خلال 30 يومًا │ └────────────────────────────────────────────────────────────┘
آخر العمليات:
- جدول بآخر 10 فواتير: رقم الفاتورة، الوقت، الإجمالي، طريقة الدفع، الكاشير
الشاشة 03 — POS (نقطة البيع / الكاشير)
الوظيفة: الشاشة الأسرع والأكثر استخدامًا. مصممة لبيئة الزحمة.
التخطيط:
text
┌─────────────────────────────────────────────────────────────────┐ │ ZEZO AI POS [الوردية مفتوحة] [المستخدم: أحمد] │ ├─────────────────────────────────────────────────────────────────┤ │ 🔍 ابحث عن منتج... [Barcode] [F2=بحث] │ ├───────────────┬─────────────────────────────────────────────────┤ │ التصنيفات │ المنتجات │ │ │ │ │ ▸ الكل │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │ ▸ سجائر │ │WINSTON │ │PALLMALL│ │CHESTER │ │ WEST │ │ │ ▸ مشروبات │ │ 20 SAR │ │ 19 SAR │ │ 19 SAR │ │ 19 SAR │ │ │ ▸ بطاقات │ └────────┘ └────────┘ └────────┘ └────────┘ │ │ ▸ شيشة │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │ ▸ مستلزمات │ │MARLBORO│ │DAVIDOFF│ │ KENT │ │ L&M │ │ │ │ │ 25 SAR │ │ 29 SAR │ │ 21 SAR │ │ 22 SAR │ │ │ │ └────────┘ └────────┘ └────────┘ └────────┘ │ ├───────────────┴─────────────────────────────────────────────────┤ │ السلة │ │ ┌───────────────────────────────────────────────────────────┐ │ │ │ WINSTON × 2 40 SAR [−][+] [🗑️] │ │ │ │ CHESTER × 1 19 SAR [−][+] [🗑️] │ │ │ └───────────────────────────────────────────────────────────┘ │ │ │ │ المجموع الفرعي: 59.00 SAR │ │ الخصم: 0.00 SAR │ │ الضريبة: 0.00 SAR │ │ ───────────────────────────────────────────────────── │ │ الإجمالي: 59.00 SAR │ │ │ │ [CASH] [CARD] [MIXED] [HOLD] [RESUME] [PAY] │ └─────────────────────────────────────────────────────────────────┘
متطلبات السرعة:
- بحث فوري (Debounced Search 150ms)
- Barcode Scanner Support
- Keyboard Shortcuts:
F2= بحثF4= الدفعF6= تعليق الفاتورةF8= استرجاع فاتورة معلقة+/-= تعديل الكميةDelete= حذف من السلة
- إضافة منتج بضغطة واحدة
- تعديل الكمية مباشرة في السلة
- لا إعادة تحميل للصفحة (AJAX/Fetch)
- طباعة الإيصال بعد الدفع مباشرة
سلوك الدفع المختلط:
text
┌─────────────────────────────────────┐ │ الدفع المختلط │ │ ───────────────────────────────── │ │ الإجمالي: 59.00 SAR │ │ نقد: 40.00 SAR [___] │ │ شبكة: 19.00 SAR [___] │ │ ───────────────────────────────── │ │ المتبقي: 0.00 SAR │ │ [تأكيد الدفع] │ └─────────────────────────────────────┘
الشاشة 04 — Products (المنتجات)
الوظيفة: إدارة كتالوج المنتجات.
شريط الأدوات:
- زر
+ إضافة منتج - بحث
- فلتر (تصنيف، حالة، مخزون منخفض)
- تصدير Excel/PDF
جدول المنتجات:
| SKU | الاسم | التصنيف | سعر الشراء | سعر البيع | المخزون | الحد الأدنى | الحالة | إجراءات |
|---|---|---|---|---|---|---|---|---|
| WINSTON | وينستون | سجائر | 16.00 | 20.00 | 120 | 5 | نشط | ✏️ 🗑️ |
| PALLMALL | بال مال | سجائر | 15.00 | 19.00 | 85 | 5 | نشط | ✏️ 🗑️ |
نموذج إضافة/تعديل منتج:
text
┌─────────────────────────────────────────┐ │ إضافة منتج جديد │ │ ───────────────────────────────────── │ │ SKU: [WINSTON____] │ │ الاسم (AR): [وينستون____] │ │ الاسم (EN): [WINSTON____] │ │ التصنيف: [سجائر ▼] │ │ الماركة: [▼] │ │ سعر الشراء: [16.00] │ │ سعر البيع: [20.00] │ │ الضريبة: [0%] │ │ الوحدة: [قطعة ▼] │ │ الحد الأدنى: [5] │ │ الحد الأقصى: [100] │ │ الباركود: [6291234567890] [+] │ │ ───────────────────────────────────── │ │ [حفظ] [إلغاء] │ └─────────────────────────────────────────┘
ميزة AI: عند كتابة اسم منتج جديد، يقترح AI:
- التصنيف المناسب
- سعر البيع المقترح بناءً على أسعار مشابهة
- الحد الأدنى للمخزون
الشاشة 05 — Inventory (المخزون)
الوظيفة: تتبع كل حركة مخزون.
تبويبات:
- المخزون الحالي — جدول بالمنتجات والكميات الحالية
- حركات المخزون — Stock Movements Log
- التسويات — Inventory Adjustments
- منخفض المخزون — Low Stock Alerts
- تقييم المخزون — Inventory Valuation
جدول حركات المخزون:
| التاريخ | المنتج | النوع | الكمية | قبل | بعد | المرجع | المستخدم |
|---|---|---|---|---|---|---|---|
| 2026-10-03 10:30 | WINSTON | SALE | -2 | 122 | 120 | INV-1001 | أحمد |
| 2026-10-03 09:15 | PALLMALL | PURCHASE | +50 | 35 | 85 | PO-2001 | محمد |
| 2026-10-03 08:00 | WINSTON | OPENING | +120 | 0 | 120 | – | النظام |
أنواع الحركات:
OPENING_BALANCE— رصيد افتتاحيPURCHASE— شراءSALE— بيعRETURN— استرجاعADJUSTMENT— تسويةDAMAGE— تلفTRANSFER— نقل بين الفروع
معادلة المخزون:
text
الرصيد الحالي = الرصيد السابق + المشتريات - المبيعات + المرتجعات ± التسويات
الشاشة 06 — Purchases (المشتريات)
الوظيفة: إدارة فواتير الشراء من الموردين.
شاشة فاتورة شراء:
text
┌─────────────────────────────────────────────────────────┐ │ فاتورة شراء جديدة │ │ ───────────────────────────────────────────────────── │ │ المورد: [شركة الدخان المتحدة ▼] │ │ رقم الفاتورة: [PO-2026-0045] │ │ التاريخ: [2026-10-03] │ │ ───────────────────────────────────────────────────── │ │ المنتجات: │ │ ┌─────────────────────────────────────────────────┐ │ │ │ المنتج │ الكمية │ سعر الشراء │ الإجمالي │ │ │ │ WINSTON │ 50 │ 16.00 │ 800.00 │ │ │ │ PALLMALL │ 30 │ 15.00 │ 450.00 │ │ │ └─────────────────────────────────────────────────┘ │ │ [+] إضافة منتج │ │ ───────────────────────────────────────────────────── │ │ المجموع: 1,250.00 SAR │ │ المدفوع: 1,000.00 SAR │ │ المتبقي: 250.00 SAR │ │ ───────────────────────────────────────────────────── │ │ [حفظ كمسودة] [اعتماد واستلام] │ └─────────────────────────────────────────────────────────┘
عند اعتماد الشراء:
text
Purchase → Purchase Items → Stock Movement (+) → Inventory Update → Audit Log
الشاشة 07 — Sales (المبيعات)
الوظيفة: عرض وإدارة كل عمليات البيع.
جدول المبيعات:
| رقم الفاتورة | التاريخ | الكاشير | الإجمالي | الدفع | الحالة | إجراءات |
|---|---|---|---|---|---|---|
| INV-1001 | 10:30 | أحمد | 59.00 | نقد | مكتملة | 👁️ 🖨️ ↩️ |
| INV-1002 | 10:35 | أحمد | 120.00 | شبكة | مكتملة | 👁️ 🖨️ ↩️ |
| INV-1003 | 10:40 | محمد | 45.00 | مختلط | مكتملة | 👁️ 🖨️ ↩️ |
تفاصيل الفاتورة:
- المنتجات والكميات
- طريقة الدفع
- الوردية
- الكاشير
- الإيصال
الاسترجاع:
- يتطلب صلاحية
pos.refundأوsales.void - لا يُسمح إلا إذا الكمية المرتجعة ≤ المبيعة
- يُسجّل في
sale_returns+stock_movements(RETURN) +cash_transactions(REFUND)
الشاشة 08 — Cash (النقد)
الوظيفة: إدارة الصندوق النقدي وتسويته.
تبويبات:
- حركات النقد — Cash Transactions
- إدخال نقد — Cash In
- إخراج نقد — Cash Out
- المصروفات — Expenses
- التسوية — Reconciliation
جدول حركات النقد:
| الوقت | النوع | الوصف | المبلغ | الرصيد بعد | المستخدم |
|---|---|---|---|---|---|
| 08:00 | OPENING | رصيد افتتاحي | +500 | 500 | أحمد |
| 08:15 | SALE | فاتورة INV-1001 | +59 | 559 | أحمد |
| 10:00 | EXPENSE | كهرباء | -50 | 509 | أحمد |
| 12:00 | SALE | فاتورة INV-1005 | +120 | 629 | أحمد |
شاشة التسوية:
text
┌─────────────────────────────────────────┐ │ تسوية النقد - الوردية #10 │ │ ───────────────────────────────────── │ │ الرصيد الافتتاحي: 500.00 SAR │ │ إجمالي المبيعات النقدية: 2,940.00 SAR │ │ إجمالي المصروفات: -200.00 SAR │ │ إجمالي الاسترجاعات: -100.00 SAR │ │ ───────────────────────────────────── │ │ النقد المتوقع: 3,140.00 SAR │ │ النقد الفعلي: [_______] SAR │ │ ───────────────────────────────────── │ │ الفرق: [_______] SAR │ │ ───────────────────────────────────── │ │ [إغلاق الوردية] │ └─────────────────────────────────────────┘
الشاشة 09 — Cards (البطاقات)
الوظيفة: إدارة 3 ماكينات بطاقات وتسويتها.
الماكينات:
Cards No.1— مكينة رقم 1Cards No.2— مكينة رقم 2Cards No.3— مكينة رقم 3
جدول الماكينات:
| الماكينة | البداية | الشحن | المبيعات | الربح | الباقي | الفرق |
|---|---|---|---|---|---|---|
| Cards No.1 | 1,000 | 500 | 1,840 | 12 | 3,328 | 0 |
| Cards No.2 | 800 | 300 | 950 | 8 | 2,042 | -5 |
| Cards No.3 | 1,200 | 0 | 1,100 | 10 | 2,290 | 0 |
معادلة التسوية:
text
Start + Add + Sales - Commission = Expected End Expected End - Actual End = Difference
شاشة التسوية لكل ماكينة:
text
┌─────────────────────────────────────────┐ │ تسوية Cards No.2 - الوردية #10 │ │ ───────────────────────────────────── │ │ Start (البداية): 800.00 SAR │ │ Add (الشحن): 300.00 SAR │ │ Sales (المبيعات): 950.00 SAR │ │ Commission (الربح): 8.00 SAR │ │ ───────────────────────────────────── │ │ Expected End: 2,042.00 SAR │ │ Actual End: [_______] SAR │ │ ───────────────────────────────────── │ │ Difference: [_______] SAR │ │ ───────────────────────────────────── │ │ [حفظ التسوية] │ └─────────────────────────────────────────┘
الشاشة 10 — Shifts (الورديات)
الوظيفة: إدارة ورديات الكاشيرين.
دورة حياة الوردية:
text
OPEN SHIFT (opening_cash)
↓
SALES (cash + card + mixed)
↓
CASH TRANSACTIONS (expenses, deposits)
↓
CARD TRANSACTIONS (reconciliation)
↓
CLOSE SHIFT (actual_cash, actual_card)
↓
RECONCILIATION (expected vs actual)
شاشة فتح وردية:
text
┌─────────────────────────────────────────┐ │ فتح وردية جديدة │ │ ───────────────────────────────────── │ │ الجهاز: [POS-01 ▼] │ │ الرصيد الافتتاحي: [500.00] SAR │ │ ملاحظات: [_____________] │ │ ───────────────────────────────────── │ │ [فتح الوردية] │ └─────────────────────────────────────────┘
شاشة إغلاق وردية:
text
┌─────────────────────────────────────────┐ │ إغلاق الوردية #10 │ │ ───────────────────────────────────── │ │ ملخص الوردية: │ │ إجمالي المبيعات: 4,850.00 SAR │ │ عدد الفواتير: 187 │ │ النقد المتوقع: 3,140.00 SAR │ │ الشبكة المتوقعة: 1,910.00 SAR │ │ المصروفات: -200.00 SAR │ │ ───────────────────────────────────── │ │ إدخال التسوية: │ │ النقد الفعلي: [_______] SAR │ │ الشبكة الفعلية: [_______] SAR │ │ ───────────────────────────────────── │ │ الفرق النقدي: [_______] SAR │ │ الفرق الشبكي: [_______] SAR │ │ ───────────────────────────────────── │ │ [إغلاق الوردية نهائيًا] │ └─────────────────────────────────────────┘
قيود الإغلاق:
- لا توجد فواتير معلقة (
held) - تم إدخال
actual_cashوactual_card - تم حساب الفروقات
الشاشة 11 — Reports (التقارير)
الوظيفة: تحويل البيانات إلى قرارات.
أنواع التقارير:
| التقرير | الوصف | الفترة |
|---|---|---|
| Daily Sales | مبيعات اليوم | يومي |
| Monthly Sales | مبيعات الشهر | شهري |
| Product Sales | مبيعات كل منتج | مخصص |
| Inventory | حالة المخزون | لحظي |
| Purchases | المشتريات | مخصص |
| Cash | حركات النقد | مخصص |
| Cards | حركات البطاقات | مخصص |
| Shifts | تقرير الوردية | لكل وردية |
| Profit | الأرباح | مخصص |
| Returns | الاسترجاعات | مخصص |
| Expenses | المصروفات | مخصص |
| AI Analytics | تحليلات AI | مخصص |
تقرير يومي نموذجي:
text
┌─────────────────────────────────────────┐ │ تقرير يومي - 2026-10-03 │ │ ───────────────────────────────────── │ │ إجمالي المبيعات: 4,850.00 SAR │ │ عدد الفواتير: 187 │ │ ───────────────────────────────────── │ │ النقد: 2,940.00 SAR │ │ الشبكة: 1,910.00 SAR │ │ ───────────────────────────────────── │ │ المصروفات: -200.00 SAR │ │ صافي النقد: 2,740.00 SAR │ │ ───────────────────────────────────── │ │ أعلى 5 منتجات: │ │ 1. WINSTON — 45 وحدة — 900 SAR │ │ 2. MARLBORO — 32 وحدة — 800 SAR │ │ 3. L&M — 28 وحدة — 616 SAR │ │ 4. PALLMALL — 25 وحدة — 475 SAR │ │ 5. CHESTER — 22 وحدة — 418 SAR │ │ ───────────────────────────────────── │ │ [تصدير PDF] [تصدير Excel] [طباعة] │ └─────────────────────────────────────────┘
الشاشة 12 — AI Assistant (مساعد الذكاء الاصطناعي)
الوظيفة: التفاعل مع البيانات باللغة الطبيعية.
واجهة المحادثة:
text
┌─────────────────────────────────────────────┐ │ ZEZO AI │ │ ───────────────────────────────────────── │ │ ماذا تريد أن تعرف؟ │ │ │ │ 👤 ما مبيعات اليوم؟ │ │ │ │ 🤖 إجمالي المبيعات اليوم: 4,850 SAR │ │ عدد الفواتير: 187 │ │ النقد: 2,940 SAR | الشبكة: 1,910 SAR │ │ │ │ 👤 ما المنتجات التي تحتاج إعادة طلب؟ │ │ │ │ 🤖 لديك 3 منتجات وصلت للحد الأدنى: │ │ • SHISHA 80 (متبقي 3) │ │ • WINSTON DU MAX (متبقي 4) │ │ • DAVIDOFF L (متبقي 5) │ │ │ │ 👤 هل هناك فرق في النقد؟ │ │ │ │ 🤖 نعم، يوجد فرق 15 SAR في الوردية #10 │ │ المتوقع: 3,140 SAR | الفعلي: 3,125 SAR │ │ [عرض التفاصيل] [تسوية] │ │ │ ├─────────────────────────────────────────────┤ │ اكتب سؤالك... [Send] │ └─────────────────────────────────────────────┘
أمثلة على الأسئلة المدعومة:
- “أعطني تقرير اليوم”
- “ما هي المنتجات الأكثر مبيعًا؟”
- “كم قيمة المخزون الحالي؟”
- “هل هناك فرق في تسوية البطاقات؟”
- “أضف منتج WINSTON بسعر 20”
- “اعمل تسوية للوردية الحالية”
- “من الكاشير صاحب أعلى مبيعات اليوم؟”
البنية الداخلية:
text
User Message
↓
Intent Detection (NLP)
↓
Context Builder (shift, user, permissions)
↓
Tool Registry (select appropriate tool)
↓
Permission Engine (check access)
↓
Business Rules (validate)
↓
Tool Execution (call service)
↓
Verification (confirm result)
↓
Response Generation
الشاشة 13 — Users & Roles (المستخدمون والصلاحيات)
الأدوار:
| الدور | الصلاحيات |
|---|---|
| Super Admin | كل شيء |
| Owner | كل شيء ما عدا إعدادات النظام العميقة |
| Manager | إدارة كاملة ما عدا حذف المنتجات وتغيير الأسعار |
| Cashier | POS فقط + ورديته |
| Inventory Manager | المنتجات + المخزون + المشتريات |
| Accountant | التقارير + النقد + البطاقات |
| AI Operator | AI + التقارير |
مصفوفة الصلاحيات: (كما في المستند السابق)
الجزء الثالث: باقات الاشتراك
الباقة 01 — ZEZO POS STARTER
الجمهور: المتاجر الصغيرة
السعر: 49 SAR/شهر — 490 SAR/سنة
المميزات:
- متجر واحد
- فرع واحد
- جهاز POS واحد
- 2 مستخدمين
- 500 منتج
- POS أساسي
- إدارة المنتجات
- إدارة المخزون
- النقد
- تقارير أساسية
- دعم فني أساسي
الباقة 02 — ZEZO POS PRO
الجمهور: المتاجر المتوسطة
السعر: 149 SAR/شهر — 1,490 SAR/سنة
المميزات:
- متجر واحد
- 3 فروع
- 5 أجهزة POS
- 15 مستخدم
- 5,000 منتج
- كل مميزات Starter
- المشتريات والموردين
- إدارة البطاقات (3 ماكينات)
- الورديات الكاملة
- تقارير متقدمة
- AI Insights أساسي
- دعم فني أولوية
الباقة 03 — ZEZO AI BUSINESS
الجمهور: السلاسل والمتاجر الكبيرة
السعر: 349 SAR/شهر — 3,490 SAR/سنة
المميزات:
- 5 متاجر
- 10 فروع
- 20 جهاز POS
- 50 مستخدم
- 50,000 منتج
- كل مميزات PRO
- AI Assistant كامل
- AI Recommendations
- Forecasting (توقع المبيعات)
- تقارير آلية يومية/أسبوعية
- API للتكامل
- تكامل مع أنظمة خارجية
- دعم فني مخصص
الباقة 04 — ZEZO AI ENTERPRISE
الجمهور: المؤسسات
السعر: مخصص
المميزات:
- فروع غير محدودة
- أجهزة غير محدودة
- مستخدمون غير محدودين
- RBAC متقدم
- Workflows مخصصة
- API كامل
- AI Agents مخصصون
- سياسات AI مخصصة
- Audit System كامل
- بنية تحتية مخصصة
- SLA مخصص
- مدير حساب مخصص
الجزء الرابع: بنية قاعدة البيانات الكاملة
4.1 مخطط ERD المبسط
text
STORES ├── BRANCHES │ ├── TERMINALS │ └── SHIFTS │ ├── SALES │ │ ├── SALE_ITEMS → PRODUCTS │ │ └── PAYMENTS │ ├── CASH_TRANSACTIONS │ └── CARD_TRANSACTIONS → CARD_MACHINES ├── USERS → USER_ROLES → ROLES → ROLE_PERMISSIONS → PERMISSIONS ├── CATEGORIES ├── BRANDS ├── PRODUCTS │ ├── PRODUCT_BARCODES │ ├── PRODUCT_PRICES │ ├── STOCK_MOVEMENTS │ └── INVENTORY_ADJUSTMENTS ├── SUPPLIERS │ └── PURCHASES → PURCHASE_ITEMS → PRODUCTS ├── CUSTOMERS ├── EXPENSES ├── RECEIPTS ├── AI_EVENTS │ ├── AI_RECOMMENDATIONS │ └── AI_ACTIONS ├── AUDIT_LOGS ├── SETTINGS ├── NOTIFICATIONS └── SUBSCRIPTIONS → SUBSCRIPTION_PLANS
4.2 الجداول الكاملة (Laravel Migrations)
4.2.1 جداول الهوية
php
// database/migrations/001_create_stores_table.php
Schema::create('stores', function (Blueprint $table) {
$table->id();
$table->string('name', 150);
$table->string('name_ar', 180);
$table->string('legal_name', 200)->nullable();
$table->string('tax_number', 60)->nullable();
$table->string('currency', 10)->default('SAR');
$table->string('timezone', 60)->default('Asia/Riyadh');
$table->string('locale', 10)->default('ar');
$table->string('logo_path', 255)->nullable();
$table->boolean('is_active')->default(true);
$table->timestamps();
$table->softDeletes();
$table->index('is_active');
});
// database/migrations/002_create_branches_table.php
Schema::create('branches', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->string('code', 30);
$table->string('name', 150);
$table->string('name_ar', 180);
$table->text('address')->nullable();
$table->string('phone', 30)->nullable();
$table->boolean('is_active')->default(true);
$table->timestamps();
$table->unique(['store_id', 'code']);
});
// database/migrations/003_create_terminals_table.php
Schema::create('terminals', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('branch_id')->constrained()->restrictOnDelete();
$table->string('code', 30);
$table->string('name', 150);
$table->string('device_token', 120)->nullable();
$table->timestamp('last_seen_at')->nullable();
$table->boolean('is_active')->default(true);
$table->timestamps();
$table->unique(['store_id', 'code']);
});
// database/migrations/004_create_roles_table.php
Schema::create('roles', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->nullable()->constrained()->cascadeOnDelete();
$table->string('name', 80);
$table->string('name_ar', 120);
$table->text('description')->nullable();
$table->boolean('is_system')->default(false);
$table->timestamps();
$table->unique(['store_id', 'name']);
});
// database/migrations/005_create_permissions_table.php
Schema::create('permissions', function (Blueprint $table) {
$table->id();
$table->string('module', 60);
$table->string('action', 60);
$table->string('name', 150)->unique();
$table->string('name_ar', 180);
$table->text('description')->nullable();
$table->boolean('is_sensitive')->default(false);
$table->timestamps();
$table->index('module');
});
// database/migrations/006_create_users_table.php
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('branch_id')->nullable()->constrained()->nullOnDelete();
$table->string('username', 80)->unique();
$table->string('email', 150)->unique();
$table->string('phone', 30)->nullable();
$table->string('password');
$table->string('full_name', 150);
$table->string('avatar_path', 255)->nullable();
$table->string('locale', 10)->default('ar');
$table->boolean('is_active')->default(true);
$table->timestamp('last_login_at')->nullable();
$table->string('last_login_ip', 45)->nullable();
$table->unsignedInteger('failed_attempts')->default(0);
$table->timestamp('locked_until')->nullable();
$table->rememberToken();
$table->timestamps();
$table->softDeletes();
$table->index('store_id');
$table->index('is_active');
});
// database/migrations/007_create_role_permissions_table.php
Schema::create('role_permissions', function (Blueprint $table) {
$table->foreignId('role_id')->constrained()->cascadeOnDelete();
$table->foreignId('permission_id')->constrained()->cascadeOnDelete();
$table->timestamp('granted_at')->useCurrent();
$table->primary(['role_id', 'permission_id']);
});
// database/migrations/008_create_user_roles_table.php
Schema::create('user_roles', function (Blueprint $table) {
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->foreignId('role_id')->constrained()->cascadeOnDelete();
$table->timestamp('assigned_at')->useCurrent();
$table->primary(['user_id', 'role_id']);
});
4.2.2 جداول المنتجات
php
// database/migrations/009_create_categories_table.php
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('parent_id')->nullable()->constrained('categories')->nullOnDelete();
$table->string('name', 120);
$table->string('name_ar', 150);
$table->integer('sort_order')->default(0);
$table->boolean('is_active')->default(true);
$table->timestamps();
$table->index('store_id');
});
// database/migrations/010_create_brands_table.php
Schema::create('brands', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->string('name', 120);
$table->string('name_ar', 150)->nullable();
$table->boolean('is_active')->default(true);
$table->timestamps();
$table->index('store_id');
});
// database/migrations/011_create_products_table.php
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('category_id')->nullable()->constrained()->nullOnDelete();
$table->foreignId('brand_id')->nullable()->constrained()->nullOnDelete();
$table->string('sku', 60);
$table->string('name', 180);
$table->string('name_ar', 200)->nullable();
$table->string('name_en', 200)->nullable();
$table->text('description')->nullable();
$table->string('image_path', 255)->nullable();
$table->string('unit', 30)->default('piece');
$table->decimal('purchase_price', 12, 3)->default(0);
$table->decimal('selling_price', 12, 3)->default(0);
$table->decimal('tax_rate', 6, 3)->default(0);
$table->decimal('stock_quantity', 14, 3)->default(0);
$table->decimal('minimum_stock', 14, 3)->default(0);
$table->decimal('maximum_stock', 14, 3)->nullable();
$table->boolean('track_stock')->default(true);
$table->boolean('allow_negative')->default(false);
$table->enum('status', ['active', 'inactive', 'archived'])->default('active');
$table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
$table->timestamps();
$table->softDeletes();
$table->unique(['store_id', 'sku']);
$table->index(['store_id', 'status']);
$table->index(['store_id', 'stock_quantity', 'minimum_stock']);
});
// database/migrations/012_create_product_barcodes_table.php
Schema::create('product_barcodes', function (Blueprint $table) {
$table->id();
$table->foreignId('product_id')->constrained()->cascadeOnDelete();
$table->string('barcode', 80)->unique();
$table->string('barcode_type', 30)->default('EAN13');
$table->boolean('is_primary')->default(false);
$table->timestamps();
$table->index('product_id');
});
// database/migrations/013_create_product_prices_table.php
Schema::create('product_prices', function (Blueprint $table) {
$table->id();
$table->foreignId('product_id')->constrained()->cascadeOnDelete();
$table->enum('price_type', ['purchase', 'selling', 'wholesale', 'minimum']);
$table->decimal('price', 12, 3);
$table->timestamp('effective_from')->useCurrent();
$table->timestamp('effective_to')->nullable();
$table->foreignId('changed_by')->nullable()->constrained('users')->nullOnDelete();
$table->string('reason', 255)->nullable();
$table->timestamps();
$table->index(['product_id', 'price_type', 'effective_from'], 'idx_prices_product_type');
});
4.2.3 جداول المخزون
php
// database/migrations/014_create_stock_movements_table.php
Schema::create('stock_movements', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('product_id')->constrained()->restrictOnDelete();
$table->enum('type', [
'OPENING_BALANCE', 'PURCHASE', 'SALE', 'RETURN',
'ADJUSTMENT', 'DAMAGE', 'TRANSFER_IN', 'TRANSFER_OUT'
]);
$table->decimal('quantity', 14, 3);
$table->decimal('before_quantity', 14, 3);
$table->decimal('after_quantity', 14, 3);
$table->decimal('unit_cost', 12, 3)->nullable();
$table->decimal('total_cost', 14, 3)->nullable();
$table->string('reference_type', 60)->nullable();
$table->unsignedBigInteger('reference_id')->nullable();
$table->foreignId('user_id')->nullable()->constrained()->nullOnDelete();
$table->foreignId('shift_id')->nullable()->constrained()->nullOnDelete();
$table->string('notes', 500)->nullable();
$table->timestamps();
$table->index(['product_id', 'created_at']);
$table->index(['store_id', 'created_at']);
$table->index('type');
$table->index(['reference_type', 'reference_id'], 'idx_sm_reference');
});
// database/migrations/015_create_inventory_adjustments_table.php
Schema::create('inventory_adjustments', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('product_id')->constrained()->restrictOnDelete();
$table->foreignId('movement_id')->constrained('stock_movements')->restrictOnDelete();
$table->enum('reason', ['COUNT', 'DAMAGE', 'LOSS', 'EXPIRY', 'CORRECTION', 'OTHER']);
$table->decimal('old_quantity', 14, 3);
$table->decimal('new_quantity', 14, 3);
$table->decimal('difference', 14, 3);
$table->text('notes')->nullable();
$table->foreignId('approved_by')->nullable()->constrained('users')->nullOnDelete();
$table->foreignId('user_id')->constrained()->restrictOnDelete();
$table->timestamps();
$table->index(['store_id', 'created_at']);
});
4.2.4 جداول المشتريات
php
// database/migrations/016_create_suppliers_table.php
Schema::create('suppliers', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->string('code', 40);
$table->string('name', 180);
$table->string('name_ar', 200)->nullable();
$table->string('phone', 30)->nullable();
$table->string('email', 150)->nullable();
$table->text('address')->nullable();
$table->string('tax_number', 60)->nullable();
$table->decimal('balance', 14, 3)->default(0);
$table->boolean('is_active')->default(true);
$table->timestamps();
$table->softDeletes();
$table->unique(['store_id', 'code']);
});
// database/migrations/017_create_purchases_table.php
Schema::create('purchases', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('branch_id')->nullable()->constrained()->nullOnDelete();
$table->foreignId('supplier_id')->nullable()->constrained()->nullOnDelete();
$table->string('invoice_number', 80)->nullable();
$table->date('invoice_date');
$table->decimal('subtotal', 14, 3)->default(0);
$table->decimal('tax_amount', 14, 3)->default(0);
$table->decimal('discount_amount', 14, 3)->default(0);
$table->decimal('total_amount', 14, 3)->default(0);
$table->decimal('paid_amount', 14, 3)->default(0);
$table->decimal('due_amount', 14, 3)->default(0);
$table->enum('status', ['draft', 'pending', 'received', 'partial', 'cancelled'])->default('draft');
$table->text('notes')->nullable();
$table->foreignId('created_by')->constrained('users')->restrictOnDelete();
$table->foreignId('received_by')->nullable()->constrained('users')->nullOnDelete();
$table->timestamp('received_at')->nullable();
$table->timestamps();
$table->index(['store_id', 'invoice_date']);
$table->index('supplier_id');
$table->index('status');
});
// database/migrations/018_create_purchase_items_table.php
Schema::create('purchase_items', function (Blueprint $table) {
$table->id();
$table->foreignId('purchase_id')->constrained()->cascadeOnDelete();
$table->foreignId('product_id')->constrained()->restrictOnDelete();
$table->decimal('quantity', 14, 3);
$table->decimal('received_qty', 14, 3)->default(0);
$table->decimal('unit_cost', 12, 3);
$table->decimal('tax_rate', 6, 3)->default(0);
$table->decimal('discount', 12, 3)->default(0);
$table->decimal('line_total', 14, 3);
$table->timestamps();
$table->index('purchase_id');
$table->index('product_id');
});
4.2.5 جداول البطاقات والدفع
php
// database/migrations/019_create_card_machines_table.php
Schema::create('card_machines', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('branch_id')->constrained()->restrictOnDelete();
$table->string('code', 30);
$table->string('name', 120);
$table->string('bank_name', 120)->nullable();
$table->string('terminal_id', 80)->nullable();
$table->decimal('commission_rate', 6, 3)->default(0);
$table->boolean('is_active')->default(true);
$table->integer('sort_order')->default(0);
$table->timestamps();
$table->unique(['store_id', 'code']);
});
// database/migrations/020_create_payment_methods_table.php
Schema::create('payment_methods', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->string('code', 40);
$table->string('name', 100);
$table->string('name_ar', 120);
$table->enum('type', ['cash', 'card', 'wallet', 'credit', 'other']);
$table->boolean('requires_ref')->default(false);
$table->boolean('is_active')->default(true);
$table->integer('sort_order')->default(0);
$table->timestamps();
$table->unique(['store_id', 'code']);
});
4.2.6 جداول الورديات والمبيعات
php
// database/migrations/021_create_shifts_table.php
Schema::create('shifts', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('branch_id')->constrained()->restrictOnDelete();
$table->foreignId('terminal_id')->nullable()->constrained()->nullOnDelete();
$table->foreignId('user_id')->constrained()->restrictOnDelete();
$table->foreignId('closed_by')->nullable()->constrained('users')->nullOnDelete();
$table->string('shift_number', 60);
$table->decimal('opening_cash', 14, 3)->default(0);
$table->decimal('expected_cash', 14, 3)->default(0);
$table->decimal('actual_cash', 14, 3)->default(0);
$table->decimal('cash_difference', 14, 3)->default(0);
$table->decimal('expected_card', 14, 3)->default(0);
$table->decimal('actual_card', 14, 3)->default(0);
$table->decimal('card_difference', 14, 3)->default(0);
$table->decimal('total_sales', 14, 3)->default(0);
$table->decimal('total_returns', 14, 3)->default(0);
$table->decimal('total_expenses', 14, 3)->default(0);
$table->enum('status', ['open', 'closed', 'reconciled'])->default('open');
$table->timestamp('opened_at')->useCurrent();
$table->timestamp('closed_at')->nullable();
$table->text('notes')->nullable();
$table->timestamps();
$table->unique(['store_id', 'shift_number']);
$table->index(['store_id', 'opened_at']);
$table->index('status');
});
// database/migrations/022_create_sales_table.php
Schema::create('sales', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('branch_id')->constrained()->restrictOnDelete();
$table->foreignId('terminal_id')->nullable()->constrained()->nullOnDelete();
$table->foreignId('shift_id')->nullable()->constrained()->nullOnDelete();
$table->foreignId('user_id')->constrained()->restrictOnDelete();
$table->foreignId('customer_id')->nullable()->constrained()->nullOnDelete();
$table->string('invoice_number', 60);
$table->enum('sale_type', ['sale', 'return', 'exchange'])->default('sale');
$table->decimal('subtotal', 14, 3)->default(0);
$table->decimal('discount_amount', 14, 3)->default(0);
$table->decimal('tax_amount', 14, 3)->default(0);
$table->decimal('total_amount', 14, 3)->default(0);
$table->decimal('paid_amount', 14, 3)->default(0);
$table->decimal('change_amount', 14, 3)->default(0);
$table->decimal('due_amount', 14, 3)->default(0);
$table->unsignedInteger('item_count')->default(0);
$table->enum('status', ['draft', 'held', 'completed', 'refunded', 'partially_refunded', 'voided'])->default('draft');
$table->text('notes')->nullable();
$table->timestamp('completed_at')->nullable();
$table->timestamps();
$table->unique(['store_id', 'invoice_number']);
$table->index(['store_id', 'created_at']);
$table->index(['branch_id', 'created_at']);
$table->index('shift_id');
$table->index('user_id');
$table->index('status');
});
// database/migrations/023_create_sale_items_table.php
Schema::create('sale_items', function (Blueprint $table) {
$table->id();
$table->foreignId('sale_id')->constrained()->cascadeOnDelete();
$table->foreignId('product_id')->constrained()->restrictOnDelete();
$table->string('product_name', 200);
$table->decimal('quantity', 14, 3);
$table->decimal('unit_price', 12, 3);
$table->decimal('unit_cost', 12, 3)->nullable();
$table->decimal('tax_rate', 6, 3)->default(0);
$table->decimal('discount', 12, 3)->default(0);
$table->decimal('line_subtotal', 14, 3);
$table->decimal('line_total', 14, 3);
$table->timestamps();
$table->index('sale_id');
$table->index('product_id');
});
// database/migrations/024_create_payments_table.php
Schema::create('payments', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('sale_id')->constrained()->cascadeOnDelete();
$table->foreignId('payment_method_id')->constrained()->restrictOnDelete();
$table->foreignId('card_machine_id')->nullable()->constrained()->nullOnDelete();
$table->decimal('amount', 14, 3);
$table->string('reference_number', 120)->nullable();
$table->enum('status', ['pending', 'completed', 'failed', 'refunded'])->default('completed');
$table->timestamp('paid_at')->useCurrent();
$table->foreignId('user_id')->nullable()->constrained()->nullOnDelete();
$table->string('notes', 500)->nullable();
$table->timestamps();
$table->index('sale_id');
$table->index('payment_method_id');
$table->index(['store_id', 'paid_at']);
});
4.2.7 جداول النقد والبطاقات
php
// database/migrations/025_create_cash_transactions_table.php
Schema::create('cash_transactions', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('branch_id')->constrained()->restrictOnDelete();
$table->foreignId('shift_id')->nullable()->constrained()->nullOnDelete();
$table->foreignId('user_id')->constrained()->restrictOnDelete();
$table->enum('type', [
'OPENING', 'SALE', 'REFUND', 'EXPENSE',
'DEPOSIT', 'WITHDRAWAL', 'ADJUSTMENT', 'CLOSING'
]);
$table->enum('direction', ['in', 'out']);
$table->decimal('amount', 14, 3);
$table->decimal('balance_after', 14, 3);
$table->string('description', 500)->nullable();
$table->string('reference_type', 60)->nullable();
$table->unsignedBigInteger('reference_id')->nullable();
$table->timestamps();
$table->index('shift_id');
$table->index(['store_id', 'created_at']);
$table->index('type');
});
// database/migrations/026_create_card_transactions_table.php
Schema::create('card_transactions', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('branch_id')->constrained()->restrictOnDelete();
$table->foreignId('card_machine_id')->constrained()->restrictOnDelete();
$table->foreignId('shift_id')->nullable()->constrained()->nullOnDelete();
$table->foreignId('user_id')->nullable()->constrained()->nullOnDelete();
$table->enum('type', ['OPENING', 'SALE', 'ADD', 'WITHDRAWAL', 'COMMISSION', 'CLOSING', 'ADJUSTMENT']);
$table->decimal('start_balance', 14, 3)->nullable();
$table->decimal('end_balance', 14, 3)->nullable();
$table->decimal('amount', 14, 3)->default(0);
$table->decimal('commission', 14, 3)->default(0);
$table->decimal('difference', 14, 3)->default(0);
$table->string('reference_type', 60)->nullable();
$table->unsignedBigInteger('reference_id')->nullable();
$table->string('notes', 500)->nullable();
$table->timestamps();
$table->index(['card_machine_id', 'created_at']);
$table->index('shift_id');
$table->index(['store_id', 'created_at']);
});
4.2.8 جداول الاسترجاع والمصروفات
php
// database/migrations/027_create_sale_returns_table.php
Schema::create('sale_returns', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('sale_id')->constrained()->restrictOnDelete();
$table->foreignId('shift_id')->nullable()->constrained()->nullOnDelete();
$table->foreignId('user_id')->constrained()->restrictOnDelete();
$table->string('return_number', 60);
$table->string('reason', 255)->nullable();
$table->decimal('total_amount', 14, 3)->default(0);
$table->enum('refund_method', ['cash', 'card', 'store_credit'])->default('cash');
$table->enum('status', ['pending', 'approved', 'rejected', 'completed'])->default('pending');
$table->foreignId('approved_by')->nullable()->constrained('users')->nullOnDelete();
$table->timestamps();
$table->timestamp('completed_at')->nullable();
$table->unique(['store_id', 'return_number']);
$table->index('sale_id');
});
// database/migrations/028_create_sale_return_items_table.php
Schema::create('sale_return_items', function (Blueprint $table) {
$table->id();
$table->foreignId('return_id')->constrained('sale_returns')->cascadeOnDelete();
$table->foreignId('sale_item_id')->constrained()->restrictOnDelete();
$table->foreignId('product_id')->constrained()->restrictOnDelete();
$table->decimal('quantity', 14, 3);
$table->decimal('unit_price', 12, 3);
$table->decimal('line_total', 14, 3);
$table->timestamps();
$table->index('return_id');
});
// database/migrations/029_create_expenses_table.php
Schema::create('expenses', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('branch_id')->constrained()->restrictOnDelete();
$table->foreignId('shift_id')->nullable()->constrained()->nullOnDelete();
$table->string('category', 80);
$table->string('description', 500);
$table->decimal('amount', 14, 3);
$table->foreignId('payment_method_id')->nullable()->constrained()->nullOnDelete();
$table->string('reference_no', 80)->nullable();
$table->foreignId('user_id')->constrained()->restrictOnDelete();
$table->foreignId('approved_by')->nullable()->constrained('users')->nullOnDelete();
$table->date('expense_date');
$table->timestamps();
$table->index(['store_id', 'expense_date']);
$table->index('shift_id');
});
// database/migrations/030_create_customers_table.php
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->string('code', 40)->nullable();
$table->string('name', 180);
$table->string('phone', 30)->nullable();
$table->string('email', 150)->nullable();
$table->text('address')->nullable();
$table->decimal('balance', 14, 3)->default(0);
$table->unsignedInteger('loyalty_points')->default(0);
$table->boolean('is_active')->default(true);
$table->timestamps();
$table->index('store_id');
$table->index(['store_id', 'phone']);
});
// database/migrations/031_create_receipts_table.php
Schema::create('receipts', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('sale_id')->constrained()->cascadeOnDelete();
$table->string('receipt_no', 60);
$table->enum('format', ['thermal', 'a4', 'pdf', 'email'])->default('thermal');
$table->string('file_path', 255)->nullable();
$table->timestamp('printed_at')->nullable();
$table->unsignedInteger('print_count')->default(0);
$table->timestamps();
$table->unique(['store_id', 'receipt_no']);
$table->index('sale_id');
});
4.2.9 جداول الاشتراكات
php
// database/migrations/032_create_subscription_plans_table.php
Schema::create('subscription_plans', function (Blueprint $table) {
$table->id();
$table->string('code', 40)->unique();
$table->string('name', 150);
$table->string('name_ar', 180);
$table->text('description')->nullable();
$table->decimal('price_monthly', 12, 3)->default(0);
$table->decimal('price_yearly', 12, 3)->default(0);
$table->unsignedInteger('max_stores')->default(1);
$table->unsignedInteger('max_branches')->default(1);
$table->unsignedInteger('max_terminals')->default(1);
$table->unsignedInteger('max_users')->default(1);
$table->unsignedInteger('max_products')->default(500);
$table->json('features_json')->nullable();
$table->boolean('is_active')->default(true);
$table->integer('sort_order')->default(0);
$table->timestamps();
});
// database/migrations/033_create_subscriptions_table.php
Schema::create('subscriptions', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('plan_id')->constrained('subscription_plans')->restrictOnDelete();
$table->enum('status', ['trial', 'active', 'past_due', 'cancelled', 'expired'])->default('trial');
$table->enum('billing_cycle', ['monthly', 'yearly'])->default('monthly');
$table->timestamp('started_at')->useCurrent();
$table->timestamp('current_period_start');
$table->timestamp('current_period_end');
$table->timestamp('trial_ends_at')->nullable();
$table->timestamp('cancelled_at')->nullable();
$table->timestamps();
$table->index(['store_id', 'status']);
$table->index('current_period_end');
});
4.2.10 جداول الذكاء الاصطناعي
php
// database/migrations/034_create_ai_events_table.php
Schema::create('ai_events', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('user_id')->nullable()->constrained()->nullOnDelete();
$table->enum('event_type', ['USER_QUERY', 'SYSTEM_SCAN', 'SCHEDULED_ANALYSIS', 'ALERT', 'ACTION_RESULT']);
$table->string('intent', 120)->nullable();
$table->text('input_text')->nullable();
$table->json('context_json')->nullable();
$table->json('tool_calls')->nullable();
$table->text('response_text')->nullable();
$table->json('response_json')->nullable();
$table->unsignedInteger('tokens_used')->nullable();
$table->unsignedInteger('latency_ms')->nullable();
$table->enum('status', ['success', 'failed', 'partial'])->default('success');
$table->timestamps();
$table->index(['store_id', 'created_at']);
$table->index('event_type');
});
// database/migrations/035_create_ai_recommendations_table.php
Schema::create('ai_recommendations', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('event_id')->nullable()->constrained('ai_events')->nullOnDelete();
$table->enum('category', [
'LOW_STOCK', 'SALES_TREND', 'SLOW_MOVING', 'HIGH_MOVING',
'CASH_DIFFERENCE', 'CARD_DIFFERENCE', 'UNUSUAL_TRANSACTION',
'INVENTORY_RISK', 'OPERATIONAL_ALERT', 'FORECAST'
]);
$table->enum('severity', ['info', 'warning', 'critical'])->default('info');
$table->string('title', 200);
$table->string('title_ar', 220);
$table->text('body');
$table->text('body_ar');
$table->string('entity_type', 60)->nullable();
$table->unsignedBigInteger('entity_id')->nullable();
$table->json('data_json')->nullable();
$table->enum('status', ['new', 'seen', 'approved', 'rejected', 'expired'])->default('new');
$table->timestamp('expires_at')->nullable();
$table->timestamps();
$table->index(['store_id', 'status']);
$table->index('category');
$table->index('severity');
});
// database/migrations/036_create_ai_actions_table.php
Schema::create('ai_actions', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->restrictOnDelete();
$table->foreignId('recommendation_id')->nullable()->constrained('ai_recommendations')->nullOnDelete();
$table->foreignId('event_id')->nullable()->constrained('ai_events')->nullOnDelete();
$table->string('tool_name', 120);
$table->json('tool_args_json');
$table->enum('status', ['proposed', 'pending_approval', 'approved', 'rejected', 'executed', 'failed', 'rolled_back'])->default('proposed');
$table->boolean('requires_approval')->default(true);
$table->foreignId('approved_by')->nullable()->constrained('users')->nullOnDelete();
$table->timestamp('approved_at')->nullable();
$table->foreignId('executed_by')->nullable()->constrained('users')->nullOnDelete();
$table->timestamp('executed_at')->nullable();
$table->json('result_json')->nullable();
$table->text('error_message')->nullable();
$table->timestamps();
$table->index(['store_id', 'status']);
$table->index('tool_name');
});
4.2.11 جداول السجلات والإعدادات
php
// database/migrations/037_create_audit_logs_table.php
Schema::create('audit_logs', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->nullable()->constrained()->nullOnDelete();
$table->foreignId('user_id')->nullable()->constrained()->nullOnDelete();
$table->string('action', 80);
$table->string('entity_type', 80);
$table->unsignedBigInteger('entity_id')->nullable();
$table->json('before_json')->nullable();
$table->json('after_json')->nullable();
$table->string('ip_address', 45)->nullable();
$table->string('user_agent', 255)->nullable();
$table->uuid('request_id')->nullable();
$table->timestamps();
$table->index(['store_id', 'created_at']);
$table->index('user_id');
$table->index(['entity_type', 'entity_id'], 'idx_audit_entity');
$table->index('action');
});
// database/migrations/038_create_settings_table.php
Schema::create('settings', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->nullable()->constrained()->cascadeOnDelete();
$table->string('group_key', 80);
$table->string('setting_key', 120);
$table->text('setting_value')->nullable();
$table->enum('value_type', ['string', 'int', 'decimal', 'bool', 'json'])->default('string');
$table->boolean('is_public')->default(false);
$table->timestamps();
$table->unique(['store_id', 'group_key', 'setting_key'], 'uq_settings');
});
// database/migrations/039_create_notifications_table.php
Schema::create('notifications', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->constrained()->cascadeOnDelete();
$table->foreignId('user_id')->nullable()->constrained()->cascadeOnDelete();
$table->string('type', 80);
$table->string('title', 200);
$table->text('body')->nullable();
$table->json('data_json')->nullable();
$table->boolean('is_read')->default(false);
$table->timestamp('read_at')->nullable();
$table->timestamps();
$table->index(['user_id', 'is_read']);
$table->index(['store_id', 'created_at']);
});
4.3 Seed Data — الأصناف الـ26
php
// database/seeders/ProductSeeder.php
public function run(): void
{
$store = Store::first();
$category = Category::where('name', 'Cigarettes')->first();
$products = [
['sku' => 'WINSTON', 'name' => 'WINSTON', 'name_ar' => 'وينستون', 'price' => 20],
['sku' => 'PALLMALL', 'name' => 'PALLMALL', 'name_ar' => 'بال مال', 'price' => 19],
['sku' => 'CHESTER', 'name' => 'CHESTER', 'name_ar' => 'شيستر', 'price' => 19],
['sku' => 'WEST', 'name' => 'WEST', 'name_ar' => 'وست', 'price' => 19],
['sku' => 'GOLDLEAF18', 'name' => 'GOLDLEAF 18', 'name_ar' => 'غولد ليف 18', 'price' => 18],
['sku' => 'MONTECARLO', 'name' => 'MONTE CARLO', 'name_ar' => 'مونت كارلو', 'price' => 18],
['sku' => 'DAVIDOFFSH', 'name' => 'DAVIDOFF SH', 'name_ar' => 'ديفيدوف صغير', 'price' => 20],
['sku' => 'PANLIAMANT', 'name' => 'PANLIAMANT', 'name_ar' => 'بارليمنت', 'price' => 20],
['sku' => 'LM', 'name' => 'L&M', 'name_ar' => 'ال ام', 'price' => 22],
['sku' => 'ROTHMANS', 'name' => 'ROTHMANS', 'name_ar' => 'روثمان', 'price' => 21],
['sku' => 'MARLBORO', 'name' => 'MARLBORO', 'name_ar' => 'مارلبورو', 'price' => 25],
['sku' => 'DAVIDOFFL', 'name' => 'DAVIDOFF L', 'name_ar' => 'ديفيدوف كبير', 'price' => 29],
['sku' => 'KENT', 'name' => 'KENT', 'name_ar' => 'كنت', 'price' => 21],
['sku' => 'DINHIL', 'name' => 'DINHIL', 'name_ar' => 'دنهل', 'price' => 20],
['sku' => 'MARLBOROS', 'name' => 'MARLBORO S', 'name_ar' => 'مارلبورو صغير', 'price' => 24],
['sku' => 'WINSTONTALL19', 'name' => 'WINSTON TALL 19','name_ar' => 'وينستون 19', 'price' => 19],
['sku' => 'WESTTALL18', 'name' => 'WEST TALL 18', 'name_ar' => 'وست 18', 'price' => 18],
['sku' => 'BENSON', 'name' => 'BENSON', 'name_ar' => 'بنسون', 'price' => 25],
['sku' => 'GOLDLEAF16', 'name' => 'GOLDLEAF 16', 'name_ar' => 'غولد ليف 16', 'price' => 16],
['sku' => 'LIGHTER1SR', 'name' => 'LIGHTER 1SR', 'name_ar' => 'ولاعة', 'price' => 1],
['sku' => 'WINSTONDMAX', 'name' => 'WINSTON DU MAX','name_ar' => 'وينستون ديماكس','price' => 21],
['sku' => 'SHISHA15', 'name' => 'SHISHA 15', 'name_ar' => 'شيشة 15', 'price' => 15],
['sku' => 'SHISHA20', 'name' => 'SHISHA 20', 'name_ar' => 'شيشة 20', 'price' => 20],
['sku' => 'SHISHA80', 'name' => 'SHISHA 80', 'name_ar' => 'شيشة 80', 'price' => 80],
['sku' => 'LM18', 'name' => 'L&M 18', 'name_ar' => 'ال ام 18', 'price' => 19],
['sku' => 'PALLMALL16', 'name' => 'PALLMALL 16', 'name_ar' => 'بال مال 16', 'price' => 16],
];
foreach ($products as $p) {
Product::create([
'store_id' => $store->id,
'category_id' => $category->id,
'sku' => $p['sku'],
'name' => $p['name'],
'name_ar' => $p['name_ar'],
'name_en' => $p['name'],
'purchase_price' => $p['price'] * 0.8,
'selling_price' => $p['price'],
'stock_quantity' => 0,
'minimum_stock' => 5,
'unit' => 'piece',
'status' => 'active',
]);
}
}
الجزء الخامس: Prompt الاحترافي الكامل
markdown
# ZEZO AI POS — Master Build Prompt أنت مهندس برمجيات أول ومتخصص في بناء أنظمة POS احترافية. ## المهمة حوّل ZEZO AI POS من مفهوم إلى نظام PHP + MySQL جاهز للإنتاج. ## السياق - الاستضافة: pos3.twisttaste.com - الموارد: 200GB disk, 6144MB RAM, 5 CPU, 200 PHP workers - الاستخدام الحالي: 94% (يجب تحسين الأداء) - التقنية: PHP 8.2+, MySQL 8, JavaScript ## البيانات الأولية 26 صنفًا (سجائر، شيشة، ولاعة) بأسعارها المحددة في Seed Data. ## المطلوب 1. **Database Schema كامل** (40 جدول) 2. **Laravel Migrations** جاهزة للتشغيل 3. **Models + Relations** كاملة 4. **Seeders** للأصناف الـ26 5. **Authentication + RBAC** (7 أدوار، 35 صلاحية) 6. **POS Screen** سريعة (AJAX, barcode, keyboard shortcuts) 7. **Inventory System** (Stock Movements) 8. **Cash + Card Management** (تسوية) 9. **Shifts** (فتح/إغلاق/تسوية) 10. **Reports** (11 تقرير) 11. **AI Layer** (Tool Registry + Permission Engine) 12. **API** (REST, 15 endpoint) 13. **Audit Logs** لكل عملية حساسة 14. **Subscription System** (4 باقات) ## قواعد العمل الحرجة 1. البيع ذرّي: Sale + Items + Payments + Stock + Audit = Transaction واحد 2. المخزون لا يُعدّل مباشرة — فقط عبر Stock Movements 3. AI لا يصل مباشرة إلى MySQL — عبر Tool Registry + Permission Engine 4. كل عملية حساسة → Audit Log 5. الوردية لا تُغلق إلا بعد التسوية الكاملة ## البنية
app/
├── Models/ (40 model)
├── Services/ (Business Logic)
├── Repositories/ (Data Access)
├── Controllers/ (HTTP)
├── Policies/ (Authorization)
├── Events/ (Domain Events)
├── Listeners/ (Event Handlers)
├── Jobs/ (Queue Jobs)
├── AI/ (AI Layer)
│ ├── IntentDetector
│ ├── ContextBuilder
│ ├── ToolRegistry
│ ├── PermissionEngine
│ └── Tools/
└── Reports/ (Report Generators)
database/
├── migrations/ (40 migration)
├── seeders/ (12 seeder)
└── factories/ (Test data)
routes/
├── web.php
├── api.php
└── ai.php
resources/
├── views/ (Blade templates)
├── css/
└── js/
text
## المراحل (17 Phase) 1. Architecture Blueprint ✅ 2. Database (Migrations + Models) 3. Authentication + RBAC 4. Products 5. Inventory 6. Purchases 7. POS 8. Payments 9. Cash 10. Cards 11. Shifts 12. Reports 13. AI Layer 14. Subscriptions 15. Security 16. Testing 17. Deployment ## المخرجات المطلوبة - INSTALLATION.md - ARCHITECTURE.md - DATABASE.md - API.md - AI.md - SECURITY.md ## ابدأ الآن المرحلة 2: Database - أنشئ 40 migration - أنشئ 40 model مع Relations - أنشئ 12 seeder - شغّل `php artisan migrate --seed` - تحقق من العلاقات - لا تنتقل للمرحلة 3 حتى تنجح كل الاختبارات
الخلاصة
هذا المستند يقدم:
- التعريف الجديد الكامل للمنصة ZEZO AI POS
- شرح كل شاشة بالتفصيل (13 شاشة)
- 4 باقات اشتراك مع المميزات
- 40 جدول قاعدة بيانات كاملة مع Laravel Migrations
- Seed Data للأصناف الـ26
- Prompt احترافي جاهز للاستخدام مع أي وكيل تطوير
الخطوة التالية: اختر إحدى هذه المسارات:
- (أ) توليد Models + Relations كاملة (PHP)
- (ب) توليد Controllers + Services
- (ج) تصميم POS Screen (HTML/CSS/JS)
- (د) بناء AI Layer كامل
- (هـ) كتابة Tests
أخبرني أي مسار تريد أن نبدأ به.
قم با إعادة تحويلها الى prompt يقوم ببناء وتوليد جميع البيانات التالية كاملة
هل يمكنك إعادة بناء وتنفيذ جميع البيانات التالية مع دمجها مع السابق
تصميم POS Screen (HTML/CSS/JS)
توليد Models + Relations كاملة (HTML/CSS/JS-PHP)
(د) بناء AI Layer كامل
مع بناء وتصميم
UI/UX Design System
Color Palette
Typography
Component Library
RTL/LTR Handling
Dark Mode
Responsive Breakpoints
ماذا لو انقطع الإنترنت أثناء البيع؟
ماذا لو فشلت الطباعة؟
ماذا لو تعطلت ماكينة البطاقات؟
ماذا لو تكرر الباركود؟
مع تفصيل
Localization (i18n)
مع تحديد
Print Templates
مع بناء وإنشاء
Barcode Generation
Customer Display
Multi-Currency
مع تفصيل وبناء
Tax Engine — 15% الضريبة (VAT/Saudi)
مع ذكر تفاصيل
Loyalty Program
وانشاء وبناء
Supplier Portal
مع ربط واضح
الشاشة (UI)
- الـ Controller
- الـ Service
- الـ Repository
- الجدول
مع مثال
مثال End-to-End لعملية كاملة
(مثال: بيع منتج → ماذا يحدث خطوة بخطوة في الكود؟)
بناء وتركيب
تسلسل زمني واضح للتنفيذ
(ما يُبنى أولاً؟ ما يعتمد على ما؟)
هل يمكن البدء ببناء قاعدة البيانات؟
هل يمكن البدء ببناء Models؟
كتابة وصف جميع تفاصيل
هل يمكن بناء POS Screen
مثال End-to-End كامل
عملية بيع منتج WINSTON × 2 بالتفصيل الكامل:
- Cashier يضغط على المنتج في POS
- JavaScript يضيفه للسلة
- Cashier يضغط PAY
- AJAX POST /api/sales
- SaleController@store
- SaleService::createSale()
- DB Transaction begins:
a. Sale::create()
b. SaleItem::create() × 2
c. Payment::create()
d. StockMovement::create()
e. CashTransaction::create()
f. AuditLog::create() - Transaction commits
- Response: invoice_number, receipt_url
- JavaScript يطبع الإيصال
- Cashier يرى “تمت العملية بنجاح”
مع الكود الفعلي لكل خطوة
Models + Relations كاملة
POS Screen كامل
AI Layer Implementation
Deployment Guide
إكمال End-to-End Example
POS Screen
أسئلة حول كيفية ربط الطبقات
Implementation Guide
✅ رؤية واضحة للمنتج
✅ تفكير معماري سليم
✅ قاعدة بيانات شاملة
✅ Business Rules قوية
✅ AI Philosophy صحيحة
✅ Permission Matrix دقيق
✅ Seed Data كامل
المرحلة الحالية: Database Specification ✅
المرحلة التالية 1: Application Layer
├── Models (40 model)
├── Relations
├── Repositories
└── Services
المرحلة التالية 2: HTTP Layer
├── Controllers
├── Form Requests
├── Policies
├── Middleware
└── Routes
المرحلة التالية 3: POS Screen
├── HTML/Blade
├── CSS Design System
├── JavaScript
└── AJAX Endpoints
المرحلة التالية 4: AI Layer
├── Intent Detector
├── Tool Registry
├── Permission Engine
└── AI Provider Integration
المرحلة التالية 5: Reports
├── Report Generators
├── Export (PDF/Excel)
└── Scheduled Reports
المرحلة التالية 6: Testing
├── Unit Tests
├── Feature Tests
└── Factories
المرحلة التالية 7: Deployment
├── Server Setup
├── CI/CD
├── Monitoring
└── Backup
UI Design System
Error Handling
Testing Examples
Performance Tuning
Backup Strategy
ZEZO AI POS — MASTER BUILD PROMPT
Full Enterprise POS + AI + Offline + Saudi VAT + Supplier Platform
0. ROLE
أنت الآن تعمل كـ:
Senior Software Architect + Laravel/PHP Engineer + Full-Stack Engineer + Database Architect + POS Systems Engineer + AI Engineer + UI/UX Designer + DevOps Engineer + QA Engineer
لديك مسؤولية بناء نظام POS مؤسسي كامل باسم:
ZEZO AI POS
النظام ليس مجرد شاشة مبيعات، بل منصة Retail/POS متكاملة قابلة للتوسع، تعمل Online وOffline، وتحتوي على طبقة AI، وإدارة المخزون، والعملاء، والموردين، والمدفوعات، والضرائب، والولاء، والتقارير، والطباعة، وشاشات العملاء، والصلاحيات، والتدقيق Audit، والمراقبة.
1. OBJECTIVE
قم بإعادة بناء وتنفيذ النظام بالكامل من الصفر اعتمادًا على المتطلبات التالية.
لا تكتفِ بالشرح النظري.
يجب أن تنتج:
- Architecture
- Folder Structure
- Database Schema
- Migrations
- Models
- Relations
- Repositories
- Services
- Controllers
- Form Requests
- Policies
- Middleware
- Routes
- API Contracts
- POS UI
- CSS Design System
- JavaScript Application Layer
- AJAX/Fetch API
- Offline Mode
- Synchronization Engine
- Printing System
- Barcode System
- Customer Display
- Multi-Currency
- Saudi VAT Engine
- Loyalty Program
- Supplier Portal
- AI Layer
- Reports
- Testing
- Seed Data
- Deployment
- Monitoring
- Backup
ويجب تقديم كود فعلي قابل للبناء والتشغيل وليس pseudo-code فقط.
2. TECHNOLOGY STACK
اعتمد Stack واضحًا ومتناسقًا.
Backend
- PHP 8.3+
- Laravel
- REST API
- Laravel Validation
- Laravel Policies
- Laravel Events
- Laravel Jobs/Queues
- Laravel Scheduler
- Laravel Cache
- Laravel Notifications
- Laravel Logging
Database
- PostgreSQL
- Redis
Frontend
- HTML5
- CSS3
- JavaScript ES6+
- Blade
- AJAX / Fetch API
يمكن استخدام:
- Alpine.js
- Tailwind CSS
إذا كان استخدامها سيجعل النظام أفضل.
لكن لا تجعل النظام يعتمد على Framework Frontend ضخم دون سبب.
3. ARCHITECTURE
استخدم Layered Architecture واضحة:
UI
↓
Controller
↓
Form Request
↓
Policy / Permission
↓
Service
↓
Repository
↓
Model
↓
Database
مع:
AI Layer
↓
Intent Detector
↓
Context Engine
↓
Permission Engine
↓
Tool Registry
↓
Tool Execution
↓
Verification
↓
Audit
والنظام كاملًا:
POS UI
↓
HTTP/API
↓
Controller
↓
Service
↓
Repository
↓
Model
↓
Database
4. PROJECT STRUCTURE
أنشئ Folder Structure احترافيًا.
مثال:
zezo-ai-pos/
│
├── app/
│ ├── Models/
│ ├── Http/
│ │ ├── Controllers/
│ │ ├── Requests/
│ │ ├── Middleware/
│ │ └── Resources/
│ │
│ ├── Services/
│ ├── Repositories/
│ ├── Policies/
│ ├── Events/
│ ├── Listeners/
│ ├── Jobs/
│ ├── Actions/
│ ├── DTOs/
│ ├── AI/
│ │ ├── Intent/
│ │ ├── Tools/
│ │ ├── Providers/
│ │ ├── Permissions/
│ │ ├── Context/
│ │ └── Verification/
│ │
│ └── Support/
│
├── database/
│ ├── migrations/
│ ├── seeders/
│ └── factories/
│
├── resources/
│ ├── views/
│ │ ├── layouts/
│ │ ├── pos/
│ │ ├── customers/
│ │ ├── products/
│ │ ├── suppliers/
│ │ ├── reports/
│ │ └── settings/
│ │
│ ├── css/
│ └── js/
│
├── routes/
│ ├── web.php
│ ├── api.php
│ └── channels.php
│
├── tests/
│ ├── Unit/
│ ├── Feature/
│ └── Integration/
│
├── lang/
│ ├── ar/
│ └── en/
│
├── public/
├── storage/
├── docker/
├── docs/
└── deployment/
5. DATABASE FIRST
ابدأ ببناء قاعدة البيانات قبل طبقة التطبيق.
أنشئ Database Specification كاملة.
حدد:
- Tables
- Columns
- Types
- Primary Keys
- Foreign Keys
- Unique Constraints
- Indexes
- Composite Indexes
- Nullable Fields
- Defaults
- Soft Deletes
- Timestamps
- Audit Fields
6. DATABASE DOMAINS
يجب أن تغطي قاعدة البيانات على الأقل:
Organization
- organizations
- branches
- warehouses
- terminals
Users
- users
- roles
- permissions
- role_permissions
- user_roles
Products
- products
- product_categories
- product_brands
- product_variants
- product_barcodes
- product_prices
- units
- taxes
Inventory
- inventories
- stock_levels
- stock_movements
- stock_adjustments
- stock_transfers
- warehouses
Sales
- sales
- sale_items
- payments
- payment_methods
- refunds
- refund_items
Cash
- cash_registers
- cash_sessions
- cash_transactions
Customers
- customers
- customer_addresses
- customer_groups
Loyalty
- loyalty_accounts
- loyalty_transactions
- loyalty_rules
- loyalty_rewards
Suppliers
- suppliers
- supplier_users
- purchase_orders
- purchase_order_items
- goods_receipts
- supplier_invoices
- supplier_payments
Tax
- tax_rates
- tax_transactions
- tax_documents
Currency
- currencies
- exchange_rates
Printing
- print_templates
- print_jobs
- print_logs
AI
- ai_agents
- ai_tools
- ai_tool_permissions
- ai_conversations
- ai_messages
- ai_actions
- ai_execution_logs
Audit
- audit_logs
- system_events
- failed_jobs
7. MODELS
قم ببناء Models كاملة.
الهدف:
40+ Models
وكل Model يجب أن يحتوي على:
- $fillable
- $casts
- Relationships
- Scopes
- Accessors
- Mutators عند الحاجة
- SoftDeletes عند الحاجة
- Business methods
- Validation considerations
8. RELATIONSHIPS
عرّف العلاقات كاملة.
مثال:
class Sale extends Model
{
public function items()
{
return $this->hasMany(SaleItem::class);
}
public function payments()
{
return $this->hasMany(Payment::class);
}
public function customer()
{
return $this->belongsTo(Customer::class);
}
public function cashier()
{
return $this->belongsTo(User::class, 'cashier_id');
}
public function branch()
{
return $this->belongsTo(Branch::class);
}
}
لكن لا تكتفِ بهذا المثال.
أنشئ العلاقات لكل Models.
9. REPOSITORY LAYER
لا تجعل Controllers تتعامل مباشرة مع Database في العمليات المعقدة.
استخدم:
Controller
↓
Service
↓
Repository
↓
Model
مثال:
interface SaleRepositoryInterface
{
public function create(array $data): Sale;
public function findById(int $id): ?Sale;
public function findByInvoiceNumber(string $number): ?Sale;
}
ثم:
class SaleRepository implements SaleRepositoryInterface
{
public function create(array $data): Sale
{
return Sale::create($data);
}
}
10. SERVICE LAYER
أنشئ Services متخصصة.
مثل:
SaleService
PaymentService
InventoryService
StockMovementService
CashService
CustomerService
LoyaltyService
TaxService
BarcodeService
PrintService
CurrencyService
SupplierService
PurchaseOrderService
ReportService
AuditService
SyncService
OfflineSaleService
11. POS SCREEN
ابنِ POS Screen كاملة.
يجب أن تكون:
- Fast
- Responsive
- Touch Friendly
- Keyboard Friendly
- RTL
- LTR
- Dark Mode
- Mobile Compatible
- Tablet Compatible
- Desktop Compatible
التصميم:
┌─────────────────────────────────────────────┐
│ ZEZO POS Branch Cashier Time │
├─────────────────────────────────────────────┤
│ │
│ Product Search / Barcode Scanner │
│ │
├─────────────────────┬───────────────────────┤
│ │ │
│ Product Grid │ Cart │
│ │ │
│ [Product] [Product] │ WINSTON × 2 │
│ [Product] [Product] │ Subtotal │
│ [Product] [Product] │ VAT │
│ │ Discount │
│ │ Total │
│ │ │
│ │ [PAY] │
└─────────────────────┴───────────────────────┘
12. POS JAVASCRIPT
أنشئ POS Application State.
مثال:
const POS = {
cart: [],
customer: null,
currency: 'SAR',
taxRate: 0.15,
offline: false
};
أنشئ:
addProduct()
removeProduct()
updateQuantity()
calculateSubtotal()
calculateTax()
calculateTotal()
applyDiscount()
selectCustomer()
processPayment()
completeSale()
printReceipt()
13. AJAX API
أنشئ API endpoints واضحة.
مثال:
GET /api/products
GET /api/products/barcode/{barcode}
POST /api/sales
GET /api/sales/{id}
POST /api/payments
POST /api/refunds
POST /api/pos/sync
POST /api/pos/offline-sales
GET /api/customers/search
POST /api/customers
GET /api/inventory
14. CONTROLLERS
أنشئ:
SaleController
PaymentController
ProductController
CustomerController
InventoryController
SupplierController
PurchaseOrderController
LoyaltyController
ReportController
PrintController
BarcodeController
AIController
SyncController
كل Controller يجب أن يكون Thin Controller.
مثال:
public function store(StoreSaleRequest $request)
{
$this->authorize('create', Sale::class);
$sale = $this->saleService->createSale(
$request->validated()
);
return response()->json([
'success' => true,
'data' => $sale
]);
}
15. FORM REQUESTS
أنشئ:
StoreSaleRequest
StorePaymentRequest
StoreProductRequest
StoreCustomerRequest
StoreSupplierRequest
StorePurchaseOrderRequest
RefundSaleRequest
مع Validation كاملة.
16. PERMISSION ENGINE
أنشئ Permission Matrix.
مثال:
| Action | Cashier | Supervisor | Manager | Admin |
|---|---|---|---|---|
| Sell | ✓ | ✓ | ✓ | ✓ |
| Refund | Limited | ✓ | ✓ | ✓ |
| Discount | Limited | ✓ | ✓ | ✓ |
| Void Sale | ✗ | ✓ | ✓ | ✓ |
| View Reports | Limited | ✓ | ✓ | ✓ |
| Manage Products | ✗ | Limited | ✓ | ✓ |
| Manage Users | ✗ | ✗ | Limited | ✓ |
| AI Actions | Limited | ✓ | ✓ | ✓ |
لا تسمح للـ AI بتجاوز Permission Engine.
17. END-TO-END SALE
نفّذ هذا المثال فعليًا:
WINSTON × 2
العملية:
1. Cashier clicks WINSTON
2. JavaScript adds item to cart
3. Quantity becomes 2
4. POS calculates subtotal
5. POS calculates VAT
6. Cashier clicks PAY
7. JavaScript sends AJAX POST
8. /api/sales
9. SaleController@store
10. StoreSaleRequest validates
11. Permission checked
12. SaleService::createSale()
13. DB Transaction begins
14. Sale::create()
15. SaleItem::create()
16. SaleItem::create()
17. Payment::create()
18. StockMovement::create()
19. CashTransaction::create()
20. LoyaltyTransaction::create()
21. TaxTransaction::create()
22. AuditLog::create()
23. Transaction commits
24. Invoice generated
25. Receipt generated
26. Response returned
27. JavaScript updates UI
28. PrintService prints receipt
29. Customer Display updates
30. Cashier sees success
اكتب الكود الفعلي لكل مرحلة.
18. DATABASE TRANSACTION
يجب استخدام:
DB::transaction(function () {
// sale
// items
// payment
// inventory
// cash
// tax
// loyalty
// audit
});
إذا فشل أي عنصر:
Rollback
↓
No partial sale
↓
Error logged
↓
User notified
19. VAT / SAUDI TAX ENGINE
أنشئ Tax Engine مستقل.
الإعداد الأساسي:
VAT = 15%
Currency = SAR
Country = Saudi Arabia
لكن لا تضع 15% في كل مكان.
استخدم:
TaxRate
TaxRule
TaxService
مثال:
$tax = $taxService->calculate(
subtotal: $subtotal,
taxRate: $rate
);
يدعم:
- Tax Inclusive
- Tax Exclusive
- Tax Exempt
- Zero Rated
- Taxable
- Discounts before tax
- Discounts after tax حسب Business Rule
- Tax rounding
- Invoice tax breakdown
اجعل النظام قابلًا لتغيير معدل الضريبة مستقبلًا.
20. MULTI-CURRENCY
أنشئ:
Currency
ExchangeRate
CurrencyService
Money DTO
يدعم:
SAR
USD
EUR
GBP
AED
KWD
ويجب أن يكون:
Base Currency
Transaction Currency
Exchange Rate
Converted Amount
مع منع أخطاء Floating Point قدر الإمكان باستخدام Decimal/Minor Units.
21. BARCODE SYSTEM
أنشئ Barcode Engine.
يدعم:
- Barcode scanning
- Barcode generation
- EAN
- UPC
- Code128
- Internal SKU barcode
مثال:
Product
↓
SKU
↓
Barcode
↓
Scanner
↓
Product lookup
↓
POS
ويجب معالجة:
Duplicate Barcode
إذا كان Barcode موجودًا:
REJECT
↓
Show conflict
↓
Identify existing product
↓
Require authorized resolution
لا تسمح بتكرار Barcode غير المقصود.
22. OFFLINE MODE
هذا جزء أساسي.
السؤال:
ماذا يحدث إذا انقطع الإنترنت أثناء البيع؟
لا يتوقف POS.
استخدم:
Service Worker
IndexedDB
Local Queue
Sync Engine
Idempotency Keys
المسار:
Internet Lost
↓
POS detects offline
↓
Sale stored locally
↓
Local invoice/reference generated
↓
Cashier completes transaction
↓
Internet returns
↓
Sync Queue starts
↓
Server validates
↓
Server processes
↓
Sync marked completed
يجب منع Duplicate Sales.
استخدم:
idempotency_key
device_id
terminal_id
local_transaction_id
23. SYNC ENGINE
أنشئ:
OfflineSale
SyncQueue
SyncAttempt
SyncConflict
الحالات:
PENDING
SYNCING
SYNCED
FAILED
CONFLICT
REQUIRES_REVIEW
أنشئ Retry Strategy:
1st retry
2nd retry
3rd retry
Exponential Backoff
24. PRINTING FAILURE
السؤال:
ماذا لو فشلت الطباعة؟
البيع لا يجب أن يفشل بسبب الطباعة.
المبدأ:
Sale Success
≠
Print Success
إذا تم البيع:
Transaction committed
↓
Print Job created
↓
Printer attempts printing
إذا فشلت:
Print Job = FAILED
↓
Retry
↓
Manual Print
↓
Alternative Printer
لا تقم بعمل Rollback للبيع بسبب فشل الطابعة.
25. CARD TERMINAL FAILURE
السؤال:
ماذا لو تعطلت ماكينة البطاقات؟
أنشئ Payment State Machine:
INITIATED
PROCESSING
AUTHORIZED
CAPTURED
FAILED
CANCELLED
TIMEOUT
REVERSED
إذا حدث Timeout:
لا تفترض أن الدفع فشل.
يجب:
Check Payment Provider
↓
Reconcile
↓
Determine final status
مع منع double charge.
26. CUSTOMER DISPLAY
أنشئ Customer Display.
يعرض:
Store Logo
Product
Quantity
Price
Subtotal
VAT
Discount
Total
Payment
Thank You
يمكن ربطه عبر:
WebSocket
Broadcast
POS:
Cart Updated
↓
Event
↓
Customer Display
27. LOYALTY PROGRAM
أنشئ Loyalty Engine.
يدعم:
Customer
Loyalty Account
Points
Transactions
Rewards
Rules
Tiers
مثال:
1 SAR = 1 Point
مع:
- Earn
- Redeem
- Expire
- Reverse
- Refund Adjustment
- Tier levels
- Reward rules
لا تعدّل الرصيد مباشرة.
استخدم Ledger:
LoyaltyTransaction
28. SUPPLIER PORTAL
أنشئ Supplier Portal.
المورد يستطيع:
Login
View Purchase Orders
Accept PO
Reject PO
Confirm quantities
Upload invoice
View payments
View shipment status
View receiving status
Portal Architecture:
Supplier
↓
Supplier User
↓
Supplier Portal
↓
API
↓
Supplier Services
↓
Database
مع Permission Isolation.
المورد يرى بياناته فقط.
29. PRINT TEMPLATES
أنشئ Print Template Engine.
Templates:
POS Receipt
Tax Invoice
Refund Receipt
Purchase Order
Supplier Invoice
Daily Closing
Barcode Label
Product Label
يدعم:
58mm
80mm
A4
مع:
Arabic
English
RTL
LTR
30. I18N / LOCALIZATION
أنشئ Localization كامل:
ar
en
كل النصوص يجب ألا تكون hard-coded داخل الواجهة.
مثال:
__('pos.pay')
وليس:
<button>Pay</button>
يدعم:
Arabic
English
RTL
LTR
Date Formats
Number Formats
Currency Formats
Pluralization
Tax Labels
Invoice Labels
31. UI/UX DESIGN SYSTEM
أنشئ Design System كامل.
Color Palette
عرّف:
Primary
Secondary
Success
Warning
Danger
Info
Background
Surface
Border
Text
Muted
مع Light/Dark variants.
32. TYPOGRAPHY
أنشئ Typography System:
Display
H1
H2
H3
Body
Small
Caption
Button
Input
Table
اختر Font يدعم العربية والإنجليزية بشكل ممتاز.
33. COMPONENT LIBRARY
أنشئ:
Button
Input
Select
Search
Modal
Drawer
Dropdown
Toast
Alert
Badge
Card
Table
Pagination
Tabs
Breadcrumb
Avatar
Product Card
Cart Item
Payment Modal
Barcode Scanner
Customer Selector
34. RTL / LTR
يجب أن يعمل النظام:
Arabic → RTL
English → LTR
ولا تعتمد على CSS hacks.
استخدم logical properties:
margin-inline
padding-inline
inset-inline
border-inline
text-align: start
35. DARK MODE
يجب أن يدعم:
Light
Dark
System
مع حفظ Preference.
36. RESPONSIVE BREAKPOINTS
أنشئ Breakpoints واضحة:
Mobile
Tablet
Desktop
Large Desktop
POS Terminal
والواجهة يجب ألا تنهار عند اختلاف الشاشة.
37. ERROR HANDLING
أنشئ Error Architecture.
أنواع الأخطاء:
ValidationError
AuthenticationError
AuthorizationError
PaymentError
InventoryError
TaxError
PrinterError
NetworkError
SyncError
AIError
DatabaseError
يجب أن يحصل المستخدم على رسالة مفهومة.
وفي الخلفية:
Detailed Logs
Stack Trace
Correlation ID
Request ID
Audit
38. AI LAYER
أنشئ AI Layer كاملة.
Architecture:
User
↓
AI Interface
↓
Intent Detector
↓
Context Engine
↓
Permission Engine
↓
Tool Registry
↓
Tool Execution
↓
Verification Engine
↓
Response
↓
Audit
39. AI INTENT DETECTOR
يدعم نوايا مثل:
sales_summary
inventory_query
low_stock_detection
customer_lookup
customer_analysis
product_lookup
refund_assistance
pricing_analysis
supplier_analysis
report_generation
daily_summary
anomaly_detection
40. AI TOOL REGISTRY
أنشئ Tool Registry.
مثال:
search_products
get_inventory
create_sale
get_sales_report
find_customer
calculate_tax
get_supplier
generate_report
كل Tool يحتوي:
name
description
schema
permissions
risk_level
handler
verification
audit_required
41. AI PERMISSION ENGINE
AI لا ينفذ أي Action بشكل مطلق.
قبل كل Tool Call:
Intent
↓
User
↓
Role
↓
Permission
↓
Tool Permission
↓
Risk
↓
Approval?
↓
Execute
مثال:
AI may READ inventory
AI may ANALYZE sales
AI may GENERATE reports
AI may NOT issue refund without permission
AI may NOT change prices without permission
AI may NOT delete data
42. AI VERIFICATION ENGINE
بعد تنفيذ Tool:
Tool Result
↓
Validation
↓
Business Rules
↓
Consistency Check
↓
Verification
↓
Audit
إذا كانت النتيجة غير موثوقة:
REJECT
↓
RETRY
OR
ESCALATE TO HUMAN
43. AI PROVIDER ABSTRACTION
لا تربط النظام بمزود AI واحد.
استخدم:
AIProviderInterface
مثل:
OpenAIProvider
LocalProvider
FutureProvider
ويكون:
AI Provider
↓
Model
↓
Prompt
↓
Context
↓
Tool Calls
قابلًا للاستبدال.
44. AI CONTEXT
أنشئ Context Object:
User Context
Branch Context
Terminal Context
Customer Context
Cart Context
Inventory Context
Business Context
Permission Context
Conversation Context
لا ترسل كل البيانات إلى النموذج.
استخدم:
Relevant Context Selection
45. REPORTING
أنشئ:
Sales Reports
Product Reports
Inventory Reports
Customer Reports
Supplier Reports
Tax Reports
Cash Reports
Profit Reports
AI Reports
يدعم:
PDF
Excel
CSV
Print
Scheduled Reports
46. TESTING
أنشئ:
Unit Tests
مثل:
TaxServiceTest
SaleServiceTest
LoyaltyServiceTest
InventoryServiceTest
CurrencyServiceTest
Feature Tests
مثل:
CreateSaleTest
RefundSaleTest
PaymentTest
OfflineSyncTest
SupplierPortalTest
Integration Tests
مثل:
POS → API → Service → DB
Payment → Inventory → Cash
47. FACTORIES
أنشئ Factories لجميع Models المهمة.
مثل:
UserFactory
ProductFactory
CustomerFactory
SaleFactory
SaleItemFactory
SupplierFactory
PaymentFactory
48. SEED DATA
أنشئ Seeders كاملة.
يجب أن تتضمن:
Admin
Manager
Supervisor
Cashier
Roles
Permissions
Branches
Warehouses
Products
Categories
Customers
Suppliers
Currencies
Tax Rates
Payment Methods
Loyalty Rules
وأنشئ Demo Dataset.
49. SECURITY
طبّق:
Authentication
Authorization
CSRF
XSS Protection
SQL Injection Protection
Rate Limiting
Input Validation
Mass Assignment Protection
Secure Cookies
Password Hashing
API Authentication
Audit Logging
50. PERFORMANCE
طبّق:
Database Indexes
Eager Loading
Query Optimization
Caching
Redis
Queue Workers
Lazy Loading حيث يلزم
Pagination
API Response Optimization
Asset Optimization
حدد N+1 Query risks.
51. BACKUP STRATEGY
أنشئ Backup Strategy:
Database Daily Backup
Database Incremental Backup
Files Backup
Configuration Backup
Offsite Backup
Retention Policy
Backup Verification
Restore Testing
حدد:
RPO
RTO
52. MONITORING
أنشئ Monitoring:
Application Logs
Database Monitoring
Queue Monitoring
Failed Jobs
Payment Failures
Printer Failures
Sync Failures
AI Errors
API Errors
System Health
أنشئ:
/health
Endpoint.
53. DEPLOYMENT
أنشئ Deployment Guide كامل.
يتضمن:
Server Requirements
PHP
PostgreSQL
Redis
Nginx
SSL
Queue Worker
Scheduler
Storage
Environment Variables
Database Migration
Seed
Cache
Queue
Permissions
Supervisor
Monitoring
Backup
54. DOCKER
أنشئ:
Dockerfile
docker-compose.yml
nginx.conf
php.ini
supervisor.conf
الخدمات:
app
nginx
postgres
redis
queue
scheduler
55. CI/CD
أنشئ Pipeline:
Push
↓
Install Dependencies
↓
Lint
↓
Static Analysis
↓
Unit Tests
↓
Feature Tests
↓
Build
↓
Deploy
↓
Migration
↓
Cache
↓
Health Check
56. COMPLETE END-TO-END EXAMPLE
أريد مثالًا كاملًا حقيقيًا:
SELL WINSTON × 2
افترض:
Product:
WINSTON
Quantity:
2
Unit Price:
20 SAR
Subtotal:
40 SAR
VAT:
15%
VAT:
6 SAR
Total:
46 SAR
اشرح واكتب الكود لكل خطوة:
POS UI
↓
JavaScript
↓
AJAX
↓
Route
↓
Controller
↓
Request
↓
Policy
↓
Service
↓
Transaction
↓
Repository
↓
Models
↓
Database
↓
Payment
↓
Inventory
↓
Cash
↓
Tax
↓
Loyalty
↓
Audit
↓
Receipt
↓
Print
↓
Customer Display
↓
Response
↓
POS Success
ويجب أن تعرض:
JavaScript
await fetch(...)
Route
Route::post(...)
Controller
public function store(...)
Service
public function createSale(...)
Repository
public function create(...)
Models
Sale
SaleItem
Payment
StockMovement
CashTransaction
TaxTransaction
AuditLog
Database
أظهر البيانات التي ستُكتب في كل Table.
57. FAILURE SCENARIOS
يجب أن تشرح وتنفذ الكود لكل سيناريو:
Scenario A
Internet disconnected.
Scenario B
Printer fails.
Scenario C
Card terminal timeout.
Scenario D
Duplicate barcode.
Scenario E
Insufficient stock.
Scenario F
Payment rejected.
Scenario G
Database error.
Scenario H
Two terminals sell the last item simultaneously.
Scenario I
Offline transaction conflicts with server.
Scenario J
AI requests unauthorized action.
لكل حالة:
Detection
↓
State
↓
Action
↓
Rollback / Retry / Queue
↓
User Message
↓
Audit
58. CONCURRENCY
يجب حماية المخزون من:
Race Conditions
Double Sale
Overselling
Duplicate Payment
Duplicate Sync
استخدم عند الحاجة:
Database Transactions
Row Locks
Atomic Updates
Idempotency
Unique Constraints
59. IMPLEMENTATION ORDER
نفّذ المشروع بهذا الترتيب:
PHASE 0
Architecture
↓
PHASE 1
Database
Migrations
Indexes
Constraints
Seeders
↓
PHASE 2
Models
40+ Models
Relations
Factories
↓
PHASE 3
Application Layer
Repositories
Services
DTOs
Actions
↓
PHASE 4
HTTP Layer
Controllers
Requests
Policies
Middleware
Routes
Resources
↓
PHASE 5
POS
Blade
HTML
CSS
JavaScript
AJAX
Cart
Payment
Receipt
↓
PHASE 6
Offline
IndexedDB
Service Worker
Queue
Sync
Conflict Resolution
↓
PHASE 7
Payment / Cash / Inventory
↓
PHASE 8
Tax / Currency / Barcode
↓
PHASE 9
Customer / Loyalty
↓
PHASE 10
Supplier Portal
↓
PHASE 11
AI Layer
↓
PHASE 12
Reports
↓
PHASE 13
Testing
↓
PHASE 14
Performance / Security
↓
PHASE 15
Deployment
60. DEPENDENCY GRAPH
أنشئ Dependency Graph واضح:
Database
↓
Models
↓
Repositories
↓
Services
↓
Controllers
↓
API
↓
POS
وبالتوازي:
Models
↓
AI Context
↓
AI Tools
↓
Permission Engine
↓
AI Runtime
61. IMPLEMENTATION RULES
لا تستخدم:
TODO
Coming Soon
Implement Later
...
ولا تضع:
// implementation omitted
ولا تختصر أجزاء أساسية.
إذا كان المشروع كبيرًا، قسّم التنفيذ إلى Modules، لكن كل Module يجب أن يكون قابلًا للدمج.
62. CODE QUALITY
استخدم:
SOLID
DRY
KISS
Clean Code
Separation of Concerns
Dependency Injection
Interfaces
DTOs
Service Classes
Repository Pattern
Domain-oriented organization where useful
63. API RESPONSE STANDARD
استخدم Standard موحد:
{
"success": true,
"message": "Sale created successfully",
"data": {},
"meta": {},
"errors": []
}
وفي الخطأ:
{
"success": false,
"message": "Unable to process sale",
"data": null,
"errors": []
}
64. AUDIT SYSTEM
كل العمليات الحساسة يجب تسجيلها:
Who
What
When
Where
Before
After
IP
Device
Terminal
Correlation ID
خصوصًا:
Refund
Discount
Price Change
Stock Adjustment
Payment
User Permission Change
AI Tool Execution
65. OBSERVABILITY
كل Request مهم يجب أن يحتوي:
request_id
correlation_id
user_id
branch_id
terminal_id
لتتبع العملية End-to-End.
66. DOCUMENTATION
أنشئ Documentation:
README.md
ARCHITECTURE.md
DATABASE.md
API.md
POS.md
AI.md
OFFLINE.md
TAX.md
LOYALTY.md
SUPPLIER.md
DEPLOYMENT.md
TESTING.md
SECURITY.md
67. FINAL DELIVERABLE
في نهاية البناء يجب أن يكون الناتج:
ZEZO AI POS
│
├── Database
├── Models
├── Relations
├── Repositories
├── Services
├── Controllers
├── APIs
├── POS UI
├── Design System
├── Offline Engine
├── Sync Engine
├── Payment Engine
├── Inventory Engine
├── Tax Engine
├── Currency Engine
├── Barcode Engine
├── Loyalty Engine
├── Supplier Portal
├── Customer Display
├── Print Engine
├── AI Layer
├── Permission Engine
├── Verification Engine
├── Reports
├── Tests
├── Seed Data
├── Security
├── Monitoring
├── Backup
├── Docker
├── CI/CD
└── Deployment
68. OUTPUT FORMAT REQUIRED
لا تعطِني شرحًا عامًا فقط.
نفّذ العمل على شكل مراحل عملية.
لكل Phase اعرض:
1. Objective
2. Architecture
3. Folder Structure
4. Files To Create
5. Database Changes
6. Full Code
7. Relationships
8. API
9. UI
10. Tests
11. Security
12. Error Handling
13. Example
14. Integration With Previous Phase
15. Verification Checklist
69. STARTING POINT
ابدأ الآن من:
PHASE 1 — DATABASE FOUNDATION
قم ببناء:
Database Architecture
ERD
Tables
Columns
Foreign Keys
Indexes
Constraints
Enums
Migrations
Seeders
ثم انتقل إلى:
PHASE 2 — 40+ MODELS + RELATIONS
ثم:
PHASE 3 — REPOSITORIES + SERVICES
ثم:
PHASE 4 — CONTROLLERS + APIs
ثم:
PHASE 5 — COMPLETE POS SCREEN
ثم:
PHASE 6 — OFFLINE POS
ثم:
PHASE 7 — PAYMENT + INVENTORY + CASH
ثم:
PHASE 8 — VAT + CURRENCY + BARCODE
ثم:
PHASE 9 — CUSTOMER + LOYALTY
ثم:
PHASE 10 — SUPPLIER PORTAL
ثم:
PHASE 11 — AI LAYER
ثم:
PHASE 12 — REPORTING
ثم:
PHASE 13 — TESTING
ثم:
PHASE 14 — PERFORMANCE + SECURITY
ثم:
PHASE 15 — DEPLOYMENT
70. CRITICAL ARCHITECTURAL RULE
لا تبنِ النظام كـ:
POS Screen → Database
بل:
POS
↓
Controller
↓
Request
↓
Policy
↓
Service
↓
Repository
↓
Model
↓
Database
والـ AI:
AI
↓
Intent
↓
Context
↓
Permission
↓
Tool
↓
Service
↓
Repository
↓
Database
↓
Verification
↓
Audit
وبالتالي:
AI لا يتجاوز Application Layer.
71. BUSINESS TRANSACTION PRINCIPLE
أي عملية مالية يجب أن تكون:
Atomic
Consistent
Auditable
Idempotent
Recoverable
Verifiable
خصوصًا:
Sale
Payment
Refund
Stock
Cash
Tax
Loyalty
Offline Sync
72. FINAL ARCHITECTURAL VISION
المنتج النهائي يجب أن يكون:
ZEZO AI POS — An AI-Native, Offline-First, Enterprise Retail Operating System
وليس مجرد POS.
المبدأ:
SELL
MANAGE
ANALYZE
AUTOMATE
PREDICT
VERIFY
LEARN
والنظام يجب أن يستطيع الانتقال من:
Transaction
إلى:
Business Intelligence
ثم إلى:
AI-Assisted Operations
ثم إلى:
AI-Native Retail Operating System
73. BEGIN NOW
ابدأ مباشرة بـ:
DATABASE SPECIFICATION
ثم:
MIGRATIONS
ثم:
MODELS + RELATIONS
ثم:
APPLICATION LAYER
ولا تنتقل إلى POS قبل التأكد من أن:
Database
Models
Relations
Services
Transactions
Permissions
مصممة بشكل صحيح.
وفي كل مرحلة، وضّح:
ما الذي تم بناؤه؟
ما الذي يعتمد عليه؟
ما الذي سيُبنى بعده؟
كيف يتم اختباره؟
كيف يتم ربطه بالطبقة السابقة؟
ابدأ التنفيذ الآن.