FE: module gift_card — thẻ quà #
Phần chung (khởi tạo client, lỗi, danh sách, ngôn ngữ) ở tài liệu FE của Core:
docs/fe/common.md (bản đọc: xforge-documentation, ADR-0102 của xforge-core).
Sửa file này CÙNG PR khi đổi hành vi FE thấy được của module.
CMS / admin (XforgeClient) #
Menu: key gift_card.gift_cards (quyền gift_card.read). Route CRUD chuẩn,
không thùng rác: listGiftCards, getGiftCard, createGiftCard,
updateGiftCard, deleteGiftCard, listGiftCardOptions; thêm
adjustGiftCard, listGiftCardTransactions, refundOrderToGiftCard và
listGiftCardOrderRefundables.
| Field | Ghi chú |
|---|---|
code | Vắng khi tạo = server sinh 16 ký tự. Tự đặt: 12–32 chữ / số (đếm sau khi bỏ gạch / khoảng trắng); lưu CHỮ HOA, bỏ khoảng trắng / gạch |
amount | Mệnh giá (chỉ khi tạo), chuỗi tiền; làm tròn theo tiền tệ rồi phải > 0 (0.4 VND tròn về 0 → 400 validation_failed); tiền tệ là của store |
balance | Số dư hiện tại (chỉ đọc); đổi qua adjustGiftCard hoặc đơn hàng |
expiresAt | Mốc thời gian ISO UTC; null = không hết hạn |
active | false = tạm khoá thẻ (giỏ / chốt đơn từ chối) |
- Mã là tiền của người cầm. Response của
createGiftCardcó ĐỦ mã một lần: in / gửi cho người mua ngay. Gửi lại cùngIdempotency-KeyKHÔNG trả lại mã (409idempotency_response_withheld, thẻ không phát thêm, response không có id thẻ): tìm thẻ vừa tạo ởlistGiftCards(mới nhất trước); chỉ người có quyềngift_card.view_codemới xem lại được ĐỦ mã (getGiftCard) — người chỉ cógift_card.createmất response lần đầu thì phải nhờ người có quyền. Sau đócodebị che (****ABCD,codeMasked: true) trừ khi người dùng có quyềngift_card.view_code. - Danh sách không tìm theo một phần mã. Tra thẻ khách mang tới:
listGiftCards({ query: { code: "<đủ mã>" } })(không phân biệt hoa / thường, gạch, khoảng trắng). adjustGiftCard({ body: { amount, note } }):amountcó dấu (dương = nạp, âm = trừ),notebắt buộc. Số dư không được âm → 409gift_card_insufficient_balance(details.balance).deleteGiftCardchỉ xoá thẻ chưa từng dùng; thẻ đã có giao dịch → 409gift_card_in_use, hãy tắtactive.listGiftCardTransactions: sổ của thẻ, mới nhất trước, phân trang con trỏ:issue,redeem(trả cho đơn, số âm, kèmorderInfo),release(về lại thẻ khi đơn huỷ hoặc nhân viên hoàn, kèmorderInfo;notelà lý do hoàn),adjust.balancelà số dư sau giao dịch.
Hoàn phần thẻ của đơn về lại thẻ #
refundOrderToGiftCard hoàn riêng phần đơn đã trả bằng thẻ, nhân viên quyết số
tiền. createRefund (module refund) chỉ hoàn tiền mặt / chuyển khoản, hệ
thống KHÔNG tự chia một lần hoàn giữa tiền và thẻ. Màn chi tiết đơn:
listGiftCardOrderRefundables({ query: { order_id } })(quyềngift_card.read): mỗi thẻ đã trả cho đơn một dònggiftCardId,giftCardInfo(codeluôn che,currency,balance,active),redeemed,released,refundable. Danh sách rỗng = đơn không trả bằng thẻ, ẩn nút.refundablelà"0"thì tắt nút (đơn chưa trả xong, đã hoàn hết hoặc đã huỷ).refundOrderToGiftCard({ body: { orderId, giftCardId, amount, reason? } })(quyềngift_card.adjust).amountlàm tròn theo tiền tệ, tối đarefundable. Response là dòng ở bước 1 đã cập nhật, kèmorderId,orderInfo,amount(số vừa hoàn).reasonlưu vàonotecủa dòng sổrelease.
Đơn huỷ sau đó chỉ trả về thẻ phần còn lại; đơn đã huỷ thì refundable là
"0". Hoàn về thẻ KHÔNG đổi status / paymentStatus của đơn. Thẻ đang tắt /
hết hạn vẫn nhận lại tiền.
code | Status | FE nên |
|---|---|---|
gift_card_refund_exceeds | 409 | tải lại refundable, hiện details.available |
gift_card_refund_order_not_paid | 409 | đơn chưa trả xong: huỷ đơn để trả thẻ (details.paymentStatus) |
gift_card_order_not_found | 404 | đơn không thuộc store |
gift_card_not_found | 404 | thẻ không thuộc store |
Storefront #
Không có route riêng: khách nhập mã thẻ vào giỏ như mã giảm giá
(setMyCartCodes, trang module cart); được nhập nhiều thẻ. Thẻ trả phần còn
lại của đơn SAU giảm giá, thuế và phí giao: giỏ và đơn có khoản trong
adjustments (source: "gift_card", scope: "offset") và
totals.offsetTotal. code của khoản này đã bị che (****ABCD) ở giỏ, báo giá
và đơn — mã đủ chỉ còn trong codes của giỏ (của chính khách).
- Giỏ chưa có phí giao, nên số thẻ trả ở giỏ có thể nhỏ hơn lúc chốt đơn (chốt
đơn cộng phí giao rồi mới trừ thẻ). Thẻ đủ trả cả đơn thì
grandTotallà 0 và đơn không cần thanh toán thêm. - Thẻ không dùng được → 409
gift_card_not_applicable,details.reason:inactive,expired,no_balance,currency_mismatch; mã không được lưu (hoặc nằm trongrejectedCodesnếu đã lưu trước). Chốt đơn khi đó cũng trả lỗi này — bỏ mã (setMyCartCodes) rồi chốt lại. - Số dư bị trừ lúc chốt đơn. Đơn huỷ thì phần đã trừ về lại thẻ. Nhân viên hoàn
phần thẻ của đơn đã trả bằng thao tác riêng (mục CMS); hoàn tiền (
refund) chỉ là tiền mặt / chuyển khoản.