# Design: แผนการเบิกจ่ายเป็นงวด (Research Disbursement Plan) **Date:** 2026-06-17 **Page:** `http://localhost:4200/app/agency-report-research` (typeUrl=27) **Approved by:** User --- ## 1. Summary เพิ่มฟีเจอร์ "แผนการเบิกจ่ายเป็นงวด" ให้กับหน้า `agency-report-research` โดยมีปุ่มไอคอนต่อแต่ละโครงการในตาราง list20-research เมื่อกดจะเปิด MatDialog popup สำหรับกรอก/แก้ไขแผนการเบิกจ่าย 3 งวด พร้อมบันทึกลง DB ผ่าน API เดิม --- ## 2. Data Model ### 2.1 Backend — เพิ่ม 6 field ใน `change_project_research_detail` | Field | Type | Description | |-------|------|-------------| | `disbursement_1_amount` | `decimal?` | จำนวนเงิน งวดที่ 1 | | `disbursement_1_date` | `DateTime?` | ว/ด/ป งวดที่ 1 | | `disbursement_2_amount` | `decimal?` | จำนวนเงิน งวดที่ 2 | | `disbursement_2_date` | `DateTime?` | ว/ด/ป งวดที่ 2 | | `disbursement_last_amount` | `decimal?` | จำนวนเงิน งวดสุดท้าย | | `disbursement_last_date` | `DateTime?` | ว/ด/ป งวดสุดท้าย | **ทำไม:** เก็บข้อมูลบน record เดิม ไม่ต้องสร้างตารางใหม่ ข้อมูลต่อโครงการมีเพียง 1 ชุด (3 งวด) **หมายเหตุ:** `รวมเบิกจ่ายทั้งสิ้น` คำนวณใน frontend (sum ของ 3 amount) ไม่เก็บใน DB ### 2.2 Migration ไฟล์: `Migrations/YYYYMMDDHHMMSS_disbursement_plan_research.cs` - `AddColumn` ทั้ง 6 field ใน table `change_project_research_detail` schema `BUDGET` --- ## 3. Architecture ### 3.1 Backend (ASP.NET Core) - **ไม่ต้องสร้าง controller ใหม่** — `t_change_project_research_detail` มี `[GeneratedUidController]` อยู่แล้ว - เพิ่ม field ในโมเดล → migration → deploy - PUT endpoint เดิม `/api/request_budget/change_project_research_detail/{uid}` รองรับ field ใหม่โดยอัตโนมัติ ### 3.2 Frontend (Angular) ``` list20-research component └─ เพิ่ม Output: onDisbursementPlan (EventEmitter) └─ เพิ่มคอลัมน์ "แผนเบิกจ่าย" + ปุ่มไอคอน request-budget-statistics.container └─ handle onDisbursementPlan → เปิด MatDialog DisbursementPlanResearchDialogComponent (ใหม่) ├─ Input: data (change_project_research_detail row) ├─ Form: disbursement_1_amount, disbursement_1_date, disbursement_2_amount, disbursement_2_date, disbursement_last_amount, disbursement_last_date ├─ Computed: total = sum(amounts) └─ Save: PUT via ChangeProjectResearchDetailService ``` --- ## 4. UI Design ### 4.1 ตาราง list20-research — คอลัมน์เพิ่มใหม่ | คอลัมน์ | เนื้อหา | |---------|---------| | แผนเบิกจ่าย | badge "✓ กรอกแล้ว" (สีเขียว) ถ้า disbursement_1_amount ไม่ null, badge "ยังไม่กรอก" (สีเทา) ถ้ายังไม่มีข้อมูล | | เครื่องมือ | เพิ่มปุ่มไอคอนเงิน (💰) ก่อนปุ่ม edit — สีเขียวเข้มถ้ากรอกแล้ว, สีเขียวอ่อนถ้ายังไม่กรอก | ### 4.2 Dialog — ตาราง ``` ┌─────────────────────────────────────────────┬──────────────────┐ │ แผนการเบิกจ่ายเงิน │ รวมเบิกจ่าย │ ├──────────────┬──────────────┬───────────────┤ ทั้งสิ้น (บาท) │ │ งวดที่ 1 │ งวดที่ 2 │ งวดสุดท้าย │ │ ├──────┬───────┼──────┬───────┼──────┬────────┤ │ │ จำนวน│ ว/ด/ป │ จำนวน│ ว/ด/ป │ จำนวน│ ว/ด/ป │ [คำนวณอัตโนมัติ] │ │ เงิน │ │ เงิน │ │ เงิน │ │ │ ├──────┼───────┼──────┼───────┼──────┼────────┼──────────────────┤ │ input│ date │ input│ date │ input│ date │ readonly computed │ └──────┴───────┴──────┴───────┴──────┴────────┴──────────────────┘ ``` - Input จำนวนเงิน: ใช้ `appCurrencyInputMask` (pattern เดิมในโปรเจกต์) - Input วันที่: `mat-datepicker` - รวม: คำนวณ real-time ด้วย getter ### 4.3 Actions - **บันทึก**: confirmSave → PUT detail → updateSuccess → close dialog → reload list - **ยกเลิก**: ปิด dialog ไม่บันทึก --- ## 5. Files to Create/Modify ### Backend | File | Action | |------|--------| | `Modules/RequestBudgets/Databases/Models/change_project_research_detail.cs` | เพิ่ม 6 field | | `Migrations/YYYYMMDDHHMMSS_disbursement_plan_research.cs` | สร้างใหม่ | ### Frontend | File | Action | |------|--------| | `presenter/popup/disbursement-plan-research-dialog/disbursement-plan-research-dialog.component.ts` | สร้างใหม่ | | `presenter/popup/disbursement-plan-research-dialog/disbursement-plan-research-dialog.component.html` | สร้างใหม่ | | `presenter/popup/disbursement-plan-research-dialog/disbursement-plan-research-dialog.component.scss` | สร้างใหม่ | | `presenter/list/.../list20-research/list20-research.component.html` | เพิ่มคอลัมน์ + ปุ่ม | | `presenter/list/.../list20-research/list20-research.component.ts` | เพิ่ม Output onDisbursementPlan | | `container/.../request-budget-statistics.container.ts` | handle event + เปิด dialog | | `request-budget-statistics.module.ts` | ลงทะเบียน component ใหม่ | --- ## 6. Error Handling - ถ้า save ล้มเหลว: แสดง `swSV.errText(err?.error?.description)` - Dialog ใช้ `ChangeDetectionStrategy.OnPush` + `cdRef.detectChanges()` ตาม pattern เดิม --- ## 7. Out of Scope - ไม่สร้างหน้าแยก (ใช้ dialog แทน) - ไม่รองรับหลายชุดแผนต่อโครงการ (1 โครงการ = 1 แผน) - ไม่เพิ่ม column ใน list view (แสดงเฉพาะใน dialog)