ea440da990941a1c718474a926f48bc3b2ea663d
134 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| ea440da990 |
[CLAUDE] Domain+App+Api+Infra+FE-Admin+FE-User: S34 Plan 2 G-O1 Danh bạ nội bộ
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m46s
Phase 10.2 Văn phòng số — Internal Directory (1 endpoint reuse Users + EmployeeProfiles + Departments, FE card grid avatar/dept/email/phone/Ext). BE Task 1+2 (em main solo): - Application/Office/DirectoryFeatures.cs — GetDirectoryQuery + DirectoryItemDto 12 field LEFT JOIN Users.IsActive + Departments + EmployeeProfiles - Api/Controllers/DirectoryController.cs — GET /api/directory?search=&departmentId= class-level [Authorize] (mọi authenticated NV tra cứu danh bạ nội bộ) - MenuKeys.cs +Off+OffDanhBa const + All[] update - DbInitializer.SeedMenuTreeAsync Off Order=29 + OffDanhBa Order=1 dưới Off FE Task 3 (Implementer Case 2 Pattern 16-bis 4-place mirror cross-app — 5×): - types/directory.ts SHA256 7349d9f64e78 × 2 app IDENTICAL - pages/office/InternalDirectoryPage.tsx SHA256 2aa7e0eed2c8 × 2 app IDENTICAL Card grid responsive 1/2/3/4 col + filter dept dropdown + search input Avatar 14×14 initials gradient PALETTE 6 màu (Pattern 14 Tailwind JIT) EmployeeCode badge + Department emerald badge + email mailto + phone tel Internal phone Ext: amber badge + empty/loading state Vietnamese 100% - App.tsx route /directory × 2 app - lib/menuKeys.ts Off+OffDanhBa const × 2 app - components/Layout.tsx resolvePath staticMap Off_DanhBa:/directory × 2 app (gotcha #50 — 5 places mirror crossapp DON'T MISS) Verify: - dotnet build PASS (2 warn DocxRenderer existing, 0 error) - dotnet test 120/120 PASS (58 Domain + 62 Infra baseline preserve) - npm build × 2 app PASS 0 TS err (fe-admin 1436KB / fe-user 1350KB) Implementer MEMORY Pattern 16-bis reinforced 5× cumulative (S29 Plan CA HF1 + S29 Plan B Chunk D + S33 Plan B G-H1 Task 5 + S34 Plan G-O1 Task 3). Endpoint smoke pending CICD post-deploy Stage 4 (Run #XXX expected ~3m30s). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 9616ae219c |
[CLAUDE] FE-Admin+FE-User: Plan B G-H1 Task 5 — EmployeesPage 2-panel + EmployeeCreatePage cookie-cutter mirror
Phase 10.1 G-H1 Phase 2 Task 5 — FE 2 app cookie-cutter mirror PE pattern.
Phase 1 ULTRA-MINIMAL scope (Implementer afdc812 scaffold):
- 2-panel ListPage (filter left + list+detail right, KHÔNG 3-panel vì Hrm
no workflow)
- 6-section inline collapsible detail (Cơ bản/Công tác/Đào tạo/Thân nhân/
Kỹ năng/Hồ sơ) — NO separate DetailTabs component file
- CreatePage Header form minimal (UserId picker + Status + DateOfBirth +
Gender + Phone + HireDate + Nationality)
- Display read-only Phase 1 satellite (no inline edit — defer Phase 1.5)
## Files (6 new + 6 modified × 2 app = 12)
### NEW (3 × 2 app, SHA256 IDENTICAL cross-app mirror)
| File | LOC | SHA256 prefix |
|------|----:|---|
| `fe-{admin,user}/src/types/employee.ts` | 283 | CCFC70666568 |
| `fe-{admin,user}/src/pages/hrm/EmployeesListPage.tsx` | 417 | DC859C897C5C |
| `fe-{admin,user}/src/pages/hrm/EmployeeCreatePage.tsx` | 178 | C796F25D01AC |
10 const-object enum mirror BE Domain.Hrm.Enums + DTOs:
- EmployeeStatus/Gender/MaritalStatus/EmployeeType/DegreeLevel/
EducationMode/GradeLevel/FamilyRelationKind/SkillKind/EmployeeDocumentType
- EmployeeListItem + EmployeeDetail + 5 satellite DTO type
### MODIFIED (3 × 2 app)
- `fe-{admin,user}/src/lib/menuKeys.ts` — +Hrm + HrmHoSo const
- `fe-{admin,user}/src/components/Layout.tsx` — +Hrm_HoSo:'/employees' staticMap
(LESSON Plan CA Hotfix 1 gotcha #50: page route mới phải thêm staticMap
entry cùng commit, else silent sidebar drop)
- `fe-{admin,user}/src/App.tsx` — +2 route /employees + /employees/new
## Pattern reinforcement
- **Pattern 16-bis 4-place mirror cross-app** reinforced 4× cumulative (S29
Plan CA HF1 + S29 Plan B Chunk D + S33 Task 5 admin + S33 Task 5 user).
Comment header trong Layout.tsx ghi explicit Plan CA Hotfix 1 #50 lesson.
- **Pattern 12-bis cross-module entity FE port PE → Hrm** reinforced 4× (Plan
B Chunk C Mig 33 + G-H1 Task 4 BE + Task 5 FE types mirror PE types/page
structure mirror PE 2-panel scope-down 3→2 panel).
## Reviewer ae752c0 verdict: PASS (commit
|
|||
| 14feb6955d |
[CLAUDE] FE-Admin+FE-User: Plan B Chunk E3 — ContractDetailPage Section 5 LevelOpinionsV2 dynamic
Em main solo sau Implementer E3 stuck mid-task. Minimum viable mirror PE Section 5 LevelOpinionsSectionV2 pattern. V2 contract pin ApprovalWorkflowId → render dynamic Section 5 với opinion data UPSERT từ Service ApproveV2Async (Plan B Chunk B2 |
|||
| 62b50d112b |
[CLAUDE] FE-Admin+FE-User: Plan B Chunk D — ContractCreatePage Workspace V2 Select dropdown
Mirror PE PeWorkspaceCreateView Workspace pattern. Drafter pick V2 workflow IsUserSelectable=true filter ApplicableType=Contract(3). Changes × 2 app: - Add useQuery fetch /api/approval-workflows-v2?applicableType=3 + filter client-side isUserSelectable=true (mirror PE Mig 25 pattern) - Add Select dropdown "Quy trình duyệt V2 (tùy chọn)" trong ContractHeaderForm (create mode panel 2) - Wire approvalWorkflowId vào CreateContractCommand POST body - Conditional UI: blank = V1 fallback auto pick (7 prod contract behavior giữ nguyên); user pick V2 → pin ApprovalWorkflowId Mig 32 schema - Hint khi 0 workflows V2 admin ghim → message rõ V1 fallback Verify: - npm run build × 2 app PASS 0 TS err (1.32MB fe-user, 1.40MB fe-admin) - Mirror 2 app §3.9: +44 LOC mỗi file = +88 LOC total byte-similar - API endpoint /api/approval-workflows-v2 existing (Mig 25 Plan AA S24) - BE CreateContractCommand.ApprovalWorkflowId field đã add Chunk E1 (em main commit prior) — FE wire safe - Backward compat: V1 contract path unchanged khi user bỏ trống dropdown Plan B chain (6 chunks): - A1 |
|||
| e55d96b856 |
[CLAUDE] FE-User: Plan CA Hotfix 1 — Add 7 master/catalog leaf routes vào resolvePath staticMap
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m24s
Bug UAT bro screenshot 2026-05-22: eoffice sidebar group "DANH MỤC" expand chỉ thấy "Danh mục chi tiết" (Catalogs sub-group), 3 leaf Suppliers/Projects/ Departments + 4 sub-catalog leaves KHÔNG render. Root cause: fe-user/src/components/Layout.tsx:238 `MenuLeaf` component `if (!path) return null` → silent drop khi resolvePath(key) trả null. Implementer Chunk B ( |
|||
| c995f42e0d |
[CLAUDE] FE-Admin+FE-User: Plan CA Chunk C — Sidebar filter 2 app (admin HIDE + user SHOW)
fe-admin/src/components/Layout.tsx: - Add ADMIN_HIDDEN_MASTER_KEYS Set với 9 menu key danh mục - Extend isAdminHidden predicate: hide Ct_* + ADMIN_HIDDEN_MASTER_KEYS - Master/Suppliers/Projects/Departments/Catalogs/4 sub-catalogs giờ ẩn khỏi admin sidebar fe-user/src/components/Layout.tsx: - Remove `Master, Suppliers, Projects, Departments` khỏi USER_HIDDEN_KEYS - Catalogs (root + 4 leaf) auto-visible qua tree-inherit từ Master - Giữ ẩn `System, Users, Roles, Permissions, Forms, Reports` (admin tools) Verify: - npm run build × 2 app PASS 0 TS err - fe-admin bundle `index-BQidGwKU.js` 1,404 KB gz 357 KB (rotate) - fe-user bundle `index-Co8LTtad.js` 1,317 KB gz 342 KB (rotate) - Pattern 5 (mirror 2 app §3.9) applied — cùng 1 plan touch 2 file Layout Plan CA chain: - Chunk A |
|||
| 06a441cf4e |
[CLAUDE] FE-User: Plan CA Chunk B — Move 4 master pages từ fe-admin → fe-user
- Copy SuppliersPage/ProjectsPage/DepartmentsPage/CatalogsPage (948 LOC mirror) - Extend menuKeys.ts với 5 key Catalogs* (CatalogUnits/Materials/Services/WorkItems) - Add 7 route App.tsx (/master/suppliers + /master/projects + /master/departments + 4 catalogs tab) - fe-user component parity verified (DataTable, PageHeader, PermissionGuard, 6 shadcn ui) Verify: - fe-user npm run build PASS 0 TS err (1916 modules, 14.14s) - 4 file SHA256 byte-identical mirror fe-admin (all 4 hash match) - 0 BE touch (Chunk A em main solo parallel) Pending Chunk C: sidebar filter 2 app (fe-admin HIDE 9 menu, fe-user SHOW) Pending Chunk D: smoke verify + role demo user Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| d99069a305 |
[CLAUDE] FE-User+FE-Admin: Plan AG6 — Compact PE card 3 row gọn đẹp
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m21s
Anh feedback 2026-05-21: "Cho thông tin bên trong này nó gọn đẹp lại nhé". PE card hiện 4-5 row hơi dài. Compact xuống 3 row tightly packed: Row 1: [Tên gói thầu] [Status badge] Row 2: PE/2026/A/035 · 10:40 19/05/2026 Row 3: 👤 Drafter · Phòng ban [✓ HĐ if any] Changes: - py-2.5 → py-2 (compact vertical padding) - Drop Type label "Duyệt NCC" badge redundant (page header đã hiện) - Combine maPhieu + createdAt vào 1 row với separator · - Combine drafter + department + contract badge vào 1 row (conditional render) - "✓ Đã tạo HĐ" → "✓ HĐ" short label inline cuối row 3 - Separator color slate-300 nhẹ hơn slate-500 Verify: - npm build fe-user PASS 0 TS err 1292.66 KB (gzip 337.19 KB) - npm build fe-admin PASS 0 TS err 1404.01 KB (gzip 357.70 KB) - 2 file SHA256 IDENTICAL 3645307C... (mirror §3.9) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 083b601ea4 |
[CLAUDE] FE-User+FE-Admin: Plan AG5 — PE List tree 3-level Project > Năm > NCC > PE
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m32s
Anh feedback 2026-05-21: "Folder cấp dưới dự án là theo năm và dưới năm là theo NCC nhé". Plan AG3 chỉ 1-level Project > PE. Plan AG5 extend xuống 3 cấp: Năm + NCC. Group structure: - Level 1: 📁 Project (bg-slate-50, font-medium 13px) - Level 2: 📅 Năm {year} (border-l ml-3, 12px) - Level 3: 🏢 NCC (border-l ml-3, 12px, italic slate-400 nếu "Chưa chọn NCC") - Leaf: PE card (border-l ml-3, giữ nguyên content) Sort: - Project A-Z (vi locale) - Năm DESC (2026 trước 2025) - NCC A-Z (vi locale) - PE within NCC: createdAt DESC Fallback: - empty projectName → "(Dự án đã xoá)" - selectedSupplierName null (PE chưa DaDuyet) → "(Chưa chọn NCC)" group + italic style Drop redundant selectedSupplierName line trong PE card (đã hiện ở NCC group header). localStorage keys: - Project: projectId - Năm: `${projectId}::y${year}` - NCC: `${projectId}::y${year}::s${supplierId|'_none_'}` Verify: - npm build fe-user PASS 0 TS err 1292.68 KB (gzip 337.18 KB) 1907 modules - npm build fe-admin PASS 0 TS err 1404.02 KB (gzip 357.70 KB) 1926 modules - 2 file SHA256 IDENTICAL E5FE4979... (mirror §3.9) - KHÔNG BE change, KHÔNG Mig, KHÔNG test (UAT mode) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 2bf01184ca |
[CLAUDE] App+FE-User+FE-Admin: Plan AG4 — bổ sung Drafter + Department vào PE List card
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m27s
Anh UAT 2026-05-21: PE card danh sách thiếu người tạo + phòng ban tạo. Bổ sung 4 field qua BE JOIN Users + Departments LEFT (cả 2 nullable theo PE entity). BE — 4 file: - PurchaseEvaluationDtos.cs: +4 fields DrafterUserId/DrafterName/DepartmentId/DepartmentName - PurchaseEvaluationFeatures.cs ListHandler: JOIN Users + Departments LEFT, projection +4 - PurchaseEvaluationFeatures.cs InboxHandler: mirror JOIN + projection +4 - CreateContractFromEvaluationFeatures.cs ListApproved: mirror JOIN + projection +4 FE — 4 file × 2 app mirror: - types/purchaseEvaluation.ts: PeListItem +4 fields - pages/pe/PurchaseEvaluationsListPage.tsx: PE card render thêm dòng "👤 {drafterName} · {departmentName}" giữa Mã phiếu và Supplier. Conditional: chỉ render khi có ít nhất 1 field. Verify: - dotnet build clean 0 err - dotnet test SolutionErp.slnx 111/111 PASS (58 Domain + 53 Infra) — no regression - npm build fe-user PASS 0 TS err 1290.31 KB (gzip 336.79 KB) 1907 modules - npm build fe-admin PASS 0 TS err 1401.66 KB (gzip 357.30 KB) 1926 modules - 2 FE PE List file SHA256 IDENTICAL C6996194... (mirror §3.9) - KHÔNG Mig (chỉ DTO + projection extend) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| fbad4a9251 |
[CLAUDE] FE-User+FE-Admin: Plan AG3 — PE List tree consistent (drop single-PE flat branch)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m19s
Anh feedback 2026-05-21: "nếu có 1 thì cũng để tương tự luôn nhé, đừng để khác các thằng kia". Plan AG2 render single-PE project flat card + UPPERCASE label phía trên — khác phong cách với multi-PE project (folder <details>). UX inconsistent. Plan AG3 drop nhánh single-PE flat. Mọi dự án dù 1 hay nhiều PE đều render <details> folder collapsed với badge count "(N)" — consistent visual. Diff: -60 LOC (drop entire single-PE flat block). Verify: - npm build fe-user PASS 0 TS err - npm build fe-admin PASS 0 TS err - 2 file SHA256 IDENTICAL 749FF703... (mirror §3.9) - KHÔNG BE change, KHÔNG Mig, KHÔNG test (UAT mode) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| c5429c0d10 |
[CLAUDE] FE-User+FE-Admin: Plan AG2 — Simplify PE List tree 1-level + Panel 1 widen 400px
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m29s
Anh feedback Plan AG (2-level Project > Gói thầu > PE) cầu kỳ quá. Simplify xuống 1-level + widen panel cho dễ đọc. 3 changes: 1. Panel 1 widen 340px → 400px (lg:grid-cols-[400px_1fr_360px]) 2. Drop GoiThauGroup nested type + inner <details> tree, useMemo group 1-level Project > PE[]; PE sort by createdAt DESC trong group (mirror BE sort) 3. Smart render: single-PE project → flat card (no <details> wrapper, project name UPPERCASE label inline) / multi-PE project → <details> tree expand 4. localStorage key rename 'pe_list_expanded_projects' (drop ::gtKey composite suffix) UAT visual: dự án solo PE hiện flat (không cần click expand), dự án có nhiều phiếu render tree compact. Drop redundant projectName ở PE card (đã có ở group header / UPPERCASE label). Verify: - npm build fe-user PASS 0 TS err 1291.76 KB (gzip 336.90 KB) 1907 modules - npm build fe-admin PASS 0 TS err 1403.10 KB (gzip 357.41 KB) 1926 modules - 2 file SHA256 IDENTICAL 37520D01... (mirror §3.9) - KHÔNG BE change, KHÔNG Mig, KHÔNG test (UAT mode per feedback_uat_skip_verify) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 0bf6c7ec63 |
[CLAUDE] FE-User+FE-Admin: Plan AG Chunk A+B+C — PE List tree view 2-level Project > Gói thầu
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m39s
UAT feedback bro Tra Sol 2026-05-21: UI Duyệt NCC flat list "đám rừng" → tree view giống Outlook folder. Phase 1 FE-only mirror 2 app §3.9 — KHÔNG schema mới (Phase 2 ProjectPackage defer sau UAT confirm). Chunk A — Data transform useMemo group: - Map<projectId, Map<normalizedGoiThau, PeListItem[]>> - Normalize TenGoiThau: trim + toLowerCase, display raw đầu tiên trong group - Sort: Project A-Z + gói thầu A-Z (vi locale) - Fallback: "(Dự án đã xoá)" empty projectName + "(Chưa phân loại)" empty TenGoiThau - Filter (pendingMe → DaGuiDuyet) áp dụng TRƯỚC group Chunk B — UI render <details>/<summary> 2-level: - Replace flat <ul><li> bằng nested <details> HTML native (no shadcn Accordion — gap component lib) - 📁 Project + 📄 Gói thầu icon + count badge inline - Chevron rotation via Tailwind group-open/proj + group-open/gt named groups - PE card content preserve nguyên (line 209-248 unchanged) Chunk C — Expand state localStorage persist: - Key 'pe_list_expanded_groups' Set<string> - Project level key: projectId; Gói thầu level key: ${projectId}::${normalizedGoiThau} - Default empty Set (all collapse) — bro Tra Sol expect Outlook-style closed default Verify: - npm build fe-user PASS 0 TS err 1291.33 KB (gzip 337.00 KB) 1907 modules 16.05s - npm build fe-admin PASS 0 TS err 1402.68 KB (gzip 357.51 KB) 1926 modules 6.86s - KHÔNG BE change, KHÔNG Mig, KHÔNG test (UAT mode per feedback_uat_skip_verify) Pending: Reviewer pre-commit + CICD Run #222 verify Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 506cada86b |
[CLAUDE] FE-User FE-Admin: Plan AF — userMap fallback resolve historical entries pre-Plan AE
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m23s
Bro UAT 2026-05-19 post-Plan AE: phiếu cũ entries vẫn show "Hệ thống" thay
vì user name. Plan AE chỉ forward fix — entries CŨ pre-deploy có
userName="" empty, FE fallback "Hệ thống".
Fix Plan AF — Option A bro chốt (FE fallback lookup, no DB write):
ApprovalsTab + HistoryTab build userMap useMemo từ PeDetailBundle data
có sẵn (KHÔNG cần extra fetch /api/users admin permission):
- ev.drafterUserId + ev.drafterName
- ev.approvals[].approverUserId + approverName
- ev.approvalFlow.steps[].levels[].approvers[].userId + fullName
- ev.levelOpinions[].signedByUserId + signedByFullName
- ev.departmentOpinions[].userId + userName
resolveUserName / resolveActorName helper:
1. Trust entry.userName nếu non-empty
2. Lookup userMap qua entry.userId
3. Fallback 'Hệ thống' nếu không match
Cover gần hết users tham gia phiếu (drafter + approver + signer). Edge
case: user edit phiếu nhưng KHÔNG xuất hiện trong workflow → vẫn fallback.
Pattern reusable: synthetic data recovery cho audit trail từ embedded
domain data sources, no extra API contract change.
Mirror 2 app §3.9 identical logic.
Verify:
- npm build × fe-user PASS 0 TS err (9.12s)
- npm build × fe-admin PASS 0 TS err (8.91s)
- BE unchanged from
|
|||
| 0aaf2df04a |
[CLAUDE] FE-User FE-Admin: Plan AD — Lịch sử duyệt redesign drop phase badges + next-target hint
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m24s
Bro UAT 2026-05-19 post-Plan AC2 deploy: phase badges "Đã gửi duyệt →
Đã gửi duyệt" gây nhầm (Reject event nhìn giống Approve, không rõ gửi
duyệt cho ai).
Fix Plan AD — Option A bro chốt:
1. DROP fromPhase→toPhase badges entirely khỏi ApprovalsTab — redundant
visual noise khi 3/4 mode return giữ Phase=ChoDuyet, và misleading cho
user thấy "Đã gửi duyệt → Đã gửi duyệt" lặp lại.
2. ADD next-target hint parse từ comment via helper extractNextTargetHint():
Approve patterns:
- Comment "sang Cấp X" → "→ Cấp X"
- Comment "sang Bước X" → "→ Bước X (Cấp 1)"
- Comment "[Duyệt vượt cấp tới Cấp cuối]" → "→ Vượt cấp tới Cấp cuối"
- toPhase=DaDuyet(20) → "→ Đã duyệt hoàn tất"
Reject patterns:
- Comment "không lùi được" → "→ Không lùi được"
- Comment "Người chỉ định" + Bước/Cấp → "→ Trả về Người chỉ định (Bước X Cấp Y)"
- Comment "Người soạn thảo"/"Drafter" → "→ Trả về Người soạn thảo"
- Comment "Trả về 1 Cấp"/"Trả về Cấp X" → "→ Lùi về Cấp X" / "→ Lùi 1 Cấp"
- Comment "Trả về 1 Bước"/"Trả về Bước X" → "→ Lùi về Bước X" / "→ Lùi 1 Bước"
- toPhase=TuChoi(99) → "→ Từ chối hoàn toàn"
3. Layout cleaner: [Decision badge] [Next-target hint] flex-wrap min-w-0 +
timestamp shrink-0 right. Comment + actor stays below.
4. Cleanup import: drop unused PurchaseEvaluationPhaseColor (no longer
needed after dropping phase badges). Keep PurchaseEvaluationPhaseLabel
(still used at line 157+ for InfoTab phase label).
Mirror 2 app §3.9 identical logic.
Verify:
- npm build × fe-user + fe-admin PASS 0 TS err
- BE/test unchanged from
|
|||
| 25837b6220 |
[CLAUDE] FE-User FE-Admin: Plan AC2 — FE merge view recover historical Reject events PE cũ
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m22s
Bro UAT 2026-05-19 phản hồi sau Plan AC deploy: phiếu cũ PE/2026/A/032 vẫn KHÔNG show events Trả lại pre-deploy (Bro test trả lại Phan Văn Chương → Trà từ TRƯỚC |
|||
| a734bf2b8b |
[CLAUDE] PurchaseEvaluation: Plan AC — fix Lịch sử duyệt panel show Trả lại + Duyệt vượt cấp
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m27s
Bro UAT 2026-05-19 screenshot: panel "Lịch sử duyệt" KHÔNG show Return mode events (Bro Trả lại từ Phan Văn Chương → Trà missing) + KHÔNG distinct event Duyệt vượt cấp (skipToFinal F2). Root cause: - PurchaseEvaluationApprovals.Add() chỉ ở Approve branch (line 472 V2 + 660 V1) - Reject branch line 75-103 NEVER adds Approval row — chỉ log Changelog - skipToFinal advance branch line 532-572 dùng existing line 472 row nhưng comment KHÔNG distinct "vượt cấp" semantic vs approve thường Fix Plan AC: 1. BE Service.cs Reject branch (line 75-103): capture pre-call Step/Level trước ApplyReturnModeAsync mutate pointer, add Approval row sau khi mutate: Decision=Reject + FromPhase + ToPhase=evaluation.Phase + Comment carry from-position + mode summary. Cover cả Trả lại (TraLai+pointer-mode) + Từ chối (TuChoi terminal). 2. BE Service.cs line 472 Approve branch: enrich Comment với prefix "[Duyệt vượt cấp tới Cấp cuối]" khi skipToFinal=true để Lịch sử duyệt distinguish vượt cấp với approve thường. 3. FE PeDetailTabs.tsx × 2 app ApprovalsTab: add Decision badge phân biệt Approve (emerald) / Trả lại (amber) / Từ chối (rose). Vì 3/4 mode Trả lại (OneLevel/OneStep/Assignee) giữ Phase=ChoDuyet → fromPhase→toPhase badge giống Approve. Decision badge bù visual phân biệt. Verify: - dotnet build clean 0 err 2 warn (pre-existing DocxRenderer) - dotnet test 111/111 PASS - npm build × fe-user + fe-admin PASS 0 TS err Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| cdfd54212c |
[CLAUDE] PurchaseEvaluation: Plan AB Chunk A — fix Changelog visibility Bug 1 Budget Adjust + Bug 2 Return Mode
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Failing after 1m6s
- BE ApplyReturnModeAsync 4 mode add Changelog.Add() common path (refactor Drafter early return) - FE PeDetailTabs.tsx HistoryTab filter extend cover Header+ngân sách (B1) + Workflow+Trả lại (B2) - FE empty placeholder + comment update reflect new filter scope - Mirror 2 app §3.9 Bug 1: Budget Adjust handler đã log (Header+Update) nhưng FE filter strict TraLai-only Bug 2: Return mode Service không log Changelog — chỉ approval phase transition Verify: - Build clean 0 err - npm build × 2 app pass 0 TS err - 111 test baseline preserve (UAT skip test-after defer) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| ee0902ac13 |
[CLAUDE] FE-User FE-Admin: Plan AA wrap fix - sidebar label dài wrap về đầu hàng + text smaller
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m25s
UAT feedback 2026-05-15 sau Run #213 deploy: bro screenshot sidebar label custom Mig 27 dài "1. Duyệt Nhà Cung Cấp - Thầu phụ (NCC -TP)" wrap 2 dòng, dòng 2 "(NCC -TP)" indent SAU icon thay vì về đầu hàng. Root cause: flex container [items-center, gap-2] + inner span chứa Icon + label text → text wraps within INNER span (đã indent past icon area). Pattern phù hợp cho 1-dòng label, KHÔNG phù hợp khi multi-line. Fix pattern (3 sites fe-user + 2 sites fe-admin mirror rule §3.9): - MenuGroup button: flex → relative block + inline-block icon + inline text + absolute ChevronDown right. Text wrap về left edge button (under icon). - MenuLeaf NavLink: flex → block + inline-block icon + inline text. - StaticLeaf NavLink (fe-user only): mirror MenuLeaf pattern. Smaller text: - text-[13px] → text-[12px] (medium label group + leaf) - text-sm (14px) → text-[12px] (MenuLeaf top level) - text-[12px] → text-[11px] (MenuLeaf deep level) - leading-snug (1.375) compact 2-line height Icon adjust: -mt-0.5 align with inline text baseline. Button px-3 pr-7: pad right 28px reserve cho absolute ChevronDown (KHÔNG bị đẩy xuống khi label wrap). Verify: - npm run build fe-user PASS clean 432ms - npm run build fe-admin PASS clean 494ms Em main solo CSS polish < 30 min (criteria #6 REFUSE Implementer). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| fbbd361929 |
[CLAUDE] FE-User: Plan AA redesign v2 - Table layout rowSpan tận dụng full width + 7 label tiếng Việt + color coding 2 layer
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m14s
UAT feedback 2026-05-15 sau Run #212 deploy: bro request layout DẠNG TABLE tận dụng hết width thay vì stack vertical panel-per-NV (visual rộng theo chiều ngang). Refactor WorkflowCard structure → 4-col HTML table với rowSpan: Table cols: | Bước (Phòng) | Cấp | NV duyệt | Quyền duyệt | | rowSpan=N | rowSpan=M | per-NV | grid 2-col 7 checkbox | - Bước column: rowSpan = total NV trong Step. Header tone đậm Step palette. - Cấp column: rowSpan = N NV cùng Order (OR-of-N). Badge ring Cấp palette. Nếu N > 1: hint "N NV OR (chỉ cần 1 NV duyệt)". - NV duyệt column: 1 row per NV slot. Tên + email gray. - Quyền duyệt column: grid grid-cols-1 md:grid-cols-2 với 7 checkbox label: - 4 return mode (col-span-1): "Trả về 1 Cấp trước" / "Trả về 1 Bước trước" / "Trả về Người chỉ định" / "Trả về Drafter (mặc định)" - 3 long label (col-span-2): "Cho phép chỉnh sửa Section 2 (Hạng mục/NCC/Báo giá) lúc đang duyệt" / "Cho phép chỉnh sửa Section ngân sách lúc đang duyệt" / "Cho phép duyệt thẳng Cấp cuối khi đang duyệt" Color coding 2 layer preserved: - Step (Bước) bg + headerBg: blue/purple/emerald/amber/pink cycle (5 màu) - Cấp badge: violet/sky/teal/orange/rose cycle (5 màu) - NV + Quyền duyệt cell: bg-white/80 (lighten Step tone, vẫn show through) Helper extracted `buildStepRows(step)` build flat Row[] với rowSpan metadata (isFirstInStep + isFirstInCap + rowSpanStep + rowSpanCap). Drop StepBlock + NvPermissionPanel components (chuyển inline table cells). colgroup width hint: Bước=160px / Cấp=100px / NV=240px / Quyền duyệt=1fr (rest). Tại 1280-1366px viewport (laptop nhỏ Plan AA sidebar widen) Quyền duyệt cell ~400-500px → grid 2-col fit 7 label OK. Verify: - npm run build fe-user PASS clean 0 TS err, 522ms, 1907 modules - Bundle 1284.22 KB (+1.31 KB from baseline) Em main solo CSS/UX redesign (criteria #2 + #4 Implementer REFUSE — UX layout decision rowSpan grouping + cell distribution decision). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 4d60598369 |
[CLAUDE] FE-User: Plan AA redesign - WorkflowMatrixViewPage panel-per-NV layout + color coding 2 layer (Step/Cấp)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m20s
UAT feedback 2026-05-15 sau Run #211 deploy: bro request hiển thị rõ ràng giống admin Designer (panel per NV + 7 label tiếng Việt) + màu sắc khác nhau giữa Cấp duyệt + giữa Phòng ban để phân biệt. Redesign WorkflowMatrixViewPage.tsx ~250 LOC (drop table 11 cột symbol khó hiểu): NEW layout per Step (Phòng): - Step container có unique color (cycle 5 màu: blue/purple/emerald/amber/pink) - Step header bar với tone đậm: "Bước N — Phòng X" - Group levels theo level.order → 1 Cấp group = N NV panel song song (OR-of-N) - Cấp badge có unique color (cycle 5 màu: violet/sky/teal/orange/rose) - "1 NV duyệt" hoặc "N NV (OR-of-N — chỉ cần 1 NV duyệt là qua Cấp)" hint - NV permission panel mirror admin Designer line 853-949: - Header "QUYỀN DUYỆT {NV name} {email}" amber-700 uppercase - 7 checkbox label tiếng Việt rõ (read-only disabled accent-emerald): 1. Trả về 1 Cấp trước 2. Trả về 1 Bước trước 3. Trả về Người chỉ định 4. Trả về Drafter (mặc định) 5. Cho phép chỉnh sửa Section 2 (Hạng mục/NCC/Báo giá) lúc đang duyệt 6. Cho phép chỉnh sửa Section ngân sách lúc đang duyệt 7. Cho phép duyệt thẳng Cấp cuối khi đang duyệt - Grid 2-col cho 4 return mode + col-span-2 cho 3 Allow* label dài - Inactive label slate-400, active slate-800 font-medium Color palette (Tailwind JIT — full class strings array): - STEP_PALETTE: 5 màu cycle theo sIdx % 5 - LEVEL_PALETTE: 5 màu cycle theo (level.order - 1) % 5 Drop FlagCell table cell helper. Replace với StepBlock + NvPermissionPanel + FlagRow components. Verify: - npm run build fe-user PASS clean 0 TS err, 423ms, 1907 modules - Bundle 1282.91 KB (+0.32 KB from baseline — minor add new components) Em main solo CSS/UX redesign decision (criteria #2 Implementer REFUSE — UX flow decision needed cho color palette + layout structure). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| da218f1dd4 |
[CLAUDE] FE-User: Plan AA hotfix - WorkflowMatrixViewPage container px-6 → px-2 (dịch content sang trái)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m18s
UAT request 2026-05-15 sau deploy Run #210: bro muốn matrix view content sát sidebar trái thay vì gap 24px (px-6) — tận dụng width gain từ Plan AA sidebar widen + remove truncate. Fix 1 line `WorkflowMatrixViewPage.tsx:43` container: - px-6 (24px) → px-2 (8px) - py-5 (20px) giữ nguyên - PageHeader title + WorkflowCard + Table cùng shift left -16px Verify: - npm run build fe-user PASS clean 0 TS err, 486ms, bundle 1282.59 KB unchanged Em main solo CSS polish trivial < 30 min (per criteria #6 Implementer REFUSE). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| c6678022f7 |
[CLAUDE] FE-User: Plan AA Chunk B - WorkflowMatrixViewPage read-only matrix view + types extend
NEW files:
- pages/pe/WorkflowMatrixViewPage.tsx ~215 LOC
- useQuery GET /approval-workflows-v2?applicableType=N&isUserSelectable=true
- PageHeader "Luồng duyệt — {label}" + Network icon
- Loading/Error/Empty state 3 variant rõ
- WorkflowCard per ghim version: header (code/version + badge "Đang dùng" emerald + "Được ghim" amber Pin icon)
- Table 10 cột read-only: Bước rowSpan | Cấp | NV duyệt + 7 Allow* flag (✓/—)
- FlagCell helper component TS indexed-access type union 7 keys
- Mirror admin Designer ApprovalWorkflowsV2Page layout (drop edit mutations)
- types/approvalWorkflowV2.ts ~55 LOC
- 5 type subset: AwLevelDto + AwStepDto + AwDefinitionDto + AwTypeSummaryDto + AwAdminOverviewDto
- Field name khớp BE record positional param (history not versions)
MODIFIED:
- App.tsx +import + Route /purchase-evaluations/workflow-matrix trước /workspace
Why:
- Chunk A BE đã wire endpoint với filter param + menu seed Pe_DuyetNcc_WfView
cho user xem matrix workflow admin Designer ghim trước khi tạo phiếu.
Verify:
- npm run build fe-user PASS clean 0 TS err, 1907 modules, 2.61s
- Reviewer cumulative A+B PASS 0 critical/major/minor
Pending Chunk C: Docs session log + STATUS + HANDOFF + 4 agent MEMORY drift.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| ee776d5745 |
[CLAUDE] Domain+App+Api+FE-User+FE-Admin: Plan AA Chunk A - BE IsUserSelectable filter + menu seed Pe_DuyetNcc_WfView + sidebar widen w-72 xl:w-80 + revert Plan U truncate
BE changes:
- MenuKeys.cs +helper PurchaseEvaluationWorkflowView(typeCode) => "Pe_{typeCode}_WfView"
- DbInitializer.cs SeedMenuTreeAsync:
- tree.Add LuongDuyet (Order=2 first child) cho 2 type PE
- INSERT-only loop -> INSERT-OR-UPDATE-Order (shift existing prod rows Order+1)
- Idempotent: skip nếu Order match, UPDATE nếu mismatch
- DbInitializer.cs SeedPurchaseEvaluationPermissionDefaultsAsync +WfView leaf cho 7 role Read
- ApprovalWorkflowV2AdminFeatures.cs GetAwAdminOverviewQuery +IsUserSelectable bool? = null
+ handler conditional Where(d => d.IsUserSelectable == ius)
- ApprovalWorkflowsV2Controller.cs Overview signature +[FromQuery] bool? isUserSelectable
pass-through to mediator (gotcha #44 fix preserved class-level [Authorize] bare)
FE Layout changes (mirror 2 app rule §3.9):
- fe-user resolvePath regex (List|Create|Pending|WfView) + route
/purchase-evaluations/workflow-matrix?type=N
- fe-user + fe-admin sidebar w-60 xl:w-72 -> w-72 xl:w-80 (+48/+32px gain)
- Revert Plan U S23 t11 truncate × 5 sites (3 fe-user MenuGroup+MenuLeaf+StaticLeaf
+ 2 fe-admin MenuGroup+MenuLeaf). Keep min-w-0 flex-1 + shrink-0 + title
tooltip (no harm). Bro request hiển thị đầy đủ label custom Mig 27 dài.
Why:
- User UAT request 2026-05-15: thêm menu "Luồng duyệt" trên Danh sách hiển thị
ma trận phân quyền workflow V2 admin Designer ghim ra cho user xem trước khi
tạo phiếu. Filter IsUserSelectable=true (Mig 25).
- Sidebar Plan U S23 t11 truncate hiển thị "..." → bro muốn full label.
Widen sidebar +32-48px + bỏ truncate cho phép wrap natural khi cực dài.
Verify:
- dotnet build SolutionErp.slnx PASS clean 0 err 2 warn pre-existing DocxRenderer
- Investigator Pre-A confirm gotcha #44 đã fix permanent từ 2026-05-08
- Reviewer cumulative PASS 0 critical / 0 major / 0 minor blocker
Pending Chunk B: FE WorkflowMatrixViewPage.tsx ~215 LOC + types + App.tsx route.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 86d8806afc |
[CLAUDE] FE-Admin FE-User: Chunk U — Sidebar truncate long label + tooltip (Mig 27 DisplayLabel dài wrap fix)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m30s
Bro UAT screenshot 2026-05-15: Submenu "1. Duyệt Nhà Cung Cấp - Thầu phụ
(NCC -TP)" trong sidebar fe-user wrap 2 dòng (label dài ~50 chars vs
sidebar w-60 = 240px chỉ fit ~25 chars).
Root: Admin đã set DisplayLabel custom qua Mig 27 (S20 t7 Menu eOffice
admin page) — `MenuItems.Pe_DuyetNcc` DisplayLabel = "1. Duyệt Nhà Cung
Cấp - Thầu phụ (NCC -TP)" (Label gốc = "Duyệt NCC" ngắn). FE render
{effectiveLabel(node)} thẳng vào span flex KHÔNG có truncate.
Fix Plan U mirror 2 app (rule §3.9):
3 nơi render label trong fe-user/Layout.tsx + 2 nơi mirror fe-admin:
1. MenuNodeRenderer button (accordion toggle):
```diff
- <span className="flex items-center gap-2">
+ <span className="flex min-w-0 flex-1 items-center gap-2">
- <Icon className="h-4 w-4" />
- {effectiveLabel(node)}
+ <Icon className="h-4 w-4 shrink-0" />
+ <span className="truncate" title={effectiveLabel(node)}>{effectiveLabel(node)}</span>
</span>
- <ChevronDown ... transition />
+ <ChevronDown ... shrink-0 ... transition />
```
2. MenuLeaf NavLink:
```diff
- <NavLink to={path} className={cn('flex items-center gap-2.5...')}>
+ <NavLink to={path} title={effectiveLabel(node)} className={cn('flex min-w-0 items-center gap-2.5...')}>
- <Icon className={cn(isDeep ? 'h-3.5 w-3.5' : 'h-4 w-4')} />
- {effectiveLabel(node)}
+ <Icon className={cn('shrink-0', isDeep ? 'h-3.5 w-3.5' : 'h-4 w-4')} />
+ <span className="truncate">{effectiveLabel(node)}</span>
</NavLink>
```
3. StaticLeaf NavLink (fe-user only — Hộp thư static entry):
Pattern tương tự MenuLeaf
fe-admin dùng `node.label` thay vì `effectiveLabel(node)` (admin sidebar
luôn show Label gốc, KHÔNG đụng DisplayLabel per S20 t7 Q2=b).
Pattern key:
- `min-w-0 flex-1` trên flex parent — cần thiết để truncate child shrink
- `shrink-0` trên Icon + ChevronDown — giữ size không co
- `truncate` (Tailwind = overflow-hidden text-ellipsis whitespace-nowrap) trên span text
- `title={label}` tooltip hover show full label nếu user cần đọc đầy đủ
Verify:
- npm run build fe-user PASS 16.79s clean
- npm run build fe-admin PASS 8.16s clean
- 0 TS error
KHÔNG đụng BE. Admin tự control DisplayLabel qua Mig 27 Menu eOffice page
— Plan U chỉ ensure FE render gracefully với label dài (truncate +
tooltip hover) thay vì wrap broken visual.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 108268a2e2 |
[CLAUDE] FE-Admin FE-User: Chunk Q — Fix layout banner F3 violet mx-5 inset gap khiến button "+ Thêm hạng mục" lệch
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m15s
Bro UAT screenshot 2026-05-15 sau Plan O+P deploy: PE/2026/A/025 Phase=ChoDuyet actor NV Test có F3 AllowApproverEditDetails=TRUE — banner violet "Bạn được phép chỉnh sửa Hạng mục / NCC / Báo giá" render ĐÚNG nhưng layout: ``` [Section padding px-5 = 20px] [Banner mx-5 inset 20px both sides] ← gap 20px right edge [ItemsTab header flex justify-between] [text "1 hạng mục..."] [Button "+ Thêm hạng mục"] ``` Banner mx-5 đẩy inset 20px khỏi Section padding x-5 → tạo gap visual 20px bên phải banner. Phía dưới gap đó là button right-aligned (full Section width) → trông button "lệch" so với banner end + có khoảng trắng phía trên. Fix mirror 2 app (rule §3.9): ```diff - <div className="mx-5 mt-2 rounded border border-violet-200 bg-violet-50 px-3 py-2 text-[11px] text-violet-800"> + <div className="mb-3 rounded border border-violet-200 bg-violet-50 px-3 py-2 text-[11px] text-violet-800"> ``` - `mx-5` → drop (banner full Section padding width) - `mt-2` → `mb-3` (consistent spacing với ItemsTab header `mb-3` style) Visual sau fix: ``` [Section padding px-5] [Banner full width] [ItemsTab header: text + button align Section right edge] ``` Button "+ Thêm hạng mục" align cùng phải edge với banner. KHÔNG còn gap visual. Files (2 mirror): - fe-user/src/components/pe/PeDetailTabs.tsx:218-223 - fe-admin/src/components/pe/PeDetailTabs.tsx:213-218 Verify: - npm run build fe-user PASS clean (0 TS err, 7.67s) - npm run build fe-admin PASS clean (0 TS err, 7.50s) KHÔNG đụng BE. KHÔNG đụng logic. CSS layout polish only. Pending: bro UAT verify layout fix + Plan P CICD Monitor verify F1+F2 wire (spawn earlier, vẫn running). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 508b17a43c |
[CLAUDE] FE-Admin FE-User: Chunk M3 — Rename Phase=TraLai display label "Trả lại" → "Cần chỉnh sửa lại"
Plan M Chunk M3 — UAT disconnect fix: bro UAT phát hiện label "Trả lại" + "Bản nháp" không phân biệt rõ với end-user → rename Phase=TraLai (98) display label sang "Cần chỉnh sửa lại" để self-descriptive. Scope HẸP — chỉ status display reference (KHÔNG đụng action verb): - types/purchaseEvaluation.ts × 2 app: PurchaseEvaluationPhaseLabel[98] + PeDisplayStatusLabel.TraLai = 2 const map rename - components/pe/PeWorkflowPanel.tsx × 2 app: 2 inline literal hardcode trong F1 dialog tooltip `Phase → "..."` + confirm message `Phiếu sẽ về "..."` — status reference, KHÔNG phải action verb KHÔNG đụng: - Action button label `← Trả lại` (verb, giữ nguyên) - F1 mode picker label `Trả về Người soạn thảo` (4 mode action, giữ nguyên) - Comments narrative giữ rationale dev (rule §6.5) - types/contracts.ts + types/budget.ts Phase 98 'Trả lại' — module Contract + Budget khác PE, ngoài scope M3 Mirror 2 app rule §3.9 strict applied. Verify: - npm run build fe-admin PASS clean (0 TS err, 9.40s) - npm run build fe-user PASS clean (0 TS err, 6.92s) Diff: +4/-4 LOC × 4 file = 8 LOC total Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 83c9f7b45d |
[CLAUDE] PurchaseEvaluation FE-Admin FE-User: Chunk L5 — PE list UX: ngày tạo thay SLA countdown + sort UpdatedAt DESC
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m10s
Bro UAT S23 t2 yêu cầu 2 UX changes PE list:
1. Đổi "Còn N ngày Mh" (SlaTimer countdown) → "DD/MM/YYYY HH:mm" (ngày giờ tạo phiếu).
2. Sort: phiếu vừa update (Tạo / Gửi duyệt / Trả lại) đưa lên đầu, phiếu cũ phía dưới.
BE changes:
- PurchaseEvaluationListItemDto +UpdatedAt: DateTime? field (auto AuditingInterceptor refresh
mọi SaveChanges — covers Insert/Update/Transition events natural).
- ListPurchaseEvaluationsQueryHandler sort: OrderByDescending(UpdatedAt ?? CreatedAt)
(was: OrderByDescending(CreatedAt)).
- GetMyPurchaseEvaluationInboxQueryHandler sort: OrderByDescending(UpdatedAt ?? CreatedAt)
(was: OrderBy(SlaDeadline ?? MaxValue) — SLA priority deprecated).
- CreateContractFromEvaluationFeatures.cs: +UpdatedAt arg trong DTO ctor (compile fix
consumer downstream).
- Select projection 3 callsites populate UpdatedAt.
FE × 2 app (mirror rule §3.9):
- PeListItem type +updatedAt: string | null (optional — null khi phiếu chưa Update).
- PurchaseEvaluationsListPage: replace <SlaTimer deadline={p.slaDeadline} ... /> với
Vietnamese date format "{DD/MM/YYYY HH:mm}" qua Intl.DateTimeFormat (vi-VN locale,
full date+time options). title tooltip hiện full timestamp.
- Remove SlaTimer import (unused warning).
UpdatedAt sort logic insight: AuditingInterceptor (Infrastructure) auto-refresh
UpdatedAt mọi SaveChanges → mọi event tự nhiên (Drafter tạo / Gửi duyệt từ Workspace
/ Approver duyệt Cấp tiếp / Approver trả lại / Admin override) đều bump UpdatedAt
→ phiếu vừa action lên đầu list. Phiếu mới Insert UpdatedAt=null → fallback CreatedAt
→ vẫn lên đầu (vì CreatedAt vừa now).
Verify:
- dotnet build production projects clean (0 err, 2 pre-existing warn)
- dotnet test SolutionErp.slnx 104/104 PASS (DTO change KHÔNG impact test — tests
don't construct ListItemDto)
- npm run build × 2 app pass clean
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| f212f04365 |
[CLAUDE] FE-Admin FE-User: Chunk L3 — Fix Trả lại dialog default mode = first available F1 (mode đang gửi duyệt)
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Failing after 48s
Bro UAT S23 t2 catch screenshot: tick AllowReturnToAssignee + untick AllowReturnToDrafter cho slot Approver → user click "Trả lại" → dialog mở với default state `returnMode=Drafter` (S17 backward compat fallback). Radio Drafter HIDDEN vì allowReturnToDrafter=false → user thấy radio Assignee đã pick + Bùi Lê Thủy Trà từ dropdown → click Xác nhận → BE receive `returnMode: 4` (Drafter từ initial state) → throw "Cấp Approver hiện tại không bật mode 'Drafter'. Liên hệ Admin Designer". Bro intent: "cho duyệt trong muốn cho trả lại trong mode đang gửi duyệt chứ ko phải draft, draft chỉ khi trả lại cho người soạn thôi" — 3 F1 modes (OneLevel/OneStep/ Assignee) là "trả lại trong mode đang gửi duyệt" (Phase=ChoDuyet lùi pointer); Drafter mode = trả về Người soạn (Phase=TraLai), CHỈ default khi không có F1 nào. Fix FE × 2 app PeWorkflowPanel.tsx (mirror rule §3.9): - Import useEffect - useEffect khi target=TraLai → compute first available F1 mode: - allowReturnOneLevel ? OneLevel - : allowReturnOneStep ? OneStep - : allowReturnToAssignee ? Assignee - : Drafter (fallback) - setReturnMode(firstAvailable) → Dialog mở với mode đúng selected → user click Xác nhận → BE receive correct mode → ApplyReturnModeAsync check correct flag → PASS. Pattern lesson saved: dialog initial state phải compute từ permission flags KHÔNG hardcode default — admin có thể disable mọi mode khác Drafter, hoặc ngược lại enable F1 only. Verify: - npm run build × 2 app pass (0 TS err) - Bundle hash rotate × 2 app Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 10ddc8761b |
[CLAUDE] FE-Admin FE-User: Chunk L2 — Fix F4 BudgetAdjustSection bypass readOnly khi Approver scope (menu Duyệt)
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Failing after 1m1s
Bro UAT S23 t2 catch: "Đã stick cho edit trong luồng duyệt nhưng trong menu duyệt -> vẫn không edit đc ngân sách". Investigator audit root cause: - BudgetAdjustSection canAdjust = !readOnly && (...) — `!readOnly` short-circuit block F4 logic - Menu Duyệt route truyền readOnly=true xuống PeDetailTabs → button "Điều chỉnh" hidden dù admin đã tick AllowApproverEditBudget cho slot + actor match - F3 wire ItemsTab ĐÚNG via `itemsReadOnly = readOnly && !approverEditMode` pattern bypass — F4 không follow same pattern Refactor canAdjust × 2 app (rule §3.9 mirror): ``` - canAdjust = !readOnly && (isAdmin || (isDrafter && isDrafterPhase) || isApproverChoDuyet) + canAdjust = isAdmin + || (!readOnly && isDrafter && isDrafterPhase) + || isApproverChoDuyet ``` → F4 Approver scope (Mig 30) BYPASS readOnly: - Admin: bypass readOnly (full quyền) - Drafter (Nháp/TraLai): chỉ Workspace (readOnly=false) - Approver ChoDuyet + flag tick + actor match: bypass readOnly → button "Điều chỉnh" visible trong menu Duyệt Mirror F3 pattern (itemsReadOnly line 118). F4 wire S22+5 ban đầu miss BYPASS pattern — fixed S23 t2. Verify: - npm run build × 2 app pass (0 TS err, bundle hash rotated) - Bro UAT verify: tick F4 → vào menu Duyệt → click "Điều chỉnh ngân sách" → modal open editable Pattern lesson saved memory: per-NV admin opt-in flag wire RULE — FE bypass readOnly khi flag tick + actor match + phase match (mirror F3 itemsReadOnly). F4 BudgetAdjustSection retroactive fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| f3db9e6cc0 |
[CLAUDE] PurchaseEvaluation: Chunk L1 — Fix F2 skipToFinal semantic: skip pointer tới NV cuối (KHÔNG terminate DaDuyet)
Bro UAT S23 t2 catch: Plan K K2 implement F2 SAI semantic — set Phase=DaDuyet terminal auto-approve. Bro intent: "Duyệt thẳng đến CEO, bỏ qua các bước khác chứ ko phải chuyển sang đã duyệt." Refactor Service.cs ApproveV2Async F2 branch: - Resolve lastStepIdx = steps.Count - 1, lastLevelMaxOrder = max(LevelOrder) trong Step cuối - Advance pointer: CurrentWorkflowStepIndex = lastStepIdx + CurrentApprovalLevelOrder = lastLevelMaxOrder - Phase GIỮ NGUYÊN ChoDuyet — NV cuối (CEO/last approver) vẫn cần ký thật để tiến DaDuyet - Audit log "Approver skip thẳng tới Bước X Cấp Y (NV cuối) — bỏ qua các Bước/Cấp trung gian" - Guard no-op: actor đã ở slot cuối → fall through advance logic (normal → DaDuyet) (KHÔNG double-advance khi skipToFinal=true ngay slot cuối) - Reset SLA 7d cho NV cuối nhận lại FE × 2 app PeWorkflowPanel.tsx (mirror rule §3.9): - Description text update: "Phiếu sẽ skip tới NV cuối (CEO/cấp ký cuối) — NV cuối vẫn cần duyệt thật để hoàn tất." - Amber warning update: "Bỏ qua mọi Cấp/Bước trung gian, phiếu chuyển thẳng tới NV cuối. NV cuối vẫn phải ký duyệt thật để phiếu thành 'Đã duyệt'." Verify: - dotnet build production projects clean (0 err, 2 pre-existing warn) - npm run build × 2 app pass Pattern lesson saved memory: Service skipToFinal semantic = advance pointer NOT terminate. K7 tests TODO update: 3 Approver F2 tests assert pointer moved to last slot, NOT Phase=DaDuyet. Defer test fix sau UAT confirm UX. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| ebe2469470 |
[CLAUDE] FE-Admin FE-User: Chunk E — K6 Workspace DROP Drafter checkbox + ADD Approver toggle (Mig 31 F2 refactor)
Plan K Chunk E mirror 2 app rule §3.9. Refactor F2 UX flow:
DROP fe-admin + fe-user Workspace Drafter checkbox:
- PeDetailTabs.tsx Workspace action bar: REMOVE "Gửi thẳng Cấp cuối (skip trung gian)"
violet label + state skipToFinal + allowSkipToFinal lookup + skipToFinal payload
- submitForApproval mutation signature simplify: opts: { skipToFinal: boolean } → void
- Confirm dialog text + button label drop skipToFinal conditional
ADD fe-admin + fe-user Approver toggle trong PeWorkflowPanel dialog:
- State skipToFinalApprover default false
- Visible khi Approve forward (NOT Cancel + NOT SendBack) + currentLevelOptions?.allowApproverSkipToFinal
- Checkbox violet panel với description "Phiếu sẽ tiến thẳng tới Đã duyệt (terminal)"
- Amber warning khi checked: "Hành động KHÔNG quay lại được"
- Mutation payload +skipToFinal: !isReject && skipToFinalApprover
- onSuccess reset state
Type ApprovalWorkflowOptions × 2 app: +allowApproverSkipToFinal: boolean (7th)
Type PeDetailBundle × 2 app: REMOVE drafterAllowSkipToFinal field + comment Mig 29+30+31
UX design Dialog approach (consistent với Trả lại Mode picker pattern):
- Skip thẳng Cấp cuối = destructive action → confirm dialog amber warning
- Mirror Mig 28 Trả lại 4 mode picker UX consistency
- Em main solo K6 per UX flow decision criteria
Per bro decision Plan K S23 t1: "Chỗ cấu hình cho phép skip → duyệt thẳng cho phép
trong trạng thái đang duyệt" + "Tất cả đều cấu hình ngay trong chỗ setup quy trình duyệt".
Verify:
- npm run build × 2 app pass clean (0 TS err)
- Pre-existing warnings unchanged (chunk size + INEFFECTIVE_DYNAMIC_IMPORT)
- Bundle hash rotated × 2 app
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| b04a11a62f |
[CLAUDE] FE-PE: S22+5 Chunk B — Designer checkbox +AllowApproverEditBudget per slot + Section read flag (mirror 2 app)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m23s
FE Admin Designer (ApprovalWorkflowsV2Page.tsx): - LevelDto + EditLevelEntry +allowApproverEditBudget - copyFromDefinition + makeDefaultLevelEntry propagate default false - POST body include allowApproverEditBudget cho mỗi Level slot - NEW checkbox UI per Level inline panel: "Cho phép chỉnh sửa Section ngân sách lúc đang duyệt" (col-span-2, mirror pattern allowApproverEditDetails Mig 29) FE Types mirror 2 app: - fe-admin + fe-user `ApprovalWorkflowOptions` +allowApproverEditBudget FE BudgetAdjustSection refactor (mirror 2 app): - Trước: isApproverChoDuyet = phase ChoDuyet + actor in approvers - Sau: isApproverChoDuyet = phase ChoDuyet + actor in approvers + currentLevelOptions.allowApproverEditBudget=true (per slot opt-in) - Drafter scope Nháp/Trả lại unchanged - Admin bypass unchanged UX impact: - Admin Designer phải tick checkbox cho NV slot mới được edit ngân sách lúc duyệt - Nếu KHÔNG tick → button "Điều chỉnh" trong Section 5 KHÔNG hiện cho approver - Drafter vẫn edit bình thường khi phiếu Nháp/Trả lại Verify: - npm run build fe-admin — 569ms pass - npm run build fe-user — 528ms pass Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 30d51c89bb |
[CLAUDE] FE-PE: S22+4 Chunk B — Attachment preview dialog + View button + Section "Điều chỉnh ngân sách" (mirror 2 app)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m26s
Feature 1 (FE attachment preview):
- NEW component `AttachmentPreviewDialog.tsx` (shared 2 app):
* Fetch BE `/view` endpoint as blob → object URL (bearer auth qua axios)
* Render iframe (PDF) hoặc img (image) trong Dialog size=lg
* Helper `isPreviewable(fileName)` check ext PDF/PNG/JPG/JPEG/WEBP/GIF
- Update `SupplierAttachmentsCell` (per-NCC quote files):
* Click filename KHÔNG còn trigger download — chuyển sang explicit buttons
* Eye violet button "Xem trước" khi previewable
* Download brand button cạnh bên (always visible)
- Update `GeneralAttachmentsSection` (bảng so sánh general):
* Same pattern: Eye + Download split buttons
- Word/Excel (.doc/.docx/.xls/.xlsx) → download-only (UAT users mở local Office)
- Mirror fe-admin + fe-user (rule §3.9)
Feature 2 (Section "Điều chỉnh ngân sách"):
- NEW component `BudgetAdjustSection` in PeDetailTabs (mirror 2 app)
- Section 5 cuối Detail view sau "4. Ý kiến cấp duyệt"
- canAdjust 3 scope:
* Admin → bypass
* Drafter của phiếu + Phase DangSoanThao/TraLai
* Approver currentLevel (match approvalFlow.approvers) + Phase ChoDuyet
- 2 mode edit: Select Budget link OR Manual amount + name
- Banner amber khi Approver điều chỉnh trong duyệt (audit notice)
- Save → PATCH /api/purchase-evaluations/{id}/budget-adjust (Chunk A BE)
- History display defer S22+5 (changelogs fetch separate endpoint, không có
trong PeDetailBundle — UAT user xem Panel 3 "Lịch sử thay đổi")
Verify:
- npm run build fe-admin — 577ms pass
- npm run build fe-user — 550ms pass
- dotnet test SolutionErp.slnx — 104/104 PASS regression-free
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 40f64c6b32 |
[CLAUDE] PE-Workflow: UAT S22+1 — disable cả 3 button khi không quyền + BE guard
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m29s
User UAT feedback: "Nếu đã không được quyền thao tác thì ko được quyền thao tác hết tất cả các hành động" — trước đây chỉ "Duyệt" disabled, "Trả lại" + "Từ chối" vẫn enabled (design intent S17 cũ). FE 2 app mirror (PeWorkflowPanel.tsx): - `isDisabled = blockedByV2Level` (drop `isForwardApprove &&` qualifier) - Tooltip update "mới thao tác được (Duyệt / Trả lại / Từ chối)" - Comment refresh ghi UAT S22+1 spec + cross-ref BE EnsureCanRejectV2Async BE defense-in-depth (PurchaseEvaluationWorkflowService.cs): - Helper mới `EnsureCanRejectV2Async` mirror FE actorInV2Level logic: Skip silent khi admin/V1/non-ChoDuyet/no actor/no pointer. Throw ForbiddenException khi V2 + ChoDuyet + actor != currentLevel.ApproverUserId. - Invoke ở top Reject branch (cover cả TuChoi + Trả lại sub-branches). - Chặn request forge: non-approver gọi PATCH /transitions direct sẽ 403. Test (test-before §7 — security guard critical algorithm): - ReturnMode tests existing 7/7 vẫn PASS (a2.Id = currentLevel approver, guard accept) - +1 NEW test `Reject_NonApprover_V2_Throws_ForbiddenException` — outsider Drafter role gọi Reject phiếu V2 → throw + Phase không mutate Verify: - dotnet test SolutionErp.slnx — 104/104 PASS (+1 guard regression) Δ: 103 → 104 - npm run build × 2 app — pass (482ms + 583ms) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 5ccb2a7057 |
[CLAUDE] FE-PE: S21 t5 Chunk C — eOffice read currentLevelOptions + drafterAllowSkipToFinal (per-NV) mirror 2 app
Types refactor `fe-{admin,user}/src/types/purchaseEvaluation.ts`:
- `ApprovalWorkflowOptions` REMOVE allowDrafterSkipToFinal (F2 đã move per-User).
Còn 5 flag (F1 4 mode + F3 EditDetails).
- `PeDetailBundle`:
- RENAME `workflowOptions` → `currentLevelOptions` (clearer semantic per-slot)
- ADD `drafterAllowSkipToFinal: boolean` (BE resolve từ DrafterUserId → User entity)
PeWorkflowPanel.tsx (mirror 2 app):
- RENAME local var `wfOptions` → `levelOptions`
- READ `evaluation.currentLevelOptions` (Cấp hiện tại)
- 4 mode radio render conditional theo levelOptions.allowReturnXxx (unchanged
logic, just rename source)
PeDetailTabs.tsx (mirror 2 app):
- F3 approverEditMode: READ `evaluation.currentLevelOptions?.allowApproverEditDetails`
thay vì workflowOptions.allowApproverEditDetails (semantic per-NV slot)
- F2 allowSkipToFinal: READ `evaluation.drafterAllowSkipToFinal` thay vì
workflowOptions.allowDrafterSkipToFinal (semantic per-Drafter user)
Backward compat verified:
- Phiếu cũ trước Mig 29 vẫn return currentLevelOptions populated (BE backfill
Mig 29 đã copy 5 Allow* per Level)
- drafterAllowSkipToFinal: BE backfill chỉ TRUE cho user từng Drafter PE link
workflow.AllowDrafterSkipToFinal=true (preserve admin config S21 t4)
- Phiếu V1 legacy: currentLevelOptions=null → FE fallback chỉ Drafter mode
Verify:
- npm run build × 2 app pass (fe-user 450ms + fe-admin 439ms, cache hot)
- 0 TS6 err, warning chunk size pre-existing
Pending Chunk D: Docs (schema-diagram §14 update + STATUS + HANDOFF + session log).
Note: User Management page chưa có F2 checkbox UX (defer commit sau khi admin
UAT request — BE field đã có, FE chỉ cần thêm 1 toggle vào UserEdit dialog).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| d27caafcf5 |
[CLAUDE] FE-PE: Chunk D — eOffice Trả lại modes + Skip CEO + Approver edit Section 2 (F1+F2+F3) mirror 2 app
Types (fe-{admin,user}/src/types/purchaseEvaluation.ts):
- ApprovalWorkflowOptions type (6 boolean Allow* flag)
- WorkflowReturnMode const-object {OneLevel,OneStep,Assignee,Drafter}
- PeDetailBundle +workflowOptions field (null nếu V1 legacy)
PeWorkflowPanel.tsx F1 (mirror 2 app):
- State returnMode + returnTargetUserId thêm vào transition mutation payload
- Dialog Trả lại render radio list 1-4 mode enabled theo workflowOptions:
• Trả về 1 Cấp trước (lùi pointer trong cùng Bước, peer review)
• Trả về 1 Bước trước (Cấp cuối Bước trước nhận lại)
• Trả về Người chỉ định (pick từ dropdown NV đã ký levelOpinions)
• Trả về Người soạn thảo (default Drafter S17 fallback)
- Banner amber rounded box dưới radio list mô tả hành vi mode chọn
- onSuccess reset returnMode về Drafter + returnTargetUserId null
PeDetailTabs.tsx F2 (mirror 2 app):
- State skipToFinal + allowSkipToFinal (từ workflowOptions)
- submitForApproval mutationFn accept opts.skipToFinal → POST body
- Workspace action bar: thêm checkbox violet "Gửi thẳng Cấp cuối (skip trung gian)"
hiển thị conditional theo allowSkipToFinal + canSubmitForApproval
- Confirm dialog message dynamic: "Gửi thẳng" warning vs default tuần tự
- Button label dynamic: "Lưu & Gửi thẳng CẤP CUỐI →" vs "Lưu & Gửi Duyệt →"
PeDetailTabs.tsx F3 (mirror 2 app):
- useAuth import + compute approverEditMode (phase=ChoDuyet +
workflow.AllowApproverEditDetails + actor match currentApproval.approvers)
- itemsReadOnly = readOnly && !approverEditMode → ItemsTab nhận
- Banner violet "ⓘ Bạn được phép chỉnh sửa Hạng mục/NCC/Báo giá" khi
approverEditMode + readOnly (Duyệt menu) — UX nhắc về quyền extended
InfoTab + NccSelectorRow + BudgetFieldRow GIỮ strict isEditablePhase (KHÔNG
trong F3 scope — Header section + Section 3 winner KHÔNG cho Approver edit).
Verify:
- npm run build × 2 app pass (fe-user 7.52s, fe-admin 499ms cached)
- 0 TS6 err, warning chunk size pre-existing
- BE Chunk B đã accept skipToFinal + returnMode + returnTargetUserId trong
TransitionPurchaseEvaluationCommand → wire E2E complete
Pending Chunk E: Docs schema-diagram §14 update + STATUS + HANDOFF + session log.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 4b29d00716 |
[CLAUDE] FE-PE: Chunk B — Fix button "Trả lại" gửi decision=Approve thay vì Reject (gotcha #45) mirror 2 app
Bug pattern: button "← Trả lại" trong PeWorkflowPanel.tsx hiển thị đúng label
(L205-207 isSendBack include TraLai) NHƯNG payload `isReject` (L64-66) thiếu
nhánh TraLai → gửi decision=1 (Approve) thay vì 2 (Reject) khi target=TraLai
(98). BE Service vào APPROVE STEP → ApproveV2Async UPSERT opinion "đã duyệt"
+ advance Cấp tiếp theo. User UAT thấy: "Trả về nhưng hệ thống vẫn duyệt".
Inconsistency thứ 2: dialog `isSendBack` (L247-248) cũng thiếu nhánh TraLai
→ dialog title fallback `✓ Duyệt → Trả lại` + KHÔNG hiển thị amber warning.
Fix 3 chỗ × 2 app (fe-user + fe-admin, rule §3.9 mirror):
1. `isReject` payload — thêm nhánh `target=TraLai && phase!=TraLai`
2. dialog `isSendBack` — thêm nhánh TraLai + guard phase != TraLai
3. Comments document context bug + cross-ref BE guard Chunk A
Sync với BE guard (Chunk A `de00887` `PurchaseEvaluationWorkflowService.cs`):
- BE throw ConflictException khi target ∈ {TraLai, TuChoi} && decision != Reject
- 2 phía cùng đúng → no payload mismatch
Verify:
- npm run build × 2 app pass (fe-user 17.91s, fe-admin 6.71s, 0 TS6 err)
- Warning chunk size pre-existing (NOT introduced)
Pending Chunk C: docs gotcha #45 + STATUS + HANDOFF + session log.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 6e338f745e |
[CLAUDE] FE: Responsive cho laptop màn hình nhỏ — sidebar slim + Section/HangMucCard padding tighter + workspace 2-panel breakpoint
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m13s
User Session 20 turn 11: "giao diện hiện tại chưa đáp ứng tốt cho laptop màn hình nhỏ -> Căn chỉnh lại nhé." Pain points trên laptop 1280-1366px viewport (fe-user content panel 1280-288=992px hoặc fe-admin workspace 2-panel content còn ~672px): - Sidebar 288px chiếm nhiều - PE Workspace list panel 320px = thừa - Section padding px-5 + HangMucCard p-3 cộng gộp tốn ~16-20px mỗi cell - Inline NCC table 7 cột bị compressed FE-only mirror fe-admin + fe-user. Targeted fixes (no breaking change): ### 1. Sidebar slim — w-60 (240px) lg/xl giảm xuống → bump xl:w-72 - fe-admin Layout aside: `w-72` → `w-60 xl:w-72` - fe-user Layout aside: `w-72` → `w-60 xl:w-72` - Trên màn ≥xl (1280px+) → giữ 288px như cũ - Trên màn <xl (laptop nhỏ) → 240px, save 48px cho content ### 2. PE Workspace 2-panel list breakpoint - `lg:grid-cols-[320px_1fr]` → `lg:grid-cols-[260px_1fr] xl:grid-cols-[320px_1fr]` - Trên lg (1024-1279): list 260px (đủ pick) → content +60px - Trên xl+ (1280+): list 320px như cũ - Save total: ~60px cho NCC table render ### 3. Section + HangMucCard padding responsive - Section component `<section className="px-5 py-4">` → `px-3 py-3 sm:px-5 sm:py-4` (xs/sm: tighter 12px each side, save 16px width) - HangMucCard header `flex items-start gap-3 ... p-3` → `flex flex-wrap items-start gap-2 ... p-2 sm:gap-3 sm:p-3` → +flex-wrap: stat "Số tiền NS" wrap xuống dòng khi container hẹp - HangMucCard expand panel `p-3` → `p-2 sm:p-3` Net width gain trên laptop 1366px (typical): - Sidebar slim: +48px - Workspace list: +60px - Section padding: +16px - HangMucCard padding: +8px Total ~+132px cho NCC table area render comfortable thêm 1-2 cột KHÔNG đụng dialog widths, schema BE, hoặc semantic breakpoints lớn. Verify: - npm run build × fe-admin pass - npm run build × fe-user pass Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 66551db4d8 |
[CLAUDE] FE-PE: AddSupplierDialog auto-fill từ master khi chọn NCC
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m0s
User Session 20 turn 10: chọn NCC từ dropdown master → auto-load các field
đã có sẵn (contactPerson/phone/email/note) vào form, đỡ phải nhập tay lại.
FE-only mirror fe-admin + fe-user.
AddSupplierDialog dropdown "NCC (master)" onChange:
- Lookup suppliers.data find(s => s.id === selectedId) → master row
- setForm prev → ghi đè 4 field:
* contactName ← picked.contactPerson ?? ''
* contactPhone ← picked.phone ?? ''
* contactEmail ← picked.email ?? ''
* note ← picked.note ?? ''
- KHÔNG đụng displayName / paymentTermText / thanhTien (manual cho user)
- Hint "✓ Đã tự điền từ Master — bạn có thể sửa lại nếu cần." text-[10px]
text-emerald-600 dưới dropdown khi đã chọn supplier
Mapping master Supplier → PE.Supplier fields (skip address vì không có
field tương ứng — có thể nhét vào note nếu user cần, manual).
User vẫn override các field auto-fill được sau đó (input bình thường).
Đổi supplier giữa lúc đã chỉnh tay → re-fill từ master mới (mặc định ghi đè).
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 83aae8ea64 |
[CLAUDE] FE-PE: Winner NCC revert badge → icon ✓ đậm + hover transition
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m50s
User Session 20 turn 9: bỏ badge "🏆 Trúng thầu" emerald-600 rounded-full text-white, revert về icon stick ✓ prefix như cũ nhưng: - Đậm hơn: text-base font-bold text-emerald-700 - Tên NCC khi winner: text-emerald-900 đậm - Row hover transition: hover:bg-emerald-200/70 (winner) + hover:bg-white/80 hover:shadow-sm (non-winner palette) - Transition smooth qua `transition` class NCC row visual khi winner: - border-l-emerald-500 (giữ) - bg-emerald-100/70 (giữ) - font-semibold + shadow-sm + ring-1 ring-inset ring-emerald-300 (giữ) - +hover:bg-emerald-200/70 (mới — sáng lên hover) - Prefix ✓ text-base font-bold emerald-700 (đậm hơn icon cũ) - Tên NCC text-emerald-900 (đậm hơn slate-900 mặc định) NCC row non-winner: - palette cycle (blue/purple/sky/teal/pink) giữ - +hover:bg-white/80 hover:shadow-sm (mới — nổi nhẹ khi hover) Mirror fe-admin + fe-user. Verify: - npm run build × fe-admin pass - npm run build × fe-user pass Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 3ec7b5a1b0 |
[CLAUDE] FE-PE: AddSupplier +Số tiền inline + NCC 5-màu palette + Winner 🏆 nổi bật
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m8s
User Session 20 turn 8 yêu cầu chuỗi UX NCC grid:
1. Thêm NCC dialog cho nhập luôn Số tiền báo giá cho hạng mục
2. Số tiền hiện ra cột so sánh hạng mục (đã có sẵn cột "Số tiền")
3. Trang trí 3+ NCC khác nhau 3+ màu khác nhau
4. NCC được chọn (winner) nổi bật hơn
FE-only mirror fe-admin + fe-user.
### AddSupplierDialog — sequential POST tạo NCC + Quote
- Thêm prop `detailId?: string` (truyền từ HangMucCard call site)
- Form state +`thanhTien: 0`
- showQuote = !!detailId — chỉ render input "Số tiền báo giá" khi gọi từ
HangMucCard (call site khác giữ behavior cũ tạo NCC only)
- Mutation 2 step:
1. POST /purchase-evaluations/{id}/suppliers → response {id} (BE controller
PurchaseEvaluationsController.AddSupplier trả Ok(new {id = newId}))
2. Nếu detailId + thanhTien > 0 → POST /quotes với purchaseEvaluationDetailId
+ purchaseEvaluationSupplierId (newSupplierRowId) + thanhTien
- Toast: "Đã thêm NCC + báo giá" (có quote) hoặc "Đã thêm NCC" (no quote)
- Section input "Số tiền" trong card brand-50/40 + VND format suffix đ + hint
"Để trống / 0 → chỉ tạo NCC, chưa báo giá. Sửa lại sau bằng cách click số
tiền trong bảng."
- HangMucCard pass detailId={detail.id} khi mount AddSupplierDialog
### NCC row 5-màu cycle palette
- NEW const NCC_PALETTES (literal Tailwind class strings để JIT scan):
blue / purple / sky / teal / pink (border-l-4 colored + bg subtle 50/40)
- Loop ev.suppliers.map((s, idx) → palette = NCC_PALETTES[idx % 5]
- Tr className: `align-top border-l-4` + palette (non-winner) hoặc winner
override
### Winner highlight nổi bật
- Tr non-winner: cycle palette (5 màu)
- Tr winner override:
- border-l-emerald-500 (thay vì palette stripe)
- bg-emerald-100/70 (đậm hơn 50/60 cũ)
- font-semibold + shadow-sm
- ring-1 ring-inset ring-emerald-300 (viền trong cho ô nổi)
- NCC name cell: badge inline-flex rounded-full bg-emerald-600 text-white
text-[9px] font-bold uppercase "🏆 Trúng thầu" (thay icon ✓ cũ)
- Note text bumped lên text-amber-700 (chút đậm hơn 600 cũ cho visible khi
winner bg đậm hơn)
KHÔNG đụng schema BE. 2 endpoint sẵn (POST /suppliers + POST /quotes) chain.
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 1ed6530fdd |
[CLAUDE] FE-User: Chunk D — Layout filter !isVisible + render displayLabel
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m51s
Session 20 turn 7 Chunk D. fe-user (eOffice) áp dụng Ẩn/Hiện + Đổi tên menu
admin set qua MenuVisibilityPage.
fe-user/types/menu.ts: MenuItem + MenuNode +isVisible bool +displayLabel
string|null (mirror fe-admin).
fe-user/components/Layout.tsx:
- filterForUser: filter 2 tầng — USER_HIDDEN_KEYS hardcode (Master/System/
Forms/Reports — structural never-show) + dynamic !isVisible (Mig 27)
- Helper effectiveLabel(n) = displayLabel?.trim() || label — admin custom
label thắng, fallback gốc
- Replace 3 callsite `{node.label}` → `{effectiveLabel(node)}` (Group/Leaf/
NavLink render)
- USER_FIXED_TOP entry "__inbox" +isVisible:true +displayLabel:null (giữ
type check pass)
fe-admin Layout KHÔNG đụng — admin sidebar luôn dùng Label gốc + render hết
menu (kể cả isVisible=false), per user Q2=b.
Verify:
- npm run build × fe-user pass
- npm run build × fe-admin pass (no regression)
Pending Chunk E: Docs S20 turn 7 + STATUS + HANDOFF
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| f568945069 |
[CLAUDE] FE-PE: Manual budget "Nhập tay" — drop Tên field, format VND
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m12s
User Session 20 turn 6 screenshot: chế độ "Nhập tay (không link)" Section 2
b. Ngân sách vẫn còn input "Tên (vd Tạm tính T11/2025)" cùng số tiền. User
chỉ cần nhập số tiền — bỏ Tên + áp VND format consistent.
3 file × 2 app = 6 file FE update:
- PeDetailTabs.tsx BudgetFieldRow (Section 2 detail editor)
- PeWorkspaceCreateView.tsx (workspace mode "new")
- PeHeaderForm.tsx (Create/Edit header page)
Mỗi file:
- Drop Input "Tên ngân sách" UI khỏi manual mode (state field giữ '' để
backward compat — BE save luôn null)
- Manual mode UI giờ chỉ 1 input số tiền (max-w-xs):
* type="text" inputMode="numeric" + value={formatVndInput(amount)}
* onChange={parseVnd} strip non-digit → number
* Suffix "đ" tuyệt đối inset-y-0 right-3
* Hint "VND — nhập số, tự format dấu chấm ngàn (vd 1.000.000)"
- Helpers parseVnd + formatVndInput inline mỗi file (mirror PeDetailTabs)
PeDetailTabs BudgetFieldRow cleanup:
- Drop state manualName + setManualName
- Drop manualName từ dirty check
- Save payload: budgetManualName: null luôn (không phụ thuộc state)
- Hủy thay đổi: drop reset manualName line
Read-only display (legacy data) giữ ev.budgetManualName nếu data cũ có tên
(đoạn render khi !canEdit) — không xóa hiển thị, chỉ ẩn input UI.
BE schema KHÔNG đụng — endpoint PUT /pe/:id vẫn nhận budgetManualName field,
chỉ FE luôn gửi null.
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 169459e66f |
[CLAUDE] FE-PE: NCC cell button visual + Hạng mục header gộp 1 ô Ngân sách + DetailDialog rút gọn
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m0s
User Session 20 turn 5: 2 yêu cầu UX rõ ràng chỗ nhập tiền.
FE-only mirror fe-admin + fe-user.
1. NCC grid cell "Số tiền" → button visual rõ ràng cho user biết là chỗ nhập:
- Trước: <td onClick> trông như text cell (chỉ hover bg → user không
biết click được)
- Sau: <button> trong td:
* Empty (chưa nhập): border-dashed border-slate-300 bg-slate-50
text-slate-400 + label "+ Nhập số tiền" + hover brand
* Filled: border-solid border-slate-300 bg-white font-semibold + số tiền
+ suffix " đ" + hover brand
* Winner: border-emerald-300 bg-emerald-50 text-emerald-700
- Read-only mode: hiển thị <div> số tiền (không button)
- Drop `cellHover` var không còn dùng
2. Hạng mục header gộp 3 stat (KL / ĐG ngân sách / Thành tiền NS) → 1 ô
"Số tiền ngân sách" lớn hơn (text-base font-semibold + suffix đ):
- Trước: 3 columns hiển thị KL + ĐG + TT (kỹ thuật, user không cần thấy)
- Sau: 1 column "Số tiền ngân sách: X đ" — duy nhất số quan trọng
- "NS link Δ" comparison column giữ (nếu có Budget link FYI)
3. DetailDialog rút gọn 11 input → 3 input chính:
- Trước: groupCode + groupName + itemCode + noiDung + donViTinh +
KL ngân sách + KL thi công + đơn giá + thành tiền auto + ghi chú (10
input grid 3 cols)
- Sau: Tên hạng mục (noiDung) + Số tiền ngân sách (VND format + suffix
đ + hint) + Ghi chú (3 input vertical)
- Helper setBudgetAmount: user nhập 1 số → set cả donGia + thanhTien
(KL=1 ngầm). BE giữ schema 3 field backward compat.
- Form state default đổi: groupCode="01" groupName="Hạng mục chính"
donViTinh="gói" KL=1 (consistent với Chunk A BE seed)
- Drop updateAndRecalc helper (không còn auto-calc KL × ĐG)
KHÔNG đụng schema BE.
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 17c5f14e20 |
[CLAUDE] FE-PE: NCC table SĐT+Email rõ ràng + validate format + Số tiền format VND
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m0s
User Session 20 turn 4: NCC info cơ bản (SĐT + Email), ràng buộc format,
input tiền VND format dấu chấm 1.000.000.
FE-only mirror fe-admin + fe-user.
1. Helpers cấu hình ở top file (gần fmtMoney):
- parseVnd(s): strip non-digit → number (0 nếu rỗng)
- formatVndInput(n): n.toLocaleString('vi-VN') hoặc '' khi n=0
- PHONE_RE /^0\d{9,10}$/ — VN bắt đầu 0, 10-11 digits sau strip space/dash/dot
- EMAIL_RE /^[^\s@]+@[^\s@]+\.[^\s@]+$/
- isValidPhone(s) / isValidEmail(s) — empty OK (optional)
2. NCC inline table HangMucCard — bỏ cột "Liên hệ" tổng hợp (ContactName +
Phone + Email gộp), thay bằng 2 cột riêng:
Trước: NCC | Liên hệ | Điều khoản TT | File báo giá | Số tiền | Action
Sau: NCC | SĐT | Email | Điều khoản TT | File báo giá | Số tiền | Action
SĐT cell font-mono (đọc số rõ); Email cell truncate + title hover full.
3. AddSupplierDialog + EditSupplierDialog — validate phone + email:
- Input type="tel" / type="email" + inputMode + placeholder example
- border-red-300 khi invalid + dòng error text [10px] mt-0.5 red-600
- Disable nút Lưu/Thêm khi hasError = phoneError || emailError
- ContactName + DisplayName + Note + PaymentTermText giữ (optional fields,
backward compat — user nói "cơ bản thôi" áp cho display, dialog giữ
đầy đủ field tránh churn schema)
4. QuoteDialog "Số tiền" input format VND:
- type="text" inputMode="numeric" thay vì type="number" (để format dấu
chấm ngàn không phá bởi browser number parser)
- value={formatVndInput(form.thanhTien)} → display "1.000.000"
- onChange={parseVnd(e.target.value)} → strip non-digit → state raw number
- Suffix span "đ" tuyệt đối inset-y-0 right-3 pointer-events-none
- Hint dưới input: "VND — nhập số, tự format dấu chấm ngàn (vd 1.000.000)"
- Class font-mono text-right pr-12 (chừa chỗ suffix)
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| e03314e2e7 |
[CLAUDE] FE-PE: NCC table 1 cột "Số tiền" + QuoteDialog 1 input đơn giản hóa
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m11s
User Session 20 turn 3: "Tạm thời chỉ cần nhập số tiền vào là đc, không cần
3 cột có VAT / ko VAT / tổng. 2 cột kia ẩn đi, chỉ 1 cột nhập tiền duy nhất."
FE-only mirror fe-admin + fe-user:
NCC inline table HangMucCard — bỏ 2 th + 2 td:
Trước: NCC | Liên hệ | Điều khoản TT | File báo giá | ĐG chưa VAT | ĐG có VAT | Thành tiền | Action
Sau: NCC | Liên hệ | Điều khoản TT | File báo giá | Số tiền | Action
QuoteDialog — đơn giản hóa form:
Trước: 3 input (Đơn giá chưa VAT / ĐG có VAT / Thành tiền auto-calc) + Ghi chú
+ display khoiLuong info
Sau: 1 input "Số tiền" (autoFocus) — map thẳng vào thanhTien field
Schema BE giữ nguyên (bgVat / chuaVat / note vẫn POST):
- Row mới: bgVat=0, chuaVat=0, note=''
- Existing: giữ giá trị cũ
Bỏ prop khoiLuong (không dùng — không còn auto-calc thanhTien = chuaVat × khoiLuong)
Bỏ updateAndRecalc helper
KHÔNG đụng schema BE — endpoint POST /purchase-evaluations/{id}/quotes giữ
nguyên payload shape, chỉ FE rút gọn input mặt người dùng nhập.
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| c4ece8071f |
[CLAUDE] FE-PE: Section Ý kiến revise — ô vuông cards grid-cols-2 + counter Cấp đúng semantic
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m11s
User feedback Session 20 turn 2:
1. "Chỗ ý kiến vẫn hiển thị ô vuông như trước nhé" — revert visual về cards
grid-cols-2 mirror S19 (Chunk C cũ dùng vertical list inline không phải
ô vuông như trước).
2. "Số bước duyệt khác số người duyệt trong 1 bước, check lại" — counter cũ
`{opinions.length}/{totalApprovers}` sai semantic vì OR-of-N (mỗi Cấp chỉ
cần 1 NV ký, không cần ký tất cả NV). totalApprovers đếm tổng NV gây hiểu
lầm.
Fix (FE-only mirror fe-admin + fe-user):
- StepOpinionsBox body chuyển từ `space-y-2` (vertical list) sang
`grid grid-cols-1 md:grid-cols-2 gap-3` — mỗi opinion = 1 card đầy đủ
border-emerald-200 + bg-white + p-3 (mirror visual S19 LevelOpinionBox).
- StepOpinionEntry restore styling đầy đủ:
- Header: "Cấp N — Tên NV" font-semibold + admin override badge amber +
"✓ Đã duyệt" emerald rounded-full badge
- Body: comment text-sm
- Footer: signedAt border-t separator (như S19)
- Counter mới: `{signedLevels}/{totalLevels} cấp đã duyệt · {totalApprovers}
NV tham gia` — đếm Cấp distinct (Set unique levelOrder) thay vì count NV.
Tooltip giải thích "OR-of-N" cho user hiểu.
- KHÔNG đụng schema Mig 26 (vẫn UPSERT 1 row / Level qua Service).
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
- Test pass mặc định skip (Q4 UAT iteration)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| f2f01f4765 |
[CLAUDE] FE-PE: Chunk C — Section Ý kiến gộp đồng cấp cùng Phòng (1 box / Step)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m54s
Restructure Section 5 (rename Section 4 sau Chunk B) "Ý kiến cấp duyệt".
User Session 20 Q3=a: gộp các comment đồng cấp cùng Phòng → 1 ô / bước
(dù bước có nhiều người), CHỈ hiển thị comment của NV đã duyệt.
Trước (Mig 26 S19 LevelOpinionsSectionV2):
forEach step → grid-cols-2 cho forEach Level × forEach Approver → 1 box / NV
Hiển thị cả NV chưa duyệt với placeholder "— chưa duyệt"
Sau (Chunk C):
forEach step → 1 StepOpinionsBox (đại diện Phòng)
Box body: filter opinions có stepOrder == step.order
→ sort theo levelOrder asc, signedAt asc
→ render StepOpinionEntry per signed opinion
NV chưa duyệt KHÔNG hiển thị
Header box: "Bước N — Tên · {dept badge} · X/Y đã duyệt"
FE (mirror fe-admin + fe-user):
- LevelOpinionsSectionV2 forEach step → StepOpinionsBox (replace grid-cols-2)
- StepOpinionsBox: header phòng + body list signed opinions
- StepOpinionEntry: tên NV + Cấp badge + Admin override badge nếu có
+ timestamp + comment
- Drop LevelOpinionBox function (per-NV pattern bỏ)
- KHÔNG đụng schema Mig 26 (PE Service ApproveV2Async UPSERT giữ 1 row /
Level — chỉ FE re-group render)
Verify:
- npm run build × fe-admin pass · fe-user pass
- Test pass mặc định skip (Phase 9 UAT iteration, Q4 user public luôn)
Pending Chunk D: Docs S20 changelog + STATUS + HANDOFF
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 2bba851135 |
[CLAUDE] FE-PE: Chunk B — NCC nested expand dưới Hạng mục, bỏ Section 4 riêng
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled
Restructure ItemsTab → nested cards (tầng 1 = hạng mục, tầng 2 = NCC tham
gia + báo giá inline). Replace bảng matrix grid (hạng mục × NCC) cũ — user
Session 20 yêu cầu UX nested cho 1 hạng mục demo.
FE (mirror fe-admin + fe-user):
- ItemsTab giờ render list HangMucCard (1 card / 1 hạng mục)
- HangMucCard mới: header info hạng mục + expand panel default OPEN
- Expand panel: NCC inline table columns:
NCC | Liên hệ | Điều khoản TT | File báo giá | ĐG chưa VAT | ĐG có VAT | Thành tiền | Action
- Quote click cell → QuoteDialog cũ (reuse)
- NCC button: + Thêm NCC (AddSupplierDialog) / ✏ Sửa (EditSupplierDialog) / ✓ Winner / 🗑 Xóa
- Budget Δ compute per-card (KHÔNG tfoot tổng — 1 hạng mục)
- Bỏ Section 4 "NCC tham gia" cũ trong main render — gộp vào Section 2
- Drop function SuppliersTab (dead code) — giữ AddSupplierDialog +
EditSupplierDialog + SupplierAttachmentsCell cho HangMucCard reuse
Section layout mới (4 section):
1. Thông tin gói thầu
2. Hạng mục + Báo giá NCC (nested)
3. Chọn NCC / TP thắng thầu
4. Ý kiến cấp duyệt
Verify:
- npm run build × fe-admin pass (warning chunk size, không liên quan)
- npm run build × fe-user pass
- Test pass mặc định skip (Phase 9 UAT iteration, Q4 user public luôn)
Pending Chunk C: Section 5 (rename 4) gộp đồng cấp cùng Phòng — 1 box / Step
Pending Chunk D: Docs S20 changelog + STATUS + HANDOFF
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|