diff --git a/fe-admin/src/components/pe/PeDetailTabs.tsx b/fe-admin/src/components/pe/PeDetailTabs.tsx
index 0ee33ad..4746bcd 100644
--- a/fe-admin/src/components/pe/PeDetailTabs.tsx
+++ b/fe-admin/src/components/pe/PeDetailTabs.tsx
@@ -27,6 +27,7 @@ import {
PurchaseEvaluationPhaseLabel,
PurchaseEvaluationTypeLabel,
getPeDisplayStatus,
+ isEditablePhase,
type PeAttachment,
type PeChangelog,
type PeDepartmentOpinion,
@@ -69,7 +70,9 @@ export function PeDetailTabs({
autoEditHeader?: boolean
}) {
const navigate = useNavigate()
- const isDraft = evaluation.phase === PurchaseEvaluationPhase.DangSoanThao
+ // isDraft renamed → canEditPhase: bao gồm cả TraLai (per user 2026-05-07).
+ // Header bar action buttons (Sửa header / Xóa) hiện khi phase editable + !readOnly.
+ const canEditPhase = isEditablePhase(evaluation.phase)
const opinionsReadOnly = readOnly || mode === 'workspace'
return (
@@ -107,7 +110,7 @@ export function PeDetailTabs({
- {isDraft && !readOnly && (
+ {canEditPhase && !readOnly && (
<>
- {list.data?.total ?? 0}
+ {rows.length}
@@ -100,17 +103,17 @@ export function PeListPanel({
className="pl-8"
/>
- {forcedPhase === undefined ? (
+ {editableOnly ? (
+
+ Lọc cố định: Bản nháp + Trả lại (chỉ phiếu sửa được)
+
+ ) : (
- ) : (
-
- Lọc cố định: {PeDisplayStatusLabel[getPeDisplayStatus(forcedPhase)]}
-
)}
@@ -179,16 +182,30 @@ export function PeListPanel({
✓ Đã tạo HĐ
)}
- {/* Edit pencil — visible on hover (chỉ khi onEditClick được truyền) */}
- {onEditClick && (
-
- )}
+ {/* Edit pencil — LUÔN visible (user 2026-05-07).
+ Bright/active khi phase editable (DangSoanThao + TraLai).
+ Dim/disabled khi phase không edit được (Đã gửi duyệt / Đã duyệt
+ / Từ chối) — click không có tác dụng. */}
+ {onEditClick && (() => {
+ const editable = isEditablePhase(p.phase)
+ return (
+
+ )
+ })()}
))}
diff --git a/fe-admin/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx b/fe-admin/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx
index 4870150..ed4ac91 100644
--- a/fe-admin/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx
+++ b/fe-admin/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx
@@ -20,7 +20,6 @@ import { PeWorkspaceCreateView } from '@/components/pe/PeWorkspaceCreateView'
import { api } from '@/lib/api'
import { getErrorMessage } from '@/lib/apiError'
import {
- PurchaseEvaluationPhase,
PurchaseEvaluationType,
PurchaseEvaluationTypeLabel,
type PeDetailBundle,
@@ -93,7 +92,7 @@ export function PurchaseEvaluationWorkspacePage() {
showCreateButton
onCreate={() => setParams({ mode: 'new', id: null, editHeader: null })}
onEditClick={id => setParams({ id, mode: null, editHeader: '1' })}
- forcedPhase={PurchaseEvaluationPhase.DangSoanThao}
+ editableOnly
/>
{/* Panel 2: Empty | Header form | Detail tabs (workspace mode) */}
diff --git a/fe-admin/src/types/purchaseEvaluation.ts b/fe-admin/src/types/purchaseEvaluation.ts
index 400ba6a..149b05f 100644
--- a/fe-admin/src/types/purchaseEvaluation.ts
+++ b/fe-admin/src/types/purchaseEvaluation.ts
@@ -24,7 +24,8 @@ export const PurchaseEvaluationPhase = {
ChoCEODuyetPA: 5,
ChoCEODuyetNCC: 6,
DaDuyet: 7,
- TuChoi: 99,
+ TraLai: 98, // approver trả về Drafter sửa — vẫn cho edit
+ TuChoi: 99, // terminal từ chối — KHÔNG edit
} as const
export type PurchaseEvaluationPhase = typeof PurchaseEvaluationPhase[keyof typeof PurchaseEvaluationPhase]
@@ -36,6 +37,7 @@ export const PurchaseEvaluationPhaseLabel: Record = {
5: 'Chờ CEO duyệt PA',
6: 'Chờ CEO duyệt NCC',
7: 'Đã duyệt',
+ 98: 'Trả lại',
99: 'Từ chối',
}
@@ -47,9 +49,17 @@ export const PurchaseEvaluationPhaseColor: Record = {
5: 'bg-fuchsia-100 text-fuchsia-700',
6: 'bg-pink-100 text-pink-700',
7: 'bg-emerald-100 text-emerald-700',
+ 98: 'bg-yellow-100 text-yellow-800',
99: 'bg-red-100 text-red-700',
}
+// Phase nào được phép edit phiếu (Drafter sửa header + detail).
+// User 2026-05-07: chỉ Đang soạn thảo + Trả lại (Từ chối là terminal, không edit).
+export function isEditablePhase(phase: number): boolean {
+ return phase === PurchaseEvaluationPhase.DangSoanThao
+ || phase === PurchaseEvaluationPhase.TraLai
+}
+
// Display status meta — gom các phase chi tiết thành 4 nhóm hiển thị end-user
// friendly. Workflow timeline + workflow service vẫn dùng phase chi tiết.
// User 2026-05-07 chỉnh:
@@ -60,6 +70,7 @@ export const PurchaseEvaluationPhaseColor: Record = {
export const PeDisplayStatus = {
BanNhap: 'BanNhap',
DaGuiDuyet: 'DaGuiDuyet',
+ TraLai: 'TraLai',
DaDuyet: 'DaDuyet',
TuChoi: 'TuChoi',
} as const
@@ -68,6 +79,7 @@ export type PeDisplayStatus = typeof PeDisplayStatus[keyof typeof PeDisplayStatu
export const PeDisplayStatusLabel: Record = {
BanNhap: 'Bản nháp',
DaGuiDuyet: 'Đã gửi duyệt',
+ TraLai: 'Trả lại',
DaDuyet: 'Đã duyệt',
TuChoi: 'Từ chối',
}
@@ -75,6 +87,7 @@ export const PeDisplayStatusLabel: Record = {
export const PeDisplayStatusColor: Record = {
BanNhap: 'bg-slate-100 text-slate-700',
DaGuiDuyet: 'bg-amber-100 text-amber-700',
+ TraLai: 'bg-yellow-100 text-yellow-800',
DaDuyet: 'bg-emerald-100 text-emerald-700',
TuChoi: 'bg-red-100 text-red-700',
}
@@ -82,6 +95,7 @@ export const PeDisplayStatusColor: Record = {
export function getPeDisplayStatus(phase: number): PeDisplayStatus {
if (phase === PurchaseEvaluationPhase.DangSoanThao) return PeDisplayStatus.BanNhap
if (phase === PurchaseEvaluationPhase.DaDuyet) return PeDisplayStatus.DaDuyet
+ if (phase === PurchaseEvaluationPhase.TraLai) return PeDisplayStatus.TraLai
if (phase === PurchaseEvaluationPhase.TuChoi) return PeDisplayStatus.TuChoi
return PeDisplayStatus.DaGuiDuyet
}
diff --git a/fe-user/src/components/pe/PeDetailTabs.tsx b/fe-user/src/components/pe/PeDetailTabs.tsx
index 0ee33ad..4746bcd 100644
--- a/fe-user/src/components/pe/PeDetailTabs.tsx
+++ b/fe-user/src/components/pe/PeDetailTabs.tsx
@@ -27,6 +27,7 @@ import {
PurchaseEvaluationPhaseLabel,
PurchaseEvaluationTypeLabel,
getPeDisplayStatus,
+ isEditablePhase,
type PeAttachment,
type PeChangelog,
type PeDepartmentOpinion,
@@ -69,7 +70,9 @@ export function PeDetailTabs({
autoEditHeader?: boolean
}) {
const navigate = useNavigate()
- const isDraft = evaluation.phase === PurchaseEvaluationPhase.DangSoanThao
+ // isDraft renamed → canEditPhase: bao gồm cả TraLai (per user 2026-05-07).
+ // Header bar action buttons (Sửa header / Xóa) hiện khi phase editable + !readOnly.
+ const canEditPhase = isEditablePhase(evaluation.phase)
const opinionsReadOnly = readOnly || mode === 'workspace'
return (
@@ -107,7 +110,7 @@ export function PeDetailTabs({
- {isDraft && !readOnly && (
+ {canEditPhase && !readOnly && (
<>
- {list.data?.total ?? 0}
+ {rows.length}
@@ -100,17 +103,17 @@ export function PeListPanel({
className="pl-8"
/>
- {forcedPhase === undefined ? (
+ {editableOnly ? (
+
+ Lọc cố định: Bản nháp + Trả lại (chỉ phiếu sửa được)
+
+ ) : (
- ) : (
-
- Lọc cố định: {PeDisplayStatusLabel[getPeDisplayStatus(forcedPhase)]}
-
)}
@@ -179,16 +182,30 @@ export function PeListPanel({
✓ Đã tạo HĐ
)}
- {/* Edit pencil — visible on hover (chỉ khi onEditClick được truyền) */}
- {onEditClick && (
-
- )}
+ {/* Edit pencil — LUÔN visible (user 2026-05-07).
+ Bright/active khi phase editable (DangSoanThao + TraLai).
+ Dim/disabled khi phase không edit được (Đã gửi duyệt / Đã duyệt
+ / Từ chối) — click không có tác dụng. */}
+ {onEditClick && (() => {
+ const editable = isEditablePhase(p.phase)
+ return (
+
+ )
+ })()}
))}
diff --git a/fe-user/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx b/fe-user/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx
index 4870150..ed4ac91 100644
--- a/fe-user/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx
+++ b/fe-user/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx
@@ -20,7 +20,6 @@ import { PeWorkspaceCreateView } from '@/components/pe/PeWorkspaceCreateView'
import { api } from '@/lib/api'
import { getErrorMessage } from '@/lib/apiError'
import {
- PurchaseEvaluationPhase,
PurchaseEvaluationType,
PurchaseEvaluationTypeLabel,
type PeDetailBundle,
@@ -93,7 +92,7 @@ export function PurchaseEvaluationWorkspacePage() {
showCreateButton
onCreate={() => setParams({ mode: 'new', id: null, editHeader: null })}
onEditClick={id => setParams({ id, mode: null, editHeader: '1' })}
- forcedPhase={PurchaseEvaluationPhase.DangSoanThao}
+ editableOnly
/>
{/* Panel 2: Empty | Header form | Detail tabs (workspace mode) */}
diff --git a/fe-user/src/types/purchaseEvaluation.ts b/fe-user/src/types/purchaseEvaluation.ts
index 400ba6a..149b05f 100644
--- a/fe-user/src/types/purchaseEvaluation.ts
+++ b/fe-user/src/types/purchaseEvaluation.ts
@@ -24,7 +24,8 @@ export const PurchaseEvaluationPhase = {
ChoCEODuyetPA: 5,
ChoCEODuyetNCC: 6,
DaDuyet: 7,
- TuChoi: 99,
+ TraLai: 98, // approver trả về Drafter sửa — vẫn cho edit
+ TuChoi: 99, // terminal từ chối — KHÔNG edit
} as const
export type PurchaseEvaluationPhase = typeof PurchaseEvaluationPhase[keyof typeof PurchaseEvaluationPhase]
@@ -36,6 +37,7 @@ export const PurchaseEvaluationPhaseLabel: Record = {
5: 'Chờ CEO duyệt PA',
6: 'Chờ CEO duyệt NCC',
7: 'Đã duyệt',
+ 98: 'Trả lại',
99: 'Từ chối',
}
@@ -47,9 +49,17 @@ export const PurchaseEvaluationPhaseColor: Record = {
5: 'bg-fuchsia-100 text-fuchsia-700',
6: 'bg-pink-100 text-pink-700',
7: 'bg-emerald-100 text-emerald-700',
+ 98: 'bg-yellow-100 text-yellow-800',
99: 'bg-red-100 text-red-700',
}
+// Phase nào được phép edit phiếu (Drafter sửa header + detail).
+// User 2026-05-07: chỉ Đang soạn thảo + Trả lại (Từ chối là terminal, không edit).
+export function isEditablePhase(phase: number): boolean {
+ return phase === PurchaseEvaluationPhase.DangSoanThao
+ || phase === PurchaseEvaluationPhase.TraLai
+}
+
// Display status meta — gom các phase chi tiết thành 4 nhóm hiển thị end-user
// friendly. Workflow timeline + workflow service vẫn dùng phase chi tiết.
// User 2026-05-07 chỉnh:
@@ -60,6 +70,7 @@ export const PurchaseEvaluationPhaseColor: Record = {
export const PeDisplayStatus = {
BanNhap: 'BanNhap',
DaGuiDuyet: 'DaGuiDuyet',
+ TraLai: 'TraLai',
DaDuyet: 'DaDuyet',
TuChoi: 'TuChoi',
} as const
@@ -68,6 +79,7 @@ export type PeDisplayStatus = typeof PeDisplayStatus[keyof typeof PeDisplayStatu
export const PeDisplayStatusLabel: Record = {
BanNhap: 'Bản nháp',
DaGuiDuyet: 'Đã gửi duyệt',
+ TraLai: 'Trả lại',
DaDuyet: 'Đã duyệt',
TuChoi: 'Từ chối',
}
@@ -75,6 +87,7 @@ export const PeDisplayStatusLabel: Record = {
export const PeDisplayStatusColor: Record = {
BanNhap: 'bg-slate-100 text-slate-700',
DaGuiDuyet: 'bg-amber-100 text-amber-700',
+ TraLai: 'bg-yellow-100 text-yellow-800',
DaDuyet: 'bg-emerald-100 text-emerald-700',
TuChoi: 'bg-red-100 text-red-700',
}
@@ -82,6 +95,7 @@ export const PeDisplayStatusColor: Record = {
export function getPeDisplayStatus(phase: number): PeDisplayStatus {
if (phase === PurchaseEvaluationPhase.DangSoanThao) return PeDisplayStatus.BanNhap
if (phase === PurchaseEvaluationPhase.DaDuyet) return PeDisplayStatus.DaDuyet
+ if (phase === PurchaseEvaluationPhase.TraLai) return PeDisplayStatus.TraLai
if (phase === PurchaseEvaluationPhase.TuChoi) return PeDisplayStatus.TuChoi
return PeDisplayStatus.DaGuiDuyet
}
diff --git a/src/Backend/SolutionErp.Domain/PurchaseEvaluations/PurchaseEvaluationPhase.cs b/src/Backend/SolutionErp.Domain/PurchaseEvaluations/PurchaseEvaluationPhase.cs
index bc6dcd0..f18dd54 100644
--- a/src/Backend/SolutionErp.Domain/PurchaseEvaluations/PurchaseEvaluationPhase.cs
+++ b/src/Backend/SolutionErp.Domain/PurchaseEvaluations/PurchaseEvaluationPhase.cs
@@ -16,5 +16,6 @@ public enum PurchaseEvaluationPhase
ChoCEODuyetPA = 5, // chỉ B (duyệt phương án trước)
ChoCEODuyetNCC = 6, // chung cả A & B — duyệt chọn đơn vị
DaDuyet = 7, // terminal thành công
- TuChoi = 99, // terminal từ chối
+ TraLai = 98, // approver trả về cho Drafter sửa (vẫn cho edit, khác TuChoi)
+ TuChoi = 99, // terminal từ chối — KHÔNG cho edit/thao tác
}