12 KiB
คำขอระหว่างปี — ขั้นตอนบันทึกฉบับร่าง / ส่งกองนโยบายและแผน
บริบท
เมนู "คำขอระหว่างปี" (/budget-web/app/request-budget-between-year, routing type: 21) ปัจจุบันเมื่อกด "บันทึก" (ครั้งแรก) ระบบจะสร้างระเบียน request_budget (is_between_year=true) ด้วย status_id = 0 และ is_examine = true ทันที แล้วพากลับไปหน้ารายการ — ระเบียนนี้จะไปปรากฏในเมนู "ตรวจสอบคำเสนอขอโครงการ" (check-project-proposal, type: 2) แท็บ "จัดการคำเสนอขอ" โดยอัตโนมัติ เพราะแท็บนั้น query request_budget_and_strategic?status_id=1... แต่ทดสอบจริงพบว่าระเบียนที่ status_id=0 จากฟอร์มก็ไปโผล่ที่นั่นแล้ว (มีสถานะ "รอตรวจสอบ") กล่าวคือ ปัจจุบันไม่มีขั้นตอนกลาง — บันทึกปุ๊บ = ส่งงานแผนปั๊บ ผู้ใช้ไม่มีโอกาสร่างทิ้งไว้ก่อน
ผู้ใช้ (เจ้าหน้าที่หน่วยงาน/คณะ ผู้กรอกคำขอ) ต้องการขั้นตอนกลาง: ร่างไว้ก่อน แล้วค่อยเลือกส่งเป็นชุดเมื่อพร้อม
โค้ดที่มีอยู่แล้วบางส่วนสะท้อนว่าเคยมีความตั้งใจทำ flow นี้มาก่อนแต่ทำไม่เสร็จ:
list-between-year.component.htmlมีคอลัมน์สถานะที่ comment ไว้ ตรงกับความหมายstatus_id==0→ "ร่าง",status_id==1(และยังไม่is_ok/is_modify) → รอดำเนินการrequest-budget-statistics.container.ts→getAll()query เริ่มต้นของdataSourceBetweenYear$มี filter&status_id=1ค้างอยู่ (ไม่ตรงกับonsearch()ที่ไม่กรอง) — เป็น bug ที่ต้องแก้ไปพร้อมกัน มิฉะนั้นร่าง (status_id=0) จะไม่โผล่ในรายการเริ่มต้นเลย
check-project-proposal แท็บ "จัดการคำเสนอขอ" (query status_id=1) เป็นเมนูที่งานแผนใช้ตรวจสอบอยู่แล้ว ไม่ต้องแก้ไขเมนูนั้น — งานนี้ทำเฉพาะฝั่ง "คำขอระหว่างปี" ให้ควบคุมได้ว่าจะยังไม่ส่ง (ร่าง) หรือส่งแล้ว (status_id: 1) เท่านั้น การไปโผล่ที่ check-project-proposal เป็นผลพลอยได้อัตโนมัติจากการเปลี่ยน status_id ซึ่งมีอยู่แล้ว
ขอบเขต
เฉพาะเมนู "คำขอระหว่างปี" (list + form ของ between-year เท่านั้น) ไม่แตะเมนู check-project-proposal หรือเมนูอื่นที่ใช้ container เดียวกัน (request-budget-statistics.container.ts) เกินความจำเป็น (จะเพิ่ม handler ใหม่ 1 ตัวในไฟล์นี้เท่านั้น)
การไหลของสถานะ
| status_id | is_ok / is_modify | ป้ายในรายการ | แก้ไข/ลบได้ไหม |
|---|---|---|---|
| 0 | - | ร่าง | ได้ปกติ |
| 1 | ทั้งคู่ false/null | ส่งงานแผน | ดูได้อย่างเดียว (form disable, ปุ่มลบปิด) |
| 1 | is_modify = true | ส่งแก้ไข | (ปรับปรุงจากงานแผนผ่านเมนูอื่นอยู่แล้ว นอกขอบเขตนี้) |
| 1 | is_ok = true | ตรวจสอบแล้ว | (นอกขอบเขตนี้) |
หมายเหตุ: แถวสถานะ is_modify/is_ok เกิดจากการทำงานของงานแผนในเมนู check-project-proposal ซึ่งมีอยู่แล้วในโค้ดปัจจุบัน งานนี้แค่แสดงป้ายให้ถูกต้องตามข้อมูลจริงในรายการเดียวกัน ไม่ต้องสร้าง logic ใหม่สำหรับสองแถวนี้
การเปลี่ยนแปลงที่ต้องทำ
1. Bug fix: request-budget-statistics.container.ts → getAll()
ลบ &status_id=1 ออกจาก query เริ่มต้นของ dataSourceBetweenYear$ (บรรทัด ~199) ให้เหลือ ?is_between_year=true เท่านั้น เพื่อให้ทั้งร่างและที่ส่งแล้วแสดงในรายการเดียวกัน (ตรงกับพฤติกรรมของ onsearch() ที่มีอยู่แล้ว)
2. ฟอร์ม request-budget-between-year-form.component.ts
- ปุ่ม "บันทึก" (label ในเทมเพลต) เปลี่ยนเป็น "บันทึกฉบับร่าง"
- ตอน
save()กรณีstate === 'add': คงstatus_id = 0ไว้ (ร่าง) แต่เอาis_examine = trueออก จาก path นี้ (ย้ายไปตั้งตอนส่งแทน เพราะ "กำลังตรวจสอบ" ควรเป็นจริงก็ต่อเมื่อส่งไปงานแผนแล้วเท่านั้น) - ตอนโหลดข้อมูลกรณี
state === 'edit'(ในngOnInit, หลังthis.form.patchValue(x)): ถ้าx.status_id !== 0(ถูกส่งไปแล้ว) → เรียกthis.form.disable()และตั้ง flagisLocked = true(component property ใหม่) - เทมเพลตฟอร์ม: ถ้า
isLockedให้ซ่อนปุ่ม "บันทึกฉบับร่าง" (เหลือแต่ "ยกเลิก"/กลับ) ฟิลด์ทั้งหมด disable อยู่แล้วจากการform.disable()
3. List list-between-year.component.ts / .html
- เพิ่ม
selection = new SelectionModel<any>(true, [])(import จาก@angular/cdk/collections) ตามแพทเทิร์นเดียวกับlist6/list24 - เพิ่มคอลัมน์ checkbox หน้าสุด: เช็คได้เฉพาะแถว
status_id === 0(ร่าง) แถวอื่น disable ล่วงหน้า (ไม่ให้เลือกส่งซ้ำ) - Uncomment คอลัมน์สถานะเดิม เพิ่มเข้า columns array ของ header/row/footer และแก้ข้อความ:
status_id == 0→ badge "ร่าง"is_modify == true→ badge "ส่งแก้ไข"is_ok == true→ badge "ตรวจสอบแล้ว"status_id == 1(ไม่เข้าเงื่อนไขบนสองข้อ) → badge "ส่งงานแผน" (เดิม comment ไว้ว่า "รอตรวจสอบ" เปลี่ยนข้อความ)
- ไอคอน "ลบ" (
delete): disable เมื่อstatus_id !== 0 - ไอคอน "แก้ไข" (
edit): ไม่ disable — กดได้เสมอ (เข้าไปดู แต่ฟอร์มจะ read-only เองถ้าไม่ใช่ร่าง ตามข้อ 2) - เพิ่มปุ่ม toolbar ใหม่ "ส่งกองนโยบายและแผน" ข้าง "เพิ่มคำขอระหว่างปี":
disabledเมื่อselection.selected.length === 0, คลิกแล้วemitผ่าน@Output() onsend = new EventEmitter()ส่งthis.selection.selected(array ของแถวที่เลือก)
4. เดินสาย output ผ่านชั้น presenter กลาง
request-budget-statistics-list.component.htmlส่วน*ngIf="typeUrl == 21": เพิ่ม(onsend)="onsend.emit($event)"(หรือชื่อ output ที่สอดคล้อง) ให้ bubble ต่อไปยัง containerrequest-budget-statistics.container.html: เพิ่ม(onsend)="sendBetweenYearToPlan($event)"บน<app-request-budget-statistics-list>
5. Handler ใหม่ใน request-budget-statistics.container.ts
เมธอดใหม่ sendBetweenYearToPlan(selected: any[]):
- ถ้า
selected.length === 0return - confirm ด้วย
this.swSV.confirmSave()(แพทเทิร์นเดียวกับ handler อื่นในไฟล์นี้) - เมื่อ confirm: map
selectedเป็น payload ที่ตั้งstatus_id: 1, is_examine: trueทับค่าเดิมของแต่ละแถว แล้วเรียกthis.requestBudgetSV.updateMany(payload) - สำเร็จ:
this.swSV.updateSuccess()แล้วthis.getAll()(หรือเทียบเท่า) เพื่อ refreshdataSourceBetweenYear$,this.cdRef.detectChanges() - ผิดพลาด:
catchError→this.swSV.errText(err?.error?.description || 'ส่งไม่สำเร็จ')
Error handling
- กดส่งโดยไม่เลือกอะไร: ปุ่มถูก disable ไว้แล้ว ไม่ต้องมี error state เพิ่ม
- API update ล้มเหลว: แสดง error ผ่าน
swSV.errTextตามแพทเทิร์นเดิมของไฟล์ ไม่ rollback selection (ผู้ใช้กดส่งซ้ำได้) - แถวที่ถูกล็อกแล้วไม่มีทางถูกส่งซ้ำ เพราะ checkbox ถูก disable ไว้ตั้งแต่ต้น (client-side guard เท่านั้น ไม่ได้เพิ่ม guard ฝั่ง backend เพราะนอกขอบเขตงานนี้)
Testing
- Manual/browser verification (ตาม superpowers:verify skill ของโปรเจกต์): เพิ่มคำขอระหว่างปีใหม่ → ยืนยันบันทึกเป็น "ร่าง", แก้ไข/ลบได้
- ติ๊ก checkbox 1-2 แถวร่าง กด "ส่งกองนโยบายและแผน" → ยืนยันเปลี่ยนเป็น "ส่งงานแผน", แก้ไข/ลบไม่ได้ (เข้าไปดูฟอร์ม read-only ได้)
- ยืนยันรายการที่ส่งแล้วไปปรากฏในเมนู "ตรวจสอบคำเสนอขอโครงการ" แท็บ "จัดการคำเสนอขอ" เหมือนเดิม (ไม่ต้องแก้โค้ดฝั่งนั้น)
- ยืนยัน checkbox ของแถวที่ส่งแล้วไม่สามารถติ๊กเลือกซ้ำได้