-- ============================================================ -- Warehouse Management Database - Init Script (PostgreSQL) -- Based on WareHouseDB.md specification -- ============================================================ -- ============================================================ -- ENUM Types -- ============================================================ CREATE TYPE container_type_enum AS ENUM ('empty_box', 'tray', 'paper_box', 'plastic_box', 'bag', 'other'); CREATE TYPE component_item_status_enum AS ENUM ('normal', 'damaged', 'long_unused', 'expired', 'pending_inspection'); CREATE TYPE invoice_type_enum AS ENUM ('import', 'export'); CREATE TYPE invoice_status_enum AS ENUM ('draft', 'pending', 'approved', 'completed', 'cancelled'); CREATE TYPE transaction_type_enum AS ENUM ('import', 'export', 'adjustment', 'transfer'); -- ============================================================ -- Trigger function: auto-update updated_at -- ============================================================ CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = CURRENT_TIMESTAMP; RETURN NEW; END; $$ LANGUAGE plpgsql; -- ============================================================ -- 1. warehouses (Kho) -- ============================================================ CREATE TABLE warehouses ( id BIGSERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, description TEXT, address VARCHAR(500), created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TRIGGER trg_warehouses_updated_at BEFORE UPDATE ON warehouses FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 2. rooms (Phòng) -- ============================================================ CREATE TABLE rooms ( id BIGSERIAL PRIMARY KEY, warehouse_id BIGINT NOT NULL REFERENCES warehouses(id), name VARCHAR(255) NOT NULL, description TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TRIGGER trg_rooms_updated_at BEFORE UPDATE ON rooms FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 3. cabinets (Tủ) -- ============================================================ CREATE TABLE cabinets ( id BIGSERIAL PRIMARY KEY, room_id BIGINT NOT NULL REFERENCES rooms(id), name VARCHAR(255) NOT NULL, description TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TRIGGER trg_cabinets_updated_at BEFORE UPDATE ON cabinets FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 4. shelves (Tầng / Kệ) -- ============================================================ CREATE TABLE shelves ( id BIGSERIAL PRIMARY KEY, cabinet_id BIGINT NOT NULL REFERENCES cabinets(id), name VARCHAR(255) NOT NULL, level_index INT NOT NULL, description TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TRIGGER trg_shelves_updated_at BEFORE UPDATE ON shelves FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 5. containers (Vật chứa) -- ============================================================ CREATE TABLE containers ( id BIGSERIAL PRIMARY KEY, shelf_id BIGINT NOT NULL REFERENCES shelves(id), name VARCHAR(255) NOT NULL, container_type container_type_enum NOT NULL, description TEXT, max_capacity INT, metadata JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TRIGGER trg_containers_updated_at BEFORE UPDATE ON containers FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 6. component_types (Loại linh kiện) -- ============================================================ CREATE TABLE component_types ( id BIGSERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, description TEXT, metadata JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT uk_component_types_name UNIQUE (name) ); CREATE TRIGGER trg_component_types_updated_at BEFORE UPDATE ON component_types FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 7. components (Linh kiện) -- ============================================================ CREATE TABLE components ( id BIGSERIAL PRIMARY KEY, component_type_id BIGINT NOT NULL REFERENCES component_types(id), name VARCHAR(255) NOT NULL, description TEXT, unit VARCHAR(50) NOT NULL DEFAULT 'cái', total_quantity INT NOT NULL DEFAULT 0, min_quantity INT NOT NULL DEFAULT 0, metadata JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TRIGGER trg_components_updated_at BEFORE UPDATE ON components FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 8. component_codes (Mã linh kiện) -- ============================================================ CREATE TABLE component_codes ( id BIGSERIAL PRIMARY KEY, component_id BIGINT NOT NULL REFERENCES components(id), code VARCHAR(255) NOT NULL, code_type VARCHAR(100), is_primary BOOLEAN NOT NULL DEFAULT FALSE, metadata JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT uk_component_codes_code_type UNIQUE (code, code_type) ); -- ============================================================ -- 9. component_items (Linh kiện tại từng vị trí) -- ============================================================ CREATE TABLE component_items ( id BIGSERIAL PRIMARY KEY, component_id BIGINT NOT NULL REFERENCES components(id), container_id BIGINT NOT NULL REFERENCES containers(id), quantity INT NOT NULL DEFAULT 0, status component_item_status_enum NOT NULL DEFAULT 'normal', metadata JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT uk_component_items_comp_cont_status UNIQUE (component_id, container_id, status) ); CREATE TRIGGER trg_component_items_updated_at BEFORE UPDATE ON component_items FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 10. component_status_history (Lịch sử thay đổi tình trạng) -- ============================================================ CREATE TABLE component_status_history ( id BIGSERIAL PRIMARY KEY, component_item_id BIGINT NOT NULL REFERENCES component_items(id), old_status component_item_status_enum, new_status component_item_status_enum NOT NULL, changed_quantity INT, note TEXT, changed_by VARCHAR(255), changed_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP ); -- ============================================================ -- 11. invoice_configs (Cấu hình hóa đơn mẫu) -- ============================================================ CREATE TABLE invoice_configs ( id BIGSERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, type invoice_type_enum NOT NULL, description TEXT, is_active BOOLEAN NOT NULL DEFAULT TRUE, metadata JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TRIGGER trg_invoice_configs_updated_at BEFORE UPDATE ON invoice_configs FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 12. invoice_config_items (Chi tiết cấu hình hóa đơn) -- ============================================================ CREATE TABLE invoice_config_items ( id BIGSERIAL PRIMARY KEY, invoice_config_id BIGINT NOT NULL REFERENCES invoice_configs(id), component_id BIGINT NOT NULL REFERENCES components(id), required_quantity INT NOT NULL, allow_alternative BOOLEAN NOT NULL DEFAULT FALSE, priority_order INT NOT NULL DEFAULT 0, note TEXT, metadata JSONB, CONSTRAINT uk_invoice_config_items_config_comp UNIQUE (invoice_config_id, component_id) ); -- ============================================================ -- 13. alternative_components (Linh kiện thay thế) -- ============================================================ CREATE TABLE alternative_components ( id BIGSERIAL PRIMARY KEY, invoice_config_item_id BIGINT NOT NULL REFERENCES invoice_config_items(id), alternative_component_id BIGINT NOT NULL REFERENCES components(id), conversion_ratio DECIMAL(10,2) NOT NULL DEFAULT 1.00, priority INT NOT NULL DEFAULT 0, note TEXT, metadata JSONB, CONSTRAINT uk_alternative_components_item_alt UNIQUE (invoice_config_item_id, alternative_component_id) ); -- ============================================================ -- 14. invoices (Hóa đơn nhập/xuất) -- ============================================================ CREATE TABLE invoices ( id BIGSERIAL PRIMARY KEY, invoice_code VARCHAR(100) NOT NULL, type invoice_type_enum NOT NULL, status invoice_status_enum NOT NULL DEFAULT 'draft', invoice_config_id BIGINT REFERENCES invoice_configs(id), total_items INT NOT NULL DEFAULT 0, note TEXT, created_by VARCHAR(255), approved_by VARCHAR(255), completed_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, metadata JSONB, CONSTRAINT uk_invoices_invoice_code UNIQUE (invoice_code) ); CREATE TRIGGER trg_invoices_updated_at BEFORE UPDATE ON invoices FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 15. invoice_items (Chi tiết hóa đơn) -- ============================================================ CREATE TABLE invoice_items ( id BIGSERIAL PRIMARY KEY, invoice_id BIGINT NOT NULL REFERENCES invoices(id), component_id BIGINT NOT NULL REFERENCES components(id), original_component_id BIGINT REFERENCES components(id), required_quantity INT NOT NULL, actual_quantity INT NOT NULL DEFAULT 0, is_substituted BOOLEAN NOT NULL DEFAULT FALSE, is_short BOOLEAN NOT NULL DEFAULT FALSE, shortage_quantity INT NOT NULL DEFAULT 0, note TEXT, metadata JSONB, CONSTRAINT uk_invoice_items_invoice_comp UNIQUE (invoice_id, component_id) ); -- ============================================================ -- 16. invoice_item_locations (Vị trí xuất/nhập cho từng item) -- ============================================================ CREATE TABLE invoice_item_locations ( id BIGSERIAL PRIMARY KEY, invoice_item_id BIGINT NOT NULL REFERENCES invoice_items(id), container_id BIGINT NOT NULL REFERENCES containers(id), quantity INT NOT NULL ); -- ============================================================ -- 17. invoice_status_history (Lịch sử trạng thái hóa đơn) -- ============================================================ CREATE TABLE invoice_status_history ( id BIGSERIAL PRIMARY KEY, invoice_id BIGINT NOT NULL REFERENCES invoices(id), old_status VARCHAR(50), new_status VARCHAR(50) NOT NULL, changed_by VARCHAR(255), note TEXT, changed_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP ); -- ============================================================ -- 18. stock_transactions (Lịch sử nhập xuất kho) -- ============================================================ CREATE TABLE stock_transactions ( id BIGSERIAL PRIMARY KEY, invoice_id BIGINT NOT NULL REFERENCES invoices(id), component_id BIGINT NOT NULL REFERENCES components(id), container_id BIGINT NOT NULL REFERENCES containers(id), transaction_type transaction_type_enum NOT NULL, quantity INT NOT NULL, balance_after INT, note TEXT, created_by VARCHAR(255), created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), username VARCHAR(50) UNIQUE NOT NULL, email VARCHAR(255) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, full_name VARCHAR(100), is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, created_by VARCHAR(50) ); -- Bảng Roles: Lưu các vai trò (admin, editor, viewer...) CREATE TABLE roles ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(50) UNIQUE NOT NULL, description VARCHAR(255), created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, created_by VARCHAR(50) ); -- Bảng Permissions: Lưu các quyền hạn (read, write, delete...) CREATE TABLE permissions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(100) UNIQUE NOT NULL, description VARCHAR(255), created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, created_by VARCHAR(50) ); -- Bảng user_roles: Liên kết user với role (N-N) CREATE TABLE user_roles ( user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE, assigned_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (user_id, role_id) ); -- Bảng role_permissions: Liên kết role với permission (N-N) CREATE TABLE role_permissions ( role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE, permission_id UUID NOT NULL REFERENCES permissions(id) ON DELETE CASCADE, assigned_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (role_id, permission_id) ); -- ============================================================ -- Indexes -- ============================================================ -- Comment: Tạo index cho việc tìm kiếm nhanh (tùy chọn) CREATE INDEX idx_users_username ON users(username); CREATE INDEX idx_users_email ON users(email); CREATE INDEX idx_roles_name ON roles(name); -- Index cho truy vấn nhanh CREATE INDEX idx_user_roles_user_id ON user_roles(user_id); CREATE INDEX idx_user_roles_role_id ON user_roles(role_id); CREATE INDEX idx_role_permissions_role_id ON role_permissions(role_id); CREATE INDEX idx_role_permissions_permission_id ON role_permissions(permission_id); -- Tìm linh kiện theo vị trí CREATE INDEX idx_component_items_component ON component_items(component_id); CREATE INDEX idx_component_items_container ON component_items(container_id); CREATE INDEX idx_component_items_status ON component_items(status); -- Tìm mã linh kiện CREATE INDEX idx_component_codes_code ON component_codes(code); CREATE INDEX idx_component_codes_component ON component_codes(component_id); -- Thống kê hóa đơn theo thời gian CREATE INDEX idx_invoices_type_status ON invoices(type, status); CREATE INDEX idx_invoices_created_at ON invoices(created_at); CREATE INDEX idx_invoices_type_created ON invoices(type, created_at); -- Thống kê giao dịch kho CREATE INDEX idx_stock_transactions_component_date ON stock_transactions(component_id, created_at); CREATE INDEX idx_stock_transactions_type_date ON stock_transactions(transaction_type, created_at); CREATE INDEX idx_stock_transactions_invoice ON stock_transactions(invoice_id); -- Tìm vị trí container (theo cấu trúc phân cấp) CREATE INDEX idx_containers_shelf ON containers(shelf_id); CREATE INDEX idx_shelves_cabinet ON shelves(cabinet_id); CREATE INDEX idx_cabinets_room ON cabinets(room_id); CREATE INDEX idx_rooms_warehouse ON rooms(warehouse_id); -- ============================================================ -- Seed: Default permissions (theo module) -- ============================================================ -- Warehouse module INSERT INTO permissions (name, description) VALUES ('warehouse:create', 'Tạo kho mới'), ('warehouse:read', 'Xem thông tin kho'), ('warehouse:update', 'Cập nhật kho'), ('warehouse:delete', 'Xóa kho'); -- Room module INSERT INTO permissions (name, description) VALUES ('room:create', 'Tạo phòng mới'), ('room:read', 'Xem thông tin phòng'), ('room:update', 'Cập nhật phòng'), ('room:delete', 'Xóa phòng'); -- Cabinet module INSERT INTO permissions (name, description) VALUES ('cabinet:create', 'Tạo tủ mới'), ('cabinet:read', 'Xem thông tin tủ'), ('cabinet:update', 'Cập nhật tủ'), ('cabinet:delete', 'Xóa tủ'); -- Shelf module INSERT INTO permissions (name, description) VALUES ('shelf:create', 'Tạo kệ mới'), ('shelf:read', 'Xem thông tin kệ'), ('shelf:update', 'Cập nhật kệ'), ('shelf:delete', 'Xóa kệ'); -- Container module INSERT INTO permissions (name, description) VALUES ('container:create', 'Tạo vật chứa mới'), ('container:read', 'Xem thông tin vật chứa'), ('container:update', 'Cập nhật vật chứa'), ('container:delete', 'Xóa vật chứa'); -- Component Type module INSERT INTO permissions (name, description) VALUES ('component_type:create', 'Tạo loại linh kiện mới'), ('component_type:read', 'Xem loại linh kiện'), ('component_type:update', 'Cập nhật loại linh kiện'), ('component_type:delete', 'Xóa loại linh kiện'); -- Component module INSERT INTO permissions (name, description) VALUES ('component:create', 'Tạo linh kiện mới'), ('component:read', 'Xem thông tin linh kiện'), ('component:update', 'Cập nhật linh kiện'), ('component:delete', 'Xóa linh kiện'); -- Invoice module INSERT INTO permissions (name, description) VALUES ('invoice:create', 'Tạo hóa đơn mới'), ('invoice:read', 'Xem thông tin hóa đơn'), ('invoice:update', 'Cập nhật hóa đơn'), ('invoice:delete', 'Xóa hóa đơn'), ('invoice:approve', 'Duyệt hóa đơn'); -- Stock module INSERT INTO permissions (name, description) VALUES ('stock:import', 'Nhập kho'), ('stock:export', 'Xuất kho'), ('stock:adjust', 'Điều chỉnh tồn kho'), ('stock:transfer', 'Chuyển kho'), ('stock:read', 'Xem báo cáo tồn kho'); -- User & RBAC module INSERT INTO permissions (name, description) VALUES ('user:create', 'Tạo người dùng mới'), ('user:read', 'Xem thông tin người dùng'), ('user:update', 'Cập nhật người dùng'), ('user:delete', 'Xóa người dùng'), ('role:manage', 'Quản lý vai trò và quyền hạn'); -- Seed: SYS_ADMIN role INSERT INTO roles (name, description, created_by) VALUES ('SYS_ADMIN', 'Quản trị viên hệ thống - toàn quyền', 'system'); -- Gán TẤT CẢ permissions cho SYS_ADMIN INSERT INTO role_permissions (role_id, permission_id) SELECT r.id, p.id FROM roles r CROSS JOIN permissions p WHERE r.name = 'SYS_ADMIN';