diff --git a/fe-admin/src/components/pe/PeWorkflowPanel.tsx b/fe-admin/src/components/pe/PeWorkflowPanel.tsx index c11e298..09bf34e 100644 --- a/fe-admin/src/components/pe/PeWorkflowPanel.tsx +++ b/fe-admin/src/components/pe/PeWorkflowPanel.tsx @@ -63,11 +63,18 @@ export function PeWorkflowPanel({ mutationFn: async () => { // Decision = Reject (2) khi: // - target = TuChoi (huỷ phiếu) - // - target = DangSoanThao từ phase trung gian (= Trả lại — smart reject Mig 16 + // - target = DangSoanThao từ phase trung gian (= Trả lại legacy Mig 16 // set RejectedFromPhase + clear N-stage rows + Drafter resume jump-back) + // - target = TraLai (98) từ phase trung gian — Session 17 spec mới: Trả + // lại là Phase RIÊNG (gotcha #45 — thiếu nhánh này gây "Trả về nhưng + // hệ thống vẫn duyệt" do BE nhận decision=Approve → ApproveV2Async). + // BE có guard mirror trong PurchaseEvaluationWorkflowService.TransitionAsync + // throw ConflictException nếu payload mismatch — phải sync 2 phía. const isReject = target === PurchaseEvaluationPhase.TuChoi || (target === PurchaseEvaluationPhase.DangSoanThao && evaluation.phase !== PurchaseEvaluationPhase.DangSoanThao) + || (target === PurchaseEvaluationPhase.TraLai + && evaluation.phase !== PurchaseEvaluationPhase.TraLai) return api.post(`/purchase-evaluations/${evaluation.id}/transitions`, { targetPhase: target, decision: isReject ? 2 : 1, @@ -250,8 +257,13 @@ export function PeWorkflowPanel({ {target !== null && (() => { const isCancel = target === PurchaseEvaluationPhase.TuChoi - const isSendBack = target === PurchaseEvaluationPhase.DangSoanThao + // isSendBack sync với button label + payload isReject (gotcha #45). + // Include cả DangSoanThao (legacy Mig 16) lẫn TraLai (Session 17 spec) + // — cả 2 là Trả lại Drafter sửa. + const isSendBack = (target === PurchaseEvaluationPhase.DangSoanThao + || target === PurchaseEvaluationPhase.TraLai) && evaluation.phase !== PurchaseEvaluationPhase.DangSoanThao + && evaluation.phase !== PurchaseEvaluationPhase.TraLai const dialogTitle = isCancel ? '✗ Từ chối phiếu (khoá hoàn toàn)' : isSendBack diff --git a/fe-user/src/components/pe/PeWorkflowPanel.tsx b/fe-user/src/components/pe/PeWorkflowPanel.tsx index 3612929..32e3fbe 100644 --- a/fe-user/src/components/pe/PeWorkflowPanel.tsx +++ b/fe-user/src/components/pe/PeWorkflowPanel.tsx @@ -59,11 +59,18 @@ export function PeWorkflowPanel({ mutationFn: async () => { // Decision = Reject (2) khi: // - target = TuChoi (huỷ phiếu) - // - target = DangSoanThao từ phase trung gian (= Trả lại — smart reject Mig 16 + // - target = DangSoanThao từ phase trung gian (= Trả lại legacy Mig 16 // set RejectedFromPhase + clear N-stage rows + Drafter resume jump-back) + // - target = TraLai (98) từ phase trung gian — Session 17 spec mới: Trả + // lại là Phase RIÊNG (gotcha #45 — thiếu nhánh này gây "Trả về nhưng + // hệ thống vẫn duyệt" do BE nhận decision=Approve → ApproveV2Async). + // BE có guard mirror trong PurchaseEvaluationWorkflowService.TransitionAsync + // throw ConflictException nếu payload mismatch — phải sync 2 phía. const isReject = target === PurchaseEvaluationPhase.TuChoi || (target === PurchaseEvaluationPhase.DangSoanThao && evaluation.phase !== PurchaseEvaluationPhase.DangSoanThao) + || (target === PurchaseEvaluationPhase.TraLai + && evaluation.phase !== PurchaseEvaluationPhase.TraLai) return api.post(`/purchase-evaluations/${evaluation.id}/transitions`, { targetPhase: target, decision: isReject ? 2 : 1, @@ -244,8 +251,13 @@ export function PeWorkflowPanel({ {target !== null && (() => { const isCancel = target === PurchaseEvaluationPhase.TuChoi - const isSendBack = target === PurchaseEvaluationPhase.DangSoanThao + // isSendBack sync với button label L205-207 + payload isReject L64-68 + // (gotcha #45). Include cả DangSoanThao (legacy Mig 16) lẫn TraLai + // (Session 17 spec) — cả 2 là Trả lại Drafter sửa. + const isSendBack = (target === PurchaseEvaluationPhase.DangSoanThao + || target === PurchaseEvaluationPhase.TraLai) && evaluation.phase !== PurchaseEvaluationPhase.DangSoanThao + && evaluation.phase !== PurchaseEvaluationPhase.TraLai const dialogTitle = isCancel ? '✗ Từ chối phiếu (khoá hoàn toàn)' : isSendBack