From 29f2da97dab630ffbe35c62e127930bf0af1fd23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nut=2E=E0=B9=84=E0=B8=9B=E0=B9=80=E0=B8=A3=E0=B8=B7?= =?UTF-8?q?=E0=B9=88=E0=B8=AD=E0=B8=A2?= Date: Mon, 7 Sep 2026 19:56:58 +0700 Subject: [PATCH] docs: mark income-budget-review plan tasks complete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All backend (Tasks 1-3) and frontend (Tasks 4-7) code written, deployed to production, and verified end-to-end (Task 8) via a synthetic test record — except Task 7's manual browser click-through, which needs the user's own login to confirm visually. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_0153wBt23EjW125ZsADwWVAs --- .../2026-09-07-income-budget-review-stage.md | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/docs/superpowers/plans/2026-09-07-income-budget-review-stage.md b/docs/superpowers/plans/2026-09-07-income-budget-review-stage.md index 34140ff..b2dc7f9 100644 --- a/docs/superpowers/plans/2026-09-07-income-budget-review-stage.md +++ b/docs/superpowers/plans/2026-09-07-income-budget-review-stage.md @@ -54,7 +54,7 @@ frontend เพิ่ม dashboard component (reuse pattern จาก `income-re (1=รอตรวจสอบ, 2=ส่งแก้ไข, 3=ตรวจสอบแล้ว), `remark: string`, บวก field จาก `base_table` (`created_by`, `created_datetime`, `updated_by`, `updated_datetime`, `owner_agency_uid`, `status_id`) -- [ ] **Step 1: สร้างโมเดล C#** +- [x] **Step 1: สร้างโมเดล C#** ```csharp // rmutr-api/Modules/IncomeBudgetReview/Databases/Models/income_budget_review.cs @@ -80,7 +80,7 @@ namespace rmutr_budget_api.Modules.IncomeBudgetReview.Databases.Models } ``` -- [ ] **Step 2: สร้าง `Db.cs` ของโมดูลนี้ (DbSet + ToTable)** +- [x] **Step 2: สร้าง `Db.cs` ของโมดูลนี้ (DbSet + ToTable)** ```csharp // rmutr-api/Modules/IncomeBudgetReview/Databases/Db.cs @@ -101,7 +101,7 @@ namespace SeventyOneDev.Utilities } ``` -- [ ] **Step 3: เรียก `OnIncomeBudgetReviewModelCreating` จากจุดกลาง** +- [x] **Step 3: เรียก `OnIncomeBudgetReviewModelCreating` จากจุดกลาง** แก้ `rmutr-api/Databases/Db.cs` — ในเมธอด `OnApplicationModelCreating` เพิ่มบรรทัดสุดท้าย: @@ -111,7 +111,7 @@ namespace SeventyOneDev.Utilities } ``` -- [ ] **Step 4: เขียน migration SQL (idempotent เหมือนไฟล์อื่นในโฟลเดอร์เดียวกัน)** +- [x] **Step 4: เขียน migration SQL (idempotent เหมือนไฟล์อื่นในโฟลเดอร์เดียวกัน)** ```sql -- rmutr-api/Migrations/add_income_budget_review.sql @@ -138,7 +138,7 @@ CREATE INDEX IF NOT EXISTS ix_income_budget_review_request_expense_uid ON "{0}".income_budget_review (request_expense_uid); ``` -- [ ] **Step 5: ลงทะเบียน migration ใน `Startup.cs`** +- [x] **Step 5: ลงทะเบียน migration ใน `Startup.cs`** แก้ `rmutr-api/Startup.cs` — เพิ่มบรรทัดต่อจาก `add_faculty_uid_to_budget_income.sql` (ประมาณบรรทัด 486): @@ -147,12 +147,12 @@ CREATE INDEX IF NOT EXISTS ix_income_budget_review_request_expense_uid ApplyRawSqlMigration(dbContext, setting.Value.default_schema, "add_income_budget_review.sql"); ``` -- [ ] **Step 6: Build ตรวจสอบว่าไม่มี compile error** +- [x] **Step 6: Build ตรวจสอบว่าไม่มี compile error** Run: `cd rmutr-api && dotnet build -v q` Expected: `0 Error(s)` (มี warning เดิมได้ ไม่เกี่ยวกับ task นี้) -- [ ] **Step 7: Commit** +- [x] **Step 7: Commit** ```bash cd rmutr-api @@ -177,7 +177,7 @@ Co-Authored-By: Claude Sonnet 5 " ส่วนกลางแล้วอนุมัติผ่านใหม่) และ `request_approve_type == "04"` จะมี `t_income_budget_review` แถวใหม่ `review_status_id = 1` เกิดขึ้นเสมอ -- [ ] **Step 1: หาจุด insert ใน `ApproveGetEntity` (branch `request_expense`)** +- [x] **Step 1: หาจุด insert ใน `ApproveGetEntity` (branch `request_expense`)** เปิด `rmutr-api/Modules/Setting/Controllers/ApproveState.cs` หา block นี้ (อยู่ในเมธอด `ApproveGetEntity`, branch `if (request_expense != null)`): @@ -194,7 +194,7 @@ Co-Authored-By: Claude Sonnet 5 " } ``` -- [ ] **Step 2: แก้ไข block นี้ให้ log "รอตรวจสอบ" เมื่อ type เป็น "04"** +- [x] **Step 2: แก้ไข block นี้ให้ log "รอตรวจสอบ" เมื่อ type เป็น "04"** แทนที่ block ด้านบนด้วย: @@ -225,7 +225,7 @@ Co-Authored-By: Claude Sonnet 5 " } ``` -- [ ] **Step 3: เพิ่ม `using` ที่หัวไฟล์** +- [x] **Step 3: เพิ่ม `using` ที่หัวไฟล์** เปิด `rmutr-api/Modules/Setting/Controllers/ApproveState.cs` เพิ่มบรรทัด using (หลัง using เดิมบรรทัดที่ 18): @@ -233,12 +233,12 @@ Co-Authored-By: Claude Sonnet 5 " using rmutr_budget_api.Modules.IncomeBudgetReview.Databases.Models; ``` -- [ ] **Step 4: Build** +- [x] **Step 4: Build** Run: `cd rmutr-api && dotnet build -v q` Expected: `0 Error(s)` -- [ ] **Step 5: Commit** +- [x] **Step 5: Commit** ```bash cd rmutr-api @@ -272,7 +272,7 @@ Co-Authored-By: Claude Sonnet 5 " → `200 OK` หรือ `400 { description }` - `POST /api/income_budget_review/mark_reviewed/{request_expense_uid}` → `200 OK` หรือ `400 { description }` -- [ ] **Step 1: เขียน DTO + Service** +- [x] **Step 1: เขียน DTO + Service** ```csharp // rmutr-api/Modules/IncomeBudgetReview/Services/IncomeBudgetReview.cs @@ -517,7 +517,7 @@ namespace rmutr_budget_api.Modules.IncomeBudgetReview.Services } ``` -- [ ] **Step 2: เขียน Controller** +- [x] **Step 2: เขียน Controller** ```csharp // rmutr-api/Modules/IncomeBudgetReview/Controllers/IncomeBudgetReview.cs @@ -592,7 +592,7 @@ namespace rmutr_budget_api.Modules.IncomeBudgetReview.Controllers } ``` -- [ ] **Step 3: เขียน Configure (DI registration) แล้วเรียกจาก `Startup.cs`** +- [x] **Step 3: เขียน Configure (DI registration) แล้วเรียกจาก `Startup.cs`** ```csharp // rmutr-api/Modules/IncomeBudgetReview/Configures/IncomeBudgetReview.cs @@ -620,12 +620,12 @@ namespace rmutr_budget_api.Modules.IncomeBudgetReview.Configures services.AddIncomeBudgetReviewServices(); ``` -- [ ] **Step 4: Build** +- [x] **Step 4: Build** Run: `cd rmutr-api && dotnet build -v q` Expected: `0 Error(s)` -- [ ] **Step 5: Deploy ไปเซิร์ฟเวอร์จริงเพื่อทดสอบ** +- [x] **Step 5: Deploy ไปเซิร์ฟเวอร์จริงเพื่อทดสอบ** ```bash cd rmutr-api @@ -641,7 +641,7 @@ curl -sS -o /dev/null -w "HTTP %{http_code}\n" https://rmis.rmutr.ac.th/budget-a Expected: `HTTP 401` (service ขึ้นปกติ, endpoint ต้อง auth) -- [ ] **Step 6: ทดสอบ endpoint จริงด้วย token ที่ mint เอง (วิธีเดียวกับที่ใช้ทดสอบ my_dashboard ก่อนหน้านี้)** +- [x] **Step 6: ทดสอบ endpoint จริงด้วย token ที่ mint เอง (วิธีเดียวกับที่ใช้ทดสอบ my_dashboard ก่อนหน้านี้)** ```bash python3 - <<'EOF' > /tmp/token.txt @@ -663,7 +663,7 @@ curl -sS -H "Authorization: Bearer $TOKEN" \ Expected: `HTTP:200` กับ `{"pending":[],"returned":[],"reviewed":[]}` (ว่างเปล่าเพราะยังไม่มีเรื่องไหนผ่าน Task 2's trigger เลยตอนนี้ — ถูกต้องแล้ว จะมีข้อมูลจริงหลัง Task 2 ถูก exercise จากการอนุมัติจริงในระบบ) -- [ ] **Step 7: Commit** +- [x] **Step 7: Commit** ```bash cd rmutr-api @@ -686,7 +686,7 @@ git push origin master - Produces: `IncomeBudgetReviewService` with methods `getStatus(uid)`, `getDashboard()`, `returnForEdit(uid, remark)`, `markReviewed(uid)` — เรียก endpoint จาก Task 3 -- [ ] **Step 1: เขียน service** +- [x] **Step 1: เขียน service** ```typescript // rmutr-web/src/app/core/service/income-budget-review/income-budget-review.service.ts @@ -721,12 +721,12 @@ export class IncomeBudgetReviewService { } ``` -- [ ] **Step 2: Build ตรวจสอบว่า Angular compile ผ่าน** +- [x] **Step 2: Build ตรวจสอบว่า Angular compile ผ่าน** Run: `cd rmutr-web && node --max_old_space_size=14336 node_modules/@angular/cli/bin/ng build --configuration production --base-href /budget-web/ 2>&1 | tail -20` Expected: build จบโดยไม่มี error (มี warning เดิมได้) -- [ ] **Step 3: Commit** +- [x] **Step 3: Commit** ```bash cd rmutr-web @@ -753,7 +753,7 @@ Co-Authored-By: Claude Sonnet 5 " `{ request_expense_uid, budget_year_uid, budget_year_name_th, faculty_uid, faculty_name_th, budget_location_uid, budget_location_name_th }` -- [ ] **Step 1: สร้างโฟลเดอร์และ component (โครงเดียวกับ `income-report-approve-dashboard` ที่มีอยู่แล้ว)** +- [x] **Step 1: สร้างโฟลเดอร์และ component (โครงเดียวกับ `income-report-approve-dashboard` ที่มีอยู่แล้ว)** ```typescript // income-budget-review-dashboard.component.ts @@ -828,7 +828,7 @@ export class IncomeBudgetReviewDashboardComponent implements OnInit { } ``` -- [ ] **Step 2: เขียน template** +- [x] **Step 2: เขียน template** ```html @@ -860,7 +860,7 @@ export class IncomeBudgetReviewDashboardComponent implements OnInit { ``` -- [ ] **Step 3: เขียน style (คัดลอกจาก `income-report-approve-dashboard.component.scss` ทั้งไฟล์)** +- [x] **Step 3: เขียน style (คัดลอกจาก `income-report-approve-dashboard.component.scss` ทั้งไฟล์)** ```bash cp rmutr-web/src/app/feature/income-report/presenter/dashboard/income-report-approve-dashboard/income-report-approve-dashboard.component.scss \ @@ -870,7 +870,7 @@ cp rmutr-web/src/app/feature/income-report/presenter/dashboard/income-report-app (เนื้อหา scss เดิมใช้ได้เลย — class names `.dashboard-card`, `.chip`, `.chip-warn`, `.chip-success`, `.item-list`, `.item-row`, `.item-empty` ตรงกันกับ template ด้านบนทุกตัว) -- [ ] **Step 4: ประกาศ component ใน module** +- [x] **Step 4: ประกาศ component ใน module** แก้ `rmutr-web/src/app/feature/budget-request/request-budget-plan/request-budget-plan.module.ts` เพิ่ม import และใส่เข้า `declarations`: @@ -881,12 +881,12 @@ import { IncomeBudgetReviewDashboardComponent } from './presenter/dashboard/inco ใน `declarations: [...]` เพิ่ม `IncomeBudgetReviewDashboardComponent,` ต่อจาก `RequestBudgetListComponent,` -- [ ] **Step 5: Build** +- [x] **Step 5: Build** Run: `cd rmutr-web && node --max_old_space_size=14336 node_modules/@angular/cli/bin/ng build --configuration production --base-href /budget-web/ 2>&1 | tail -20` Expected: build ผ่าน ไม่มี error -- [ ] **Step 6: Commit** +- [x] **Step 6: Commit** ```bash cd rmutr-web @@ -913,7 +913,7 @@ Co-Authored-By: Claude Sonnet 5 " — `showActions=true` ที่ plan-02 (โชว์ปุ่ม), `false` ที่ plan-01 (โชว์อย่างเดียว) `(onchanged)` emit เมื่อกดปุ่มสำเร็จ ให้ container โหลดข้อมูลใหม่ -- [ ] **Step 1: เขียน component** +- [x] **Step 1: เขียน component** ```typescript // income-budget-review-status.component.ts @@ -1028,7 +1028,7 @@ export class IncomeBudgetReviewStatusComponent implements OnChanges { } ``` -- [ ] **Step 2: เขียน template** +- [x] **Step 2: เขียน template** ```html @@ -1066,7 +1066,7 @@ export class IncomeBudgetReviewStatusComponent implements OnChanges { ``` -- [ ] **Step 3: เขียน style** +- [x] **Step 3: เขียน style** ```scss // income-budget-review-status.component.scss @@ -1138,7 +1138,7 @@ export class IncomeBudgetReviewStatusComponent implements OnChanges { } ``` -- [ ] **Step 4: ประกาศ component ใน module** +- [x] **Step 4: ประกาศ component ใน module** แก้ `rmutr-web/src/app/feature/budget-request/request-budget-plan/request-budget-plan.module.ts` เพิ่ม import และใส่เข้า `declarations`: @@ -1149,12 +1149,12 @@ import { IncomeBudgetReviewStatusComponent } from './presenter/status/income-bud ใน `declarations: [...]` เพิ่ม `IncomeBudgetReviewStatusComponent,` -- [ ] **Step 5: Build** +- [x] **Step 5: Build** Run: `cd rmutr-web && node --max_old_space_size=14336 node_modules/@angular/cli/bin/ng build --configuration production --base-href /budget-web/ 2>&1 | tail -20` Expected: build ผ่าน ไม่มี error -- [ ] **Step 6: Commit** +- [x] **Step 6: Commit** ```bash cd rmutr-web @@ -1178,7 +1178,7 @@ Co-Authored-By: Claude Sonnet 5 " - Produces: ปุ่ม/สถานะแสดงผลจริงที่ `income-budget-plan-01` (`keyUrl==201`) และ `income-budget-plan-02` (`keyUrl==202`) — dashboard บน plan-02 เท่านั้น, status badge ทั้งสองหน้า -- [ ] **Step 1: เพิ่ม dashboard (เฉพาะ plan-02) เหนือฟอร์มค้นหา** +- [x] **Step 1: เพิ่ม dashboard (เฉพาะ plan-02) เหนือฟอร์มค้นหา** แก้ `request-budget.container.html` เพิ่มก่อนบรรทัดแรก (`
" > ``` -- [ ] **Step 2: เพิ่ม status component (ทั้งสองหน้า) หลังฟอร์มค้นหา ก่อน list** +- [x] **Step 2: เพิ่ม status component (ทั้งสองหน้า) หลังฟอร์มค้นหา ก่อน list** แก้ `request-budget.container.html` เพิ่มหลัง `` (บรรทัด 14) ก่อน `" > ``` -- [ ] **Step 3: เพิ่มเมธอด `onSelectReviewDashboardItem` ใน container** +- [x] **Step 3: เพิ่มเมธอด `onSelectReviewDashboardItem` ใน container** `RequestBudgetContainer.onClickSearch(query)` (มีอยู่แล้ว) รับ query object อิสระได้เลยโดยไม่ต้องมาจาก `RequestBudgetSearchComponent` เสมอไป (แค่ต้องมี `budget_year_uid`/`faculty_uid`/`budget_location_uid` @@ -1229,12 +1229,12 @@ dashboard ของตัวเอง (`IncomeReportContainer.onSelectDashboardI } ``` -- [ ] **Step 4: Build** +- [x] **Step 4: Build** Run: `cd rmutr-web && node --max_old_space_size=14336 node_modules/@angular/cli/bin/ng build --configuration production --base-href /budget-web/ 2>&1 | tail -20` Expected: build ผ่าน ไม่มี error -- [ ] **Step 5: Deploy ไปเซิร์ฟเวอร์จริง** +- [x] **Step 5: Deploy ไปเซิร์ฟเวอร์จริง** ```bash cd rmutr-web @@ -1252,7 +1252,7 @@ remark ในตาราง "รายละเอียดสำหรับ `https://rmis.rmutr.ac.th/budget-web/app/income-budget-plan-01` ค้นหาเรื่องเดียวกัน ต้องเห็น badge "ถูกส่งแก้ไข" เช่นกัน (ไม่มีปุ่ม) -- [ ] **Step 7: Commit** +- [x] **Step 7: Commit** ```bash cd rmutr-web @@ -1269,7 +1269,7 @@ git push origin master **Files:** ไม่มีไฟล์ใหม่ — task นี้คือ verify ผ่าน SQL + curl ตรงกับ production ตามรูปแบบที่ใช้ตลอด session -- [ ] **Step 1: หาเรื่องจริงในระบบที่ใกล้จะอนุมัติผ่านครบ (หรือสร้างเคสทดสอบด้วย SQL)** +- [x] **Step 1: หาเรื่องจริงในระบบที่ใกล้จะอนุมัติผ่านครบ (หรือสร้างเคสทดสอบด้วย SQL)** ```bash python3 - <<'EOF' @@ -1287,7 +1287,7 @@ for r in cur.fetchall(): print(r) EOF ``` -- [ ] **Step 2: ยืนยันว่า trigger (Task 2) ทำงานจริงหลังมีเรื่องอนุมัติผ่านครบในระบบจริง** +- [x] **Step 2: ยืนยันว่า trigger (Task 2) ทำงานจริงหลังมีเรื่องอนุมัติผ่านครบในระบบจริง** ```bash python3 - <<'EOF' @@ -1302,12 +1302,12 @@ EOF Expected: มากกว่า 0 หลังมีการอนุมัติจริงผ่านระบบครบอย่างน้อย 1 เรื่องนับจากตอน deploy Task 2 -- [ ] **Step 3: ยืนยัน dashboard endpoint คืนค่าตรงกับ SQL** +- [x] **Step 3: ยืนยัน dashboard endpoint คืนค่าตรงกับ SQL** เทียบ `GET /api/income_budget_review/dashboard` (ด้วย token จาก Task 3 Step 6) กับผลจาก `SELECT` ตรงในขั้นตอนที่ 1-2 ว่าจำนวนตรงกัน -- [ ] **Step 4: สรุปผลให้ผู้ใช้** +- [x] **Step 4: สรุปผลให้ผู้ใช้** รายงานว่าทดสอบผ่านจริงกี่เคส (รอตรวจสอบ → ส่งแก้ไข → กลับไป income-report เห็น remark → อนุมัติใหม่ → กลับมา "รอตรวจสอบ" อีกครั้ง → กด "ตรวจสอบแล้ว" จบ) ก่อนถือว่าเสร็จงาน