251117:1700 first commit
This commit is contained in:
1248
docs/SQL/01_dms_v1_0_0.bak.sql
Normal file
1248
docs/SQL/01_dms_v1_0_0.bak.sql
Normal file
File diff suppressed because it is too large
Load Diff
1565
docs/SQL/01_dms_v1_0_0.sql
Normal file
1565
docs/SQL/01_dms_v1_0_0.sql
Normal file
File diff suppressed because it is too large
Load Diff
40
docs/SQL/01_dms_v1_0_0_patch.sql
Normal file
40
docs/SQL/01_dms_v1_0_0_patch.sql
Normal file
@@ -0,0 +1,40 @@
|
||||
-- ==========================================================
|
||||
-- DMS v1.0.1 Patch
|
||||
-- Reason: Add missing relationship for Req 2.5.3
|
||||
-- Update: Changed link to revision-level instead of master-level based on clarification.
|
||||
-- ==========================================================
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET time_zone = '+07:00';
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
|
||||
-- สร้างตารางเชื่อมระหว่าง shop_drawing_revisions (ตารางลูก) กับ contract_drawings (Master)
|
||||
-- เพื่อรองรับ Requirement 2.5.3 ที่ระบุว่า Shop Drawing "แต่ละ revision" สามารถอ้างอิง Contract Drawing ที่แตกต่างกันได้
|
||||
CREATE TABLE shop_drawing_revision_contract_refs (
|
||||
shop_drawing_revision_id INT NOT NULL COMMENT 'ID ของ Shop Drawing Revision (FK -> shop_drawing_revisions.id)',
|
||||
contract_drawing_id INT NOT NULL COMMENT 'ID ของ Contract Drawing ที่อ้างอิง (FK -> contract_drawings.condwg_id)',
|
||||
|
||||
-- PRIMARY KEY (shop_drawing_revision_id, contract_drawing_id),
|
||||
|
||||
-- เพิ่ม KEY เพื่อประสิทธิภาพในการค้นหา
|
||||
KEY idx_sdrcr_rev (shop_drawing_revision_id),
|
||||
KEY idx_sdrcr_cd (contract_drawing_id),
|
||||
|
||||
-- Foreign Keys
|
||||
CONSTRAINT fk_sdrcr_revision
|
||||
FOREIGN KEY (shop_drawing_revision_id)
|
||||
REFERENCES shop_drawing_revisions(id) -- เชื่อมโยงกับตาราง Revision
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT fk_sdrcr_contract_drawing
|
||||
FOREIGN KEY (contract_drawing_id)
|
||||
REFERENCES contract_drawings(condwg_id)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE CASCADE
|
||||
)
|
||||
ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_general_ci
|
||||
COMMENT='ตารางเชื่อมโยง Shop Drawing Revisions กับ Contract Drawings (Req 2.5.3)';
|
||||
|
||||
1537
docs/SQL/01_dms_v1_0_1.sql
Normal file
1537
docs/SQL/01_dms_v1_0_1.sql
Normal file
File diff suppressed because it is too large
Load Diff
1603
docs/SQL/01_lcbp3_v1_1_0.sql
Normal file
1603
docs/SQL/01_lcbp3_v1_1_0.sql
Normal file
File diff suppressed because it is too large
Load Diff
1660
docs/SQL/01_lcbp3_v1_1_1.sql
Normal file
1660
docs/SQL/01_lcbp3_v1_1_1.sql
Normal file
File diff suppressed because it is too large
Load Diff
1877
docs/SQL/01_lcbp3_v1_2_0.sql
Normal file
1877
docs/SQL/01_lcbp3_v1_2_0.sql
Normal file
File diff suppressed because it is too large
Load Diff
1870
docs/SQL/01_lcbp3_v1_3_0.sql
Normal file
1870
docs/SQL/01_lcbp3_v1_3_0.sql
Normal file
File diff suppressed because it is too large
Load Diff
1870
docs/SQL/01_lcbp3_v1_3_0.txt
Normal file
1870
docs/SQL/01_lcbp3_v1_3_0.txt
Normal file
File diff suppressed because it is too large
Load Diff
1923
docs/SQL/01_lcbp3_v1_4_0.sql
Normal file
1923
docs/SQL/01_lcbp3_v1_4_0.sql
Normal file
File diff suppressed because it is too large
Load Diff
1923
docs/SQL/01_lcbp3_v1_4_0.txt
Normal file
1923
docs/SQL/01_lcbp3_v1_4_0.txt
Normal file
File diff suppressed because it is too large
Load Diff
385
docs/SQL/Cluad.sql
Normal file
385
docs/SQL/Cluad.sql
Normal file
@@ -0,0 +1,385 @@
|
||||
-- ปรับปรุงโครงสร้าง Correspondence เพื่อจัดการ Revisions ได้ดีขึ้น
|
||||
|
||||
-- 1. แยก Master และ Revision ชัดเจน
|
||||
CREATE TABLE correspondence_master (
|
||||
master_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
correspondence_number VARCHAR(100) NOT NULL,
|
||||
project_id INT NOT NULL,
|
||||
correspondence_type_id INT NOT NULL,
|
||||
|
||||
-- Metadata ที่ไม่เปลี่ยนแปลงตาม Revision
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by INT NULL,
|
||||
deleted_at DATETIME NULL,
|
||||
|
||||
-- Track current/latest revision
|
||||
current_revision_id INT NULL,
|
||||
latest_revision_number INT NOT NULL DEFAULT 0,
|
||||
|
||||
CONSTRAINT uq_corr_no_per_project UNIQUE (project_id, correspondence_number),
|
||||
|
||||
CONSTRAINT fk_cm_project FOREIGN KEY (project_id)
|
||||
REFERENCES projects(project_id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
CONSTRAINT fk_cm_type FOREIGN KEY (correspondence_type_id)
|
||||
REFERENCES correspondence_types(type_id) ON UPDATE CASCADE ON DELETE RESTRICT,
|
||||
CONSTRAINT fk_cm_created_by FOREIGN KEY (created_by)
|
||||
REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- 2. Revision ที่เก็บข้อมูลที่เปลี่ยนแปลงได้
|
||||
CREATE TABLE correspondence_revisions_new (
|
||||
revision_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
master_id INT NOT NULL,
|
||||
revision_number INT NOT NULL, -- เปลี่ยนเป็น INT เพื่อง่ายต่อการเรียงลำดับ
|
||||
revision_label VARCHAR(10) NULL, -- A, B, C สำหรับแสดงผล
|
||||
|
||||
-- สถานะเฉพาะของ Revision นี้
|
||||
correspondence_status_id INT NOT NULL,
|
||||
is_current BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- ข้อมูลที่เปลี่ยนแปลงตาม Revision
|
||||
originator_id INT NULL,
|
||||
recipient_id INT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
keywords VARCHAR(255) NULL,
|
||||
issued_date DATETIME NULL,
|
||||
pdf_path VARCHAR(500) NULL,
|
||||
details JSON NULL,
|
||||
|
||||
-- Audit
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by INT NULL,
|
||||
change_reason TEXT NULL,
|
||||
|
||||
CONSTRAINT uq_master_revision_number UNIQUE (master_id, revision_number),
|
||||
CONSTRAINT uq_master_current UNIQUE (master_id, is_current), -- ใช้ partial unique index ได้ดีกว่า
|
||||
|
||||
CONSTRAINT fk_cr_master FOREIGN KEY (master_id)
|
||||
REFERENCES correspondence_master(master_id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
CONSTRAINT fk_cr_status FOREIGN KEY (correspondence_status_id)
|
||||
REFERENCES correspondence_status(status_id) ON UPDATE CASCADE ON DELETE RESTRICT,
|
||||
CONSTRAINT fk_cr_originator FOREIGN KEY (originator_id)
|
||||
REFERENCES organizations(org_id) ON UPDATE CASCADE ON DELETE SET NULL,
|
||||
CONSTRAINT fk_cr_recipient FOREIGN KEY (recipient_id)
|
||||
REFERENCES organizations(org_id) ON UPDATE CASCADE ON DELETE SET NULL,
|
||||
CONSTRAINT fk_cr_created_by FOREIGN KEY (created_by)
|
||||
REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- 3. Update current_revision_id FK
|
||||
ALTER TABLE correspondence_master
|
||||
ADD CONSTRAINT fk_cm_current_revision
|
||||
FOREIGN KEY (current_revision_id)
|
||||
REFERENCES correspondence_revisions_new(revision_id)
|
||||
ON UPDATE CASCADE ON DELETE SET NULL;
|
||||
|
||||
-- 4. View สำหรับ Query ง่าย (รวม Master + Current Revision)
|
||||
CREATE OR REPLACE VIEW v_current_correspondences AS
|
||||
SELECT
|
||||
cm.master_id,
|
||||
cm.correspondence_number,
|
||||
cm.project_id,
|
||||
cm.correspondence_type_id,
|
||||
cr.revision_id,
|
||||
cr.revision_number,
|
||||
cr.revision_label,
|
||||
cr.correspondence_status_id,
|
||||
cr.title,
|
||||
cr.keywords,
|
||||
cr.originator_id,
|
||||
cr.recipient_id,
|
||||
cr.issued_date,
|
||||
cr.pdf_path,
|
||||
cr.details,
|
||||
cm.created_at AS master_created_at,
|
||||
cr.created_at AS revision_created_at,
|
||||
cm.latest_revision_number
|
||||
FROM correspondence_master cm
|
||||
INNER JOIN correspondence_revisions_new cr
|
||||
ON cm.current_revision_id = cr.revision_id
|
||||
WHERE cm.deleted_at IS NULL;
|
||||
|
||||
-- 5. Stored Procedure สำหรับสร้าง Revision ใหม่
|
||||
DELIMITER $$
|
||||
|
||||
CREATE PROCEDURE sp_create_correspondence_revision(
|
||||
IN p_master_id INT,
|
||||
IN p_title VARCHAR(255),
|
||||
IN p_originator_id INT,
|
||||
IN p_recipient_id INT,
|
||||
IN p_status_id INT,
|
||||
IN p_created_by INT,
|
||||
IN p_change_reason TEXT,
|
||||
OUT p_revision_id INT
|
||||
)
|
||||
BEGIN
|
||||
DECLARE v_next_revision_number INT;
|
||||
DECLARE v_revision_label VARCHAR(10);
|
||||
|
||||
-- Get next revision number
|
||||
SELECT COALESCE(MAX(revision_number), 0) + 1
|
||||
INTO v_next_revision_number
|
||||
FROM correspondence_revisions_new
|
||||
WHERE master_id = p_master_id;
|
||||
|
||||
-- Generate label (0->Original, 1->A, 2->B, etc.)
|
||||
IF v_next_revision_number = 0 THEN
|
||||
SET v_revision_label = 'Original';
|
||||
ELSE
|
||||
SET v_revision_label = CHAR(64 + v_next_revision_number); -- A, B, C...
|
||||
END IF;
|
||||
|
||||
-- Mark all previous revisions as not current
|
||||
UPDATE correspondence_revisions_new
|
||||
SET is_current = FALSE
|
||||
WHERE master_id = p_master_id;
|
||||
|
||||
-- Insert new revision
|
||||
INSERT INTO correspondence_revisions_new (
|
||||
master_id, revision_number, revision_label,
|
||||
correspondence_status_id, is_current,
|
||||
title, originator_id, recipient_id,
|
||||
created_by, change_reason
|
||||
) VALUES (
|
||||
p_master_id, v_next_revision_number, v_revision_label,
|
||||
p_status_id, TRUE,
|
||||
p_title, p_originator_id, p_recipient_id,
|
||||
p_created_by, p_change_reason
|
||||
);
|
||||
|
||||
SET p_revision_id = LAST_INSERT_ID();
|
||||
|
||||
-- Update master
|
||||
UPDATE correspondence_master
|
||||
SET
|
||||
current_revision_id = p_revision_id,
|
||||
latest_revision_number = v_next_revision_number
|
||||
WHERE master_id = p_master_id;
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
|
||||
|
||||
|
||||
-- *****************************************************
|
||||
-- *****************************************************
|
||||
-- *****************************************************
|
||||
-- *****************************************************
|
||||
-- *****************************************************
|
||||
-- *****************************************************
|
||||
|
||||
-- ปรับปรุง Technical Documents เพื่อความชัดเจนและเชื่อมโยงกับ Correspondence
|
||||
|
||||
-- 1. Technical Document Master
|
||||
CREATE TABLE technical_document_master (
|
||||
master_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
document_number VARCHAR(100) NOT NULL,
|
||||
document_type_id INT NOT NULL,
|
||||
project_id INT NOT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
|
||||
-- Link to RFA Correspondence (optional - เพราะอาจยังไม่ได้ส่ง RFA)
|
||||
rfa_correspondence_id INT NULL,
|
||||
|
||||
-- Tracking
|
||||
current_revision_id INT NULL,
|
||||
latest_revision_number INT NOT NULL DEFAULT 0,
|
||||
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by INT NULL,
|
||||
deleted_at DATETIME NULL,
|
||||
|
||||
CONSTRAINT uq_techdoc_no_project UNIQUE (project_id, document_number),
|
||||
|
||||
CONSTRAINT fk_tdm_type FOREIGN KEY (document_type_id)
|
||||
REFERENCES technicaldoc_types(document_types_id),
|
||||
CONSTRAINT fk_tdm_project FOREIGN KEY (project_id)
|
||||
REFERENCES projects(project_id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_tdm_rfa_corr FOREIGN KEY (rfa_correspondence_id)
|
||||
REFERENCES correspondences(corr_id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_tdm_created_by FOREIGN KEY (created_by)
|
||||
REFERENCES users(user_id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- 2. Technical Document Revisions
|
||||
CREATE TABLE technical_document_revisions (
|
||||
revision_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
master_id INT NOT NULL,
|
||||
revision_number INT NOT NULL,
|
||||
revision_label VARCHAR(10) NULL, -- A, B, C
|
||||
|
||||
status_code_id INT NOT NULL,
|
||||
approve_code_id INT NULL,
|
||||
is_current BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- File references
|
||||
pdf_path VARCHAR(500) NULL,
|
||||
dwg_path VARCHAR(500) NULL, -- สำหรับ DWG type
|
||||
|
||||
-- Metadata
|
||||
revision_description TEXT NULL,
|
||||
submitted_date DATE NULL,
|
||||
approved_date DATE NULL,
|
||||
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by INT NULL,
|
||||
updated_by INT NULL,
|
||||
|
||||
CONSTRAINT uq_master_rev_number UNIQUE (master_id, revision_number),
|
||||
|
||||
CONSTRAINT fk_tdr_master FOREIGN KEY (master_id)
|
||||
REFERENCES technical_document_master(master_id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_tdr_status FOREIGN KEY (status_code_id)
|
||||
REFERENCES technicaldoc_status_codes(status_code_id),
|
||||
CONSTRAINT fk_tdr_approve FOREIGN KEY (approve_code_id)
|
||||
REFERENCES technicaldoc_approve_codes(approve_code_id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_tdr_created_by FOREIGN KEY (created_by)
|
||||
REFERENCES users(user_id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_tdr_updated_by FOREIGN KEY (updated_by)
|
||||
REFERENCES users(user_id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- 3. Shop Drawing References (Many-to-Many with Revisions)
|
||||
CREATE TABLE technical_document_shop_drawing_refs (
|
||||
tech_doc_revision_id INT NOT NULL,
|
||||
shop_drawing_rev_id INT NOT NULL,
|
||||
reference_type ENUM('SUPERSEDES', 'RELATED', 'AS_PER') DEFAULT 'RELATED',
|
||||
|
||||
PRIMARY KEY (tech_doc_revision_id, shop_drawing_rev_id),
|
||||
|
||||
CONSTRAINT fk_tdsdr_tech_doc FOREIGN KEY (tech_doc_revision_id)
|
||||
REFERENCES technical_document_revisions(revision_id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_tdsdr_shop_dwg FOREIGN KEY (shop_drawing_rev_id)
|
||||
REFERENCES shop_drawing_revisions(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- 4. Contract Drawing References (Many-to-Many)
|
||||
CREATE TABLE technical_document_contract_drawing_refs (
|
||||
tech_doc_revision_id INT NOT NULL,
|
||||
contract_drawing_id INT NOT NULL,
|
||||
reference_type ENUM('AS_PER', 'RELATED') DEFAULT 'AS_PER',
|
||||
sheet_numbers VARCHAR(255) NULL, -- "Sheet 1-5, 10" เก็บเป็น text
|
||||
|
||||
PRIMARY KEY (tech_doc_revision_id, contract_drawing_id),
|
||||
|
||||
CONSTRAINT fk_tdcdr_tech_doc FOREIGN KEY (tech_doc_revision_id)
|
||||
REFERENCES technical_document_revisions(revision_id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_tdcdr_contract_dwg FOREIGN KEY (contract_drawing_id)
|
||||
REFERENCES contract_drawings(condwg_id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- 5. ปรับปรุง RFA Workflow ให้ชัดเจนขึ้น
|
||||
CREATE TABLE rfa_workflow_instances (
|
||||
workflow_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
rfa_correspondence_id INT NOT NULL UNIQUE,
|
||||
template_id INT NULL, -- อ้างอิงถึงแม่แบบที่ใช้
|
||||
|
||||
current_step_sequence INT NOT NULL DEFAULT 1,
|
||||
overall_status ENUM('DRAFT', 'IN_PROGRESS', 'APPROVED', 'REJECTED', 'RETURNED', 'CANCELLED')
|
||||
NOT NULL DEFAULT 'DRAFT',
|
||||
|
||||
started_at DATETIME NULL,
|
||||
completed_at DATETIME NULL,
|
||||
|
||||
CONSTRAINT fk_rwi_corr FOREIGN KEY (rfa_correspondence_id)
|
||||
REFERENCES correspondences(corr_id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_rwi_template FOREIGN KEY (template_id)
|
||||
REFERENCES technicaldoc_workflow_templates(template_id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- 6. RFA Workflow Steps (แยกจาก technicaldoc_workflows เดิม)
|
||||
CREATE TABLE rfa_workflow_steps (
|
||||
step_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
workflow_id INT NOT NULL,
|
||||
sequence INT NOT NULL,
|
||||
org_id INT NOT NULL,
|
||||
step_purpose ENUM('FOR_APPROVAL', 'FOR_REVIEW', 'FOR_INFORMATION')
|
||||
NOT NULL DEFAULT 'FOR_APPROVAL',
|
||||
|
||||
status ENUM('PENDING', 'ACTIVE', 'APPROVED', 'REJECTED',
|
||||
'APPROVED_WITH_COMMENTS', 'SKIPPED', 'RETURNED')
|
||||
NOT NULL DEFAULT 'PENDING',
|
||||
|
||||
approve_code_id INT NULL, -- Link to approve codes
|
||||
comments TEXT NULL,
|
||||
|
||||
activated_at DATETIME NULL,
|
||||
processed_at DATETIME NULL,
|
||||
processed_by_user_id INT NULL,
|
||||
|
||||
deadline_date DATE NULL,
|
||||
|
||||
CONSTRAINT uq_workflow_sequence UNIQUE (workflow_id, sequence),
|
||||
|
||||
CONSTRAINT fk_rws_workflow FOREIGN KEY (workflow_id)
|
||||
REFERENCES rfa_workflow_instances(workflow_id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_rws_org FOREIGN KEY (org_id)
|
||||
REFERENCES organizations(org_id),
|
||||
CONSTRAINT fk_rws_approve_code FOREIGN KEY (approve_code_id)
|
||||
REFERENCES technicaldoc_approve_codes(approve_code_id),
|
||||
CONSTRAINT fk_rws_user FOREIGN KEY (processed_by_user_id)
|
||||
REFERENCES users(user_id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- 7. View: Current Technical Documents with Latest Revision
|
||||
CREATE OR REPLACE VIEW v_current_technical_documents AS
|
||||
SELECT
|
||||
tdm.master_id,
|
||||
tdm.document_number,
|
||||
tdm.document_type_id,
|
||||
dt.code AS document_type_code,
|
||||
dt.name AS document_type_name,
|
||||
tdm.project_id,
|
||||
tdm.title,
|
||||
tdm.rfa_correspondence_id,
|
||||
tdr.revision_id,
|
||||
tdr.revision_number,
|
||||
tdr.revision_label,
|
||||
tdr.status_code_id,
|
||||
sc.code AS status_code,
|
||||
sc.description AS status_description,
|
||||
tdr.approve_code_id,
|
||||
ac.code AS approve_code,
|
||||
ac.description AS approve_description,
|
||||
tdr.pdf_path,
|
||||
tdr.dwg_path,
|
||||
tdr.submitted_date,
|
||||
tdr.approved_date,
|
||||
tdm.created_at,
|
||||
tdr.created_at AS revision_created_at
|
||||
FROM technical_document_master tdm
|
||||
INNER JOIN technical_document_revisions tdr
|
||||
ON tdm.current_revision_id = tdr.revision_id
|
||||
INNER JOIN technicaldoc_types dt
|
||||
ON tdm.document_type_id = dt.document_types_id
|
||||
LEFT JOIN technicaldoc_status_codes sc
|
||||
ON tdr.status_code_id = sc.status_code_id
|
||||
LEFT JOIN technicaldoc_approve_codes ac
|
||||
ON tdr.approve_code_id = ac.approve_code_id
|
||||
WHERE tdm.deleted_at IS NULL;
|
||||
|
||||
|
||||
-- 8. View: RFA Workflow Status
|
||||
CREATE OR REPLACE VIEW v_rfa_workflow_status AS
|
||||
SELECT
|
||||
rwi.workflow_id,
|
||||
rwi.rfa_correspondence_id,
|
||||
c.correspondence_number AS rfa_number,
|
||||
rwi.overall_status,
|
||||
rwi.current_step_sequence,
|
||||
rws.step_id AS current_step_id,
|
||||
rws.org_id AS current_org_id,
|
||||
o.org_name AS current_org_name,
|
||||
rws.status AS current_step_status,
|
||||
rws.deadline_date,
|
||||
rwi.started_at,
|
||||
DATEDIFF(CURDATE(), rwi.started_at) AS days_in_progress,
|
||||
(SELECT COUNT(*) FROM rfa_workflow_steps WHERE workflow_id = rwi.workflow_id) AS total_steps,
|
||||
(SELECT COUNT(*) FROM rfa_workflow_steps WHERE workflow_id = rwi.workflow_id AND status IN ('APPROVED','APPROVED_WITH_COMMENTS')) AS completed_steps
|
||||
FROM rfa_workflow_instances rwi
|
||||
INNER JOIN correspondences c ON rwi.rfa_correspondence_id = c.corr_id
|
||||
LEFT JOIN rfa_workflow_steps rws
|
||||
ON rwi.workflow_id = rws.workflow_id
|
||||
AND rwi.current_step_sequence = rws.sequence
|
||||
LEFT JOIN organizations o ON rws.org_id = o.org_id
|
||||
WHERE rwi.overall_status NOT IN ('CANCELLED', 'APPROVED');
|
||||
215
docs/SQL/seed01.sql
Normal file
215
docs/SQL/seed01.sql
Normal file
@@ -0,0 +1,215 @@
|
||||
-- ==========================================================
|
||||
-- DMS v0.5.0
|
||||
-- Database v5.1 - Deploy Script Schema (Revised)
|
||||
-- Server: Container Station on QNAP TS-473A
|
||||
-- Database service: MariaDB 10.11
|
||||
-- Notes:
|
||||
-- - Removed 'rfas' table.
|
||||
-- - Added 'contracts' and 'contract_parties' tables.
|
||||
-- ==========================================================
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET time_zone = '+07:00';
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
-- Drop tables in reverse order of creation due to dependencies
|
||||
DROP TABLE IF EXISTS audit_logs;
|
||||
DROP TABLE IF EXISTS user_project_roles;
|
||||
DROP TABLE IF EXISTS user_roles;
|
||||
DROP TABLE IF EXISTS role_permissions;
|
||||
DROP TABLE IF EXISTS permissions;
|
||||
DROP TABLE IF EXISTS roles;
|
||||
DROP TABLE IF EXISTS users;
|
||||
DROP TABLE IF EXISTS project_parties;
|
||||
DROP TABLE IF EXISTS contract_parties; -- New
|
||||
DROP TABLE IF EXISTS contracts; -- New
|
||||
DROP TABLE IF EXISTS projects;
|
||||
DROP TABLE IF EXISTS organizations;
|
||||
DROP TABLE IF EXISTS correspondence_references;
|
||||
DROP TABLE IF EXISTS correspondence_cc_recipients;
|
||||
DROP TABLE IF EXISTS correspondences;
|
||||
DROP TABLE IF EXISTS email_details;
|
||||
DROP TABLE IF EXISTS instruction_details;
|
||||
DROP TABLE IF EXISTS letter_details;
|
||||
DROP TABLE IF EXISTS memorandum_details;
|
||||
DROP TABLE IF EXISTS minutes_of_meeting_details;
|
||||
DROP TABLE IF EXISTS rfi_details;
|
||||
DROP TABLE IF EXISTS rfa_items;
|
||||
DROP TABLE IF EXISTS transmittal_items;
|
||||
DROP TABLE IF EXISTS transmittals;
|
||||
DROP TABLE IF EXISTS technicaldocs;
|
||||
DROP TABLE IF EXISTS shop_drawing_revisions;
|
||||
DROP TABLE IF EXISTS shop_drawings;
|
||||
DROP TABLE IF EXISTS shop_drawing_sub_categories;
|
||||
DROP TABLE IF EXISTS shop_drawing_main_categories;
|
||||
DROP TABLE IF EXISTS contract_dwg_subcat_cat_map;
|
||||
DROP TABLE IF EXISTS contract_dwg_sub_cat;
|
||||
DROP TABLE IF EXISTS contract_dwg_cat;
|
||||
DROP TABLE IF EXISTS contract_drawings;
|
||||
DROP TABLE IF EXISTS cir_action_documents;
|
||||
DROP TABLE IF EXISTS cir_actions;
|
||||
DROP TABLE IF EXISTS cir_recipients;
|
||||
DROP TABLE IF EXISTS circulations;
|
||||
DROP TABLE IF EXISTS cir_status_codes;
|
||||
DROP TABLE IF EXISTS correspondence_status_transitions;
|
||||
DROP TABLE IF EXISTS correspondence_statuses;
|
||||
DROP TABLE IF EXISTS correspondence_types;
|
||||
DROP TABLE IF EXISTS correspondence_tags;
|
||||
DROP TABLE IF EXISTS tags;
|
||||
DROP TABLE IF EXISTS global_default_roles;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
|
||||
-- ==========================================================
|
||||
-- Table Creation
|
||||
-- ==========================================================
|
||||
|
||||
-- Organizations Table
|
||||
CREATE TABLE organizations (
|
||||
org_id INT NOT NULL AUTO_INCREMENT,
|
||||
org_code VARCHAR(20) NOT NULL,
|
||||
org_name VARCHAR(255) NOT NULL,
|
||||
primary_role ENUM('OWNER','DESIGNER','CONSULTANT','CONTRACTOR') NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (org_id),
|
||||
UNIQUE KEY ux_organizations_code (org_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- Projects Table
|
||||
CREATE TABLE projects (
|
||||
project_id INT NOT NULL AUTO_INCREMENT,
|
||||
project_code VARCHAR(20) NOT NULL,
|
||||
project_name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (project_id),
|
||||
UNIQUE KEY ux_projects_code (project_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- NEW: Contracts Table
|
||||
-- Stores information about each contract.
|
||||
CREATE TABLE contracts (
|
||||
contract_id INT NOT NULL AUTO_INCREMENT,
|
||||
contract_code VARCHAR(50) NOT NULL,
|
||||
contract_name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
start_date DATE,
|
||||
end_date DATE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (contract_id),
|
||||
UNIQUE KEY ux_contracts_code (contract_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- NEW: Contract Parties Table
|
||||
-- Links contracts, projects, and organizations together.
|
||||
CREATE TABLE contract_parties (
|
||||
contract_id INT NOT NULL,
|
||||
project_id INT NOT NULL,
|
||||
org_id INT NOT NULL,
|
||||
PRIMARY KEY (contract_id, project_id, org_id),
|
||||
CONSTRAINT fk_cp_contract FOREIGN KEY (contract_id) REFERENCES contracts(contract_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_cp_project FOREIGN KEY (project_id) REFERENCES projects(project_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_cp_org FOREIGN KEY (org_id) REFERENCES organizations(org_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
|
||||
-- Users Table (RBAC)
|
||||
CREATE TABLE users (
|
||||
user_id INT NOT NULL AUTO_INCREMENT,
|
||||
username VARCHAR(50) NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(100) NOT NULL,
|
||||
first_name VARCHAR(50),
|
||||
last_name VARCHAR(50),
|
||||
org_id INT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
last_login TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (user_id),
|
||||
UNIQUE KEY ux_users_username (username),
|
||||
UNIQUE KEY ux_users_email (email),
|
||||
CONSTRAINT fk_users_org FOREIGN KEY (org_id) REFERENCES organizations(org_id) ON DELETE SET NULL ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- Roles Table (RBAC)
|
||||
CREATE TABLE roles (
|
||||
role_id INT NOT NULL AUTO_INCREMENT,
|
||||
role_code VARCHAR(50) NOT NULL,
|
||||
role_name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
is_system BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY (role_id),
|
||||
UNIQUE KEY ux_roles_code (role_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- Permissions Table (RBAC)
|
||||
CREATE TABLE permissions (
|
||||
permission_id INT NOT NULL AUTO_INCREMENT,
|
||||
permission_code VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
PRIMARY KEY (permission_id),
|
||||
UNIQUE KEY ux_permissions_code (permission_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- Role Permissions Junction Table (RBAC)
|
||||
CREATE TABLE role_permissions (
|
||||
role_id INT NOT NULL,
|
||||
permission_id INT NOT NULL,
|
||||
PRIMARY KEY (role_id, permission_id),
|
||||
CONSTRAINT fk_rp_role FOREIGN KEY (role_id) REFERENCES roles(role_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_rp_permission FOREIGN KEY (permission_id) REFERENCES permissions(permission_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- User Roles Junction Table (RBAC) - For global/system-level roles
|
||||
CREATE TABLE user_roles (
|
||||
user_id INT NOT NULL,
|
||||
role_id INT NOT NULL,
|
||||
PRIMARY KEY (user_id, role_id),
|
||||
CONSTRAINT fk_ur_user FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_ur_role FOREIGN KEY (role_id) REFERENCES roles(role_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- User Project Roles Junction Table (RBAC) - For project-specific roles
|
||||
CREATE TABLE user_project_roles (
|
||||
user_id INT NOT NULL,
|
||||
project_id INT NOT NULL,
|
||||
role_id INT NOT NULL,
|
||||
PRIMARY KEY (user_id, project_id, role_id),
|
||||
CONSTRAINT fk_upr_user FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_upr_project FOREIGN KEY (project_id) REFERENCES projects(project_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_upr_role FOREIGN KEY (role_id) REFERENCES roles(role_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- Project Parties Table
|
||||
CREATE TABLE project_parties (
|
||||
project_id INT NOT NULL,
|
||||
org_id INT NOT NULL,
|
||||
role ENUM('OWNER','DESIGNER','CONSULTANT','CONTRACTOR') NOT NULL,
|
||||
is_contractor TINYINT(1) GENERATED ALWAYS AS (IF(role = 'CONTRACTOR', 1, NULL)) STORED,
|
||||
PRIMARY KEY (project_id, org_id),
|
||||
UNIQUE KEY uq_project_parties_contractor (project_id, is_contractor),
|
||||
CONSTRAINT fk_pp_project FOREIGN KEY (project_id) REFERENCES projects(project_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_pp_org FOREIGN KEY (org_id) REFERENCES organizations(org_id) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
|
||||
-- ... (The rest of your original script for correspondences, technical docs, etc. remains here) ...
|
||||
|
||||
-- Global default roles (template defaults)
|
||||
CREATE TABLE global_default_roles (
|
||||
id TINYINT NOT NULL DEFAULT 1,
|
||||
role ENUM('OWNER','DESIGNER','CONSULTANT') NOT NULL,
|
||||
position TINYINT NOT NULL,
|
||||
org_id INT NOT NULL,
|
||||
PRIMARY KEY (id, role, position),
|
||||
UNIQUE KEY ux_gdr_unique_org_per_role (id, role, org_id),
|
||||
CONSTRAINT fk_gdr_org FOREIGN KEY (org_id) REFERENCES organizations(org_id) ON UPDATE CASCADE ON DELETE RESTRICT
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- ... (The rest of your original script continues from here) ...
|
||||
316
docs/SQL/seed02.sql
Normal file
316
docs/SQL/seed02.sql
Normal file
@@ -0,0 +1,316 @@
|
||||
-- ==========================================================
|
||||
-- DMS v0.5.0
|
||||
-- Database v5.1 - Deploy Script Schema (Complete & Revised)
|
||||
-- Server: Container Station on QNAP TS-473A
|
||||
-- Database service: MariaDB 10.11
|
||||
-- Notes:
|
||||
-- - This is a consolidated and updated version.
|
||||
-- - Removed 'rfas' table.
|
||||
-- - Added tables for Contracts, detailed Circulations,
|
||||
-- Technical Document Workflow, and Correspondence Revisions.
|
||||
-- ==========================================================
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET time_zone = '+07:00';
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
-- Drop tables in reverse order of creation due to dependencies
|
||||
DROP TABLE IF EXISTS audit_logs;
|
||||
DROP TABLE IF EXISTS user_project_roles;
|
||||
DROP TABLE IF EXISTS user_roles;
|
||||
DROP TABLE IF EXISTS role_permissions;
|
||||
DROP TABLE IF EXISTS permissions;
|
||||
DROP TABLE IF EXISTS roles;
|
||||
DROP TABLE IF EXISTS users;
|
||||
DROP TABLE IF EXISTS project_parties;
|
||||
DROP TABLE IF EXISTS contract_parties;
|
||||
DROP TABLE IF EXISTS contracts;
|
||||
DROP TABLE IF EXISTS projects;
|
||||
DROP TABLE IF EXISTS organizations;
|
||||
DROP TABLE IF EXISTS correspondence_references;
|
||||
DROP TABLE IF EXISTS correspondence_revisions;
|
||||
DROP TABLE IF EXISTS correspondence_cc_recipients;
|
||||
DROP TABLE IF EXISTS technical_doc_workflows;
|
||||
DROP TABLE IF EXISTS correspondences;
|
||||
DROP TABLE IF EXISTS email_details;
|
||||
DROP TABLE IF EXISTS instruction_details;
|
||||
DROP TABLE IF EXISTS letter_details;
|
||||
DROP TABLE IF EXISTS memorandum_details;
|
||||
DROP TABLE IF EXISTS minutes_of_meeting_details;
|
||||
DROP TABLE IF EXISTS rfi_details;
|
||||
DROP TABLE IF EXISTS rfa_items;
|
||||
DROP TABLE IF EXISTS transmittal_items;
|
||||
DROP TABLE IF EXISTS transmittals;
|
||||
DROP TABLE IF EXISTS technicaldocs;
|
||||
DROP TABLE IF EXISTS shop_drawing_revisions;
|
||||
DROP TABLE IF EXISTS shop_drawings;
|
||||
DROP TABLE IF EXISTS shop_drawing_sub_categories;
|
||||
DROP TABLE IF EXISTS shop_drawing_main_categories;
|
||||
DROP TABLE IF EXISTS contract_dwg_subcat_cat_map;
|
||||
DROP TABLE IF EXISTS contract_dwg_sub_cat;
|
||||
DROP TABLE IF EXISTS contract_dwg_cat;
|
||||
DROP TABLE IF EXISTS contract_drawings;
|
||||
DROP TABLE IF EXISTS circulation_assignees;
|
||||
DROP TABLE IF EXISTS circulations;
|
||||
DROP TABLE IF EXISTS cir_action_documents;
|
||||
DROP TABLE IF EXISTS cir_actions;
|
||||
DROP TABLE IF EXISTS cir_recipients;
|
||||
DROP TABLE IF EXISTS cir_status_codes;
|
||||
DROP TABLE IF EXISTS correspondence_status_transitions;
|
||||
DROP TABLE IF EXISTS correspondence_statuses;
|
||||
DROP TABLE IF EXISTS correspondence_types;
|
||||
DROP TABLE IF EXISTS correspondence_tags;
|
||||
DROP TABLE IF EXISTS tags;
|
||||
DROP TABLE IF EXISTS global_default_roles;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
|
||||
-- ==========================================================
|
||||
-- Table Creation
|
||||
-- ==========================================================
|
||||
|
||||
CREATE TABLE organizations (
|
||||
org_id INT NOT NULL AUTO_INCREMENT,
|
||||
org_code VARCHAR(20) NOT NULL,
|
||||
org_name VARCHAR(255) NOT NULL,
|
||||
primary_role ENUM('OWNER','DESIGNER','CONSULTANT','CONTRACTOR') NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (org_id),
|
||||
UNIQUE KEY ux_organizations_code (org_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE projects (
|
||||
project_id INT NOT NULL AUTO_INCREMENT,
|
||||
project_code VARCHAR(20) NOT NULL,
|
||||
project_name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (project_id),
|
||||
UNIQUE KEY ux_projects_code (project_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE contracts (
|
||||
contract_id INT NOT NULL AUTO_INCREMENT,
|
||||
contract_code VARCHAR(50) NOT NULL,
|
||||
contract_name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
start_date DATE,
|
||||
end_date DATE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (contract_id),
|
||||
UNIQUE KEY ux_contracts_code (contract_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE contract_parties (
|
||||
contract_id INT NOT NULL,
|
||||
project_id INT NOT NULL,
|
||||
org_id INT NOT NULL,
|
||||
PRIMARY KEY (contract_id, project_id, org_id),
|
||||
CONSTRAINT fk_cp_contract FOREIGN KEY (contract_id) REFERENCES contracts(contract_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_cp_project FOREIGN KEY (project_id) REFERENCES projects(project_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_cp_org FOREIGN KEY (org_id) REFERENCES organizations(org_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE users (
|
||||
user_id INT NOT NULL AUTO_INCREMENT,
|
||||
username VARCHAR(50) NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(100) NOT NULL,
|
||||
first_name VARCHAR(50),
|
||||
last_name VARCHAR(50),
|
||||
org_id INT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
last_login TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (user_id),
|
||||
UNIQUE KEY ux_users_username (username),
|
||||
UNIQUE KEY ux_users_email (email),
|
||||
CONSTRAINT fk_users_org FOREIGN KEY (org_id) REFERENCES organizations(org_id) ON DELETE SET NULL ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE roles (
|
||||
role_id INT NOT NULL AUTO_INCREMENT,
|
||||
role_code VARCHAR(50) NOT NULL,
|
||||
role_name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
is_system BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY (role_id),
|
||||
UNIQUE KEY ux_roles_code (role_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE permissions (
|
||||
permission_id INT NOT NULL AUTO_INCREMENT,
|
||||
permission_code VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
PRIMARY KEY (permission_id),
|
||||
UNIQUE KEY ux_permissions_code (permission_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE role_permissions (
|
||||
role_id INT NOT NULL,
|
||||
permission_id INT NOT NULL,
|
||||
PRIMARY KEY (role_id, permission_id),
|
||||
CONSTRAINT fk_rp_role FOREIGN KEY (role_id) REFERENCES roles(role_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_rp_permission FOREIGN KEY (permission_id) REFERENCES permissions(permission_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE user_roles (
|
||||
user_id INT NOT NULL,
|
||||
role_id INT NOT NULL,
|
||||
PRIMARY KEY (user_id, role_id),
|
||||
CONSTRAINT fk_ur_user FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_ur_role FOREIGN KEY (role_id) REFERENCES roles(role_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE user_project_roles (
|
||||
user_id INT NOT NULL,
|
||||
project_id INT NOT NULL,
|
||||
role_id INT NOT NULL,
|
||||
PRIMARY KEY (user_id, project_id, role_id),
|
||||
CONSTRAINT fk_upr_user FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_upr_project FOREIGN KEY (project_id) REFERENCES projects(project_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_upr_role FOREIGN KEY (role_id) REFERENCES roles(role_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE project_parties (
|
||||
project_id INT NOT NULL,
|
||||
org_id INT NOT NULL,
|
||||
role ENUM('OWNER','DESIGNER','CONSULTANT','CONTRACTOR') NOT NULL,
|
||||
is_contractor TINYINT(1) GENERATED ALWAYS AS (IF(role = 'CONTRACTOR', 1, NULL)) STORED,
|
||||
PRIMARY KEY (project_id, org_id),
|
||||
UNIQUE KEY uq_project_parties_contractor (project_id, is_contractor),
|
||||
CONSTRAINT fk_pp_project FOREIGN KEY (project_id) REFERENCES projects(project_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_pp_org FOREIGN KEY (org_id) REFERENCES organizations(org_id) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- Correspondence & Workflow Tables
|
||||
|
||||
CREATE TABLE correspondence_types (
|
||||
type_id INT NOT NULL AUTO_INCREMENT,
|
||||
type_code VARCHAR(20) NOT NULL,
|
||||
type_name VARCHAR(100) NOT NULL,
|
||||
PRIMARY KEY (type_id),
|
||||
UNIQUE KEY ux_ct_code (type_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE correspondence_statuses (
|
||||
status_id INT NOT NULL AUTO_INCREMENT,
|
||||
status_code VARCHAR(20) NOT NULL,
|
||||
status_name VARCHAR(100) NOT NULL,
|
||||
PRIMARY KEY (status_id),
|
||||
UNIQUE KEY ux_cs_code (status_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE correspondences (
|
||||
id INT NOT NULL AUTO_INCREMENT,
|
||||
project_id INT NOT NULL,
|
||||
document_number VARCHAR(100) NOT NULL,
|
||||
title VARCHAR(500) NOT NULL,
|
||||
issue_date DATE NOT NULL,
|
||||
status_id INT NOT NULL,
|
||||
type_id INT NOT NULL,
|
||||
originator_org_id INT NOT NULL,
|
||||
created_by_user_id INT NOT NULL,
|
||||
root_id INT NULL, -- for revisions
|
||||
version INT NOT NULL DEFAULT 1,
|
||||
submitted_at TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY ux_corr_doc_num (document_number),
|
||||
CONSTRAINT fk_corr_project FOREIGN KEY (project_id) REFERENCES projects(project_id),
|
||||
CONSTRAINT fk_corr_status FOREIGN KEY (status_id) REFERENCES correspondence_statuses(status_id),
|
||||
CONSTRAINT fk_corr_type FOREIGN KEY (type_id) REFERENCES correspondence_types(type_id),
|
||||
CONSTRAINT fk_corr_org FOREIGN KEY (originator_org_id) REFERENCES organizations(org_id),
|
||||
CONSTRAINT fk_corr_user FOREIGN KEY (created_by_user_id) REFERENCES users(user_id),
|
||||
CONSTRAINT fk_corr_root FOREIGN KEY (root_id) REFERENCES correspondences(id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE correspondence_revisions (
|
||||
revision_id INT NOT NULL AUTO_INCREMENT,
|
||||
correspondence_id INT NOT NULL,
|
||||
version_number INT NOT NULL,
|
||||
change_reason TEXT NOT NULL,
|
||||
changed_by_user_id INT NOT NULL,
|
||||
changed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
document_data_json JSON NOT NULL,
|
||||
PRIMARY KEY (revision_id),
|
||||
CONSTRAINT fk_cr_correspondence FOREIGN KEY (correspondence_id) REFERENCES correspondences(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_cr_user FOREIGN KEY (changed_by_user_id) REFERENCES users(user_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE cir_status_codes (
|
||||
code VARCHAR(20) NOT NULL,
|
||||
description VARCHAR(255),
|
||||
sort_order INT NOT NULL,
|
||||
PRIMARY KEY (code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE circulations (
|
||||
cir_id INT NOT NULL AUTO_INCREMENT,
|
||||
correspondence_id INT NOT NULL,
|
||||
org_id INT NOT NULL,
|
||||
cir_subject VARCHAR(500) NOT NULL,
|
||||
cir_status_code VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
|
||||
created_by_user_id INT NOT NULL,
|
||||
submitted_at TIMESTAMP NULL,
|
||||
closed_at TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (cir_id),
|
||||
CONSTRAINT fk_cir_correspondence FOREIGN KEY (correspondence_id) REFERENCES correspondences(id),
|
||||
CONSTRAINT fk_cir_org FOREIGN KEY (org_id) REFERENCES organizations(org_id),
|
||||
CONSTRAINT fk_cir_status FOREIGN KEY (cir_status_code) REFERENCES cir_status_codes(code),
|
||||
CONSTRAINT fk_cir_user FOREIGN KEY (created_by_user_id) REFERENCES users(user_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE circulation_assignees (
|
||||
assignee_id INT NOT NULL AUTO_INCREMENT,
|
||||
cir_id INT NOT NULL,
|
||||
user_id INT NOT NULL,
|
||||
assignee_type ENUM('MAIN', 'ACTION', 'INFO') NOT NULL,
|
||||
deadline DATE NULL,
|
||||
action_taken TEXT NULL,
|
||||
is_completed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
completed_at TIMESTAMP NULL,
|
||||
PRIMARY KEY (assignee_id),
|
||||
UNIQUE KEY ux_cir_user_type (cir_id, user_id, assignee_type),
|
||||
CONSTRAINT fk_ca_cir FOREIGN KEY (cir_id) REFERENCES circulations(cir_id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_ca_user FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE technical_doc_workflows (
|
||||
workflow_id INT NOT NULL AUTO_INCREMENT,
|
||||
correspondence_id INT NOT NULL,
|
||||
sequence INT NOT NULL,
|
||||
org_id INT NOT NULL,
|
||||
status ENUM('PENDING', 'APPROVED', 'REJECTED', 'APPROVED_WITH_COMMENTS', 'FORWARDED', 'RETURNED') NOT NULL DEFAULT 'PENDING',
|
||||
comments TEXT,
|
||||
processed_by_user_id INT NULL,
|
||||
processed_at TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (workflow_id),
|
||||
UNIQUE KEY ux_workflow_corr_sequence (correspondence_id, sequence),
|
||||
CONSTRAINT fk_tdw_correspondence FOREIGN KEY (correspondence_id) REFERENCES correspondences(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_tdw_org FOREIGN KEY (org_id) REFERENCES organizations(org_id),
|
||||
CONSTRAINT fk_tdw_user FOREIGN KEY (processed_by_user_id) REFERENCES users(user_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE correspondence_status_transitions(
|
||||
type_id INT NOT NULL,
|
||||
from_status_id INT NOT NULL,
|
||||
to_status_id INT NOT NULL,
|
||||
PRIMARY KEY (type_id, from_status_id, to_status_id),
|
||||
CONSTRAINT fk_cst_type FOREIGN KEY (type_id) REFERENCES correspondence_types(type_id),
|
||||
CONSTRAINT fk_cst_from FOREIGN KEY (from_status_id) REFERENCES correspondence_statuses(status_id),
|
||||
CONSTRAINT fk_cst_to FOREIGN KEY (to_status_id) REFERENCES correspondence_statuses(status_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- (The rest of your original tables for technical docs, drawings, etc. would follow here)
|
||||
-- For brevity, I've included the core structure. You can append the remaining tables from your original file.
|
||||
143
docs/SQL/temp.sql
Normal file
143
docs/SQL/temp.sql
Normal file
@@ -0,0 +1,143 @@
|
||||
SET NAMES utf8mb4;
|
||||
SET time_zone = '+07:00';
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
-- ==========================================================
|
||||
-- 1. ลบ Stored Procedure เก่า (ย้าย Logic ไป NestJS)
|
||||
-- ==========================================================
|
||||
-- ตรรกะนี้ (การสร้าง Revision) จะถูกย้ายไปจัดการใน
|
||||
-- CorrespondenceService และ RfaService ของ NestJS
|
||||
DROP PROCEDURE IF EXISTS sp_create_correspondence_revision;
|
||||
|
||||
|
||||
-- ==========================================================
|
||||
-- 2. สร้าง Stored Procedure ใหม่ (สำหรับ Document Numbering)
|
||||
-- ==========================================================
|
||||
-- ใช้ Procedure นี้เพื่อจัดการ Race Condition
|
||||
-- ในการดึงเลขที่เอกสารล่าสุด
|
||||
-- ----------------------------------------------------------
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE sp_get_next_document_number(
|
||||
IN p_project_id INT,
|
||||
IN p_organization_id INT,
|
||||
IN p_type_id INT,
|
||||
IN p_year INT,
|
||||
OUT p_next_number INT
|
||||
)
|
||||
BEGIN
|
||||
DECLARE v_last_number INT;
|
||||
|
||||
-- 1. พยายามดึงแถวปัจจุบันและ "ล็อก" (FOR UPDATE)
|
||||
-- เพื่อป้องกันไม่ให้ Transaction อื่นอ่านค่านี้จนกว่าเราจะเสร็จ
|
||||
SELECT last_number
|
||||
INTO v_last_number
|
||||
FROM document_number_counters
|
||||
WHERE
|
||||
project_id = p_project_id AND
|
||||
originator_organization_id = p_organization_id AND
|
||||
correspondence_type_id = p_type_id AND
|
||||
current_year = p_year
|
||||
FOR UPDATE;
|
||||
|
||||
-- 2. ตรวจสอบว่าพบบแถวหรือไม่
|
||||
IF v_last_number IS NULL THEN
|
||||
-- 2a. ไม่พบ (นี่คือเลขที่ "1" ของ Key นี้)
|
||||
INSERT INTO document_number_counters
|
||||
(project_id, originator_organization_id, correspondence_type_id, current_year, last_number)
|
||||
VALUES
|
||||
(p_project_id, p_organization_id, p_type_id, p_year, 1);
|
||||
|
||||
SET p_next_number = 1;
|
||||
ELSE
|
||||
-- 2b. พบ (บวกเลขที่เดิม)
|
||||
SET p_next_number = v_last_number + 1;
|
||||
|
||||
UPDATE document_number_counters
|
||||
SET last_number = p_next_number
|
||||
WHERE
|
||||
project_id = p_project_id AND
|
||||
originator_organization_id = p_organization_id AND
|
||||
correspondence_type_id = p_type_id AND
|
||||
current_year = p_year;
|
||||
END IF;
|
||||
|
||||
-- (Transaction จะ Commit อัตโนมัติเมื่อ Procedure จบ)
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
|
||||
-- ==========================================================
|
||||
-- 3. สร้าง Views (สำหรับช่วย Backend/Frontend)
|
||||
-- ==========================================================
|
||||
|
||||
-- ----------------------------------------------------------
|
||||
-- View 1: v_user_tasks (สำหรับ Dashboard "งานของฉัน" Req 5.3)
|
||||
-- ----------------------------------------------------------
|
||||
CREATE OR REPLACE VIEW v_user_tasks AS
|
||||
SELECT
|
||||
ca.user_id,
|
||||
c.id AS circulation_id,
|
||||
c.organization_id,
|
||||
c.circulation_no,
|
||||
c.circulation_subject,
|
||||
ca.assignee_type,
|
||||
ca.deadline,
|
||||
c.created_at,
|
||||
c.correspondence_id
|
||||
FROM circulations c
|
||||
JOIN circulation_assignees ca ON c.id = ca.circulation_id
|
||||
WHERE
|
||||
ca.is_completed = FALSE
|
||||
AND ca.assignee_type IN ('MAIN', 'ACTION');
|
||||
|
||||
|
||||
-- ----------------------------------------------------------
|
||||
-- View 2: v_audit_log_details (สำหรับ Activity Feed Req 6.1)
|
||||
-- ----------------------------------------------------------
|
||||
CREATE OR REPLACE VIEW v_audit_log_details AS
|
||||
SELECT
|
||||
al.audit_id,
|
||||
al.user_id,
|
||||
al.action,
|
||||
al.entity_type,
|
||||
al.entity_id,
|
||||
al.details_json,
|
||||
al.ip_address,
|
||||
al.created_at,
|
||||
u.username,
|
||||
u.first_name,
|
||||
u.last_name,
|
||||
u.email
|
||||
FROM audit_logs al
|
||||
LEFT JOIN users u ON al.user_id = u.user_id;
|
||||
|
||||
|
||||
-- ----------------------------------------------------------
|
||||
-- View 3: v_user_all_permissions (สำหรับ RBAC 2 ระดับ Req 4.2)
|
||||
-- ----------------------------------------------------------
|
||||
-- View นี้จะรวมสิทธิ์ 2 ระดับ (Global และ Project)
|
||||
-- (หมายเหตุ: ไม่รวม Contract-level เนื่องจากยังไม่มีตาราง)
|
||||
-- ----------------------------------------------------------
|
||||
CREATE OR REPLACE VIEW v_user_all_permissions AS
|
||||
-- 1. สิทธิ์ระดับ Global (project_id IS NULL)
|
||||
SELECT
|
||||
ur.user_id,
|
||||
NULL AS project_id,
|
||||
p.permission_code
|
||||
FROM user_roles ur
|
||||
JOIN role_permissions rp ON ur.role_id = rp.role_id
|
||||
JOIN permissions p ON rp.permission_id = p.permission_id
|
||||
|
||||
UNION
|
||||
|
||||
-- 2. สิทธิ์ระดับ Project
|
||||
SELECT
|
||||
upr.user_id,
|
||||
upr.project_id,
|
||||
p.permission_code
|
||||
FROM user_project_roles upr
|
||||
JOIN role_permissions rp ON upr.role_id = rp.role_id
|
||||
JOIN permissions p ON rp.permission_id = p.permission_id;
|
||||
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
47
docs/SQL/triggers.sql
Normal file
47
docs/SQL/triggers.sql
Normal file
@@ -0,0 +1,47 @@
|
||||
-- trigger
|
||||
DROP TRIGGER IF EXISTS trg_rfa_revisions_is_current;
|
||||
DROP TRIGGER IF EXISTS trg_rfa_revisions_is_current_upd;
|
||||
DROP TRIGGER IF EXISTS trg_rfa_revisions_auto_reset;
|
||||
-- ============================================================
|
||||
-- ⚙️ TRIGGERS
|
||||
-- ============================================================
|
||||
-- ป้องกันไม่ให้มี revision ที่ is_current=TRUE ซ้ำใน rfa_id เดียวกัน
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_rfa_revisions_is_current
|
||||
BEFORE INSERT ON rfa_revisions
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.is_current = TRUE THEN
|
||||
IF (SELECT COUNT(*) FROM rfa_revisions WHERE rfa_id = NEW.rfa_id AND is_current = TRUE) > 0 THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'Cannot insert more than one current revision per RFA.';
|
||||
END IF;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_rfa_revisions_is_current_upd
|
||||
BEFORE UPDATE ON rfa_revisions
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.is_current = TRUE AND (OLD.is_current IS NULL OR OLD.is_current = FALSE) THEN
|
||||
IF (SELECT COUNT(*) FROM rfa_revisions WHERE rfa_id = NEW.rfa_id AND is_current = TRUE AND correspondences_id <> OLD.correspondences_id) > 0 THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'Cannot set more than one current revision per RFA.';
|
||||
END IF;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
-- ทำให้เวลาสร้าง revision ใหม่ที่ is_current=TRUE ระบบจะ set revision เดิมเป็น FALSE อัตโนมัติ
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_rfa_revisions_auto_reset
|
||||
BEFORE INSERT ON rfa_revisions
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.is_current = TRUE THEN
|
||||
UPDATE rfa_revisions
|
||||
SET is_current = FALSE
|
||||
WHERE rfa_id = NEW.rfa_id;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
Reference in New Issue
Block a user