Files
rmutr/docs/superpowers/specs/2026-07-22-in-plan-report-submit-review-fix-design.md
T
2026-07-22 07:56:59 +07:00

92 lines
12 KiB
Markdown

# รายงานผล(ในแผน) — แก้บั๊กปุ่ม "ส่งให้กองแผนตรวจสอบ" + ล็อกฟอร์ม
## บริบท
หน้า "หน่วยงานทำรายงานผล" (`agency-report-form/list-all`, typeUrl `20`, component `MakeYearPlanFormComponent` ที่ `make-year-plant-form.component.ts`) ให้หน่วยงานติ๊กเลือกแถวที่กรอกรายงานผลแล้ว (`item.value.agency_report`) แล้วกดปุ่ม "ส่งให้กองแผนตรวจสอบ" (html:1036-1040, แสดงเมื่อ `typeUrl == 20 && isListAllMode()`)
**บั๊กปัจจุบัน**: เมธอด `save()` (ts:2377) เช็ค `if(this.isListAllMode())` เป็นเงื่อนไขแรกสุดและ `return` ทันที (ts:2380-2409) `isListAllMode()` (ts:159-161) คืนค่า `true` เมื่อ `state === 'add' && typeUrl ∈ {12,14,20}` — เนื่องจาก route `list-all` ไม่มี `:id` พารามิเตอร์ `state` จึงเป็น `'add'` เสมอ ทำให้ผู้ใช้ที่กด "ส่งให้กองแผนตรวจสอบ" (typeUrl 20) ตกเข้า branch `isListAllMode()` ซึ่งเป็น logic คนละเรื่อง (group ตาม `change_project_uid` แล้ว `ChangeProjectSV.put()`) — **ไม่อ่าน `this.selection.selected` เลย และไม่เรียก `AgencyReportSV.updateStatusAgency()`** จึงไม่มีการส่งสถานะ `agency_report.status_id` ไปกองแผนจริงๆ
Branch `else if(this.typeUrl == 20)` (ts:2439-2508) ที่ทำงานถูกต้องสมบูรณ์อยู่แล้ว (อ่าน `selection.selected` → กรองแถวที่มี `agency_report.agency_report_uid` → ตั้ง `status_id=1``AgencyReportSV.updateStatusAgency()`) จึงเป็น **dead code** ที่ไม่มีทางถูกเรียกถึงจากปุ่มนี้
ฝั่งกองแผน (`check-project-report`, typeUrl `16`) ทำงานสมบูรณ์อยู่แล้ว — 3 แท็บ (รอตรวจสอบ/ส่งแก้ไข/ตรวจสอบแล้ว ตาม `status_id` 1/2/3), ปุ่ม `save_send()`/`save_pass()` ใน `agency-report-form.component.ts` เรียก backend จริง (`PUT`) — **ไม่ต้องแก้ฝั่งนี้**
สิ่งที่ขาดเพิ่มเติมเมื่อเทียบกับ flow "รายงานนอกแผน" ที่เพิ่งทำ (`2026-07-21-out-of-plan-report-review-design.md`): list-all ไม่มี badge สถานะ/ไม่มีการกันติ๊กซ้ำ และฟอร์มรายงานฝั่งหน่วยงาน (typeUrl `202`) ไม่ถูกล็อกเมื่อสถานะเป็นรอตรวจสอบ/ตรวจสอบแล้ว (ทั้งที่ flow นอกแผน (typeUrl `282`) มี pattern นี้อยู่แล้ว)
## ขอบเขต
- แก้จุดเดียวใน `save()` ของ `make-year-plant-form.component.ts` ให้ typeUrl 20 ไม่ถูก `isListAllMode()` ดักก่อน — ไม่แก้ definition ของ `isListAllMode()` เอง (กระทบจุดอื่นในเทมเพลตน้อยที่สุด)
- เพิ่ม `[disabled]` บน checkbox ของ list-all (เฉพาะ typeUrl 20) + เพิ่ม badge สถานะข้างปุ่ม "เพิ่ม/แก้ไขรายงาน"
- เพิ่ม form-lock (`isLocked` + `form.disable()`) ให้ branch `typeUrl == 202` ใน `agency-report-form.component.ts` มิเรอร์ pattern เดียวกับ branch นอกแผน (`typeUrl == 282`) ที่มีอยู่แล้ว
- ไม่แตะ `check-project-report` (typeUrl 16), ไม่แตะ backend, ไม่แตะ flow ของรายงานนอกแผน (typeUrl 28x/29x) ที่ทำไปแล้วเมื่อวาน
- ไม่แก้ `isListAllMode()` สำหรับ typeUrl 12/14 — พฤติกรรมเดิมของสองตัวนี้ต้องเหมือนเดิมทุกประการ
## การเปลี่ยนแปลงที่ต้องทำ
### 1. แก้ `save()` dispatch bug (`make-year-plant-form.component.ts:2380`)
```ts
if(this.isListAllMode() && this.typeUrl !== 20){
```
(เดิม: `if(this.isListAllMode()){`)
ผล: typeUrl 20 ตกไปที่ `else if(this.typeUrl == 20)` (ts:2439) ซึ่งมี `switch(this.state)` — เนื่องจาก `state` เป็น `'add'` เสมอบน route นี้ จะเข้า `case 'add':` (ts:2457-2478) ที่ทำงานถูกต้องอยู่แล้วโดยไม่ต้องแก้เพิ่ม (validate `updateForm.length`, `confirmSave()`, `updateStatusAgency()`, `saveSuccess()`, `loadAllDetails()`)
typeUrl 12/14 ยังคง `isListAllMode() === true` และเงื่อนไข `&& this.typeUrl !== 20` ไม่กระทบ จึงยังตกเข้า branch เดิม (ChangeProjectSV.put) เหมือนเดิมทุกประการ
### 2. Checkbox disable + status badge (`make-year-plan-form.component.html` รอบบรรทัด 474-493)
Checkbox (html:474-479) เพิ่ม:
```html
[disabled]="typeUrl == 20 && (item.value.agency_report?.agency_report_uid == null || item.value.agency_report?.status_id === 1 || item.value.agency_report?.status_id === 3)"
```
ข้าง `report-btn` (หลังบรรทัด 492) เพิ่ม badge อ่านจาก `item.value.agency_report?.status_id` (แสดงเฉพาะเมื่อ `agency_report_uid != null`):
| status_id | ป้าย | สี |
|---|---|---|
| 0 / null | ร่าง | เทา |
| 1 | รอตรวจสอบ | เหลือง (ใช้โทนเดียวกับ badge "นอกแผน" ที่มีอยู่แล้ว: `#fef3c7`/`#92400e`) |
| 2 | ส่งแก้ไข | แดง/ส้ม |
| 3 | ตรวจสอบแล้ว | เขียว |
```html
<span *ngIf="typeUrl == 20 && item.value.agency_report?.agency_report_uid != null"
[style.background]="reportStatusBadge(item.value.agency_report?.status_id).bg"
[style.color]="reportStatusBadge(item.value.agency_report?.status_id).color"
style="display:inline-block;padding:2px 8px;border-radius:10px;font-size:10px;font-weight:600;margin-top:3px;white-space:nowrap;">
{{reportStatusBadge(item.value.agency_report?.status_id).label}}
</span>
```
เพิ่มเมธอด helper `reportStatusBadge(status_id)` ใน `make-year-plant-form.component.ts` คืนค่า `{label, bg, color}` ตามตารางด้านบน (ค่า default เมื่อ `status_id` เป็น `0`/`null`/`undefined` คือ "ร่าง")
### 3. ล็อกฟอร์มรายงานฝั่งหน่วยงาน (`agency-report-form.component.ts`, branch `typeUrl == 202`)
หา branch `typeUrl == 202` (ใน `case 'edit':`, cf. ts:469-508 ตามผลสำรวจ) เพิ่มก่อน `Swal.close()` เหมือนที่ branch `282` มี (ts:555-558):
```ts
if (x.status_id === 1 || x.status_id === 3) {
this.isLocked = true
this.form.disable()
}
```
(ไม่ต้องเช็ค `out_of_plan_report_detail_uid` ในเงื่อนไขนี้ เพราะ branch `202` ใช้กับรายงานในแผนเท่านั้นอยู่แล้ว)
ปุ่ม "บันทึก"/badge locked banner ที่มีอยู่แล้วในเทมเพลต (gate ด้วย `isLocked`, ไม่ผูกกับ typeUrl เฉพาะ) ทำงานอัตโนมัติกับ branch นี้โดยไม่ต้องแก้เทมเพลตเพิ่ม — ปุ่ม `save_send()`/`save_pass()` (typeUrl 202161) ไม่ถูกกระทบเพราะไม่ได้ gate ด้วย `!isLocked` และใช้ `getRawValue()` ที่อ่านค่าจาก disabled control ได้ปกติ
## Error handling
- กดส่งโดยไม่ติ๊กแถวที่มีรายงาน: error text เดิม "กรุณาเลือกรายการที่ต้องการส่ง" (มีอยู่แล้ว ts:2459)
- API `update_status` ล้มเหลว: `errText(err.error?.description ?? 'เกิดข้อผิดพลาด')` เดิม (ts:2467-2470) ไม่ rollback selection
- guard การเลือกแถวซ้ำเป็น client-side เท่านั้น (checkbox disabled) ไม่มี guard เพิ่มฝั่ง backend — สอดคล้องกับ pattern เดิมของโปรเจกต์ (เหมือน flow นอกแผน)
## Testing (manual/browser)
1. เข้า `agency-report-form/list-all` (typeUrl 20) → เห็น badge "ร่าง" บนแถวที่กรอกรายงานแล้วแต่ยังไม่ส่ง, ไม่มี badge บนแถวที่ยังไม่มีรายงาน
2. ติ๊กแถวที่มีรายงานสถานะ "ร่าง" 1-2 แถว → กด "ส่งให้กองแผนตรวจสอบ" → ยืนยัน error ไม่ขึ้นถ้ามีเลือกอยู่ → หลังส่งสำเร็จ badge เปลี่ยนเป็น "รอตรวจสอบ" และ checkbox แถวนั้น disabled ไปโดยอัตโนมัติ (reload)
3. กด "ส่ง" โดยไม่ติ๊กอะไร (หรือติ๊กเฉพาะแถวที่ยังไม่มีรายงาน) → ยืนยัน error "กรุณาเลือกรายการที่ต้องการส่ง" ขึ้น
4. เปิดฟอร์มรายงานของแถวที่ส่งไปแล้ว (status 1) จาก list-all → ยืนยันฟอร์ม disable ทั้งหมด ปุ่มบันทึกหาย
5. เข้า `check-project-report` ในฐานะกองแผน → เห็นรายการที่ส่งมาในแท็บ "รอตรวจสอบ" (regression check — ต้องยังทำงานเหมือนเดิมทุกประการ เพราะไม่ได้แก้โค้ดฝั่งนี้)
6. กด "ส่งกลับแก้ไข" → กลับไปหน่วยงาน → badge เปลี่ยนเป็น "ส่งแก้ไข" → checkbox กลับมาติ๊กได้ → ฟอร์มแก้ไขได้อีกครั้ง (ไม่ล็อก เพราะ status_id=2)
7. แก้ไข+ส่งใหม่ (ทำซ้ำข้อ 2) → กองแผนกด "ตรวจสอบผ่าน" → badge เปลี่ยนเป็น "ตรวจสอบแล้ว" → เปิดฟอร์มยืนยัน disable ถาวร
8. เข้า `agency-report-form/list-all` ด้วย typeUrl 12 หรือ 14 (ถ้ามีสิทธิ์ทดสอบ) → ยืนยันปุ่ม/พฤติกรรม save เดิมไม่เปลี่ยน (regression check สำหรับ Change 1)