[CLAUDE] PurchaseEvaluation: khóa sửa giá đề xuất PRO/CCM sau khi phiếu đã gửi duyệt (anh Kiệt FDC "duyệt là fix")
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m25s

Bug (anh Kiệt/team, screenshot): drafter=PRO vẫn điền được giá đề xuất Min/Max SAU khi cấp trên (chị Trà) đã duyệt — "duyệt là fix".

Root cause: UpdatePeSuggestedPricePro/CcmCommandHandler cố ý KHÔNG ràng Phase (Mig 54 "chỉnh như tài liệu sống") → sửa được mọi phase kể cả DaDuyet.

Fix:
- BE: +phase-guard — non-admin chỉ sửa giá đề xuất PRO/CCM khi phiếu ở Nháp (DangSoanThao) / Trả lại (TraLai); đã gửi duyệt (ChoDuyet) / đã duyệt (DaDuyet) / từ chối → ConflictException. Admin override (sửa-sai). Role-gate vẫn chạy trước.
- FE (2 app): SuggestedPriceRows gate canEditPro/Ccm thêm && isEditablePhase(ev.phase) → ẩn ô sửa (read-only) khi phiếu đã gửi duyệt. Đồng bộ BE.
- Test: +4 (PRO ChoDuyet->Conflict no-mutate, PRO DaDuyet->Conflict, Admin DaDuyet->override-set, CCM DaDuyet->Conflict); sửa SeedPeAsync default->DangSoanThao (spec change). 436->440 PASS.

Delete phiếu sau duyệt: ĐÃ chặn sẵn (FE nút Xóa chỉ hiện DangSoanThao + BE delete-guard block non-draft) — không cần sửa.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-07-01 16:07:25 +07:00
parent 36cbf8b1cc
commit 0c2f9f630f
4 changed files with 118 additions and 20 deletions

View File

@ -1722,13 +1722,14 @@ function SuggestedPriceRows({ ev }: { ev: PeDetailBundle }) {
onError: e => toast.error(getErrorMessage(e)),
})
// [S89 anh Kiệt FDC bug] Giá đề xuất PRO/CCM editable theo ROLE-capability đơn thuần
// (mirror ô ngân sách Block A/B dùng bs.canEditPro/canEditCcm — KHÔNG gắn !readOnly).
// BE setter fail-closed theo role (Forbidden) + "không ràng Phase, chỉnh như tài liệu
// sống" → CCM/PRO nhập được MỌI view (kể cả preview + Duyệt chưa-tới-lượt readOnly=true),
// không còn kẹt read-only khi xem phiếu ngoài đúng lượt duyệt của mình.
const canEditPro = ev.canEditProSuggestedPrice
const canEditCcm = ev.canEditCcmSuggestedPrice
// [S89 anh Kiệt FDC] Giá đề xuất PRO/CCM editable theo ROLE-capability (canEditPro/CcmSuggestedPrice)
// — nhập ở mọi view khi phiếu CÒN soạn/trả-lại. [S96 2026-07-01 — anh Kiệt "duyệt là fix"] THÊM
// gắn phase: phiếu ĐÃ GỬI DUYỆT / ĐÃ DUYỆT / TỪ CHỐI → KHÓA (read-only) — không sửa giá ngầm sau
// khi cấp duyệt đã xem. Đồng bộ BE guard (UpdatePeSuggestedPricePro/Ccm phase-gate). Admin sửa-sai
// qua API (BE cho admin override; FE ẩn cho gọn — hiếm khi cần).
const editablePhase = isEditablePhase(ev.phase) // DangSoanThao || TraLai
const canEditPro = ev.canEditProSuggestedPrice && editablePhase
const canEditCcm = ev.canEditCcmSuggestedPrice && editablePhase
// Ghi chú PRO/CCM inline-edit state (Textarea). Echo cùng body absolute-set khi lưu giá.
const [proNoteText, setProNoteText] = useState(ev.proSuggestedPriceNote ?? '')