251202:1700 Prepare to version 1.6
This commit is contained in:
@@ -156,7 +156,7 @@ VALUES (
|
|||||||
);
|
);
|
||||||
-- Seed user
|
-- Seed user
|
||||||
-- Initial SUPER_ADMIN user
|
-- Initial SUPER_ADMIN user
|
||||||
INSERT INTO `users` (
|
INSERT INTO users (
|
||||||
`user_id`,
|
`user_id`,
|
||||||
`username`,
|
`username`,
|
||||||
`password_hash`,
|
`password_hash`,
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
title: 'Functional Requirements: Document Numbering Management'
|
title: 'Functional Requirements: Document Numbering Management'
|
||||||
version: 1.5.0
|
version: 1.6.0
|
||||||
status: first-draft
|
status: draft
|
||||||
owner: Nattanin Peancharoen
|
owner: Nattanin Peancharoen
|
||||||
last_updated: 2025-12-02
|
last_updated: 2025-12-02
|
||||||
related:
|
related:
|
||||||
@@ -22,104 +22,227 @@ related:
|
|||||||
|
|
||||||
## 3.11.2. Logic การนับเลข (Counter Logic)
|
## 3.11.2. Logic การนับเลข (Counter Logic)
|
||||||
|
|
||||||
การนับเลขจะแยกตาม **Counter Key** ที่ประกอบด้วย:
|
การนับเลขจะแยกตาม **Counter Key** ที่ประกอบด้วยหลายส่วน ขึ้นกับประเภทเอกสาร
|
||||||
|
|
||||||
- `project_id` - รหัสโครงการ
|
### Counter Key Components
|
||||||
- `doc_type_id` - ชนิดเอกสาร (Correspondence, RFA, Transmittal, Drawing)
|
|
||||||
- `sub_type_id` - ประเภทย่อยของเอกสาร (nullable)
|
|
||||||
- `discipline_id` - สาขาวิชา/งาน (nullable)
|
|
||||||
- `year` - ปี พ.ศ. หรือ ค.ศ. ตามที่กำหนดใน template
|
|
||||||
|
|
||||||
### ตัวอย่าง Counter Key
|
| Component | Required? | Description | Database Source | Default if NULL |
|
||||||
|
|-----------|-----------|-------------|-----------------|-----------------|
|
||||||
|
| `project_id` | ✅ Yes | ID โครงการ | Derived from user context or organization | - |
|
||||||
|
| `originator_organization_id` | ✅ Yes | ID องค์กรผู้ส่ง | `correspondences.originator_id` | - |
|
||||||
|
| `recipient_organization_id` | Depends on type | ID องค์กรผู้รับหลัก (TO) | `correspondence_recipients` where `recipient_type = 'TO'` | NULL for RFA |
|
||||||
|
| `correspondence_type_id` | ✅ Yes | ID ประเภทเอกสาร | `correspondence_types.id` | - |
|
||||||
|
| `sub_type_id` | TRANSMITTAL only | ID ประเภทย่อย | `correspondence_sub_types.id` | 0 |
|
||||||
|
| `rfa_type_id` | RFA only | ID ประเภท RFA | `rfa_types.id` | 0 |
|
||||||
|
| `discipline_id` | RFA only | ID สาขางาน | `disciplines.id` | 0 |
|
||||||
|
| `current_year` | ✅ Yes | ปี ค.ศ. | System year (ปัจจุบัน) | - |
|
||||||
|
|
||||||
```text
|
### Counter Key แยกตามประเภทเอกสาร
|
||||||
Correspondence: project_id + doc_type_id + sub_type_id + year
|
|
||||||
RFA: project_id + doc_type_id + discipline_id + year
|
**LETTER / RFI / MEMO / EMAIL / MOM / INSTRUCTION / NOTICE / OTHER**:
|
||||||
Transmittal: project_id + doc_type_id + recipient_type + year
|
|
||||||
Drawing: project_id + doc_type_id + discipline_id + year
|
|
||||||
```
|
```
|
||||||
|
(project_id, originator_organization_id, recipient_organization_id,
|
||||||
|
correspondence_type_id, 0, 0, 0, current_year)
|
||||||
|
```
|
||||||
|
*หมายเหตุ*: ไม่ใช้ `discipline_id`, `sub_type_id`, `rfa_type_id`
|
||||||
|
|
||||||
|
**TRANSMITTAL**:
|
||||||
|
```
|
||||||
|
(project_id, originator_organization_id, recipient_organization_id,
|
||||||
|
correspondence_type_id, sub_type_id, 0, 0, current_year)
|
||||||
|
```
|
||||||
|
*หมายเหตุ*: ใช้ `sub_type_id` เพิ่มเติม
|
||||||
|
|
||||||
|
**RFA**:
|
||||||
|
```
|
||||||
|
(project_id, originator_organization_id, NULL,
|
||||||
|
correspondence_type_id, 0, rfa_type_id, discipline_id, current_year)
|
||||||
|
```
|
||||||
|
*หมายเหตุ*: RFA ไม่ใช้ `recipient_organization_id` เพราะเป็นเอกสารโครงการ (CONTRACTOR → CONSULTANT → OWNER)
|
||||||
|
|
||||||
|
### วิธีการหา project_id
|
||||||
|
|
||||||
|
เนื่องจาก Template ของ LETTER/TRANSMITTAL ไม่มี `{PROJECT}` token ระบบจะหา `project_id` จาก:
|
||||||
|
|
||||||
|
1. **User Context** (แนะนำ):
|
||||||
|
- เมื่อ User สร้างเอกสาร UI จะให้เลือก Project/Contract ก่อน
|
||||||
|
- ใช้ `project_id` จาก Context ที่เลือก
|
||||||
|
|
||||||
|
2. **จาก Organization**:
|
||||||
|
- Query `project_organizations` หรือ `contract_organizations`
|
||||||
|
- ใช้ `originator_organization_id` หา project ที่เกี่ยวข้อง
|
||||||
|
- ถ้ามีหลาย project ให้ User เลือก
|
||||||
|
|
||||||
|
3. **Validation**:
|
||||||
|
- ตรวจสอบว่า organization มีสิทธิ์ใน project นั้น
|
||||||
|
- ตรวจสอบว่า project/contract เป็น active
|
||||||
|
|
||||||
### Fallback สำหรับค่า NULL
|
### Fallback สำหรับค่า NULL
|
||||||
|
|
||||||
- กรณีที่ `discipline_id` หรือ `sub_type_id` เป็น NULL ให้ใช้ค่า Default `0` ในการจัดกลุ่ม Counter
|
- `discipline_id`: ใช้ `0` (ไม่ระบุสาขางาน)
|
||||||
- ป้องกัน Error และรับประกันความถูกต้องของ Running Number (Uniqueness Guarantee)
|
- `sub_type_id`: ใช้ `0` (ไม่มีประเภทย่อย)
|
||||||
|
- `rfa_type_id`: ใช้ `0` (ไม่ระบุประเภท RFA)
|
||||||
|
- `recipient_organization_id`: ใช้ `NULL` สำหรับ RFA, Required สำหรับ LETTER/TRANSMITTAL
|
||||||
|
|
||||||
## 3.11.3. Format Templates by Document Type
|
|
||||||
|
|
||||||
ระบบรองรับการกำหนดรูปแบบด้วย **Token Replacement**
|
## 3.11.3. Format Templates by Correspondence Type
|
||||||
|
|
||||||
### 3.11.3.1. Correspondence (หนังสือราชการ)
|
> **📝 หมายเหตุสำคัญ**
|
||||||
|
> - Templates ด้านล่างเป็น **ตัวอย่าง** สำหรับประเภทเอกสารหลัก
|
||||||
|
> - ระบบรองรับ **ทุกประเภทเอกสาร** ที่อยู่ใน `correspondence_types` table
|
||||||
|
> - หากมีการเพิ่มประเภทใหม่ในอนาคต สามารถใช้งานได้โดยอัตโนมัติ
|
||||||
|
> - Admin สามารถกำหนด Template เฉพาะสำหรับแต่ละประเภทผ่าน Admin Panel
|
||||||
|
|
||||||
#### Letter Type (TYPE = 03)
|
### 3.11.3.1. Letter (TYPE = LETTER)
|
||||||
|
|
||||||
- **Template**: `{ORG}-{ORG}-{TYPE}-{SEQ:4}-{YEAR:B.E.}`
|
**Template**:
|
||||||
- **Example**: `คคง.-สคฉ.3-0985-2568`
|
```
|
||||||
- **Counter Key**: `project_id + doc_type_id + sub_type_id + year`
|
{ORIGINATOR}-{RECIPIENT}-{SEQ:4}-{YEAR:B.E.}
|
||||||
|
```
|
||||||
|
|
||||||
#### Other Correspondence Types
|
**Example**: `คคง.-สคฉ.3-0001-2568`
|
||||||
|
|
||||||
- **Template**: `{ORG}-{ORG}-{TYPE}-{SEQ:4}-{YEAR:B.E.}`
|
**Token Breakdown**:
|
||||||
- **Example**: `คคง.-สคฉ.3-STR-0001-2568`
|
- `คคง.` = {ORIGINATOR} = รหัสองค์กรผู้ส่ง
|
||||||
- **Counter Key**: `project_id + doc_type_id + sub_type_id + year`
|
- `สคฉ.3` = {RECIPIENT} = รหัสองค์กรผู้รับหลัก (TO)
|
||||||
|
- `0001` = {SEQ:4} = Running number (เริ่ม 0001, 0002, ...)
|
||||||
|
- `2568` = {YEAR:B.E.} = ปี พ.ศ.
|
||||||
|
|
||||||
### 3.11.3.2. Transmittal
|
> **⚠️ Template vs Counter Separation**
|
||||||
|
> - {CORR_TYPE} **ไม่แสดง**ใน template เพื่อความกระชับ
|
||||||
|
> - แต่ระบบ**ยังใช้ correspondence_type_id ใน Counter Key** เพื่อแยก counter
|
||||||
|
> - LETTER, MEMO, RFI **มี counter แยกกัน** แม้ template format เหมือนกัน
|
||||||
|
|
||||||
#### Transmittal to Owner
|
**Counter Key**: `(project_id, originator_org_id, recipient_org_id, corr_type_id, 0, 0, 0, year)`
|
||||||
|
|
||||||
- **Template**: `{ORG}-{ORG}-{TYPE}-{SUB_TYPE}-{SEQ:4}-{YEAR:B.E.}`
|
---
|
||||||
- **Example**: `คคง.-สคฉ.3-03-21-0117-2568`
|
|
||||||
- **Counter Key**: `project_id + doc_type_id + recipient_type + year`
|
|
||||||
- **Note**: `recipient_type = 'OWNER'`
|
|
||||||
|
|
||||||
#### Transmittal to Contractor/Others
|
### 3.11.3.2. Transmittal (TYPE = TRANSMITTAL)
|
||||||
|
|
||||||
- **Template**: `{ORG}-{ORG}-{TYPE}-{SEQ:4}-{YEAR:B.E.}`
|
**Template**:
|
||||||
- **Example**: `ผรม.2-คคง.-0117-2568`
|
```
|
||||||
- **Counter Key**: `project_id + doc_type_id + recipient_type + year`
|
{ORIGINATOR}-{RECIPIENT}-{SUB_TYPE}-{SEQ:4}-{YEAR:B.E.}
|
||||||
- **Note**: `recipient_type = 'CONTRACTOR' | 'CONSULTANT' | 'OTHER'`
|
```
|
||||||
|
|
||||||
#### Alternative Project-based Format
|
**Example**: `คคง.-สคฉ.3-21-0117-2568`
|
||||||
|
|
||||||
- **Template**: `{PROJECT}-{ORG}-{TYPE}-{DISCIPLINE}-{SEQ:4}-{REV}`
|
**Token Breakdown**:
|
||||||
- **Example**: `LCBP3-TR-STR-0001-A`
|
- `คคง.` = {ORIGINATOR}
|
||||||
- **Counter Key**: `project_id + doc_type_id + discipline_id + year`
|
- `สคฉ.3` = {RECIPIENT}
|
||||||
|
- `21` = {SUB_TYPE} = หมายเลขประเภทย่อย (11=MAT, 12=SHP, 13=DWG, 14=MET, ...)
|
||||||
|
- `0117` = {SEQ:4}
|
||||||
|
- `2568` = {YEAR:B.E.}
|
||||||
|
|
||||||
|
> **⚠️ Template vs Counter Separation**
|
||||||
|
> - {CORR_TYPE} **ไม่แสดง**ใน template (เหมือน LETTER)
|
||||||
|
> - TRANSMITTAL มี counter แยกจาก LETTER
|
||||||
|
|
||||||
|
**Counter Key**: `(project_id, originator_org_id, recipient_org_id, corr_type_id, sub_type_id, 0, 0, year)`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### 3.11.3.3. RFA (Request for Approval)
|
### 3.11.3.3. RFA (Request for Approval)
|
||||||
|
|
||||||
- **Template**: `{PROJECT}-{ORG}-{TYPE}-{DISCIPLINE}-{SEQ:4}-{REV}`
|
**Template**:
|
||||||
- **Example**: `LCBP3-C2-RFI-ROW-0029-A`
|
```
|
||||||
- **Counter Key**: `project_id + doc_type_id + discipline_id + year`
|
{PROJECT}-{CORR_TYPE}-{DISCIPLINE}-{RFA_TYPE}-{SEQ:4}-{REV}
|
||||||
- **Note**: `{REV}` คือ revision code (A, B, C, ..., AA, AB, ...)
|
```
|
||||||
|
|
||||||
|
**Example**: `LCBP3-C2-RFA-TER-RPT-0001-A`
|
||||||
|
|
||||||
|
**Token Breakdown**:
|
||||||
|
- `LCBP3-C2` = {PROJECT} = รหัสโครงการ
|
||||||
|
- `RFA` = {CORR_TYPE} = ประเภทเอกสาร (**แสดง**ใน RFA template)
|
||||||
|
- `TER` = {DISCIPLINE} = รหัสสาขางาน (TER=Terminal, STR=Structure, ...)
|
||||||
|
- `RPT` = {RFA_TYPE} = ประเภท RFA (RPT=Report, SDW=Shop Drawing, ...)
|
||||||
|
- `0001` = {SEQ:4}
|
||||||
|
- `A` = {REV} = Revision code
|
||||||
|
|
||||||
|
> **📋 RFA Workflow**
|
||||||
|
> - RFA เป็น **เอกสารโครงการ** (Project-level document)
|
||||||
|
> - Workflow: **CONTRACTOR → CONSULTANT → OWNER**
|
||||||
|
> - ไม่มี specific `recipient_id` เพราะเป็น workflow ที่กำหนดไว้แล้ว
|
||||||
|
|
||||||
|
**Counter Key**: `(project_id, originator_org_id, NULL, corr_type_id, 0, rfa_type_id, discipline_id, year)`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### 3.11.3.4. Drawing
|
### 3.11.3.4. Drawing
|
||||||
|
|
||||||
- **Template**: `{PROJECT}-{DISCIPLINE}-{CATEGORY}-{SEQ:4}-{REV}`
|
**Status**: 🚧 **To Be Determined**
|
||||||
- **Example**: `LCBP3-STR-DRW-0001-A`
|
|
||||||
- **Counter Key**: `project_id + doc_type_id + discipline_id + category + year`
|
Drawing Numbering ยังไม่ได้กำหนด Template เนื่องจาก:
|
||||||
|
- มีความซับซ้อนสูง (Contract Drawing และ Shop Drawing มีกฎต่างกัน)
|
||||||
|
- อาจต้องใช้ระบบ Numbering แยกต่างหาก
|
||||||
|
- ต้องพิจารณาร่วมกับ RFA ที่เกี่ยวข้อง
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3.11.3.5. Other Correspondence Types
|
||||||
|
|
||||||
|
**Applicable to**: RFI, MEMO, EMAIL, MOM, INSTRUCTION, NOTICE, OTHER
|
||||||
|
|
||||||
|
**Template**:
|
||||||
|
```
|
||||||
|
{ORIGINATOR}-{RECIPIENT}-{SEQ:4}-{YEAR:B.E.}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example (RFI)**: `คคง.-สคฉ.3-0042-2568`
|
||||||
|
**Example (MEMO)**: `คคง.-ผรม.1-0001-2568`
|
||||||
|
|
||||||
|
> **🔑 Counter Separation**
|
||||||
|
> - แม้ template format **เหมือนกับ LETTER**
|
||||||
|
> - แต่แต่ละ type มี **counter แยกกัน** ผ่าน `correspondence_type_id`
|
||||||
|
> - RFI counter ≠ MEMO counter ≠ LETTER counter
|
||||||
|
|
||||||
|
**Counter Key**: `(project_id, originator_org_id, recipient_org_id, corr_type_id, 0, 0, 0, year)`
|
||||||
|
|
||||||
|
**หมายเหตุ**: ทุกประเภทที่ไม่ได้ระบุเฉพาะจะใช้ Template นี้ ถ้ามีการเพิ่ม correspondence type ใหม่ใน `correspondence_types` table จะใช้ Template นี้โดยอัตโนมัติ
|
||||||
|
|
||||||
|
|
||||||
## 3.11.4. Supported Token Types
|
## 3.11.4. Supported Token Types
|
||||||
|
|
||||||
| Token | Description | Example |
|
| Token | Description | Example | Database Source |
|
||||||
|-------|-------------|---------|
|
|-------|-------------|---------|-----------------|
|
||||||
| `{PROJECT}` | รหัสโครงการ | `LCBP3` |
|
| `{PROJECT}` | รหัสโครงการ | `LCBP3`, `LCBP3-C2` | `projects.project_code` |
|
||||||
| `{ORG}` | รหัสหน่วยงาน | `คคง.`, `สคฉ.3` |
|
| `{ORIGINATOR}` | รหัสองค์กรผู้ส่ง | `คคง.`, `ผรม.1` | `organizations.organization_code` via `correspondences.originator_id` |
|
||||||
| `{TYPE}` | รหัสชนิดเอกสาร | `RFI`, `03` |
|
| `{RECIPIENT}` | รหัสองค์กรผู้รับหลัก (TO) | `สคฉ.3`, `กทท.` | `organizations.organization_code` via `correspondence_recipients` where `recipient_type = 'TO'` |
|
||||||
| `{SUB_TYPE}` | รหัสประเภทย่อย | `21` |
|
| `{CORR_TYPE}` | รหัสประเภทเอกสาร | `RFA`, `TRANSMITTAL`, `LETTER` | `correspondence_types.type_code` |
|
||||||
| `{DISCIPLINE}` | รหัสสาขาวิชา | `STR`, `ROW` |
|
| `{SUB_TYPE}` | หมายเลขประเภทย่อย | `11`, `12`, `21` | `correspondence_sub_types.sub_type_number` |
|
||||||
| `{CATEGORY}` | หมวดหมู่ | `DRW` |
|
| `{RFA_TYPE}` | รหัสประเภท RFA | `SDW`, `RPT`, `MAT` | `rfa_types.type_code` |
|
||||||
| `{SEQ:n}` | Running number (n = จำนวนหลัก) | `0001`, `0029` |
|
| `{DISCIPLINE}` | รหัสสาขาวิชา | `STR`, `TER`, `GEO` | `disciplines.discipline_code` |
|
||||||
| `{YEAR:B.E.}` | ปี พ.ศ. | `2568` |
|
| `{SEQ:n}` | Running number (n = จำนวนหลัก) | `0001`, `0029`, `0985` | Based on `document_number_counters.last_number + 1` |
|
||||||
| `{YEAR:A.D.}` | ปี ค.ศ. | `2025` |
|
| `{YEAR:B.E.}` | ปี พ.ศ. | `2568` | `document_number_counters.current_year + 543` |
|
||||||
| `{REV}` | Revision Code | `A`, `B`, `AA` |
|
| `{YEAR:A.D.}` | ปี ค.ศ. | `2025` | `document_number_counters.current_year` |
|
||||||
|
| `{REV}` | Revision Code | `A`, `B`, `AA` | `correspondence_revisions.revision_label` |
|
||||||
|
|
||||||
## 3.11.5. Transmittal Special Logic
|
### Token Usage Notes
|
||||||
|
|
||||||
- Transmittal มีเงื่อนไขพิเศษที่เลขอาจเปลี่ยนตามผู้รับ:
|
**{SEQ:n}**:
|
||||||
- **To Owner**: ใช้ format พิเศษที่มี sub_type รหัสโครงการ
|
- `n` = จำนวนหลักที่ต้องการ (typically 4)
|
||||||
- **To Contractor/Others**: ใช้ format ทั่วไป
|
- Counter **เริ่มจาก 0001** และเพิ่มทีละ 1 (0001, 0002, 0003, ...)
|
||||||
- Counter Key จะแยกตาม `recipient_type` เพื่อให้แต่ละประเภทมี running number อิสระ
|
- Padding ด้วย 0 ทางซ้าย
|
||||||
|
- Reset ทุกปี (ตาม `current_year` ใน Counter Key)
|
||||||
|
|
||||||
## 3.11.6. กลไกความปลอดภัย (Concurrency Control)
|
**{RECIPIENT}**:
|
||||||
|
- ใช้เฉพาะผู้รับที่มี `recipient_type = 'TO'` เท่านั้น
|
||||||
|
- ถ้ามีหลาย TO ให้ใช้คนแรก (ตาม sort order)
|
||||||
|
- **ไม่ใช้สำหรับ RFA** (RFA ไม่มี {RECIPIENT} ใน template)
|
||||||
|
|
||||||
|
**{CORR_TYPE}**:
|
||||||
|
- รองรับทุกค่าจาก `correspondence_types.type_code`
|
||||||
|
- ถ้าม<E0B8B2>การเพิ่มประเภทใหม่ จะใช้งานได้ทันที
|
||||||
|
- **แสดงใน template**: RFA only
|
||||||
|
- **ไม่แสดงแต่ใช้ใน counter**: LETTER, TRANSMITTAL, และ Other types
|
||||||
|
|
||||||
|
**Deprecated Tokens** (ไม่ควรใช้):
|
||||||
|
- ~~`{ORG}`~~ → ใช้ `{ORIGINATOR}` หรือ `{RECIPIENT}` แทน
|
||||||
|
- ~~`{TYPE}`~~ → ใช้ `{CORR_TYPE}`, `{SUB_TYPE}`, หรือ `{RFA_TYPE}` แทน (ตามบริบท)
|
||||||
|
- ~~`{CATEGORY}`~~ → ไม่ได้ใช้งานในระบบปัจจุบัน
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 3.11.5. กลไกความปลอดภัย (Concurrency Control)
|
||||||
|
|
||||||
### 3.11.6.1. Redis Distributed Lock
|
### 3.11.6.1. Redis Distributed Lock
|
||||||
|
|
||||||
@@ -277,7 +400,111 @@ Drawing: project_id + doc_type_id + discipline_id + year
|
|||||||
- `document_number_audit` - เก็บ audit trail
|
- `document_number_audit` - เก็บ audit trail
|
||||||
- `documents` - เก็บ document number ที่ถูกสร้าง
|
- `documents` - เก็บ document number ที่ถูกสร้าง
|
||||||
|
|
||||||
## 3.11.14. Security Considerations
|
## 3.11.14. Database Schema Requirements
|
||||||
|
|
||||||
|
### 3.11.14.1. Counter Table Schema
|
||||||
|
|
||||||
|
ตาราง `document_number_counters` ต้องมีโครงสร้างดังนี้:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE document_number_counters (
|
||||||
|
project_id INT NOT NULL,
|
||||||
|
originator_organization_id INT NOT NULL,
|
||||||
|
recipient_organization_id INT NULL, -- NULL for RFA
|
||||||
|
correspondence_type_id INT NOT NULL,
|
||||||
|
sub_type_id INT DEFAULT 0, -- for TRANSMITTAL
|
||||||
|
rfa_type_id INT DEFAULT 0, -- for RFA
|
||||||
|
discipline_id INT DEFAULT 0, -- for RFA
|
||||||
|
current_year INT NOT NULL,
|
||||||
|
version INT DEFAULT 0 NOT NULL, -- Optimistic Lock
|
||||||
|
last_number INT DEFAULT 0,
|
||||||
|
|
||||||
|
PRIMARY KEY (
|
||||||
|
project_id,
|
||||||
|
originator_organization_id,
|
||||||
|
COALESCE(recipient_organization_id, 0),
|
||||||
|
correspondence_type_id,
|
||||||
|
sub_type_id,
|
||||||
|
rfa_type_id,
|
||||||
|
discipline_id,
|
||||||
|
current_year
|
||||||
|
),
|
||||||
|
|
||||||
|
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (originator_organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (recipient_organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (correspondence_type_id) REFERENCES correspondence_types(id) ON DELETE CASCADE
|
||||||
|
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci
|
||||||
|
COMMENT = 'ตารางเก็บ Running Number Counters';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.11.14.2. Index Requirements
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Index สำหรับ Performance
|
||||||
|
CREATE INDEX idx_counter_lookup
|
||||||
|
ON document_number_counters (
|
||||||
|
project_id,
|
||||||
|
correspondence_type_id,
|
||||||
|
current_year
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Index สำหรับ Originator lookup
|
||||||
|
CREATE INDEX idx_counter_org
|
||||||
|
ON document_number_counters (
|
||||||
|
originator_organization_id,
|
||||||
|
current_year
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.11.14.3. Important Notes
|
||||||
|
|
||||||
|
> **💡 Counter Key Design**
|
||||||
|
> - ใช้ `COALESCE(recipient_organization_id, 0)` ใน Primary Key เพื่อรองรับ NULL
|
||||||
|
> - `version` column สำหรับ Optimistic Locking (ป้องกัน race condition)
|
||||||
|
> - `last_number` เริ่มจาก 0 และเพิ่มขึ้นทีละ 1
|
||||||
|
> - Counter reset ทุกปี (เมื่อ `current_year` เปลี่ยน)
|
||||||
|
|
||||||
|
> **⚠️ Migration Notes**
|
||||||
|
> - ไม่มีข้อมูลเก่า ไม่ต้องทำ backward compatibility
|
||||||
|
> - สามารถสร้าง table ใหม่ได้เลยตาม schema ข้างต้น
|
||||||
|
> - ต้องมี seed data สำหรับ `correspondence_types`, `rfa_types`, `disciplines` ก่อน
|
||||||
|
|
||||||
|
### 3.11.14.4. Example Counter Records
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Example: LETTER from คคง. to สคฉ.3 in LCBP3-C2 year 2025
|
||||||
|
INSERT INTO document_number_counters (
|
||||||
|
project_id, originator_organization_id, recipient_organization_id,
|
||||||
|
correspondence_type_id, sub_type_id, rfa_type_id, discipline_id,
|
||||||
|
current_year, version, last_number
|
||||||
|
) VALUES (
|
||||||
|
2, -- LCBP3-C2
|
||||||
|
22, -- คคง.
|
||||||
|
10, -- สคฉ.3
|
||||||
|
6, -- LETTER
|
||||||
|
0, 0, 0,
|
||||||
|
2025, 0, 0
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Example: RFA from ผรม.2 in LCBP3-C2, discipline TER, type RPT, year 2025
|
||||||
|
INSERT INTO document_number_counters (
|
||||||
|
project_id, originator_organization_id, recipient_organization_id,
|
||||||
|
correspondence_type_id, sub_type_id, rfa_type_id, discipline_id,
|
||||||
|
current_year, version, last_number
|
||||||
|
) VALUES (
|
||||||
|
2, -- LCBP3-C2
|
||||||
|
42, -- ผรม.2
|
||||||
|
NULL, -- RFA ไม่มี specific recipient
|
||||||
|
1, -- RFA
|
||||||
|
0,
|
||||||
|
18, -- RPT (Report)
|
||||||
|
5, -- TER (Terminal)
|
||||||
|
2025, 0, 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3.11.15. Security Considerations
|
||||||
|
|
||||||
### 3.11.14.1. Authorization
|
### 3.11.14.1. Authorization
|
||||||
|
|
||||||
|
|||||||
103
specs/01-requirements/03.11-document-numbering_schema_section.md
Normal file
103
specs/01-requirements/03.11-document-numbering_schema_section.md
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
## 3.11.15. Database Schema Requirements
|
||||||
|
|
||||||
|
### 3.11.15.1. Counter Table Schema
|
||||||
|
|
||||||
|
ตาราง `document_number_counters` ต้องมีโครงสร้างดังนี้:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE document_number_counters (
|
||||||
|
project_id INT NOT NULL,
|
||||||
|
originator_organization_id INT NOT NULL,
|
||||||
|
recipient_organization_id INT NULL, -- NULL for RFA
|
||||||
|
correspondence_type_id INT NOT NULL,
|
||||||
|
sub_type_id INT DEFAULT 0, -- for TRANSMITTAL
|
||||||
|
rfa_type_id INT DEFAULT 0, -- for RFA
|
||||||
|
discipline_id INT DEFAULT 0, -- for RFA
|
||||||
|
current_year INT NOT NULL,
|
||||||
|
version INT DEFAULT 0 NOT NULL, -- Optimistic Lock
|
||||||
|
last_number INT DEFAULT 0,
|
||||||
|
|
||||||
|
PRIMARY KEY (
|
||||||
|
project_id,
|
||||||
|
originator_organization_id,
|
||||||
|
COALESCE(recipient_organization_id, 0),
|
||||||
|
correspondence_type_id,
|
||||||
|
sub_type_id,
|
||||||
|
rfa_type_id,
|
||||||
|
discipline_id,
|
||||||
|
current_year
|
||||||
|
),
|
||||||
|
|
||||||
|
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (originator_organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (recipient_organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (correspondence_type_id) REFERENCES correspondence_types(id) ON DELETE CASCADE
|
||||||
|
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci
|
||||||
|
COMMENT = 'ตารางเก็บ Running Number Counters';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.11.15.2. Index Requirements
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Index สำหรับ Performance
|
||||||
|
CREATE INDEX idx_counter_lookup
|
||||||
|
ON document_number_counters (
|
||||||
|
project_id,
|
||||||
|
correspondence_type_id,
|
||||||
|
current_year
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Index สำหรับ Originator lookup
|
||||||
|
CREATE INDEX idx_counter_org
|
||||||
|
ON document_number_counters (
|
||||||
|
originator_organization_id,
|
||||||
|
current_year
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.11.15.3. Important Notes
|
||||||
|
|
||||||
|
> **💡 Counter Key Design**
|
||||||
|
> - ใช้ `COALESCE(recipient_organization_id, 0)` ใน Primary Key เพื่อรองรับ NULL
|
||||||
|
> - `version` column สำหรับ Optimistic Locking (ป้องกัน race condition)
|
||||||
|
> - `last_number` เริ่มจาก 0 และเพิ่มขึ้นทีละ 1
|
||||||
|
> - Counter reset ทุกปี (เมื่อ `current_year` เปลี่ยน)
|
||||||
|
|
||||||
|
> **⚠️ Migration Notes**
|
||||||
|
> - ไม่มีข้อมูลเก่า ไม่ต้องทำ backward compatibility
|
||||||
|
> - สามารถสร้าง table ใหม่ได้เลยตาม schema ข้างต้น
|
||||||
|
> - ต้องมี seed data สำหรับ `correspondence_types`, `rfa_types`, `disciplines` ก่อน
|
||||||
|
|
||||||
|
### 3.11.15.4. Example Counter Records
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Example: LETTER from คคง. to สคฉ.3 in LCBP3-C2 year 2025
|
||||||
|
INSERT INTO document_number_counters (
|
||||||
|
project_id, originator_organization_id, recipient_organization_id,
|
||||||
|
correspondence_type_id, sub_type_id, rfa_type_id, discipline_id,
|
||||||
|
current_year, version, last_number
|
||||||
|
) VALUES (
|
||||||
|
2, -- LCBP3-C2
|
||||||
|
22, -- คคง.
|
||||||
|
10, -- สคฉ.3
|
||||||
|
6, -- LETTER
|
||||||
|
0, 0, 0,
|
||||||
|
2025, 0, 0
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Example: RFA from ผรม.2 in LCBP3-C2, discipline TER, type RPT, year 2025
|
||||||
|
INSERT INTO document_number_counters (
|
||||||
|
project_id, originator_organization_id, recipient_organization_id,
|
||||||
|
correspondence_type_id, sub_type_id, rfa_type_id, discipline_id,
|
||||||
|
current_year, version, last_number
|
||||||
|
) VALUES (
|
||||||
|
2, -- LCBP3-C2
|
||||||
|
42, -- ผรม.2
|
||||||
|
NULL, -- RFA ไม่มี specific recipient
|
||||||
|
1, -- RFA
|
||||||
|
0,
|
||||||
|
18, -- RPT (Report)
|
||||||
|
5, -- TER (Terminal)
|
||||||
|
2025, 0, 0
|
||||||
|
);
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user