Chưa cấu hình tài khoản ngân hàng nhận tiền — mọi đơn hàng mới sẽ không tạo được mã QR thanh toán.
Liên hệ quản trị viên (OWNER) để cấu hình[[ overview.error ]]
Tỉ lệ đơn
| Kỳ | Doanh thu | Số đơn |
|---|---|---|
| [[ b.key ]] | [[ formatMoney(b.revenue) ]] | [[ b.order_count ]] |
| Chưa có dữ liệu trong khoảng lọc. | ||
| Chi nhánh | Doanh thu | Số đơn |
|---|---|---|
| [[ s.store ]] | [[ formatMoney(s.revenue) ]] | [[ s.order_count ]] |
| Chưa có dữ liệu trong khoảng lọc. | ||
| [[ s.name ]] ×[[ s.order_count ]] | [[ formatMoney(s.revenue) ]] |
| Chưa có dữ liệu. |
| [[ c.name || c.phone || c.customer_id ]] ×[[ c.paid_count ]] | [[ formatMoney(c.total_paid) ]] |
| Chưa có dữ liệu. |
| Nhân viên | Đã xác nhận PAID | Đã huỷ | Đã hoàn tiền |
|---|---|---|---|
| [[ s.staff ]] | [[ s.paid_confirmed_count ]] | [[ s.cancelled_count ]] | [[ s.refunded_count ]] |
| Chưa có dữ liệu (chỉ tính từ khi bản vá gán nhân viên được triển khai). | |||
[[ salesReport.error ]]
| [[ o.order_type ]] ×[[ o.count ]] | [[ formatMoney(o.revenue) ]] |
| Chưa có dữ liệu. | |
| [[ s.source ]] ×[[ s.count ]] | [[ formatMoney(s.revenue) ]] |
| Chưa có dữ liệu. | |
| Mã | Lượt dùng | Tổng tiền giảm |
|---|---|---|
| [[ c.code ]] | [[ c.used_count ]] | [[ formatMoney(c.total_discount_amount) ]] |
| Chưa có dữ liệu. | ||
| Nhân viên | Số đơn giảm giá | Tổng tiền giảm | % giảm TB | Hạn mức Role | Số lần chạm hạn mức |
|---|---|---|---|---|---|
| [[ s.staff ]] | [[ s.discount_order_count ]] | [[ formatMoney(s.total_discount_amount) ]] | [[ s.avg_discount_percent ]]% | [[ s.max_discount_percent === null ? 'Không giới hạn' : s.max_discount_percent + '%' ]] | [[ s.at_limit_count ]] 0 |
| Chưa có dữ liệu. | |||||
[[ customerReport.error ]]
| Nhóm | Số khách | Doanh thu (kỳ) | Giá trị đơn TB |
|---|---|---|---|
| [[ g.group ]] | [[ g.customer_count ]] | [[ formatMoney(g.revenue_in_range) ]] | [[ formatMoney(g.avg_order_value) ]] |
| Chưa có dữ liệu. | |||
| [[ s.source ]] | [[ s.customer_count ]] |
| Chưa có dữ liệu. | |
[[ purchaseReport.error ]]
| [[ s.supplier ]] ×[[ s.po_count ]] | [[ formatMoney(s.total_amount) ]] |
| Chưa có dữ liệu. | |
| [[ p.product_name ]] ×[[ p.total_qty ]] | [[ formatMoney(p.total_cost) ]] |
| Chưa có dữ liệu. | |
| [[ s.status ]] | [[ s.count ]] |
| Chưa có dữ liệu. | |
[[ inventoryReport.error ]]
| Sản phẩm | Tồn hiện tại | Ngưỡng tối thiểu |
|---|---|---|
| [[ p.product_name ]] | [[ p.inventory_qty ]] | [[ p.safety_stock_min ]] |
| Không có sản phẩm nào sắp hết hàng. | ||
| Sản phẩm | Nhập | Xuất |
|---|---|---|
| [[ m.product_name ]] | +[[ m.in_qty ]] | -[[ m.out_qty ]] |
| Chưa có dữ liệu. | ||
[[ financeReport.error ]]
| Đơn hàng | Số tiền | Thanh toán lúc | Vấn đề |
|---|---|---|---|
| [[ m.order_id ]] | [[ formatMoney(m.amount) ]] | [[ formatDate(m.paid_at) ]] | [[ m.issue ]] |
| Không có đơn nào thiếu Phiếu Thu. | |||
| Tài khoản | Loại | Số dư hiện tại |
|---|---|---|
| [[ a.name ]] ([[ a.branch || 'Chưa gắn chi nhánh' ]]) | [[ a.type ]] | [[ formatMoney(a.balance) ]] |
| Chưa có dữ liệu. | ||
| Mã Bill | Tổng nợ | Đã trả | Còn nợ | Trạng thái |
|---|---|---|---|---|
| [[ b.bill_id ]] | [[ formatMoney(b.amount) ]] | [[ formatMoney(b.paid_amount) ]] | [[ formatMoney(b.remaining_amount) ]] | [[ b.status ]] |
| Không còn công nợ nào chưa thanh toán. | ||||
[[ ordersEmptyMessage ]]
| Mã đơn | Mã giao dịch | Số tiền | Thanh toán | Xử lý đơn | Giờ đặt | Hết hạn | ||
|---|---|---|---|---|---|---|---|---|
| [[ tx.order_id ]] | [[ tx.transaction_ref || '—' ]] | [[ formatMoney(tx.amount) ]] | [[ statusMeta(tx.status).label ]] | [[ fulfillmentLabel(tx.fulfillment_status) ]]— | [[ formatDate(tx.created_at) ]] | [[ tx.expires_at ? formatDate(tx.expires_at) : '—' ]] | [[ orders.expandedId === tx.order_id ? 'expand_less' : 'chevron_right' ]] | |
|
progress_activity
Không tải được chi tiết đơn.
Chi tiết đơn [[ orders.detail.order_id ]]Thông tin khách mua hàng [[ orders.detail.customer_name || 'Khách lẻ' ]] [[ orders.detail.customer_phone || 'Chưa có số điện thoại' ]] Địa chỉ giao hàng [[ orders.detail.shipping_address.receiver_name || '—' ]] — [[ formatPhone(orders.detail.shipping_address.phone) ]] [[ formatAddress(orders.detail.shipping_address.address, orders.detail.shipping_address.ward, orders.detail.shipping_address.province) ]]
[[ item.name || item.handle ]] × [[ item.qty ]]
[[ formatMoney(item.lineTotal || item.price) ]]
[[ orders.detail.discount_code ? 'Giảm giá' : 'Chiết khấu' ]] ([[ orders.detail.discount_percent ]]%)
-[[ formatMoney(orders.detail.discount_amount) ]]
Tổng tiền[[ formatMoney(orders.detail.total_amount) ]]
Số tiền thanh toán[[ formatMoney(orders.detail.pay_amount) ]]
Ngày hẹn[[ orders.detail.appointment_date ]]
Giờ hẹn[[ orders.detail.appointment_time ]]
Loại đơn[[ orders.detail.order_type || '—' ]]
lockĐã có vận đơn — huỷ vận đơn trước nếu cần sửa
Xử lý đơn
[[ fulfillmentLabel(orders.detail.fulfillment_status) ]]
Hãng[[ orders.detail.carrier || 'GHN' ]]
Mã vận đơn[[ orders.detail.tracking_code ]]
Phí ship[[ formatMoney(orders.detail.shipping_fee || 0) ]]
Thu hộ COD[[ formatMoney(orders.detail.cod_amount) ]]
Kiện hàng[[ orders.detail.package_weight ]]g · [[ orders.detail.package_dims ]] cm
Đóng gói lúc[[ formatDate(orders.detail.packed_at) ]]
Thanh toán
Đã đẩy lên SAPO: [[ orders.detail.sapo_order_id ]]
progress_activityĐang đồng bộ lên SAPO...
Lần đẩy trước thất bại — thử lại?
|
||||||||
[[ orders.list.length ]] đơn hàng
Tạo vận đơn · [[ shipModal.order.order_id ]]
[[ shipModal.order.shipping_address.receiver_name || '—' ]] — [[ formatPhone(shipModal.order.shipping_address.phone) ]]
[[ formatAddress(shipModal.order.shipping_address.address, shipModal.order.shipping_address.ward, shipModal.order.shipping_address.province) ]]
Shopee Express không có API cho đơn ngoài sàn — nhập mã vận đơn tạo trên app Shopee/SPX vào đây.
[[ shippingReconEmpty ]]
| Mã phiếu | Đối tác | Trạng thái | Thanh toán | Thực nhận/trả | Ngày tạo | |
|---|---|---|---|---|---|---|
| [[ r.recon_id ]] | [[ r.carrier_code ]] | [[ r.status ]] | [[ r.payment_status ]] | [[ formatMoney(r.net_total) ]] | [[ formatDate(r.created_at) ]] | chevron_right |
[[ shipping.reconList.length ]] phiếu đối soát
Phiếu [[ shipping.detail.recon_id ]] · [[ shipping.detail.carrier_code ]]
[[ shipping.detail.status ]] [[ shipping.detail.payment_status ]]Nạp xong vẫn phải kiểm lại: dòng nào Goship không có sẽ giữ nguyên và hiện chênh lệch đỏ.
| Mã vận đơn | COD hệ thống | COD đối tác | Phí hệ thống | Phí đối tác | Phí khác | Chênh lệch | |
|---|---|---|---|---|---|---|---|
| [[ it.tracking_code ]] [[ it.order_id ]] |
[[ formatMoney(it.cod_system) ]] | [[ formatMoney(it.cod_partner) ]] | [[ formatMoney(it.fee_system) ]] | [[ formatMoney(it.fee_partner) ]] | [[ formatMoney(it.other_fee) ]] |
COD [[ formatMoney(it.cod_diff) ]] Phí [[ formatMoney(it.fee_diff) ]] Khớp |
Tạo phiếu đối soát
Kéo mọi vận đơn Đã giao/Đã hoàn của đối tác trong khoảng thời gian, chưa nằm trong phiếu nào.
Chưa có vận đơn nào trong khoảng thời gian này.
| Đối tác | Vận đơn | Tỉ trọng VĐ | Tổng phí | Tỉ trọng phí | Phí TB | Phí/COD | % giao TC |
|---|---|---|---|---|---|---|---|
| [[ c.carrier ]] | [[ c.waybills ]] | [[ c.waybill_share ]]% | [[ formatMoney(c.fee) ]] | [[ c.fee_share ]]% | [[ formatMoney(c.avg_fee) ]] | [[ c.fee_cod_ratio ]] | [[ c.success_rate ]]% |
Chọn khoảng thời gian rồi bấm "Xem báo cáo".
GHN chỉ là 1 đầu mối — cấu hình chi tiết (Token/ShopID) ở tab Cấu hình → Vận chuyển GHN. Bật/tắt kết nối để hiện/ẩn khỏi lựa chọn khi tạo vận đơn.
| Mã | Tên | Phân loại | Cấu hình | Kết nối |
|---|---|---|---|---|
| [[ c.carrier_code ]] | [[ c.name ]] | [[ c.category ]] | [[ c.has_config ? '✓ Đã cấu hình' : 'Chưa cấu hình' ]] |
[[ card.label ]]
[[ card.value ]]
| Tên sản phẩm | SKU | Giá[[ products.sortDir === 'desc' ? 'arrow_downward' : 'arrow_upward' ]] | Tồn kho[[ products.sortDir === 'desc' ? 'arrow_downward' : 'arrow_upward' ]] | Sức bán[[ products.sortDir === 'desc' ? 'arrow_downward' : 'arrow_upward' ]] | Trạng thái | Hành động | |
|---|---|---|---|---|---|---|---|
|
inventory_2
[[ productsEmptyMessage ]] |
|||||||
|
image
|
[[ p.title || '—' ]]
[[ p.variant_title ]]
[[ stockBadge(p).text ]]
[[ p.handle ]]
Đã lưu MOPS
Đã bật bán
|
[[ p.sku || '—' ]] | [[ formatMoney(p.price) ]] | warning[[ (p.inventory_qty || 0).toLocaleString('vi-VN') ]] | [[ (p.sold_qty || 0).toLocaleString('vi-VN') ]] | [[ productStatusBadge(p).text ]] |
|
Hiển thị [[ productsPageFrom ]]-[[ productsPageTo ]] trên [[ productsFiltered.length ]] sản phẩm
[[ customersEmptyMessage ]]
| STT | Số điện thoại | Tên | Nhóm khách | Lần cuối đặt | Tổng đơn | Đã thanh toán | |
|---|---|---|---|---|---|---|---|
| [[ index + 1 ]] | [[ formatPhone(c.phone) ]] | [[ c.name || '—' ]] | Sỉ [[ c.default_discount_percent ]]% Lẻ | [[ formatDate(c.last_order_at) ]] | [[ c.order_count ]] | [[ formatMoney(c.total_paid) ]] | chevron_right |
[[ customersFiltered.length ]] / [[ customers.all.length ]] khách hàng
Nhập khách hàng từ Excel
Cột nhận được:
Mã khách hàng · Tên khách hàng * (bắt buộc) · Địa chỉ - SĐT (gộp — hệ thống tự tách SĐT ra khỏi địa chỉ) · SL đơn hàng (bỏ qua — số đơn tính từ dữ liệu đơn hàng thật). Có thể thêm: SĐT, Địa chỉ, Phường/Xã, Quận/Huyện, Tỉnh/TP, Email, Nhóm khách, % chiết khấu, Ghi chú.
[[ customers.imp.parseError ]]
Cột không nhận diện được (sẽ bỏ qua): [[ customers.imp.unknownCols.join(', ') ]]
| Dòng | Kết quả | Tên | SĐT | Ghi chú |
|---|---|---|---|---|
| [[ r.row ]] | [[ customerImportActionLabel(r.action) ]] | [[ r.name || '—' ]] | [[ r.phone ? formatPhone(r.phone) : '—' ]] | [[ r.reason || '' ]] |
Các dòng lỗi sẽ KHÔNG được ghi — sửa trong file rồi nhập lại phần đó.
Đã nhập xong
Thêm mới [[ customers.imp.stat.create ]] · Cập nhật [[ customers.imp.stat.update ]] · Bỏ qua [[ customers.imp.stat.skip ]] · Lỗi [[ customers.imp.stat.error ]]
| [[ r.row ]] | [[ customerImportActionLabel(r.action) ]] | [[ r.name || '—' ]] · [[ r.customer_id ]] | [[ r.reason || '' ]] |
[[ finance.error ]]
| Danh mục | Số tiền | Số giao dịch |
|---|---|---|
| [[ c.category ]] | [[ formatMoney(c.amount) ]] | [[ c.count ]] |
| Chưa có khoản chi nào trong khoảng lọc. | ||
[[ finance.listError || 'Chưa có giao dịch thu chi thủ công nào trong khoảng lọc.' ]]
| Ngày | Loại | Danh mục | Số tiền | Tài khoản | Thao tác |
|---|---|---|---|---|---|
| [[ formatDate(tx.created_at) ]] | Thu Chi | [[ tx.category ]] [[ financeTxSecondaryLine(tx) ]] |
[[ tx.type === 'INCOME' ? '+' : '−' ]][[ formatMoney(tx.amount) ]] | [[ tx.account || '—' ]] [[ tx.created_by ]] |
Đã huỷ |
[[ financeCore.accounts.error ]]
[[ financeCore.receipts.error || 'Chưa có Phiếu Thu nào.' ]]
| Mã phiếu | Nguồn | Số tiền | Trạng thái | Ngày tạo | Thao tác |
|---|---|---|---|---|---|
| [[ r.receipt_id ]] | [[ r.source_type === 'SALES_AUTO' ? 'Tự động (đơn hàng)' : 'Thủ công' ]] [[ r.note ]] |
[[ formatMoney(r.total_amount) ]] | [[ r.status ]] | [[ formatDate(r.created_at) ]] |
[[ financeCore.vouchers.error || 'Chưa có Phiếu Chi nào.' ]]
| Mã phiếu | Diễn giải | Số tiền | Trạng thái | Người tạo / duyệt | Thao tác |
|---|---|---|---|---|---|
| [[ v.voucher_id ]] | [[ v.note || '—' ]] | [[ formatMoney(v.total_amount) ]] | [[ v.status ]] | [[ v.created_by ]] → [[ v.approved_by ]] |
[[ financeCore.transfers.error || 'Chưa có Chuyển quỹ nào.' ]]
| Mã | Từ | Đến | Số tiền | Trạng thái | Thao tác |
|---|---|---|---|---|---|
| [[ t.transfer_id ]] | [[ accountName(t.from_account_id) ]] | [[ accountName(t.to_account_id) ]] | [[ formatMoney(t.amount) ]] | [[ t.status ]] |
[[ financeCore.adjustments.error || 'Chưa có Điều chỉnh quỹ nào.' ]]
| Mã | Tài khoản | Số tiền | Lý do | Trạng thái | Thao tác |
|---|---|---|---|---|---|
| [[ a.adjustment_id ]] | [[ accountName(a.account_id) ]] |
[[ a.direction === 'INCREASE' ? 'Tăng' : 'Giảm' ]]
[[ a.direction === 'INCREASE' ? '+' : '−' ]][[ formatMoney(a.amount) ]]
|
[[ a.reason ]] | [[ a.status ]] |
[[ inventory.suppliers.error || 'Chưa có nhà cung cấp nào.' ]]
| STT | Tên | Điện thoại | Trạng thái | Thao tác |
|---|---|---|---|---|
| [[ index + 1 ]] | [[ s.name ]] | [[ s.phone || '—' ]] | Đang hợp tác Ngừng hợp tác |
[[ inventory.purchaseOrders.error || 'Chưa có phiếu nhập hàng nào.' ]]
| Mã phiếu | Nhà cung cấp | Sản phẩm | Tổng tiền | Trạng thái | Thao tác |
|---|---|---|---|---|---|
| [[ po.purchase_order_id ]] | [[ supplierName(po.supplier_id) ]] | [[ po.items.length ]] sản phẩm | [[ formatMoney(po.total_amount) ]] |
[[ po.status ]]
[[ po.payment_terms === 'DEPOSIT' ? 'Cọc ' + formatMoney(po.deposit_amount) : 'Trả đủ' ]] |
Chi tiết phiếu nhập — [[ inventory.purchaseOrders.detailId ]]
Nhà cung cấp
[[ supplierName(purchaseOrderDetailTarget.supplier_id) ]]
Sản phẩm ([[ purchaseOrderDetailTarget.items.length ]])
Ghi chú
[[ purchaseOrderDetailTarget.note ]]
[[ inventory.bills.error || 'Chưa có công nợ nhà cung cấp nào.' ]]
| Mã Bill | Nhà cung cấp | Tổng nợ | Đã trả | Còn nợ | Trạng thái |
|---|---|---|---|---|---|
| [[ b.bill_id ]] | [[ supplierName(b.party_id) ]] | [[ formatMoney(b.amount) ]] | [[ formatMoney(b.paid_amount) ]] | [[ formatMoney(b.remaining_amount) ]] | [[ b.status ]] |
| Sự kiện | Mô tả | Nhận thông báo |
|---|---|---|
ORDER_CREATED |
Đơn hàng mới được tạo | ADMINSTAFF |
PAYMENT_REPORTED |
Khách báo đã chuyển khoản | ADMINACCOUNTANT |
PAYMENT_CONFIRMED |
Thanh toán được xác nhận | ADMINSTAFF |
ORDER_CANCELLED |
Đơn hàng bị huỷ | ADMINACCOUNTANT |
PAYMENT_EXPIRED |
Hết hạn thanh toán (cron) | ADMIN |
PRODUCT_SYNC_FAILED |
Đồng bộ sản phẩm thất bại | OWNERADMIN |
Thông báo gửi qua Telegram cho các nhân viên đang hoạt động thuộc vai trò tương ứng và đã cấu hình Telegram Chat ID.
[[ notifications.error ]]
| STT | Mã đơn | Sự kiện | Kênh | Trạng thái | Thời gian gửi | Lỗi | |
|---|---|---|---|---|---|---|---|
| [[ index + 1 ]] | [[ n.order_id || '—' ]] | [[ notifLabel(n.event) ]] | [[ n.channel || '—' ]] | [[ statusMeta(n.status).label ]] | [[ formatDate(n.sent_at || n.created_at) ]] | ⚠ Chi tiết | — |
[[ notifications.list.length ]] thông báo
[[ auditEmptyMessage ]]
| STT | Loại | Entity ID | Hành động | Thực hiện bởi | Thời gian |
|---|---|---|---|---|---|
| [[ index + 1 ]] | [[ log.entity_type ]] | [[ log.entity_id || '—' ]] | [[ log.action ]] | [[ log.user || '—' ]] | [[ formatDate(log.created_at) ]] |
[[ audit.list.length ]] bản ghi
[[ staffEmptyMessage ]]
| STT | Tên hiển thị | Username | Vai trò | Trạng thái | Đăng nhập cuối | Telegram | Thao tác |
|---|---|---|---|---|---|---|---|
| [[ index + 1 ]] | [[ s.name ]] | [[ s.username ]] | [[ (s.role || '—').toUpperCase() ]] | Hoạt động Vô hiệu | [[ formatDate(s.last_login) ]] | [[ s.telegram_id || '—' ]] | — Bạn — Khoá |
[[ staffFiltered.length ]] / [[ staffMgmt.all.length ]] nhân viên
Tài khoản ngân hàng nhận tiền
QR chuyển khoản của đơn hàng dùng các tài khoản này. Mỗi chi nhánh có thể chọn tài khoản mặc định riêng ở bảng bên dưới.
| Ngân hàng | Số tài khoản | Chủ tài khoản | Mặc định | Trạng thái | Thao tác |
|---|---|---|---|---|---|
| [[ a.bank_code ]] | [[ a.account_no ]] | [[ a.account_name ]] | Mặc định — | Đang dùng Đã tắt |
[[ branchesEmptyMessage ]]
| STT | Tên chi nhánh | Điện thoại | Địa chỉ | TK nhận tiền | Mặc định | Trạng thái | Thao tác |
|---|---|---|---|---|---|---|---|
| [[ index + 1 ]] | [[ b.name_vi ]] | [[ formatPhone(b.phone) ]] | [[ formatAddress(b.address, b.ward, b.province) ]] | [[ bankAccountLabel(b.default_bank_account_id) ]] Theo chi nhánh chính | Mặc định — | Đang hoạt động Ngừng hoạt động |
[[ branchesFiltered.length ]] / [[ branches.all.length ]] chi nhánh
[[ couponsEmptyMessage ]]
| Mã | Loại giảm | Đơn tối thiểu | Đã dùng / Tối đa | Hiệu lực | Trạng thái | Thao tác |
|---|---|---|---|---|---|---|
|
[[ c.code ]]
[[ c.title ]]
[[ c.description ]]
sell [[ couponScopeLabel(c) ]]
|
[[ c.value_type === 'fixed' ? formatMoney(c.value) : c.value + '%' ]] | [[ c.min_order_amount ? formatMoney(c.min_order_amount) : '—' ]] | [[ c.used_count ]] / [[ c.max_uses || '∞' ]] | [[ c.start_at ? formatDate(c.start_at) : '—' ]] → [[ c.expires_at ? formatDate(c.expires_at) : '—' ]] | Bật Tắt |
[[ couponsFiltered.length ]] / [[ couponsMgmt.all.length ]] mã giảm giá
Trạng thái hệ thống
Phiên bản hiện tại và chế độ bảo trì. Chỉ hiển thị với OWNER.
Tài khoản ngân hàng
Cấu hình tài khoản nhận thanh toán QR cho các giao dịch đơn hàng tự động.
Mã QR thanh toán được tạo tự động dựa trên 3 thông tin trên (chuẩn VietQR) — không cần cấu hình gì thêm.
SAPO API
Thông tin kết nối SAPO để đồng bộ sản phẩm (tab Sản phẩm).
Vận chuyển Goship (đa hãng)
Một kết nối duy nhất, so sánh giá & đặt vận đơn với nhiều hãng. Lấy Client ID / Client Secret tại Goship.io > Kết nối API. Bí mật — để trống nếu không đổi.
⚠️ Adapter theo tài liệu doc.goship.io, chưa test sandbox. Sau khi điền: chạy tay testGoshipToken() → testGoshipCities() (lấy mã kho lấy hàng) → testGoshipRates(orderId) → testGoshipCreate(orderId) trong Apps Script Editor.
Không có token sẵn? Điền 4 trường dưới, hệ thống tự đăng nhập lấy token (cache 6 giờ).
Mã địa giới của Goship khác mã GHN/Viettel Post. Nhập tên cũng được — hệ thống tự dò, nhưng nhập mã (lấy bằng testGoshipCities()) chắc chắn hơn.
Cách khai webhook: vào Goship > Kết nối API > Webhooks, dán URL Web App của MOPS kèm khoá ở cuối:
https://script.google.com/…/exec?wh=KHOÁ Ở TRÊN
Apps Script không đọc được header nên không kiểm được chữ ký HMAC của Goship — khoá trong URL là lớp xác thực khả thi ở đây. MOPS chỉ nhận trạng thái, không lấy số tiền từ webhook; tiền chốt qua đối soát.
Vận chuyển GHN
Giao Hàng Nhanh. Đăng ký sandbox tại 5sao.ghn.dev (Chủ cửa hàng → xem & sao chép Token/ShopID; cập nhật địa chỉ cửa hàng để lấy District/Ward gửi hàng). Token là bí mật — để trống nếu không đổi.
Vận chuyển Ahamove
Giao nội thành / trong ngày theo toạ độ. Đăng ký Open API tại Ahamove for Developers để lấy API Key + số điện thoại tài khoản. Địa chỉ người nhận đẩy dạng chuỗi để Ahamove tự geocode. API Key là bí mật — để trống nếu không đổi.
⚠️ Adapter viết theo tài liệu Open API v1, chưa test sandbox. Sau khi điền API Key + SĐT + Service ID + Địa chỉ kho, chạy tay testAhamoveToken() → testAhamoveEstimate(orderId) trong Apps Script Editor để xác nhận trước khi dùng thật.
Vận chuyển GHTK
Giao Hàng Tiết Kiệm. Địa chỉ theo tên tỉnh/quận/xã (khớp thẳng dữ liệu đơn). Lấy API Token tại khonh doanh nghiệp GHTK. Token là bí mật — để trống nếu không đổi.
⚠️ Adapter theo docs GHTK, chưa test sandbox. Sau khi điền, chạy tay testGhtkFee(orderId) → testGhtkCreate(orderId) trong Apps Script Editor.
Vận chuyển Viettel Post
Viettel Post. Địa chỉ theo ID riêng của VTP — hệ thống tự dò từ tên tỉnh/quận đơn hàng. Đăng nhập bằng Token (portal) hoặc Username + Password. Bí mật — để trống nếu không đổi.
⚠️ Adapter theo docs VTP v2, chưa test sandbox. VTP cập nhật trạng thái chủ yếu qua webhook. ID gửi hàng (Tỉnh/Quận) là ID của VTP, không phải ID GHN. Chạy tay testVtpToken() → testVtpCreate(orderId).
Telegram
Gửi thông báo đơn hàng / thanh toán tới nhóm Telegram.
Bảo mật hệ thống
Xác thực nâng cao cho vai trò OWNER.
Xác thực 2 yếu tố (2FA)
Chưa khả dụng — sẽ có trong bản cập nhật sau