Skip to content

Conversation

@rafeekhelmy9-art
Copy link

Database Schema - نظام إدارة الشركة

SQLite Database Schema

1. إعدادات الشركة (Company Settings)

CREATE TABLE company_settings (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    company_name TEXT NOT NULL DEFAULT 'نبتة المستقبل للتجارة والتوزيع',
    address TEXT,
    phone TEXT,
    logo_path TEXT,
    font_size INTEGER DEFAULT 14,
    font_family TEXT DEFAULT 'Tajawal',
    logo_width INTEGER DEFAULT 100,
    logo_height INTEGER DEFAULT 100,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- Insert default company settings
INSERT INTO company_settings (company_name) 
VALUES ('نبتة المستقبل للتجارة والتوزيع');

2. الفئات (Categories)

CREATE TABLE categories (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL UNIQUE,
    description TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_categories_name ON categories(name);

3. العملاء (Customers)

CREATE TABLE customers (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    address TEXT,
    phone TEXT,
    balance DECIMAL(15,2) DEFAULT 0.00,
    cash_on_hand DECIMAL(15,2) DEFAULT 0.00,
    notes TEXT,
    return_notes TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_customers_name ON customers(name);
CREATE INDEX idx_customers_phone ON customers(phone);

4. الموردين (Suppliers)

CREATE TABLE suppliers (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    address TEXT,
    phone TEXT,
    balance DECIMAL(15,2) DEFAULT 0.00,
    notes TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_suppliers_name ON suppliers(name);
CREATE INDEX idx_suppliers_phone ON suppliers(phone);

5. المنتجات (Products)

CREATE TABLE products (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    category_id INTEGER,
    price DECIMAL(10,2) NOT NULL DEFAULT 0.00,
    quantity INTEGER DEFAULT 0,
    barcode TEXT UNIQUE,
    image_path TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL
);

CREATE UNIQUE INDEX idx_products_barcode ON products(barcode);
CREATE INDEX idx_products_name ON products(name);
CREATE INDEX idx_products_category_id ON products(category_id);

-- Trigger to generate barcode if not provided
CREATE TRIGGER generate_product_barcode 
AFTER INSERT ON products 
WHEN NEW.barcode IS NULL
BEGIN
    UPDATE products 
    SET barcode = 'PRD' || printf('%06d', NEW.id)
    WHERE id = NEW.id;
END;

6. الفواتير (Invoices)

CREATE TABLE invoices (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    invoice_number TEXT NOT NULL UNIQUE,
    date DATE NOT NULL DEFAULT CURRENT_DATE,
    customer_id INTEGER,
    supplier_id INTEGER,
    total_amount DECIMAL(15,2) DEFAULT 0.00,
    type TEXT NOT NULL CHECK (type IN ('sale', 'purchase')),
    barcode TEXT UNIQUE,
    notes TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE,
    FOREIGN KEY (supplier_id) REFERENCES suppliers(id) ON DELETE CASCADE,
    CHECK (
        (type = 'sale' AND customer_id IS NOT NULL AND supplier_id IS NULL) OR
        (type = 'purchase' AND supplier_id IS NOT NULL AND customer_id IS NULL)
    )
);

CREATE UNIQUE INDEX idx_invoices_number ON invoices(invoice_number);
CREATE INDEX idx_invoices_date ON invoices(date);
CREATE INDEX idx_invoices_customer_id ON invoices(customer_id);
CREATE INDEX idx_invoices_supplier_id ON invoices(supplier_id);
CREATE INDEX idx_invoices_type ON invoices(type);

-- Trigger to generate invoice number
CREATE TRIGGER generate_invoice_number 
AFTER INSERT ON invoices 
WHEN NEW.invoice_number IS NULL
BEGIN
    UPDATE invoices 
    SET invoice_number = 'INV-' || printf('%04d', NEW.id)
    WHERE id = NEW.id;
END;

-- Trigger to generate invoice barcode
CREATE TRIGGER generate_invoice_barcode 
AFTER INSERT ON invoices 
BEGIN
    UPDATE invoices 
    SET barcode = 'INV' || printf('%08d', NEW.id)
    WHERE id = NEW.id;
END;

7. تفاصيل الفاتورة (Invoice Details)

CREATE TABLE invoice_details (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    invoice_id INTEGER NOT NULL,
    product_id INTEGER NOT NULL,
    quantity INTEGER NOT NULL CHECK (quantity > 0),
    unit_price DECIMAL(10,2) NOT NULL,
    total_price DECIMAL(15,2) NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (invoice_id) REFERENCES invoices(id) ON DELETE CASCADE,
    FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE
);

CREATE INDEX idx_invoice_details_invoice_id ON invoice_details(invoice_id);
CREATE INDEX idx_invoice_details_product_id ON invoice_details(product_id);

-- Trigger to calculate total_price
CREATE TRIGGER calculate_invoice_detail_total 
BEFORE INSERT ON invoice_details
BEGIN
    UPDATE NEW SET total_price = NEW.quantity * NEW.unit_price;
END;

-- Trigger to update invoice total when detail is inserted
CREATE TRIGGER update_invoice_total_on_insert 
AFTER INSERT ON invoice_details
BEGIN
    UPDATE invoices 
    SET total_amount = (
        SELECT SUM(total_price) 
        FROM invoice_details 
        WHERE invoice_id = NEW.invoice_id
    )
    WHERE id = NEW.invoice_id;
END;

-- Trigger to update product quantity on sale
CREATE TRIGGER update_product_quantity_on_sale 
AFTER INSERT ON invoice_details
WHEN (SELECT type FROM invoices WHERE id = NEW.invoice_id) = 'sale'
BEGIN
    UPDATE products 
    SET quantity = quantity - NEW.quantity
    WHERE id = NEW.product_id;
END;

-- Trigger to update product quantity on purchase
CREATE TRIGGER update_product_quantity_on_purchase 
AFTER INSERT ON invoice_details
WHEN (SELECT type FROM invoices WHERE id = NEW.invoice_id) = 'purchase'
BEGIN
    UPDATE products 
    SET quantity = quantity + NEW.quantity
    WHERE id = NEW.product_id;
END;

8. المرتجعات (Returns)

CREATE TABLE returns (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    invoice_id INTEGER NOT NULL,
    product_id INTEGER NOT NULL,
    quantity INTEGER NOT NULL CHECK (quantity > 0),
    reason TEXT,
    refund_amount DECIMAL(10,2) DEFAULT 0.00,
    date DATE NOT NULL DEFAULT CURRENT_DATE,
    notes TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (invoice_id) REFERENCES invoices(id) ON DELETE CASCADE,
    FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE
);

CREATE INDEX idx_returns_invoice_id ON returns(invoice_id);
CREATE INDEX idx_returns_product_id ON returns(product_id);
CREATE INDEX idx_returns_date ON returns(date);

-- Trigger to update product quantity on return
CREATE TRIGGER update_product_quantity_on_return 
AFTER INSERT ON returns
BEGIN
    UPDATE products 
    SET quantity = quantity + NEW.quantity
    WHERE id = NEW.product_id;
END;

9. الحركات المالية (Financial Transactions)

CREATE TABLE financial_transactions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    customer_id INTEGER,
    supplier_id INTEGER,
    amount DECIMAL(15,2) NOT NULL CHECK (amount > 0),
    type TEXT NOT NULL CHECK (type IN ('payment', 'receipt')),
    date DATE NOT NULL DEFAULT CURRENT_DATE,
    notes TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE,
    FOREIGN KEY (supplier_id) REFERENCES suppliers(id) ON DELETE CASCADE,
    CHECK (
        (customer_id IS NOT NULL AND supplier_id IS NULL) OR
        (supplier_id IS NOT NULL AND customer_id IS NULL)
    )
);

CREATE INDEX idx_financial_transactions_customer_id ON financial_transactions(customer_id);
CREATE INDEX idx_financial_transactions_supplier_id ON financial_transactions(supplier_id);
CREATE INDEX idx_financial_transactions_date ON financial_transactions(date);
CREATE INDEX idx_financial_transactions_type ON financial_transactions(type);

-- Trigger to update customer balance
CREATE TRIGGER update_customer_balance 
AFTER INSERT ON financial_transactions
WHEN NEW.customer_id IS NOT NULL
BEGIN
    UPDATE customers 
    SET balance = balance + CASE 
        WHEN NEW.type = 'payment' THEN -NEW.amount
        WHEN NEW.type = 'receipt' THEN NEW.amount
    END
    WHERE id = NEW.customer_id;
END;

-- Trigger to update supplier balance
CREATE TRIGGER update_supplier_balance 
AFTER INSERT ON financial_transactions
WHEN NEW.supplier_id IS NOT NULL
BEGIN
    UPDATE suppliers 
    SET balance = balance + CASE 
        WHEN NEW.type = 'payment' THEN NEW.amount
        WHEN NEW.type = 'receipt' THEN -NEW.amount
    END
    WHERE id = NEW.supplier_id;
END;

10. العمالة اليومية (Daily Labor)

CREATE TABLE daily_labor (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    date DATE NOT NULL DEFAULT CURRENT_DATE,
    wage DECIMAL(10,2) NOT NULL DEFAULT 0.00,
    notes TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_daily_labor_date ON daily_labor(date);
CREATE INDEX idx_daily_labor_name ON daily_labor(name);

11. المستخدمين (Users) - للمستقبل

CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT NOT NULL UNIQUE,
    password_hash TEXT NOT NULL,
    role TEXT NOT NULL DEFAULT 'user' CHECK (role IN ('admin', 'user')),
    is_active BOOLEAN DEFAULT 1,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE UNIQUE INDEX idx_users_username ON users(username);

12. سجل النشاطات (Activity Log) - للتتبع

CREATE TABLE activity_log (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER,
    action TEXT NOT NULL,
    table_name TEXT NOT NULL,
    record_id INTEGER,
    old_values TEXT, -- JSON
    new_values TEXT, -- JSON
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
);

CREATE INDEX idx_activity_log_user_id ON activity_log(user_id);
CREATE INDEX idx_activity_log_table_name ON activity_log(table_name);
CREATE INDEX idx_activity_log_created_at ON activity_log(created_at);

Views للتقارير السريعة

1. تقرير المنتجات مع الفئات

CREATE VIEW products_with_categories AS
SELECT 
    p.id,
    p.name,
    p.barcode,
    p.price,
    p.quantity,
    c.name as category_name,
    p.image_path,
    p.created_at
FROM products p
LEFT JOIN categories c ON p.category_id = c.id;

2. تقرير الفواتير مع التفاصيل

CREATE VIEW invoices_summary AS
SELECT 
    i.id,
    i.invoice_number,
    i.date,
    i.type,
    CASE 
        WHEN i.type = 'sale' THEN c.name
        WHEN i.type = 'purchase' THEN s.name
    END as client_name,
    i.total_amount,
    COUNT(id_det.id) as items_count
FROM invoices i
LEFT JOIN customers c ON i.customer_id = c.id
LEFT JOIN suppliers s ON i.supplier_id = s.id
LEFT JOIN invoice_details id_det ON i.id = id_det.invoice_id
GROUP BY i.id;

3. تقرير الأرصدة

CREATE VIEW customer_balances AS
SELECT 
    c.id,
    c.name,
    c.phone,
    c.balance,
    c.cash_on_hand,
    COALESCE(SUM(ft.amount), 0) as total_transactions
FROM customers c
LEFT JOIN financial_transactions ft ON c.id = ft.customer_id
GROUP BY c.id;

Database Constraints & Rules

إعدادات إضافية لـ SQLite

-- Enable foreign key constraints
PRAGMA foreign_keys = ON;

-- Set journal mode for better performance
PRAGMA journal_mode = WAL;

-- Set synchronous mode for balance between safety and performance
PRAGMA synchronous = NORMAL;

-- Optimize SQLite for application use
PRAGMA cache_size = -64000; -- 64MB cache
PRAGMA temp_store = MEMORY;
PRAGMA mmap_size = 268435456; -- 256MB memory-mapped I/O

نسخ احتياطية تلقائية

-- Create backup table for critical operations
CREATE TABLE backup_metadata (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    backup_type TEXT NOT NULL, -- 'auto', 'manual'
    file_path TEXT NOT NULL,
    size INTEGER,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

Database Migration System

إصدارات قاعدة البيانات

CREATE TABLE schema_version (
    version INTEGER PRIMARY KEY,
    description TEXT,
    applied_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO schema_version (version, description) 
VALUES (1, 'Initial schema creation');

Migration Scripts Structure

/database
  /migrations
    - 001_initial_schema.sql
    - 002_add_activity_log.sql
    - 003_add_user_management.sql
  /seeds
    - default_categories.sql
    - sample_data.sql

Performance Optimization

Indexes for Common Queries

-- Composite indexes for frequent searches
CREATE INDEX idx_invoice_details_invoice_product ON invoice_details(invoice_id, product_id);
CREATE INDEX idx_returns_invoice_product ON returns(invoice_id, product_id);

-- Date-based indexes for reports
CREATE INDEX idx_invoices_date_type ON invoices(date, type);
CREATE INDEX idx_financial_transactions_date_type ON financial_transactions(date, type);

-- Text search indexes
CREATE INDEX idx_products_name_lower ON products(LOWER(name));
CREATE INDEX idx_customers_name_lower ON customers(LOWER(name));

فهرسة النصوص العربية

-- Enable FTS for Arabic text search (if needed)
CREATE VIRTUAL TABLE products_fts USING fts5(
    name, 
    content='products', 
    content_rowid='id',
    tokenize='unicode61'
);

-- Triggers to keep FTS in sync
CREATE TRIGGER products_fts_insert AFTER INSERT ON products BEGIN
    INSERT INTO products_fts(rowid, name) VALUES (new.id, new.name);
END;

CREATE TRIGGER products_fts_delete AFTER DELETE ON products BEGIN
    INSERT INTO products_fts(products_fts, rowid, name) VALUES('delete', old.id, old.name);
END;

CREATE TRIGGER products_fts_update AFTER UPDATE ON products BEGIN
    INSERT INTO products_fts(products_fts, rowid, name) VALUES('delete', old.id, old.name);
    INSERT INTO products_fts(rowid, name) VALUES (new.id, new.name);
END;

@NobbZ
Copy link

NobbZ commented Oct 6, 2025

Is this hacktober spam again? This repo isn't even labelled as participating…

This kind of spam even in my personal repos (and the removal of T-Shirts) has been the reason I stopped participating in an otherwise useful event…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants