-- ==========================================================
-- DMS v0.5.0
-- Database v5.1 - Views
-- Server: Container Station on QNAPQNAP TS-473A
-- Database service: MariaDB 10.11
-- database ui: phpmyadmin 5-apache
-- backend sevice: node.js
-- frontend sevice: next.js
-- reverse proxy: nginx 1.27-alpine
-- cron service: n8n
-- scripts: alpine:3.20
-- Notes: 1) VIEW รายงานสำคัญ (correspondences/technicaldocs/latest, RFA + items, Contract drawings)
--        2) ตัวอย่างการใช้งาน (sample calls)
-- ==========================================================

SET NAMES utf8mb4;
SET time_zone = '+07:00';
SET FOREIGN_KEY_CHECKS=0;

/* ===========================================================
    VIEWS
   ===========================================================*/

-- ---------------------------
-- 1.1 Correspondence — ล่าสุดของแต่ละ family (root)
-- ---------------------------
DROP VIEW IF EXISTS v_correspondence_latest_per_root;
CREATE VIEW v_correspondence_latest_per_root AS
SELECT c.*
FROM correspondences c
JOIN (
  SELECT root_id, MAX(corr_id) AS max_corr_id
  FROM correspondences
  GROUP BY root_id
) x ON x.root_id = c.root_id AND x.max_corr_id = c.corr_id;

-- รวมชื่อชนิด / สถานะ / องค์กร
DROP VIEW IF EXISTS v_correspondence_latest_readable;
CREATE VIEW v_correspondence_latest_readable AS
SELECT
  v.corr_id, v.root_id, v.project_id,
  v.correspondence_number, v.revision,
  v.correspondence_type_id, t.type_code, t.type_name,
  v.correspondence_status_id, s.status_code, s.status_name,
  v.title, v.keywords, v.issued_date, v.created_at,
  v.originator_id, o1.org_code AS originator_code, o1.org_name AS originator_name,
  v.recipient_id,  o2.org_code AS recipient_code,  o2.org_name AS recipient_name,
  v.pdf_path
FROM v_correspondence_latest_per_root v
LEFT JOIN correspondence_types t ON t.type_id = v.correspondence_type_id
LEFT JOIN correspondence_status s ON s.status_id = v.correspondence_status_id
LEFT JOIN organizations o1 ON o1.org_id = v.originator_id
LEFT JOIN organizations o2 ON o2.org_id = v.recipient_id;

-- ---------------------------
-- 2.2 TechnicalDocs — ล่าสุดของแต่ละ original
-- ---------------------------
DROP VIEW IF EXISTS v_technicaldocs_latest_per_original;
CREATE VIEW v_technicaldocs_latest_per_original AS
SELECT t.*
FROM technicaldocs t
JOIN (
  SELECT original_id, MAX(id) AS max_id
  FROM technicaldocs
  GROUP BY original_id
) x ON x.original_id = t.original_id AND x.max_id = t.id;

DROP VIEW IF EXISTS v_technicaldocs_latest_readable;
CREATE VIEW v_technicaldocs_latest_readable AS
SELECT
  v.id, v.original_id, v.project_id, v.revision, v.title, v.pdf_path,
  v.status_code_id, ds.code  AS status_code, ds.description AS status_desc,
  v.approve_code_id, ac.code AS approve_code,
  v.document_type_id, dt.code AS doc_type_code, dt.name AS doc_type_name,
  v.created_at, v.created_by, v.updated_by
FROM v_technicaldocs_latest_per_original v
LEFT JOIN document_status_codes ds ON ds.status_code_id = v.status_code_id
LEFT JOIN approve_codes ac ON ac.approve_code_id = v.approve_code_id
LEFT JOIN document_types dt ON dt.document_types_id = v.document_type_id;

-- ---------------------------
-- 2.3 RFA + Items (อ่านง่าย)
-- ---------------------------
DROP VIEW IF EXISTS v_rfa_with_items;
CREATE VIEW v_rfa_with_items AS
SELECT
  r.rfa_corr_id AS rfa_corr_id,
  c.project_id,
  c.correspondence_number AS rfa_no,
  c.revision AS rfa_rev,
  c.title AS rfa_title,
  c.correspondence_status_id, cs.status_code AS rfa_status_code, cs.status_name AS rfa_status_name,
  td.id AS techdoc_id, td.original_id, td.revision AS techdoc_rev, td.title AS techdoc_title,
  dt.code AS doc_type_code, dt.name AS doc_type_name,
  ds.code AS doc_status_code, ds.description AS doc_status_desc
FROM rfa_items r
JOIN correspondences c ON c.corr_id = r.rfa_corr_id
LEFT JOIN correspondence_status cs ON cs.status_id = c.correspondence_status_id
JOIN technicaldocs td ON td.id = r.technical_doc_id
LEFT JOIN document_types dt ON dt.document_types_id = td.document_type_id
LEFT JOIN document_status_codes ds ON ds.status_code_id = td.status_code_id;

/* ===========================================================
   VIEW BUNDLE: CONTRACT-DWG
   ใช้กับสคีมา normalized ที่ทำไว้
   -----------------------------------------------------------
   - vw_contract_dwg_overview   → Drawing + Volume + SubCat + Categories (group concat)
   - vw_contract_dwg_full       → Drawing + Project + Volume + SubCat + Cat (row per cat)
   - vw_contract_dwg_categories → Project + SubCat + Cat (mapping detail)
   - vw_contract_dwg_volumes    → Project + Volume (basic list)
   =========================================================== */

/* -----------------------------------------------------------
   1) vw_contract_dwg_overview
   - ใช้สำหรับ dashboard / report สรุป
   - แสดง drawing แถวละ 1 โดยรวม categories ด้วย GROUP_CONCAT
   ----------------------------------------------------------- */
DROP VIEW IF EXISTS vw_contract_dwg_overview;
CREATE VIEW vw_contract_dwg_overview AS
SELECT
  d.condwg_id,
  d.project_id,
  p.project_code,
  p.project_name,
  d.condwg_no,
  d.title,
  d.sub_no,
  d.remark,
  v.volume_code,
  v.volume_name,
  sc.sub_cat_name,
  GROUP_CONCAT(DISTINCT c.cat_name ORDER BY c.cat_name SEPARATOR ', ') AS categories,
  d.created_at,
  d.updated_at
FROM contract_dwg d
JOIN projects p
  ON p.project_id = d.project_id
JOIN contract_dwg_volume v
  ON v.project_id = d.project_id AND v.volume_id = d.volume_id
JOIN contract_dwg_sub_cat sc
  ON sc.project_id = d.project_id AND sc.sub_cat_id = d.sub_cat_id
LEFT JOIN contract_dwg_subcat_cat_map m
  ON m.project_id = d.project_id AND m.sub_cat_id = d.sub_cat_id
LEFT JOIN contract_dwg_cat c
  ON c.project_id = m.project_id AND c.cat_id = m.cat_id
GROUP BY d.condwg_id, d.project_id, p.project_code, p.project_name,
         d.condwg_no, d.title, d.sub_no, d.remark,
         v.volume_code, v.volume_name, sc.sub_cat_name,
         d.created_at, d.updated_at;

/* -----------------------------------------------------------
   2) vw_contract_dwg_full
   - ใช้เวลาอยากได้ข้อมูล “row per category” (ไม่ group concat)
   - 1 drawing อาจมีหลาย row (เพราะ subcat→หลาย cat)
   ----------------------------------------------------------- */
DROP VIEW IF EXISTS vw_contract_dwg_full;
CREATE VIEW vw_contract_dwg_full AS
SELECT
  d.condwg_id,
  d.project_id,
  p.project_code,
  p.project_name,
  d.condwg_no,
  d.title,
  d.sub_no,
  d.remark,
  v.volume_code,
  v.volume_name,
  sc.sub_cat_name,
  c.cat_name,
  d.created_at,
  d.updated_at
FROM contract_dwg d
JOIN projects p
  ON p.project_id = d.project_id
JOIN contract_dwg_volume v
  ON v.project_id = d.project_id AND v.volume_id = d.volume_id
JOIN contract_dwg_sub_cat sc
  ON sc.project_id = d.project_id AND sc.sub_cat_id = d.sub_cat_id
LEFT JOIN contract_dwg_subcat_cat_map m
  ON m.project_id = d.project_id AND m.sub_cat_id = d.sub_cat_id
LEFT JOIN contract_dwg_cat c
  ON c.project_id = m.project_id AND c.cat_id = m.cat_id;

/* -----------------------------------------------------------
   3) vw_contract_dwg_categories
   - แสดง mapping ของ sub-cat ↔ cat ภายในโปรเจกต์
   - ใช้ดูโครงสร้าง category hierarchy
   ----------------------------------------------------------- */
DROP VIEW IF EXISTS vw_contract_dwg_categories;
CREATE VIEW vw_contract_dwg_categories AS
SELECT
  sc.project_id,
  p.project_code,
  p.project_name,
  sc.sub_cat_id,
  sc.sub_cat_name,
  c.cat_id,
  c.cat_name
FROM contract_dwg_sub_cat sc
JOIN projects p
  ON p.project_id = sc.project_id
LEFT JOIN contract_dwg_subcat_cat_map m
  ON m.project_id = sc.project_id AND m.sub_cat_id = sc.sub_cat_id
LEFT JOIN contract_dwg_cat c
  ON c.project_id = m.project_id AND c.cat_id = m.cat_id;

/* -----------------------------------------------------------
   4) vw_contract_dwg_volumes
   - แสดง volume ต่อโปรเจกต์
   ----------------------------------------------------------- */
DROP VIEW IF EXISTS vw_contract_dwg_volumes;
CREATE VIEW vw_contract_dwg_volumes AS
SELECT
  v.volume_id,
  v.project_id,
  p.project_code,
  p.project_name,
  v.volume_code,
  v.volume_name,
  v.description,
  v.created_at,
  v.updated_at
FROM contract_dwg_volume v
JOIN projects p
  ON p.project_id = v.project_id;

-- 4) Views สำหรับรายงาน/ค้นหา
-- ดูว่า DWG แผ่นหนึ่งอ้างอิง Contract Drawing อะไรบ้าง
DROP VIEW IF EXISTS v_dwgdoc_with_contract_dwg;
CREATE VIEW v_dwgdoc_with_contract_dwg AS
SELECT
  t.id           AS dwgdoc_id,
  t.project_id,
  dt.code        AS doc_type_code,    -- ควรเป็น DWG
  t.title        AS dwgdoc_title,
  t.revision     AS dwgdoc_rev,
  cd.condwg_id,
  cd.condwg_no,
  cd.title       AS condwg_title
FROM dwgdoc_contract_dwg scd
JOIN technicaldocs t     ON t.id = scd.technical_doc_id
JOIN document_types dt   ON dt.document_types_id = t.document_type_id
JOIN contract_dwg cd     ON cd.condwg_id = scd.condwg_id;

-- reverse lookup: จาก Contract Drawing → DWG docs ที่อ้างถึง
DROP VIEW IF EXISTS v_contract_dwg_linked_dwgdocs;
CREATE VIEW v_contract_dwg_linked_dwgdocs AS
SELECT
  cd.condwg_id, cd.project_id, cd.condwg_no, cd.title AS condwg_title,
  t.id AS dwgdoc_id, t.title AS dwgdoc_title, t.revision AS dwgdoc_rev
FROM contract_dwg cd
JOIN dwgdoc_contract_dwg scd ON scd.condwg_id = cd.condwg_id
JOIN technicaldocs t          ON t.id = scd.technical_doc_id;

-- ---------------------------------------------------------------------
-- 0) Helper: latest RFAs (per root) that actually have RFA items
--    We join latest-per-root with rfa_items to ensure “RFA-typed” entries.
-- ---------------------------------------------------------------------
DROP VIEW IF EXISTS v_kpi_rfa_latest;
CREATE VIEW v_kpi_rfa_latest AS
SELECT
  c.corr_id,
  c.root_id,
  c.project_id,
  c.correspondence_number AS rfa_no,
  c.revision              AS rfa_rev,
  c.title                 AS rfa_title,
  c.correspondence_status_id,
  s.status_code           AS rfa_status_code,
  s.status_name           AS rfa_status_name,
  c.created_at,
  c.issued_date,
  c.originator_id,
  c.recipient_id
FROM v_correspondence_latest_per_root v
JOIN correspondences c      ON c.corr_id = v.corr_id
LEFT JOIN correspondence_status s ON s.status_id = c.correspondence_status_id
WHERE EXISTS (
  SELECT 1 FROM rfa_items ri WHERE ri.rfa_corr_id = c.corr_id
);

-- ---------------------------------------------------------------------
-- 1) KPI: RFA status counts (latest only), per project
-- ---------------------------------------------------------------------
DROP VIEW IF EXISTS v_kpi_rfa_status_counts;
CREATE VIEW v_kpi_rfa_status_counts AS
SELECT
  k.project_id,
  p.project_code,
  p.project_name,
  k.rfa_status_code AS status_code,
  k.rfa_status_name AS status_name,
  COUNT(*) AS total
FROM v_kpi_rfa_latest k
JOIN projects p ON p.project_id = k.project_id
GROUP BY k.project_id, p.project_code, p.project_name, k.rfa_status_code, k.rfa_status_name;

-- ---------------------------------------------------------------------
-- 2) KPI: Latest TechnicalDocs status counts (by doc type), per project
-- ---------------------------------------------------------------------
DROP VIEW IF EXISTS v_kpi_doc_status_counts;
CREATE VIEW v_kpi_doc_status_counts AS
SELECT
  v.project_id,
  p.project_code,
  p.project_name,
  v.doc_type_code,
  v.doc_type_name,
  v.status_code AS doc_status_code,
  v.status_desc AS doc_status_desc,
  COUNT(*) AS total
FROM v_technicaldocs_latest_readable v
JOIN projects p ON p.project_id = v.project_id
GROUP BY v.project_id, p.project_code, p.project_name,
         v.doc_type_code, v.doc_type_name, v.status_code, v.status_desc;

-- ---------------------------------------------------------------------
-- 3) KPI: RFA workload by recipient org (latest only)
--    - How many RFAs (latest) are on each recipient’s queue per status
-- ---------------------------------------------------------------------
DROP VIEW IF EXISTS v_kpi_rfa_workload_by_recipient;
CREATE VIEW v_kpi_rfa_workload_by_recipient AS
SELECT
  k.project_id,
  p.project_code,
  p.project_name,
  k.recipient_id AS org_id,
  o.org_code     AS recipient_code,
  o.org_name     AS recipient_name,
  k.rfa_status_code AS status_code,
  k.rfa_status_name AS status_name,
  COUNT(*) AS total
FROM v_kpi_rfa_latest k
JOIN projects p ON p.project_id = k.project_id
LEFT JOIN organizations o ON o.org_id = k.recipient_id
GROUP BY k.project_id, p.project_code, p.project_name,
         k.recipient_id, o.org_code, o.org_name,
         k.rfa_status_code, k.rfa_status_name;

-- ---------------------------------------------------------------------
-- 4) KPI: Recent activity (last 14 days) — RFAs (latest) and TechDocs (latest)
-- ---------------------------------------------------------------------
DROP VIEW IF EXISTS v_kpi_recent_rfa_activity;
CREATE VIEW v_kpi_recent_rfa_activity AS
SELECT
  k.project_id,
  p.project_code,
  p.project_name,
  k.corr_id,
  k.rfa_no,
  k.rfa_rev,
  k.rfa_title,
  k.rfa_status_code,
  k.rfa_status_name,
  k.created_at,
  k.issued_date
FROM v_kpi_rfa_latest k
JOIN projects p ON p.project_id = k.project_id
WHERE COALESCE(k.issued_date, k.created_at) >= (CURRENT_DATE - INTERVAL 14 DAY);

DROP VIEW IF EXISTS v_kpi_recent_doc_activity;
CREATE VIEW v_kpi_recent_doc_activity AS
SELECT
  v.project_id,
  p.project_code,
  p.project_name,
  v.id          AS techdoc_id,
  v.original_id,
  v.revision,
  v.title,
  v.doc_type_code,
  v.doc_type_name,
  v.status_code AS doc_status_code,
  v.status_desc AS doc_status_desc,
  v.created_at
FROM v_technicaldocs_latest_readable v
JOIN projects p ON p.project_id = v.project_id
WHERE v.created_at >= (CURRENT_DATE - INTERVAL 14 DAY);

-- ---------------------------------------------------------------------
-- 5) KPI: RFA ↔ Items summary (latest RFA joined to items + doc types)
--    Useful for grid cards: one row per (RFA, doc type)
-- ---------------------------------------------------------------------
DROP VIEW IF EXISTS v_kpi_rfa_items_summary;
CREATE VIEW v_kpi_rfa_items_summary AS
SELECT
  k.project_id,
  p.project_code,
  p.project_name,
  k.corr_id           AS rfa_corr_id,
  k.rfa_no,
  k.rfa_rev,
  k.rfa_title,
  k.rfa_status_code,
  k.rfa_status_name,
  ri.technical_doc_id,
  td.doc_type_code,
  td.doc_type_name
FROM v_kpi_rfa_latest k
JOIN projects p ON p.project_id = k.project_id
JOIN rfa_items ri       ON ri.rfa_corr_id = k.corr_id
JOIN v_technicaldocs_latest_readable td ON td.id = ri.technical_doc_id;

-- ---------------------------------------------------------------------
-- 6) Convenience summaries for UI small tiles
-- ---------------------------------------------------------------------
DROP VIEW IF EXISTS v_kpi_tiles_rfa;
CREATE VIEW v_kpi_tiles_rfa AS
SELECT
  project_id,
  SUM(status_code='DRAFT')                                  AS draft_count,
  SUM(status_code LIKE 'SUB%')                              AS submitted_count,
  SUM(status_code LIKE 'REP%')                              AS replied_count,
  SUM(status_code LIKE 'RSB%')                              AS resubmitted_count,
  SUM(status_code LIKE 'CLB%')                              AS closed_count,
  SUM(status_code LIKE 'CCB%')                              AS canceled_count,
  COUNT(*)                                                  AS total
FROM (
  SELECT project_id, rfa_status_code AS status_code
  FROM v_kpi_rfa_latest
) x
GROUP BY project_id;

DROP VIEW IF EXISTS v_kpi_tiles_docs;
CREATE VIEW v_kpi_tiles_docs AS
SELECT
  project_id,
  SUM(status_code='DFT') AS doc_draft,
  SUM(status_code='FAP') AS doc_for_approve,
  SUM(status_code='FRE') AS doc_for_review,
  SUM(status_code='FCO') AS doc_for_construction,
  SUM(status_code='ASB') AS doc_as_built,
  SUM(status_code='OBS') AS doc_obsolete,
  SUM(status_code='CC')  AS doc_canceled,
  COUNT(*)               AS total_docs
FROM v_technicaldocs_latest_readable
GROUP BY project_id;
-- ---------------------------------------------------------------------
-- Add View from ChatGPT ปรับปรุง V5.1 -> V5.2
-- ---------------------------------------------------------------------
/* A1) Views ที่ควรมี
-- 1) View ผู้ใช้ + บทบาทระบบ (global) + บทบาทในโปรเจกต์
   ประโยชน์: ใช้ทำหน้าบริหารผู้ใช้/สิทธิ์, ตรวจสอบความครอบคลุม RBAC, และเป็นฐาน report ฝั่งผู้ใช้ → โปรเจกต์ (เชื่อมกับ KPI อื่นง่าย) 
   (อ้างอิงโครงตารางจาก deploy file)*/
-- NEW: v_user_roles_global
DROP VIEW IF EXISTS v_user_roles_global;
CREATE VIEW v_user_roles_global AS
SELECT u.user_id, u.username, u.email, u.is_active,
       r.role_code, r.role_name
FROM users u
JOIN user_roles ur ON ur.user_id = u.user_id
JOIN roles r      ON r.role_id  = ur.role_id;

-- NEW: v_user_project_roles
DROP VIEW IF EXISTS v_user_project_roles;
CREATE VIEW v_user_project_roles AS
SELECT u.user_id, u.username, u.email, u.is_active,
       p.project_id, p.project_code, p.project_name,
       r.role_code, r.role_name
FROM users u
JOIN user_project_roles upr ON upr.user_id = u.user_id
JOIN roles r                ON r.role_id   = upr.role_id
JOIN projects p             ON p.project_id= upr.project_id;

-- 2) View สรุป activity ล่าสุดของผู้ใช้ (จาก audit_logs)
-- NEW: v_user_recent_activity (14 วัน)
DROP VIEW IF EXISTS v_user_recent_activity;
CREATE VIEW v_user_recent_activity AS
SELECT a.user_id, u.username, COUNT(*) AS actions_14d,
       MIN(a.created_at) AS first_seen_14d,
       MAX(a.created_at) AS last_seen_14d
FROM audit_logs a
LEFT JOIN users u ON u.user_id = a.user_id
WHERE a.created_at >= (CURRENT_DATE - INTERVAL 14 DAY)
GROUP BY a.user_id, u.username;

-- ---------------------------------------------------------------------
-- (3) Helpful composite indexes for UI filters / dashboards
-- ---------------------------------------------------------------------

-- technicaldocs: (project, type, status)
SET @exists := (
  SELECT COUNT(*)
  FROM information_schema.statistics
  WHERE table_schema = DATABASE()
    AND table_name   = 'technicaldocs'
    AND index_name   = 'idx_td_proj_type_status'
);
SET @sql := IF(@exists = 0,
  'CREATE INDEX idx_td_proj_type_status ON technicaldocs(project_id, document_type_id, status_code_id)',
  'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;

-- correspondences: (project, type, status)
SET @exists := (
  SELECT COUNT(*)
  FROM information_schema.statistics
  WHERE table_schema = DATABASE()
    AND table_name   = 'correspondences'
    AND index_name   = 'idx_cor_proj_type_status'
);
SET @sql := IF(@exists = 0,
  'CREATE INDEX idx_cor_proj_type_status ON correspondences(project_id, correspondence_type_id, correspondence_status_id)',
  'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;

/* B) ส่วน Correspondences (procedures, views)
B1) ปรับปรุง/เติมเต็มที่ควรมี
2. เพิ่ม view thread (สำหรับเปิดหน้า “ประวัติ revision” ของเอกสารตัวเดียว)*/
-- ใช้คู่กับ view “latest per root” ที่มีอยู่แล้ว เพื่อให้ทั้ง “ล่าสุด” และ “เส้นเวลา” อยู่ครบ
-- NEW: v_correspondence_thread
DROP VIEW IF EXISTS v_correspondence_thread;
CREATE VIEW v_correspondence_thread AS
SELECT c_root.project_id, c_root.correspondence_number,
       c.corr_id, c.root_id, c.revision, c.title,
       t.type_code, s.status_code, c.created_at, c.issued_date, c.pdf_path
FROM correspondences c
JOIN correspondences c_root ON c_root.corr_id = c.root_id
LEFT JOIN correspondence_types t ON t.type_id = c.correspondence_type_id
LEFT JOIN correspondence_status s ON s.status_id = c.correspondence_status_id;

-- 3. เพิ่ม view link graph (อ้างอิง) — ใครลิงก์หาใครบ้าง ประกอบกับทริกเกอร์กัน self-link ที่มีอยู่แล้ว
-- NEW: v_correspondence_links
DROP VIEW IF EXISTS v_correspondence_links;
CREATE VIEW v_correspondence_links AS
SELECT r.src_corr_id, c1.correspondence_number AS src_no, t1.type_code AS src_type,
       r.tgt_corr_id, c2.correspondence_number AS tgt_no, t2.type_code AS tgt_type
FROM correspondence_references r
JOIN correspondences c1 ON c1.corr_id = r.src_corr_id
JOIN correspondences c2 ON c2.corr_id = r.tgt_corr_id
LEFT JOIN correspondence_types t1 ON t1.type_id = c1.correspondence_type_id
LEFT JOIN correspondence_types t2 ON t2.type_id = c2.correspondence_type_id;

/* C2) ข้อเสนอเติมเต็ม
Views รายงานใหม่สำหรับ RFA:
RFA Aging (ล่าสุดต่อ root):
วัดอายุงานจาก COALESCE(issued_date, created_at) ถึง “วันนี้” (ใช้กับแดชบอร์ด SLA)
*/
-- NEW: v_kpi_rfa_aging
DROP VIEW IF EXISTS v_kpi_rfa_aging;
CREATE VIEW v_kpi_rfa_aging AS
SELECT
  k.project_id, p.project_code, p.project_name,
  k.corr_id AS rfa_corr_id, k.rfa_no, k.rfa_status_code, k.rfa_status_name,
  k.rfa_title, k.created_at, k.issued_date,
  DATEDIFF(CURRENT_DATE, DATE(COALESCE(k.issued_date, k.created_at))) AS age_days
FROM v_kpi_rfa_latest k
JOIN projects p ON p.project_id = k.project_id;

/*RFA Turnaround Time (วัดเวลาตอบกลับแรก):
ต้องการสถานะฝั่ง “Reply by …” → คำนวณห่างระหว่าง “submitted” (หรือ created/issued) กับ “reply” แรกของ family นั้น */
-- NEW: v_kpi_rfa_turnaround_first_reply
DROP VIEW IF EXISTS v_kpi_rfa_turnaround_first_reply;
CREATE VIEW v_kpi_rfa_turnaround_first_reply AS
WITH fam AS (
  SELECT root_id,
         MIN(CASE WHEN s.status_code LIKE 'SUB%' THEN COALESCE(issued_date, created_at) END) AS first_submit_at,
         MIN(CASE WHEN s.status_code LIKE 'REP%' THEN COALESCE(issued_date, created_at) END) AS first_reply_at
  FROM correspondences c
  LEFT JOIN correspondence_status s ON s.status_id=c.correspondence_status_id
  WHERE c.corr_id IN (SELECT rfa_corr_id FROM rfa_items)  -- เฉพาะ RFA families
  GROUP BY root_id
)
SELECT c.project_id, p.project_code, p.project_name,
       c.root_id, c.correspondence_number AS rfa_no,
       fam.first_submit_at, fam.first_reply_at,
       TIMESTAMPDIFF(HOUR, fam.first_submit_at, fam.first_reply_at) AS tat_hours
FROM correspondences c
JOIN fam ON fam.root_id = c.root_id
JOIN projects p ON p.project_id = c.project_id
WHERE c.corr_id = c.root_id; -- เอาแถว root เป็นตัวแทน family

-- RFA Without Items (จับความผิดปกติ)
-- NEW: v_kpi_rfa_without_items
DROP VIEW IF EXISTS v_kpi_rfa_without_items;
CREATE VIEW v_kpi_rfa_without_items AS
SELECT c.corr_id, c.project_id, c.correspondence_number AS rfa_no, c.title, c.created_at
FROM correspondences c
JOIN correspondence_types t ON t.type_id = c.correspondence_type_id AND t.type_code='RFA'
WHERE NOT EXISTS (SELECT 1 FROM rfa_items ri WHERE ri.rfa_corr_id=c.corr_id);

/*D) รายงาน/มุมมองที่ควรมี “เพิ่ม” (user + correspondences + RFA)
ต่อไปนี้คือ “บันเดิลรายงาน” พร้อมโค้ด ซึ่งคุณสามารถใส่ต่อท้ายไฟล์ 04_..._views.sql ได้เลย
D1) User*/
-- 1) ผู้ใช้แบบ matrix (Global vs Project)
DROP VIEW IF EXISTS v_user_access_matrix;
CREATE VIEW v_user_access_matrix AS
SELECT u.user_id, u.username, u.email, u.is_active,
       COALESCE(GROUP_CONCAT(DISTINCT rg.role_code ORDER BY rg.role_code), '') AS global_roles,
       COALESCE(GROUP_CONCAT(DISTINCT CONCAT(p.project_code,':',rp.role_code) ORDER BY p.project_code, rp.role_code SEPARATOR ' | '), '') AS project_roles
FROM users u
LEFT JOIN user_roles ur      ON ur.user_id=u.user_id
LEFT JOIN roles rg           ON rg.role_id=ur.role_id
LEFT JOIN user_project_roles upr ON upr.user_id=u.user_id
LEFT JOIN roles rp               ON rp.role_id=upr.role_id
LEFT JOIN projects p             ON p.project_id=upr.project_id
GROUP BY u.user_id, u.username, u.email, u.is_active;

-- 2) ผู้ใช้ Active/Inactive 30 วัน (อิง audit_logs)
DROP VIEW IF EXISTS v_user_active_last30d;
CREATE VIEW v_user_active_last30d AS
SELECT u.user_id, u.username,
       MAX(a.created_at) AS last_action_at,
       CASE WHEN MAX(a.created_at) >= (CURRENT_DATE - INTERVAL 30 DAY) THEN 1 ELSE 0 END AS active_30d
FROM users u
LEFT JOIN audit_logs a ON a.user_id=u.user_id
GROUP BY u.user_id, u.username;

-- D2) Correspondences
-- 3) Latest per type per project (สำหรับหน้า “กล่องเอกสารล่าสุด”)
DROP VIEW IF EXISTS v_correspondence_latest_by_type;
CREATE VIEW v_correspondence_latest_by_type AS
SELECT v.project_id, p.project_code, p.project_name,
       v.correspondence_type_id, t.type_code, t.type_name,
       v.corr_id, v.correspondence_number, v.revision, v.title, v.issued_date, v.created_at
FROM v_correspondence_latest_per_root v
JOIN projects p ON p.project_id=v.project_id
LEFT JOIN correspondence_types t ON t.type_id=v.correspondence_type_id;

-- 4) Correspondence Aging (ทุกประเภท เอนกประสงค์)
DROP VIEW IF EXISTS v_kpi_correspondence_aging;
CREATE VIEW v_kpi_correspondence_aging AS
SELECT v.project_id, p.project_code, p.project_name,
       t.type_code, t.type_name,
       v.corr_id, v.correspondence_number, v.title,
       v.correspondence_status_id, s.status_code, s.status_name,
       v.created_at, v.issued_date,
       DATEDIFF(CURRENT_DATE, DATE(COALESCE(v.issued_date, v.created_at))) AS age_days
FROM v_correspondence_latest_readable v
JOIN projects p ON p.project_id=v.project_id
LEFT JOIN correspondence_status s ON s.status_id=v.correspondence_status_id
LEFT JOIN correspondence_types t ON t.type_id=v.correspondence_type_id;

-- A.1 รวมสิทธิ์ของแต่ละ role (global) เป็นรายการ perm_code แบบคอมมา
DROP VIEW IF EXISTS
CREATE OR REPLACE VIEW v_role_permission_matrix AS
SELECT
  r.role_id,
  r.role_code,
  r.role_name,
  GROUP_CONCAT(DISTINCT p.perm_code ORDER BY p.perm_code SEPARATOR ', ') AS perm_codes
FROM roles r
LEFT JOIN role_permissions rp ON rp.role_id = r.role_id
LEFT JOIN permissions p       ON p.perm_id = rp.perm_id
GROUP BY r.role_id, r.role_code, r.role_name;

-- A.2 สำหรับตรวจบทบาท/สิทธิ์ที่ใช้ในโปรเจกต์ (ใช้เวลาต้องการภาพรวมว่าในโปรเจกต์นี้มี role อะไรและสิทธิ์อะไรบ้าง)
-- เปลี่ยน :projectId เป็นหมายเลขโปรเจกต์ที่ต้องการ
SET @pid := :projectId;

SELECT
  r.role_code,
  r.role_name,
  GROUP_CONCAT(DISTINCT p.perm_code ORDER BY p.perm_code SEPARATOR ', ') AS perm_codes
FROM user_project_roles upr
JOIN roles r             ON r.role_id = upr.role_id
JOIN role_permissions rp ON rp.role_id = r.role_id
JOIN permissions p       ON p.perm_id = rp.perm_id
WHERE upr.project_id = @pid
GROUP BY r.role_code, r.role_name
ORDER BY r.role_code;

SET FOREIGN_KEY_CHECKS=1;