ZEZO AI POS — Database Specification v1

📊 3 مشاهدة

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

PermissionSuper AdminOwnerManagerCashierInventory MgrAccountantAI 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 NameModuleيغيّر البيانات؟يتطلب صلاحيةيتطلب موافقة
sales.get_todaysales❌sales.view❌
sales.get_reportsales❌reports.view❌
sales.createsales✅sales.create❌
products.getproducts❌products.view❌
products.searchproducts❌products.view❌
products.createproducts✅products.create✅
products.updateproducts✅products.update✅
products.change_priceproducts✅products.price_change✅
inventory.getinventory❌inventory.view❌
inventory.get_low_stockinventory❌inventory.view❌
inventory.adjustinventory✅inventory.adjust✅
purchases.createpurchases✅purchases.create✅
cash.get_balancecash❌cash.view❌
cash.reconcilecash✅cash.reconcile✅
cards.reconcilecards✅cards.reconcile✅
shifts.getshifts❌shifts.view❌
shifts.reportshifts❌shifts.view❌
reports.dailyreports❌reports.view❌
reports.generatereports❌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 (قواعد العمل الحرجة)

  1. البيع الذرّي: لا يُعتمد بيع إلا إذا نجح: Sale + Sale Items + Payments + Stock Movements + Cash/Card Transactions + Audit Log. أي فشل → Rollback كامل.
  2. المخزون لا يُعدّل مباشرة: كل تغيير في products.stock_quantity يجب أن يسبقه stock_movements مع before_quantity و after_quantity.
  3. منع البيع بالسالب: إذا allow_negative = 0 ولا يوجد رصيد كافٍ → رفض العملية مع رسالة واضحة.
  4. إغلاق الوردية: لا يُسمح إلا إذا:
    • لا توجد فواتير معلقة (held) في الوردية.
    • تم إدخال actual_cash و actual_card.
    • تم حساب difference تلقائيًا.
  5. تسوية البطاقات: Start + Add + Sales - Commission - Withdrawal = Expected End. الفرق يُسجّل في card_transactions.difference.
  6. تغيير السعر: يُسجّل في product_prices (تاريخ) + audit_logs (before/after) + يتطلب صلاحية products.price_change.
  7. الاسترجاع: لا يُسمح إلا إذا:
    • الفاتورة الأصلية موجودة وغير ملغاة.
    • الكمية المرتجعة ≤ الكمية المبيعة.
    • يتطلب صلاحية pos.refund أو sales.void.
  8. الوردية المفتوحة: لا يمكن للمستخدم فتح وردية جديدة إذا كانت لديه وردية مفتوحة على نفس الجهاز.
  9. AI لا ينفذ تلقائيًا: أي Tool يغيّر البيانات يتطلب ai.execute + موافقة صريحة (ai_actions.status = approved).
  10. Audit Log إلزامي: كل عملية حساسة (بيع، استرجاع، تسوية، تغيير سعر، حذف) تُسجّل في audit_logs مع before/after.

9. Implementation Roadmap (محدّث)

Phaseالمخرجالمدة التقديرية
1Architecture Blueprint + ERD✅ مكتمل (هذا المستند)
2Migrations + Models + Relations3–4 أيام
3Auth + RBAC + Seeders2–3 أيام
4Products + Categories + Barcodes2–3 أيام
5Inventory + Stock Movements3–4 أيام
6Purchases + Suppliers3 أيام
7POS Screen + Sales5–7 أيام
8Payments (Cash/Card/Mixed)2–3 أيام
9Cash Ledger + Reconciliation2–3 أيام
10Card Machines + Reconciliation2–3 أيام
11Shifts + Close/Reconcile3 أيام
12Reports (Daily/Monthly/Shift)4–5 أيام
13AI Layer + Tool Registry + Chat5–7 أيام
14Subscriptions (SaaS)3–4 أيام
15Security Hardening + Audit2–3 أيام
16Testing (Unit + Feature)4–5 أيام
17Deployment + Monitoring2–3 أيام

الإجمالي التقديري: 50–65 يوم عمل لمطور واحد متمكن.


10. الخطوة التالية

هذا المستند هو Database Specification v1. الخطوة المنطقية التالية هي:

  1. اختيار الإطار: Laravel 11 (موصى به) أم PHP MVC مخصص؟
  2. توليد Migrations فعلية: تحويل كل CREATE TABLE إلى ملف Laravel Migration.
  3. توليد Models + Relations: Product, Sale, Shift, StockMovement… مع العلاقات.
  4. بناء Seeders: تشغيلها على بيئة pos3.twisttaste.com لتأكيد صحة المخطط.
  5. بناء Auth + RBAC: JWT أو Sanctum + Permission Engine.
  6. بناء 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 → Dashboard
    • Inventory 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.0020.001205نشط✏️ 🗑️
PALLMALLبال مالسجائر15.0019.00855نشط✏️ 🗑️

نموذج إضافة/تعديل منتج:

text

┌─────────────────────────────────────────┐
│  إضافة منتج جديد                         │
│  ─────────────────────────────────────  │
│  SKU:           [WINSTON____]           │
│  الاسم (AR):    [وينستون____]           │
│  الاسم (EN):    [WINSTON____]           │
│  التصنيف:       [سجائر ▼]               │
│  الماركة:       [▼]                     │
│  سعر الشراء:    [16.00]                 │
│  سعر البيع:     [20.00]                 │
│  الضريبة:       [0%]                    │
│  الوحدة:        [قطعة ▼]                │
│  الحد الأدنى:   [5]                     │
│  الحد الأقصى:   [100]                   │
│  الباركود:      [6291234567890]  [+]    │
│  ─────────────────────────────────────  │
│  [حفظ]  [إلغاء]                         │
└─────────────────────────────────────────┘

ميزة AI: عند كتابة اسم منتج جديد، يقترح AI:

  • التصنيف المناسب
  • سعر البيع المقترح بناءً على أسعار مشابهة
  • الحد الأدنى للمخزون

الشاشة 05 — Inventory (المخزون)

الوظيفة: تتبع كل حركة مخزون.

تبويبات:

  1. المخزون الحالي — جدول بالمنتجات والكميات الحالية
  2. حركات المخزون — Stock Movements Log
  3. التسويات — Inventory Adjustments
  4. منخفض المخزون — Low Stock Alerts
  5. تقييم المخزون — Inventory Valuation

جدول حركات المخزون:

التاريخالمنتجالنوعالكميةقبلبعدالمرجعالمستخدم
2026-10-03 10:30WINSTONSALE-2122120INV-1001أحمد
2026-10-03 09:15PALLMALLPURCHASE+503585PO-2001محمد
2026-10-03 08:00WINSTONOPENING+1200120–النظام

أنواع الحركات:

  • 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-100110:30أحمد59.00نقدمكتملة👁️ 🖨️ ↩️
INV-100210:35أحمد120.00شبكةمكتملة👁️ 🖨️ ↩️
INV-100310:40محمد45.00مختلطمكتملة👁️ 🖨️ ↩️

تفاصيل الفاتورة:

  • المنتجات والكميات
  • طريقة الدفع
  • الوردية
  • الكاشير
  • الإيصال

الاسترجاع:

  • يتطلب صلاحية pos.refund أو sales.void
  • لا يُسمح إلا إذا الكمية المرتجعة ≤ المبيعة
  • يُسجّل في sale_returns + stock_movements (RETURN) + cash_transactions (REFUND)

الشاشة 08 — Cash (النقد)

الوظيفة: إدارة الصندوق النقدي وتسويته.

تبويبات:

  1. حركات النقد — Cash Transactions
  2. إدخال نقد — Cash In
  3. إخراج نقد — Cash Out
  4. المصروفات — Expenses
  5. التسوية — Reconciliation

جدول حركات النقد:

الوقتالنوعالوصفالمبلغالرصيد بعدالمستخدم
08:00OPENINGرصيد افتتاحي+500500أحمد
08:15SALEفاتورة INV-1001+59559أحمد
10:00EXPENSEكهرباء-50509أحمد
12:00SALEفاتورة INV-1005+120629أحمد

شاشة التسوية:

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 — مكينة رقم 1
  • Cards No.2 — مكينة رقم 2
  • Cards No.3 — مكينة رقم 3

جدول الماكينات:

الماكينةالبدايةالشحنالمبيعاتالربحالباقيالفرق
Cards No.11,0005001,840123,3280
Cards No.280030095082,042-5
Cards No.31,20001,100102,2900

معادلة التسوية:

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إدارة كاملة ما عدا حذف المنتجات وتغيير الأسعار
CashierPOS فقط + ورديته
Inventory Managerالمنتجات + المخزون + المشتريات
Accountantالتقارير + النقد + البطاقات
AI OperatorAI + التقارير

مصفوفة الصلاحيات: (كما في المستند السابق)


الجزء الثالث: باقات الاشتراك


الباقة 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 حتى تنجح كل الاختبارات

الخلاصة

هذا المستند يقدم:

  1. التعريف الجديد الكامل للمنصة ZEZO AI POS
  2. شرح كل شاشة بالتفصيل (13 شاشة)
  3. 4 باقات اشتراك مع المميزات
  4. 40 جدول قاعدة بيانات كاملة مع Laravel Migrations
  5. Seed Data للأصناف الـ26
  6. 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 بالتفصيل الكامل:

  1. Cashier يضغط على المنتج في POS
  2. JavaScript يضيفه للسلة
  3. Cashier يضغط PAY
  4. AJAX POST /api/sales
  5. SaleController@store
  6. SaleService::createSale()
  7. DB Transaction begins:
    a. Sale::create()
    b. SaleItem::create() × 2
    c. Payment::create()
    d. StockMovement::create()
    e. CashTransaction::create()
    f. AuditLog::create()
  8. Transaction commits
  9. Response: invoice_number, receipt_url
  10. JavaScript يطبع الإيصال
  11. 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.

مثال:

ActionCashierSupervisorManagerAdmin
Sell✓✓✓✓
RefundLimited✓✓✓
DiscountLimited✓✓✓
Void Sale✗✓✓✓
View ReportsLimited✓✓✓
Manage Products✗Limited✓✓
Manage Users✗✗Limited✓
AI ActionsLimited✓✓✓

لا تسمح للـ 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

مصممة بشكل صحيح.

وفي كل مرحلة، وضّح:

ما الذي تم بناؤه؟
ما الذي يعتمد عليه؟
ما الذي سيُبنى بعده؟
كيف يتم اختباره؟
كيف يتم ربطه بالطبقة السابقة؟

ابدأ التنفيذ الآن.

Scroll to Top

🤖 موصى به لك بناءً على اهتماماتك