Repository navigation
Feature/t231 inventory list - #72
Tonfa137206 wants to merge 3 commits into
Conversation
📝 WalkthroughWalkthroughPR bổ sung luồng kiểm kê kho gồm danh sách, tạo mới và chi tiết. PR cũng thay thế giao diện nhập liệu Excel bằng luồng upload, validate và áp dụng hợp nhất. ChangesLuồng kiểm kê kho
Nhập liệu Excel
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 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 |
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 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/AppSidebar.vue`:
- Line 52: Áp dụng phân quyền kiểm kê kho nhất quán tại
src/components/AppSidebar.vue dòng 52 và src/router/index.js dòng 33-34: bổ sung
rule canAccessRoute cho /inventory-counts và /inventory/:id thay vì để nhánh mặc
định cho phép mọi role, đồng thời giới hạn các route theo capability tương ứng.
Trong InventoryCountList.vue chỉ hiển thị thao tác tạo cho EMPLOYEE; trong
InventoryCountDetailView.vue chỉ cho phép MANAGER hủy/chốt; và cập nhật
authorization backend cho các API tạo, hủy, chốt theo đúng quyền này.
In `@src/components/InventoryCountCreateModal.vue`:
- Around line 192-193: Update the product-loading flow in
InventoryCountCreateModal so PARTIAL inventory selection can access products
beyond the first default page of getProducts(). Add product search or pagination
to let users find and select products from later pages, while preserving the
existing product selection behavior.
- Around line 186-198: Cập nhật fetchInitialData để lưu lỗi tải kho/sản phẩm vào
state thay vì chỉ console.error, đồng thời hiển thị loading/error/empty state
tương ứng trong template. Dùng isLoading và trạng thái lỗi để khóa nút gửi cho
đến khi dữ liệu kho tải thành công; giữ nguyên luồng hiển thị danh sách khi tải
thành công.
- Around line 216-224: Update handleSubmit in InventoryCountCreateModal.vue so
the submit payload is normalized with the complete inventory-count record fields
required by InventoryCountList.vue, including id, code, warehouseName, status,
createdDate, and createdBy. Prefer returning the created record from the API and
use that result when unshifting into the list; otherwise map all required fields
before insertion so detail links never use an undefined id.
In `@src/views/ImportExcelView.vue`:
- Line 109: Prevent resetFlow from disrupting the asynchronous confirm/apply
flow in ImportExcelView. In confirmImportSession, capture the current importId
and selectedFile in local variables before awaiting the response, then pass
those stable values to applyImportSession instead of reading mutable state
afterward. Disable the cancel/reset button while isApplying is true, and ensure
resetFlow cannot run during the in-progress operation.
- Around line 65-72: Guard the drag-and-drop area and the handleDrop handler so
file drops are ignored while isProcessing is true. Ensure processSelectedFile
cannot start a second concurrent processing flow or overwrite shared refs such
as importId and selectedFile, preserving the session-to-file association until
the current flow completes.
In `@src/views/InventoryCountDetailView.vue`:
- Around line 152-173: Thay dữ liệu mock trong fetchDetail bằng API tải đợt kiểm
kê theo inventoryId, ánh xạ response vào inventoryCount và items, đồng thời xử
lý lỗi qua error và trạng thái tải hiện có. Tại finalizeCount trong
src/views/InventoryCountDetailView.vue dòng 182-190, gọi API chốt theo
inventoryId và chỉ cập nhật UI sau khi backend xác nhận đã cập nhật đợt kiểm kê
cùng tồn kho; không cập nhật tồn kho khi phiếu chưa hoàn thành.
- Around line 14-31: Update the action visibility in
src/views/InventoryCountDetailView.vue lines 14-31 to require the shared
capability for finalizing inventory counts, while preserving the loading and
locked checks; do not define role policy locally. Update the create-count action
in src/views/InventoryCountList.vue lines 13-18 to require the shared capability
for creating counts. Use the existing shared permission state or permission
service in both components so staff can create counts and managers or
policy-authorized roles can finalize them; backend authorization remains
unchanged.
🪄 Autofix
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: 0b969fe5-4e81-4e83-96ca-8b744619ac74
📒 Files selected for processing (7)
src/components/AppSidebar.vuesrc/components/InventoryCountCreateModal.vuesrc/router/index.jssrc/services/excelImportService.jssrc/views/ImportExcelView.vuesrc/views/InventoryCountDetailView.vuesrc/views/InventoryCountList.vue
| }, | ||
| { label: "Phiếu nhập kho", to: "/stock-in", icon: "mdi-tray-arrow-down" }, | ||
| { label: "Phiếu xuất kho", to: "/stock-out", icon: "mdi-tray-arrow-up" }, | ||
| { label: "Kiểm kê kho", to: "/inventory-counts", icon: "mdi-clipboard-check-outline" }, |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
rg -n -C 5 --glob '*.{js,vue}' \
'canAccessRoute|beforeEach|inventory-counts|InventoryDetail|/inventory/:id|ADMIN|MANAGER|EMPLOYEE' \
srcRepository: ThienlocTran/sme-stocksense-frontend
Length of output: 27112
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- permissionService.js ---'
cat -n src/services/permissionService.js
printf '%s\n' '--- router/index.js ---'
cat -n src/router/index.js | sed -n '1,90p'
printf '%s\n' '--- inventory-count related files ---'
git ls-files | rg '(^|/)(InventoryCount|inventoryCount|inventory-count|inventoryService|auth|permission)'
printf '%s\n' '--- route and capability references ---'
rg -n -C 4 --glob '*.{js,vue}' \
'InventoryCount|inventory-count|inventoryCounts|can(Create|Cancel|Finalize|Access).*Inventory|finaliz|chốt|hủy|create.*count' \
srcRepository: ThienlocTran/sme-stocksense-frontend
Length of output: 29688
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
permission = Path("src/services/permissionService.js").read_text()
route_paths = ["/inventory-counts", "/inventory/123"]
roles = ["ADMIN", "MANAGER", "EMPLOYEE"]
# Extract the current route-policy function and emulate its explicitly visible
# branches. This is read-only and does not execute repository code.
def can_access(path, role):
if path in ("/employees", "/users", "/import-excel"):
return role == "ADMIN"
if path == "/partners":
return role in {"ADMIN", "MANAGER"}
if path in ("/approvals", "/pending-export-approvals", "/export-approvals"):
return role in {"ADMIN", "MANAGER"}
if re.fullmatch(r"/stock-in/[^/]+", path):
return role in {"ADMIN", "EMPLOYEE"}
if re.fullmatch(r"/stock-out/[^/]+", path):
return role in {"ADMIN", "MANAGER", "EMPLOYEE"}
if re.fullmatch(r"/stock-(in|out)/(?:create|[^/]+/edit)", path):
return role in {"ADMIN", "EMPLOYEE"}
return True
print("permission branches mention inventory-counts:", "/inventory-counts" in permission)
for path in route_paths:
print(path, {role: can_access(path, role) for role in roles})
PYRepository: ThienlocTran/sme-stocksense-frontend
Length of output: 361
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- InventoryCountList.vue ---'
cat -n src/views/InventoryCountList.vue | sed -n '1,380p'
printf '%s\n' '--- InventoryCountDetailView.vue ---'
cat -n src/views/InventoryCountDetailView.vue | sed -n '1,250p'
printf '%s\n' '--- InventoryCountCreateModal.vue ---'
cat -n src/components/InventoryCountCreateModal.vue | sed -n '1,320p'
printf '%s\n' '--- inventoryService.js ---'
cat -n src/services/inventoryService.js | sed -n '1,320p'
printf '%s\n' '--- inventory-count API references ---'
rg -n -C 3 --glob '*.{js,vue}' \
'inventory-count|inventoryCount|InventoryCount|/counts|count.*inventory|inventory.*count' \
srcRepository: ThienlocTran/sme-stocksense-frontend
Length of output: 48116
Áp dụng phân quyền kiểm kê kho nhất quán.
canAccessRoute thiếu rule cho /inventory-counts và /inventory/:id, nên nhánh mặc định cho phép mọi role truy cập. InventoryCountList.vue luôn hiển thị nút tạo; InventoryCountDetailView.vue luôn hiển thị nút hủy/chốt. Áp dụng capability theo role, trong đó EMPLOYEE tạo phiếu và MANAGER duyệt/chốt. Backend vẫn phải authorization các API tạo, hủy và chốt.
📍 Affects 2 files
src/components/AppSidebar.vue#L52-L52(this comment)src/router/index.js#L33-L34
🤖 Prompt for 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.
In `@src/components/AppSidebar.vue` at line 52, Áp dụng phân quyền kiểm kê kho
nhất quán tại src/components/AppSidebar.vue dòng 52 và src/router/index.js dòng
33-34: bổ sung rule canAccessRoute cho /inventory-counts và /inventory/:id thay
vì để nhánh mặc định cho phép mọi role, đồng thời giới hạn các route theo
capability tương ứng. Trong InventoryCountList.vue chỉ hiển thị thao tác tạo cho
EMPLOYEE; trong InventoryCountDetailView.vue chỉ cho phép MANAGER hủy/chốt; và
cập nhật authorization backend cho các API tạo, hủy, chốt theo đúng quyền này.
Source: Path instructions
| const fetchInitialData = async () => { | ||
| isLoading.value = true | ||
| try { | ||
| const warehouseData = await getWarehouses({ status: 'HOAT_DONG' }) | ||
| warehouses.value = warehouseData.content || warehouseData.data || warehouseData | ||
|
|
||
| const productData = await getProducts() | ||
| products.value = productData.content || productData.data || productData | ||
| } catch (error) { | ||
| console.error('Lỗi tải dữ liệu kho/sản phẩm:', error) | ||
| } finally { | ||
| isLoading.value = false | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Hiển thị lỗi tải dữ liệu và chặn gửi khi dữ liệu chưa sẵn sàng.
fetchInitialData chỉ ghi lỗi vào console. Template cũng không dùng isLoading. Khi tải kho thất bại, modal chỉ hiện danh sách trống và người dùng không thể tạo phiếu mà không biết nguyên nhân. Lưu lỗi vào state, hiển thị error state, và khóa nút gửi cho đến khi tải kho hoàn tất.
As per path instructions: "src/components/**: Kiểm tra loading, empty state, error state, form validation..."
🤖 Prompt for 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.
In `@src/components/InventoryCountCreateModal.vue` around lines 186 - 198, Cập
nhật fetchInitialData để lưu lỗi tải kho/sản phẩm vào state thay vì chỉ
console.error, đồng thời hiển thị loading/error/empty state tương ứng trong
template. Dùng isLoading và trạng thái lỗi để khóa nút gửi cho đến khi dữ liệu
kho tải thành công; giữ nguyên luồng hiển thị danh sách khi tải thành công.
Source: Path instructions
| const productData = await getProducts() | ||
| products.value = productData.content || productData.data || productData |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Tải đủ sản phẩm cho phạm vi PARTIAL.
getProducts() dùng mặc định page = 0 và size = 10. Modal chỉ cho chọn 10 sản phẩm đầu tiên. Người dùng không thể tạo kiểm kê một phần cho sản phẩm ở các trang sau. Thêm tìm kiếm hoặc phân trang trước khi cho phép chọn sản phẩm.
🤖 Prompt for 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.
In `@src/components/InventoryCountCreateModal.vue` around lines 192 - 193, Update
the product-loading flow in InventoryCountCreateModal so PARTIAL inventory
selection can access products beyond the first default page of getProducts().
Add product search or pagination to let users find and select products from
later pages, while preserving the existing product selection behavior.
| const handleSubmit = async () => { | ||
| errors.warehouseId = !formData.warehouseId | ||
| errors.productIds = formData.scope === 'PARTIAL' && formData.productIds.length === 0 | ||
|
|
||
| if (errors.warehouseId || errors.productIds) return | ||
|
|
||
| isSubmitting.value = true | ||
| try { | ||
| emit('submit', { ...formData }) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Chuẩn hóa payload submit trước khi thêm vào danh sách.
Payload hiện chỉ có warehouseId, scope, productIds, và note. Nhưng src/views/InventoryCountList.vue dòng 153-160 cần id, code, warehouseName, status, createdDate, và createdBy. Bản ghi mới sẽ có dữ liệu trống và link chi tiết thành /inventory/undefined. Trả về bản ghi đã tạo từ API, hoặc map đầy đủ dữ liệu trước khi unshift.
🤖 Prompt for 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.
In `@src/components/InventoryCountCreateModal.vue` around lines 216 - 224, Update
handleSubmit in InventoryCountCreateModal.vue so the submit payload is
normalized with the complete inventory-count record fields required by
InventoryCountList.vue, including id, code, warehouseName, status, createdDate,
and createdBy. Prefer returning the created record from the API and use that
result when unshifting into the list; otherwise map all required fields before
insertion so detail links never use an undefined id.
| <div | ||
| v-if="!validationResult" | ||
| class="border-2 border-dashed rounded-xl p-10 text-center transition-colors mb-6" | ||
| :class="isDragging ? 'border-blue-500 bg-blue-50' : 'border-gray-300 hover:bg-gray-50'" | ||
| @dragover.prevent="isDragging = true" | ||
| @dragleave.prevent="isDragging = false" | ||
| @drop.prevent="handleDrop" | ||
| > |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Chặn kéo thả file khi đang xử lý.
Vùng kéo thả vẫn nhận file khi isProcessing là true. Lần kéo thả thứ hai gọi thêm processSelectedFile và ghi đè các ref dùng chung như importId và selectedFile.
Các request hoàn thành không theo thứ tự có thể validate file thứ nhất bằng session của file thứ hai. Luồng xác nhận sau đó có thể dùng sai session hoặc sai file.
Đề xuất sửa
function handleDrop(e) {
isDragging.value = false
+ if (isProcessing.value) return
const files = e.dataTransfer.files
if (files.length > 0) processSelectedFile(files[0])
}
async function processSelectedFile(file) {
+ if (isProcessing.value) return
resetFlow()As per path instructions, "Ưu tiên lỗi ảnh hưởng thật: correctness, auth, role gating, async flow, state consistency, API error handling và dữ liệu nhạy cảm."
Also applies to: 242-254
🤖 Prompt for 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.
In `@src/views/ImportExcelView.vue` around lines 65 - 72, Guard the drag-and-drop
area and the handleDrop handler so file drops are ignored while isProcessing is
true. Ensure processSelectedFile cannot start a second concurrent processing
flow or overwrite shared refs such as importId and selectedFile, preserving the
session-to-file association until the current flow completes.
Source: Path instructions
| Xác nhận Import Dữ Liệu | ||
| </button> | ||
| <div class="mt-4 text-center"> | ||
| <button @click="resetFlow" class="text-sm text-gray-500 hover:text-gray-700 underline">Hủy bỏ / Chọn file khác</button> |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Không cho reset luồng khi đang confirm và apply.
Người dùng vẫn có thể nhấn resetFlow khi confirmImportSession đang chờ phản hồi. Hàm này đặt importId và selectedFile thành null.
Khi confirm thành công, Line 309 có thể gọi applyImportSession(null, null). Lưu sessionId và file vào biến cục bộ trước await. Đồng thời vô hiệu hóa nút hủy khi isApplying là true.
Đề xuất sửa
- <button `@click`="resetFlow" class="text-sm text-gray-500 hover:text-gray-700 underline">
+ <button :disabled="isApplying" `@click`="resetFlow" class="text-sm text-gray-500 hover:text-gray-700 underline disabled:opacity-50">
async function handleFinalImport() {
- if (!importId.value || !selectedFile.value) return
+ const sessionId = importId.value
+ const file = selectedFile.value
+ if (!sessionId || !file) return
isApplying.value = true
try {
- await confirmImportSession(importId.value)
- await applyImportSession(importId.value, selectedFile.value)
+ await confirmImportSession(sessionId)
+ await applyImportSession(sessionId, file)As per path instructions, "Ưu tiên lỗi ảnh hưởng thật: correctness, auth, role gating, async flow, state consistency, API error handling và dữ liệu nhạy cảm."
Also applies to: 301-309
🤖 Prompt for 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.
In `@src/views/ImportExcelView.vue` at line 109, Prevent resetFlow from disrupting
the asynchronous confirm/apply flow in ImportExcelView. In confirmImportSession,
capture the current importId and selectedFile in local variables before awaiting
the response, then pass those stable values to applyImportSession instead of
reading mutable state afterward. Disable the cancel/reset button while
isApplying is true, and ensure resetFlow cannot run during the in-progress
operation.
Source: Path instructions
| <!-- Actions (Chỉ hiện khi chưa chốt/hủy và đã load xong) --> | ||
| <div class="flex gap-3" v-if="!isLoading && !isLocked"> | ||
| <button | ||
| @click="cancelCount" | ||
| class="px-4 py-2 bg-white border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center" | ||
| :disabled="isCancelling || isFinalizing" | ||
| > | ||
| <svg v-if="isCancelling" class="animate-spin -ml-1 mr-2 h-4 w-4 text-gray-700" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> | ||
| Hủy đợt kiểm kê | ||
| </button> | ||
| <button | ||
| @click="finalizeCount" | ||
| class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 font-medium shadow-sm transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center" | ||
| :disabled="isCancelling || isFinalizing" | ||
| > | ||
| <svg v-if="isFinalizing" class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> | ||
| Chốt kiểm kê (Finalize) | ||
| </button> |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Dùng capability chung để giới hạn action theo role.
Các action hiện chỉ kiểm tra loading và status. Người dùng mở được màn hình có thể thấy nút tạo mới hoặc chốt kiểm kê. Điều này không phản ánh luồng StockSense: nhân viên tạo phiếu và manager duyệt/chốt phiếu.
src/views/InventoryCountDetailView.vue#L14-L31: chỉ hiển thị và cho gọi chốt kiểm kê với capability củaMANAGERhoặc role được policy cấp quyền.src/views/InventoryCountList.vue#L13-L18: chỉ hiển thị tạo đợt kiểm kê cho role có capability tạo phiếu.
Dùng state hoặc permission service dùng chung. Không đặt policy role riêng trong component. Backend vẫn phải kiểm tra quyền khi gọi API.
As per path instructions: "**/*: UI phải phản ánh đúng quyền; nhân viên tạo phiếu; manager duyệt."
📍 Affects 2 files
src/views/InventoryCountDetailView.vue#L14-L31(this comment)src/views/InventoryCountList.vue#L13-L18
🤖 Prompt for 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.
In `@src/views/InventoryCountDetailView.vue` around lines 14 - 31, Update the
action visibility in src/views/InventoryCountDetailView.vue lines 14-31 to
require the shared capability for finalizing inventory counts, while preserving
the loading and locked checks; do not define role policy locally. Update the
create-count action in src/views/InventoryCountList.vue lines 13-18 to require
the shared capability for creating counts. Use the existing shared permission
state or permission service in both components so staff can create counts and
managers or policy-authorized roles can finalize them; backend authorization
remains unchanged.
Source: Path instructions
| const fetchDetail = async () => { | ||
| isLoading.value = true | ||
| error.value = '' | ||
| try { | ||
| // Giả lập call API 600ms | ||
| await new Promise(resolve => setTimeout(resolve, 600)) | ||
|
|
||
| // Dữ liệu Mock | ||
| inventoryCount.value = { | ||
| id: inventoryId, | ||
| code: 'KK-202310-001', | ||
| warehouseName: 'Kho Trung Tâm', | ||
| status: 'IN_PROGRESS', | ||
| createdAt: '10/10/2023 08:30' | ||
| } | ||
|
|
||
| items.value = [ | ||
| { id: 1, productCode: 'SP001', productName: 'iPhone 15 Pro Max', systemQuantity: 50, actualQuantity: 50 }, | ||
| { id: 2, productCode: 'SP002', productName: 'MacBook Air M2', systemQuantity: 15, actualQuantity: 12 }, | ||
| { id: 3, productCode: 'SP003', productName: 'AirPods Pro 2', systemQuantity: 100, actualQuantity: 105 }, | ||
| { id: 4, productCode: 'SP004', productName: 'iPad Pro 11 inch', systemQuantity: 0, actualQuantity: 2 }, | ||
| ] |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Thay mock bằng API lưu và tải đợt kiểm kê theo ID.
fetchDetail luôn tạo cùng một đợt kiểm kê, bất kể inventoryId. finalizeCount chỉ đổi status trong ref, nên tải lại trang sẽ mất trạng thái chốt và tồn kho không được cập nhật bởi transaction backend.
src/views/InventoryCountDetailView.vue#L152-L173: tải chi tiết theoinventoryIdvà xử lý response/error từ API.src/views/InventoryCountDetailView.vue#L182-L190: gọi API chốt kiểm kê; chỉ đổi UI sau khi backend xác nhận cập nhật đợt kiểm kê và tồn kho.
As per path instructions: "src/views/**: không cập nhật tồn kho khi phiếu chưa hoàn thành."
📍 Affects 1 file
src/views/InventoryCountDetailView.vue#L152-L173(this comment)src/views/InventoryCountDetailView.vue#L182-L190
🤖 Prompt for 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.
In `@src/views/InventoryCountDetailView.vue` around lines 152 - 173, Thay dữ liệu
mock trong fetchDetail bằng API tải đợt kiểm kê theo inventoryId, ánh xạ
response vào inventoryCount và items, đồng thời xử lý lỗi qua error và trạng
thái tải hiện có. Tại finalizeCount trong src/views/InventoryCountDetailView.vue
dòng 182-190, gọi API chốt theo inventoryId và chỉ cập nhật UI sau khi backend
xác nhận đã cập nhật đợt kiểm kê cùng tồn kho; không cập nhật tồn kho khi phiếu
chưa hoàn thành.
Source: Path instructions
Summary by CodeRabbit