Skip to content

T121-T123: Export receipt UI and integration - #37

Merged
ThienlocTran merged 5 commits into
devfrom
feature/T121-T123-export-ui
Jul 16, 2026
Merged

ThienlocTran merged 5 commits into
devfrom
feature/T121-T123-export-ui

Conversation

@nguyenndb

@nguyenndb nguyenndb commented Jul 9, 2026 •

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features
    • Thêm màn hình danh sách, tạo/sửa và xem chi tiết phiếu xuất kho, với các thao tác phù hợp theo trạng thái.
    • Bổ sung luồng xác nhận khi gửi duyệt hoặc hủy phiếu, kèm thông báo kết quả và làm mới dữ liệu sau thao tác.
    • Hiển thị badge trạng thái, lý do từ chối, bộ lọc danh sách và điều hướng quay lại/giữ trạng thái lọc.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@nguyenndb, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 42 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5381e786-8669-41d4-a9e7-46bd95d0077d

📥 Commits

Reviewing files that changed from the base of the PR and between 27a2dbc and 1cd43f6.

📒 Files selected for processing (6)
  • docs/README_T121.md
  • docs/README_T122.md
  • docs/README_T124.md
  • src/components/ExportReceiptDetailPanel.vue
  • src/components/ExportReceiptForm.vue
  • src/services/exportReceiptService.js
📝 Walkthrough

Walkthrough

PR thêm module Phiếu xuất kho (Export Receipt) cho frontend: service exportReceiptService.js gọi API backend, ba component Vue mới (ExportReceiptList, ExportReceiptForm, ExportReceiptDetailPanel), và gắn các component này vào các view hiện có thay cho placeholder. Kèm nhiều file tài liệu đặc tả.

Changes

Module Phiếu xuất kho

Layer / File(s) Summary
Service gọi API
src/services/exportReceiptService.js
Tạo axios client và các hàm gọi API danh sách/tạo/sửa/hủy/gửi duyệt phiếu xuất, kèm chuẩn hóa lỗi và xử lý 401.
Danh sách phiếu xuất
src/components/ExportReceiptList.vue
Hiển thị danh sách theo role, lọc/phân trang, và luồng xác nhận gửi duyệt/hủy qua ConfirmDialog.
Form tạo/sửa phiếu xuất
src/components/ExportReceiptForm.vue
Form nhập header + chi tiết sản phẩm, validate tồn kho, cảnh báo đổi kho, lưu nháp/lưu & gửi duyệt.
Chi tiết phiếu xuất
src/components/ExportReceiptDetailPanel.vue
Panel readonly hiển thị chi tiết, action Sửa/Gửi duyệt/Hủy theo role & trạng thái, reload sau thao tác.
Gắn vào view hiện có
src/views/StockDocumentsView.vue, src/views/StockDocumentCreateView.vue, src/views/StockDocumentDetailView.vue
Thay FeaturePending bằng các component export tương ứng khi type !== 'in'.
Tài liệu đặc tả
docs/README_T121.md, docs/README_T122.md, docs/README_T123.md, docs/superpowers/specs/..., export-receipt-plan.md
Bổ sung đặc tả UI/UX và kế hoạch triển khai cho các màn hình phiếu xuất/nhập.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Tiêu đề mô tả đúng thay đổi chính: bổ sung UI và tích hợp luồng phiếu xuất cho T121-T123.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/T121-T123-export-ui

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🤖 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 `@docs/README_T121.md`:
- Around line 38-40: Điều chỉnh rule điều hướng để chỉ áp dụng cho luồng
tạo/sửa/submit thành công, không mô tả redirect từ màn danh sách. Cập nhật phần
liên quan trong `README_T121.md` để phản ánh đúng flow của
`ExportReceiptList.vue`, nơi action trên list chỉ refresh dữ liệu tại chỗ sau
submit/hủy và không gọi router redirect; giữ wording tập trung vào các màn
T122/T120 và bỏ ngụ ý chuyển trang từ list.

In `@docs/README_T122.md`:
- Around line 16-17: The product-selection rule in the draft-edit flow is too
strict and can hide previously chosen rows when inventory reaches zero, breaking
state consistency. Update the spec around the product dropdown so the “Inventory
> 0” filter applies only to new selections, while existing lines in an editable
draft remain visible and selectable in the current form state even if their
stock is now zero. Use the draft-edit vs create-new behavior distinction in the
product selection requirements to guide the change.
- Around line 18-20: The “Validate Số lượng xuất” requirement only covers
real-time UI checks, but backend must also re-validate inventory before
save/submit to protect data integrity. Update the spec around the inventory
validation requirement to state that the backend flow (for the save/approval
path) must compare the requested quantity against current stock, or enforce
version/optimistic locking, using the relevant inventory and submit/save
workflow as the source of truth. Keep the UI warning behavior, but make it clear
that client-side validation is not sufficient on its own.

In `@docs/superpowers/specs/2026-06-28-import-receipt-ux-ui-design.md`:
- Around line 30-35: Spec hiện đang gộp chung chặn chuyển route và refresh/đóng
tab, nhưng onBeforeRouteLeave chỉ xử lý điều hướng nội bộ. Hãy tách rõ hai cơ
chế: onBeforeRouteLeave cho route change trong app và beforeunload cho F5/đóng
tab, để mô tả đúng behavior bảo vệ dữ liệu. Cập nhật phần Unsaved Changes Guard
để nêu rõ khi nào Modal/Dialog xuất hiện và luồng confirm/discard tương ứng, đảm
bảo state consistency và async flow nhất quán.
- Around line 23-29: Role gating and self-approval behavior are inconsistent
with the current action rendering in StockDocumentsView, so update the spec to
first define the exact role matrix for who can see the Approve/Reject actions,
then describe the disabled state only for the case where Manager is viewing
their own receipt. Make the wording align with the actual conditional rendering
in StockDocumentsView so implementation can support a visible-but-disabled
button state for authorized roles rather than implying visibility for roles that
are currently excluded.

In `@src/components/ExportReceiptDetailPanel.vue`:
- Around line 112-129: `executeSubmit` (and the matching `executeCancel`)
currently only surfaces `err.message` and does not handle 401 the way
`loadReceiptDetails` does, so expired sessions do not redirect to login. Update
these handlers to detect `err.status === 401` in their catch blocks, call
`router.replace('/login')` like `loadReceiptDetails`, and keep the existing
error fallback for non-401 cases. Use the existing `executeSubmit`,
`executeCancel`, and `loadReceiptDetails` logic in
`ExportReceiptDetailPanel.vue` as the reference for consistent auth handling.

In `@src/components/ExportReceiptForm.vue`:
- Around line 87-112: The form handlers in ExportReceiptForm.vue are missing 401
handling, so expired-token failures leave the user stuck on the page. Update
loadReceiptDetails, saveReceipt, and saveAndSubmit to detect err.status === 401
and redirect with router.replace('/login'), matching the behavior already used
in ExportReceiptList and ExportReceiptDetailPanel. Keep the existing
errorMessage fallback for non-401 errors, and make sure the redirect logic is
applied in the same catch blocks for these methods.
- Around line 266-268: The delayed navigation in ExportReceiptForm’s submit flow
uses setTimeout without cleanup, so it can still call router.push('/stock-out')
after the user has already left the page. Store the timeout handle in the
component state inside the affected submit handler(s), and clear it when the
component unmounts or before starting a new timeout; apply the same cleanup
pattern to both places using this delayed redirect.
- Around line 289-293: The create-and-submit flow in ExportReceiptForm’s draft
handling is split between createDraft() and submitForApproval(), which can leave
a newly created draft unreconciled if approval submission fails. Update the
non-edit path in ExportReceiptForm so it preserves the created receiptIdToSubmit
and transitions the UI to the newly created draft (or otherwise exposes its
ID/state) when submitForApproval() errors, instead of staying in create mode and
allowing a second createDraft() on retry.

In `@src/services/exportReceiptService.js`:
- Around line 6-11: The axios client in exportReceiptClient is missing a
timeout, so requests can hang indefinitely when the backend is slow or
unresponsive. Update the axios.create configuration in exportReceiptClient to
include a reasonable timeout value alongside baseURL and headers, keeping the
existing setup intact.
🪄 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: 264acaa1-db11-40b9-8e0d-f0292f778b0e

📥 Commits

Reviewing files that changed from the base of the PR and between fadc594 and 27a2dbc.

📒 Files selected for processing (12)
  • docs/README_T121.md
  • docs/README_T122.md
  • docs/README_T123.md
  • docs/superpowers/specs/2026-06-28-import-receipt-ux-ui-design.md
  • export-receipt-plan.md
  • src/components/ExportReceiptDetailPanel.vue
  • src/components/ExportReceiptForm.vue
  • src/components/ExportReceiptList.vue
  • src/services/exportReceiptService.js
  • src/views/StockDocumentCreateView.vue
  • src/views/StockDocumentDetailView.vue
  • src/views/StockDocumentsView.vue

Comment thread docs/README_T121.md Outdated
Comment thread docs/README_T122.md Outdated
Comment thread docs/README_T122.md Outdated
Comment on lines +23 to +29
### 2.3 Self-Approval Restriction (Chặn Duyệt Chéo)
- **Scenario:** A user with the `Manager` role views a receipt that they originally created themselves.
- **UI Behavior:**
- The "Approve / Reject" (Duyệt / Từ chối) action buttons will still be visible to maintain layout consistency.
- However, the buttons will be visibly **DISABLED** (greyed out).
- Hovering over the disabled buttons will display a clear Tooltip: *"Bạn không thể tự duyệt phiếu do chính mình tạo"*.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Chốt lại role matrix trước khi mô tả nút “disabled”.

Spec đang nói Manager vẫn thấy nút rồi mới disable, nhưng src/views/StockDocumentsView.vue:250-271 hiện chỉ render action cho role ADMIN/EMPLOYEE. Nếu giữ nguyên mô tả này thì implementation sẽ không bao giờ có trạng thái “disabled” cho Manager.

Gợi ý chỉnh spec
- The "Approve / Reject" action buttons will still be visible to maintain layout consistency.
- However, the buttons will be visibly DISABLED (greyed out).
+ Chỉ mô tả disabled-state nếu role hiện tại thật sự render được nút.
+ Nếu không, hãy ẩn hẳn action theo role matrix để tránh lệch UI.

As per path instructions: ưu tiên correctness và role gating.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### 2.3 Self-Approval Restriction (Chặn Duyệt Chéo)
- **Scenario:** A user with the `Manager` role views a receipt that they originally created themselves.
- **UI Behavior:**
- The "Approve / Reject" (Duyệt / Từ chối) action buttons will still be visible to maintain layout consistency.
- However, the buttons will be visibly **DISABLED** (greyed out).
- Hovering over the disabled buttons will display a clear Tooltip: *"Bạn không thể tự duyệt phiếu do chính mình tạo"*.
### 2.3 Self-Approval Restriction (Chặn Duyệt Chéo)
- **Scenario:** A user with the `Manager` role views a receipt that they originally created themselves.
- **UI Behavior:**
- Chỉ mô tả disabled-state nếu role hiện tại thật sự render được nút.
- Nếu không, hãy ẩn hẳn action theo role matrix để tránh lệch UI.
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 23-23: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 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 `@docs/superpowers/specs/2026-06-28-import-receipt-ux-ui-design.md` around
lines 23 - 29, Role gating and self-approval behavior are inconsistent with the
current action rendering in StockDocumentsView, so update the spec to first
define the exact role matrix for who can see the Approve/Reject actions, then
describe the disabled state only for the case where Manager is viewing their own
receipt. Make the wording align with the actual conditional rendering in
StockDocumentsView so implementation can support a visible-but-disabled button
state for authorized roles rather than implying visibility for roles that are
currently excluded.

Source: Path instructions

Comment on lines +30 to +35
### 2.4 Unsaved Changes Guard (Cảnh báo mất dữ liệu)
- **Scenario:** The user is filling out the "Create Draft" or "Inspect" form and attempts to navigate away (e.g., clicking Back, refreshing the page, or clicking another sidebar menu) without saving.
- **UI Behavior:**
- The browser/router will intercept the navigation.
- A Modal/Dialog will appear warning: *"Bạn có dữ liệu chưa lưu, chắc chắn muốn rời đi?"*.
- The user must explicitly confirm to discard changes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Tách guard cho route change và refresh/đóng tab.

onBeforeRouteLeave chỉ chặn chuyển route nội bộ. Nếu muốn bảo vệ lúc F5 hoặc đóng tab, spec cần thêm cơ chế beforeunload riêng; nếu không người dùng vẫn có thể mất dữ liệu dù mô tả nói “browser/router sẽ intercept”.

Gợi ý chỉnh spec
- The browser/router will intercept the navigation.
+ The router will intercept internal navigation.
+ A separate beforeunload guard will handle refresh/close tab.

As per path instructions: ưu tiên state consistency và async flow.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### 2.4 Unsaved Changes Guard (Cảnh báo mất dữ liệu)
- **Scenario:** The user is filling out the "Create Draft" or "Inspect" form and attempts to navigate away (e.g., clicking Back, refreshing the page, or clicking another sidebar menu) without saving.
- **UI Behavior:**
- The browser/router will intercept the navigation.
- A Modal/Dialog will appear warning: *"Bạn có dữ liệu chưa lưu, chắc chắn muốn rời đi?"*.
- The user must explicitly confirm to discard changes.
### 2.4 Unsaved Changes Guard (Cảnh báo mất dữ liệu)
- **Scenario:** The user is filling out the "Create Draft" or "Inspect" form and attempts to navigate away (e.g., clicking Back, refreshing the page, or clicking another sidebar menu) without saving.
- **UI Behavior:**
- The router will intercept internal navigation.
- A separate beforeunload guard will handle refresh/close tab.
- A Modal/Dialog will appear warning: *"Bạn có dữ liệu chưa lưu, chắc chắn muốn rời đi?"*.
- The user must explicitly confirm to discard changes.
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 30-30: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 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 `@docs/superpowers/specs/2026-06-28-import-receipt-ux-ui-design.md` around
lines 30 - 35, Spec hiện đang gộp chung chặn chuyển route và refresh/đóng tab,
nhưng onBeforeRouteLeave chỉ xử lý điều hướng nội bộ. Hãy tách rõ hai cơ chế:
onBeforeRouteLeave cho route change trong app và beforeunload cho F5/đóng tab,
để mô tả đúng behavior bảo vệ dữ liệu. Cập nhật phần Unsaved Changes Guard để
nêu rõ khi nào Modal/Dialog xuất hiện và luồng confirm/discard tương ứng, đảm
bảo state consistency và async flow nhất quán.

Source: Path instructions

Comment thread src/components/ExportReceiptDetailPanel.vue
Comment thread src/components/ExportReceiptForm.vue
Comment thread src/components/ExportReceiptForm.vue Outdated
Comment thread src/components/ExportReceiptForm.vue Outdated
Comment thread src/services/exportReceiptService.js
@ThienlocTran
ThienlocTran merged commit cdd2bf6 into dev Jul 16, 2026
1 check passed
@coderabbitai coderabbitai Bot mentioned this pull request Jul 29, 2026
@ThienlocTran
ThienlocTran deleted the feature/T121-T123-export-ui branch July 31, 2026 11:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants