Repository navigation
Release/1.2 - #35
Release/1.2#35
Conversation
…receipt-list-ui feat(inbound): add employee import receipt list UI
…orm-ui feat(inbound): add import receipt form UI
…eference-dropdowns feat(inbound): improve import receipt reference dropdown resilience
…etail-table-total feat(inbound): show import receipt item totals and summary
…orm-actions feat(inbound): integrate import receipt actions
…ceipt-rejection-reason feat(inbound): show rejected import receipt reason
…ect modal) - T95: pending-approval list view with status filter and pagination - T96: approval detail modal (info + product table) - T97: approve integration (two-level) with refresh - T98: reject modal with required-reason validation - add approval service functions in importReceiptService.js
…on-ui T105: Create import receiving and inspection UI
Feature/t69 inventory list UI
…y-transaction-UI Feature/t72 history inventory transaction UI
…eipt-approval-ui to resolve conflict in importReceiptService.js
…pproval-ui feat(T95-T98): import receipt approval UI (list, detail, approve, rej…
…pproval-ui Update Ui add button history
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (13)
📝 WalkthroughWalkthroughPR này thêm luồng phiếu nhập kho end-to-end, màn hình tra cứu tồn kho/giao dịch kho, cập nhật phân quyền theo role, và mở rộng một số component/style dùng chung để hỗ trợ các màn hình mới. ChangesPhân quyền và điều hướng
Luồng phiếu nhập kho
Tồn kho, giao dịch kho và UI dùng chung
Estimated code review effort: 4 (Complex) | ~75 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai full review |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 22
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/ImportInspectionPanel.vue`:
- Around line 34-38: The permission check in ImportInspectionPanel.vue is
hard-coded in canProcessReceipt using authStore.currentRole, which can drift
from the shared authorization rules. Move this logic out of the component and
use the centralized permission/service state already used by the
router/sidebar/permission layer, then have the component consume that shared
source for UX-only gating while keeping backend authorization unchanged.
- Around line 209-219: Bắt buộc kiểm tra dữ liệu giải trình trước khi lưu biên
bản trong handleSaveDiscrepancyReport: nếu reason/action còn rỗng thì chặn lưu
và hiển thị lỗi thay vì chỉ dựa vào hasDiscrepancy. Hãy bổ sung validation ngay
trước khi gọi createDiscrepancyReport/buildDiscrepancyPayload để đảm bảo payload
luôn có lý do và hướng xử lý hợp lệ, đồng thời giữ trạng thái “Hoàn Tất Nhập
Kho” bị khóa cho đến khi biên bản được lưu với dữ liệu đầy đủ.
- Around line 94-127: The loadData request guard only protects the success path,
so stale requests can still overwrite error or loading state in the
catch/finally blocks. Update loadData in ImportInspectionPanel.vue to check the
currentRequestId again inside catch and finally before setting error.value or
loading.value, and keep all state mutations for receipt/inspectItems/discrepancy
fields tied to the latest request only.
In `@src/components/SearchFilterBar.vue`:
- Around line 2-23: SearchFilterBar is applying fallthrough attrs twice, once to
the root wrapper and again to the input via attrs. Update the SearchFilterBar
component to disable inherited attrs with defineOptions({ inheritAttrs: false })
so useAttrs() only feeds the <input>, keeping id, data-testid, and aria-* on the
correct element.
In `@src/router/index.js`:
- Around line 61-72: Clarify that resolveRouteAccess in src/router/index.js is
only a frontend navigation guard for UX and does not provide real authorization.
Update the route-guard logic or surrounding comment near
resolveRouteAccess/getCurrentRoleCode to explicitly state that backend API
endpoints must still enforce role checks, since users can bypass the router and
call APIs directly.
In `@src/services/importReceiptService.js`:
- Around line 248-254: The getProducts() response handling in
importReceiptService should normalize the API payload before reading content,
since data may be null/empty or returned as a direct array. Update the logic
around importReceiptClient.get and the data.content access so it safely handles
missing bodies and supports both { content: [...] } and array responses,
returning a valid product list instead of an empty dropdown.
- Around line 6-11: Add a timeout to the axios client created in
importReceiptClient so stuck requests do not leave awaiters loading
indefinitely. Update the axios.create configuration in importReceiptService to
include an explicit timeout value alongside API_BASE_URL and the existing
Content-Type header, keeping the change scoped to the importReceiptClient setup.
In `@src/services/inventoryService.js`:
- Around line 6-11: The inventoryClient created in inventoryService should
include a shared timeout so requests fail fast instead of leaving the inventory
screen stuck loading; update the axios.create configuration for inventoryClient
to add a reasonable timeout value alongside baseURL and headers, and ensure the
existing request flow still routes failures through normalizeInventoryError.
In `@src/views/ApprovalsView.vue`:
- Around line 149-171: Prevent duplicate approve requests by adding an in-flight
guard to confirmApprove and wiring a loading state into ConfirmDialog. Use the
existing actionState/actionMessage flow in ApprovalsView.vue so the approve
action is disabled or ignored while approveImportReceipt is running, and make
sure confirmApprove() exits early if an approval is already pending.
- Around line 67-87: `fetchPendingApprovals` đang có nguy cơ để response cũ ghi
đè state mới khi người dùng đổi filter/trang nhanh. Hãy thêm cơ chế chặn request
lỗi thời trong `ApprovalsView.vue`—ví dụ dùng request sequence/id hoặc
`AbortController` gắn với lần gọi hiện tại—và chỉ cập nhật `receipts`,
`totalPages`, `totalElements`, `errorMessage` khi response thuộc request mới
nhất. Giữ logic này trong `fetchPendingApprovals` và các điểm gọi liên quan để
đảm bảo chỉ dữ liệu mới nhất được render.
In `@src/views/InventoryTransactionsView.vue`:
- Around line 62-65: `onMounted` vẫn gọi `fetchTransactions()` ngay cả khi
`loadDropdowns()` đã bị 401 và redirect sang `/login`, nên cần chặn request tiếp
theo sau khi auth fail. Hãy sửa luồng trong `InventoryTransactionsView` để
`loadDropdowns()` trả về trạng thái thành công/thất bại hoặc ném lỗi, rồi chỉ
gọi `fetchTransactions()` khi `loadDropdowns` hoàn tất bình thường; nếu có
redirect/401 thì thoát sớm và không chạy thêm request nào.
- Around line 82-95: Add date-range validation in fetchTransactions before
calling getInventoryTransactions so the view does not send an invalid request
when from is after to. Use the existing filters.from and filters.to handling in
InventoryTransactionsView.vue to detect the invalid range, set
errorMessage.value with a clear validation message, and return early without
toggling the API call. Keep the loading/error state behavior consistent with the
rest of the view and ensure the same validation is applied wherever the filter
form is submitted or refreshed.
In `@src/views/InventoryView.vue`:
- Around line 64-67: `onMounted` trong `InventoryView.vue` vẫn gọi
`fetchInventory()` dù `loadDropdowns()` đã gặp 401 và redirect `/login`, gây
request tiếp theo không còn token. Hãy cập nhật luồng khởi tạo trong `onMounted`
(và nếu cần, `loadDropdowns`/`fetchInventory`) để sau khi `loadDropdowns()` báo
lỗi auth hoặc redirect thì dừng ngay, không chạy `fetchInventory()`. Dùng một
cờ/return sớm dựa trên kết quả của `loadDropdowns()` để chặn request thứ hai và
tránh flash loading/lỗi.
- Line 224: The product status cell in InventoryView’s productStatus slot
currently treats every non-HOAT_DONG value as “Ngừng hoạt động”, which masks
null or new backend statuses. Update the StatusBadge mapping logic to handle
only known status values explicitly and render a neutral/fallback label for
unknown or missing values, so unrecognized backend data is not misrepresented.
Use the productStatus template and StatusBadge binding as the location to adjust
the enum-to-label mapping.
In `@src/views/ProductsView.vue`:
- Around line 348-352: The EmptyState in ProductsView.vue currently shows a
description that suggests adding a new product even when canManage is false,
which conflicts with the read-only UI state. Update the description used by the
EmptyState rendering so it varies by permission, keeping the “thêm sản phẩm mới”
suggestion only for users who can manage and showing a permission-appropriate
message otherwise. Use the existing canManage condition in the ProductsView
component to locate and adjust the EmptyState props.
In `@src/views/StockDocumentCreateView.vue`:
- Around line 85-87: The save/send/cancel button guards in
StockDocumentCreateView need to include role-based checks, not just receipt
status. Update the computed flags canSubmit, canCancel, and canSave to also
verify the current user role matches the allowed roles for this screen, ideally
by using the existing permissionService helper instead of hard-coding role logic
in the component. Keep the UI guard in this view aligned with the
ADMIN/MANAGER/EMPLOYEE rules, while leaving backend authorization unchanged.
- Around line 356-359: Timer điều hướng trong StockDocumentCreateView chưa được
dọn khi rời trang, nên callback setTimeout vẫn có thể chạy và gọi
router.push('/stock-in') sau khi component đã unmount. Hãy lưu lại timeout id ở
các đoạn dùng setTimeout liên quan đến isCreateMode trong
StockDocumentCreateView.vue, và clearTimeout nó trong cleanup của component
(onUnmounted hoặc beforeRouteLeave nếu phù hợp); đồng thời áp dụng cùng cách dọn
cho các timer/listener/watcher tương tự ở các đoạn được chỉ ra.
- Around line 82-84: The hasValidItems computed in StockDocumentCreateView
currently allows an empty string or NaN unitPrice to pass validation, so tighten
the item checks to reject blank/invalid prices before submit. Update the
validation logic around items.value.every to explicitly verify item.unitPrice is
a non-empty, finite number (not ''/NaN) alongside productId and quantity, and
ensure the same form validation rule is applied wherever the payload is prepared
or submitted in this view.
In `@src/views/StockDocumentDetailView.vue`:
- Around line 19-20: The ImportInspectionPanel component is being mounted even
when the id prop is empty (default value is ''), causing unnecessary API calls
with invalid parameters. Add a guard condition to prevent mounting the
ImportInspectionPanel until id has a valid value. Modify the template condition
to check that both type === 'in' AND id is not empty before rendering the
ImportInspectionPanel component. This ensures the panel only mounts when the
receiptId prop has meaningful data.
In `@src/views/StockDocumentsView.vue`:
- Around line 244-260: The permission helpers in StockDocumentsView
(canEditImportReceipt, canSubmitImportReceipt, canCancelImportReceipt) currently
allow any non-MANAGER role when the status matches, so tighten them to an
explicit allowlist for valid roles only (for example ADMIN and EMPLOYEE). Update
the role checks in these functions so empty or invalid currentRole.value does
not return true, while keeping the existing status-based behavior for allowed
roles; leave submitLabel unchanged.
- Around line 84-107: Prevent stale receipt responses from overwriting newer
filter/page results in fetchReceipts. Add request-order protection in the
StockDocumentsView.vue async flow so only the latest invocation can update
receipts, totalPages, and totalElements after listReceipts resolves. Use a
unique guard tied to fetchReceipts (such as an incrementing request token or
cancellation check) and ignore any older response before mutating state; keep
the current loading/error handling and router.replace logic intact.
In `@src/views/WarehousesView.vue`:
- Around line 325-329: The EmptyState in WarehousesView should vary its
description based on the user’s canManage permission, since the current “thêm
kho mới” hint is shown even in read-only mode. Update the EmptyState block under
the v-else-if branch to choose a different description when canManage is false,
and keep the existing add-new suggestion only for users who can manage
warehouses.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 8552809a-2a5c-4671-bd63-1b80e4633dff
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (25)
.gitignoresrc/assets/styles/import-receipt-form.csssrc/components/AppSidebar.vuesrc/components/ConfirmDialog.vuesrc/components/DataTable.vuesrc/components/EmptyState.vuesrc/components/ImportInspectionPanel.vuesrc/components/ImportReceiptHistoryModal.vuesrc/components/SearchFilterBar.vuesrc/components/StatusBadge.vuesrc/constants/warehouseOptions.jssrc/router/index.jssrc/services/importReceiptService.jssrc/services/inventoryService.jssrc/services/permissionService.jssrc/style.csssrc/views/ApprovalsView.vuesrc/views/InventoryTransactionsView.vuesrc/views/InventoryView.vuesrc/views/ProductsView.vuesrc/views/StockDocumentCreateView.vuesrc/views/StockDocumentDetailView.vuesrc/views/StockDocumentsView.vuesrc/views/WarehousesView.vuesrc/views/categories/CategoryListView.vue
Summary by CodeRabbit