[CLAUDE] PurchaseEvaluation: nguoi duyet dinh kem file khi DUYET (reuse attachment Purpose=ApprovalAttachment, no migration)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m56s

Modal Duyet them picker multi-file -> upload TRUOC khi chuyen phase (file loi/>20MB = throw, khong duyet). File hien o muc 'File dinh kem khi duyet' (download/preview) trong Panel quy trinh, gan ten nguoi tai + thoi gian. Fix 2 filter dung supplierId=null lam proxy Bang-so-sanh (banSoSanhAttachments + submit-guard) loai purpose=5 tranh lan section + false-pass. FE 2 app SHA-identical. authz: approver upload duoc (handler khong guard drafter-only). Test 354 PASS, no migration. UAT Tra Sol / 5 tester.
This commit is contained in:
pqhuy1987
2026-06-19 16:46:37 +07:00
parent 095fb492cd
commit 7886fd03dd
7 changed files with 313 additions and 14 deletions

View File

@ -206,8 +206,14 @@ export function PeDetailTabs({
if (evaluation.budgetPeriodAmount == null || evaluation.budgetPeriodAmount <= 0) {
missing.push("Chưa nhập Ngân sách kỳ này")
}
// 4. Chưa đính kèm Bảng so sánh (attachment với supplier-row null — chuẩn Section 3)
if (!evaluation.attachments?.some(a => a.purchaseEvaluationSupplierId === null)) {
// 4. Chưa đính kèm Bảng so sánh (attachment supplier-row null — chuẩn Section 3).
// S78 — loại file "đính kèm khi duyệt" (purpose=ApprovalAttachment, supplierId=null)
// khỏi check: nó KHÔNG phải bảng so sánh, không được false-pass submit-guard khi
// phiếu Trả-lại re-submit (lúc đó đã tồn tại file khi-duyệt từ vòng trước).
if (!evaluation.attachments?.some(
a => a.purchaseEvaluationSupplierId === null
&& a.purpose !== PeAttachmentPurpose.ApprovalAttachment,
)) {
missing.push("Chưa đính kèm Bảng so sánh")
}
return missing
@ -1743,9 +1749,11 @@ function ChonNccSection({ ev, readOnly = false }: { ev: PeDetailBundle; readOnly
: null
const giaChaoThau = computeGiaChaoThau(ev)
// d. Bản so sánh — attachments với purpose=ComparisonTable hoặc supplier-row null
// d. Bản so sánh — attachments supplier-row null, NHƯNG loại file "đính kèm khi
// duyệt" (S78 — purpose=ApprovalAttachment cũng supplierId=null) khỏi section này.
const banSoSanhAttachments = ev.attachments.filter(
a => a.purchaseEvaluationSupplierId === null,
a => a.purchaseEvaluationSupplierId === null
&& a.purpose !== PeAttachmentPurpose.ApprovalAttachment,
)
return (