Thanh Toán VND Qua InfoCMS
Hiện tại MCV vẫn lưu số dư ví theo USD cents. Payment rail VND dùng tỷ giá nội bộ cố định:
$1 = 26,000 VND
:::info Kế hoạch VND mặc định
Khi chuyển hệ thống sang VND mặc định, cần refactor tiền tệ sang amount_minor + currency. Với VND, amount_minor chính là số tiền VND nguyên.
:::
Nạp VND
User có thể tạo QR top-up VND từ Billing.
Số tiền VND -> quy đổi sang wallet amount USD -> tạo InfoCMS QuickQR request -> chờ callback -> credit ví
Ví dụ:
| VND đã trả | Wallet Credit |
|---|---|
| 2,600,000 VND | $100.00 |
Payment được lưu như sau:
payments.provider = infocms_qrpayments.status = requires_paymentpayments.metadata.vnd_amountpayments.metadata.exchange_rate = 26000
InfoCMS UAT QuickQR dùng:
POST {INFOCMS_BASE_URL}/ocms/v1/auth/login
Header AuthorizationHeaderParameters: base64(clientId)
Header Authorization: base64(hmac_sha512(clientId + yyyyMMdd + clientSecret, clientSecret))
Header bankCode: {INFOCMS_BANK_CODE}
Body: {"data": {"masterId": "{INFOCMS_MASTER_ID}", "clientId": "{INFOCMS_CLIENT_ID}"}}
MCV cache token trả về và dùng token đó cho QuickQR requests. Nếu cấu hình INFOCMS_ACCESS_TOKEN, hệ thống dùng trực tiếp token này thay vì login.
POST {INFOCMS_BASE_URL}/ocms/v3/ec/create_quick_qr
Header token: {INFOCMS_ACCESS_TOKEN}
Header bankCode: {INFOCMS_BANK_CODE}
Header CMS-RSA-Signature: RSA-SHA256 signature of JSON-minified data
Body: {"data": {...}}
MCV giữ RSA private key và chỉ gửi RSA public key cho InfoCMS/Infoplus.
InfoCMS public key được lưu riêng và dùng để verify callback ký bằng header CMS-RSA-Signature. Khi callback body có data, MCV verify JSON-minified data; nếu không, verify JSON-minified callback body.
Khi InfoCMS xác nhận deposit, InfoCMS gọi:
POST https://app.mcv.network/infocms/e-collect/callback
Các reference field được chấp nhận gồm orderId, order_id, transUUID, trans_uuid, provider_reference, hoặc reference.
Callback verification:
Header CMS-RSA-Signature: RSA-SHA256 signature from InfoCMS
Verified by MCV with INFOCMS_PROVIDER_PUBLIC_KEY
Callback có idempotency. Ví chỉ được credit một lần bằng key:
infocms_qr:{provider_reference}:posted
Subscription Payment Và Invoice
Với payment có metadata.payment_purpose = service_subscription, callback InfoCMS không credit ví. Hệ thống chuyển kỳ thu tương ứng sang paid và phát hành invoice tự động.
Luồng:
Admin tạo service contract
-> hệ thống sinh service_billing_cycles
-> khách tạo QR Pay cho từng kỳ
-> InfoCMS callback xác nhận tiền về
-> payment = succeeded
-> billing cycle = paid
-> service invoice = issued
-> email gửi khách hàng + billing email + admin ops
Quy tắc:
- Top-up ví không xuất hóa đơn vì đó là khoản đặt cọc.
- Subscription/service fee chỉ xuất invoice sau khi tiền thật sự được ghi nhận.
- Mỗi billing cycle chỉ có một invoice nhờ unique key
service_billing_cycle_id. - Invoice có thể xem/in tại
/subscriptions/invoices/{invoice}. - Nếu admin mark-paid thủ công, hệ thống cũng phát hành invoice theo cùng service idempotent.
MISA meInvoice
MCV đã chuẩn bị adapter MISA meInvoice ở chế độ chờ credential.
Root admin cấu hình tại:
/admin/system-settings
Khách hàng cấu hình thông tin xuất hóa đơn tại:
/profile
Billing profile lưu ở cấp account và gồm:
| Field | Ý nghĩa |
|---|---|
billing_legal_name | Tên pháp lý công ty |
billing_tax_id | Mã số thuế |
billing_address | Địa chỉ xuất hóa đơn |
billing_email | Email nhận hóa đơn |
billing_contact_name | Tên người nhận |
billing_invoice_note | Ghi chú/nội dung mong muốn trên hóa đơn |
Các trường cần nhập khi MISA bàn giao:
| Field | Ý nghĩa |
|---|---|
meinvoice.enabled | Bật/tắt gửi HĐĐT sang MISA |
meinvoice.base_url | Base URL API do MISA cung cấp |
meinvoice.auth_endpoint | Endpoint lấy token nếu dùng username/password |
meinvoice.issue_endpoint | Endpoint lập/phát hành hóa đơn |
meinvoice.company_tax_code | MST MCV phát hành hóa đơn |
meinvoice.app_id | App ID/client ID nếu MISA cấp |
meinvoice.username | Username API |
meinvoice.password | Password/client secret API |
meinvoice.access_token | Token tĩnh nếu MISA cấp thay cho login |
meinvoice.template_code | Mẫu hóa đơn |
meinvoice.invoice_series | Ký hiệu/series hóa đơn |
meinvoice.vat_percent | VAT mặc định, thường 10% |
Sau khi cấu hình, các invoice đang chờ sẽ được scheduler gửi lại mỗi 15 phút:
php artisan billing:submit-einvoices --limit=25
Trạng thái HĐĐT được lưu tại service_invoices.einvoice_status:
| Status | Ý nghĩa |
|---|---|
pending_configuration | Chưa đủ credential MISA |
disabled | MISA chưa bật |
submitted | Đã gửi sang MISA nhưng chưa thấy mã CQT/link tra cứu trong response |
issued | Đã có dữ liệu phát hành như mã CQT, số hóa đơn hoặc link tra cứu |
failed | MISA trả lỗi hoặc API lỗi |
Rút VND
User có thể yêu cầu rút VND từ Billing.
Số tiền VND -> quy đổi sang wallet amount USD -> reserve số dư ví -> tạo InfoCMS transfer request
Ví dụ:
| Số tiền rút | Wallet Reserved |
|---|---|
| 2,600,000 VND | $100.00 |
Withdrawal request được lưu trong withdrawal_requests.
Khi InfoCMS xác nhận hoặc báo fail transfer, InfoCMS gọi:
POST https://app.mcv.network/infocms/transfer/callback
Nếu transfer fail, MCV hoàn lại wallet amount đã reserve một lần bằng:
withdrawal:{withdrawal_id}:refund
Biến Môi Trường
INFOCMS_ENABLED=false
INFOCMS_BASE_URL=
INFOCMS_ACCESS_TOKEN=
INFOCMS_CLIENT_ID=
INFOCMS_CLIENT_SECRET=
INFOCMS_MERCHANT_ID=
INFOCMS_BANK_CODE=
INFOCMS_MASTER_ID=
INFOCMS_MOTHER_ACCOUNT=
INFOCMS_ECOLLECTION_NAME="MCV Network"
INFOCMS_SIGNATURE_PRIVATE_KEY=
INFOCMS_PROVIDER_PUBLIC_KEY=
INFOCMS_LOGIN_ENDPOINT=/ocms/v1/auth/login
INFOCMS_CREATE_QUICK_QR_ENDPOINT=/ocms/v3/ec/create_quick_qr
INFOCMS_TRANSFER_ENDPOINT=/transfer
Khi INFOCMS_ENABLED=false, request chạy ở sandbox mode và lưu outbound payload vào metadata. Điều này cho phép product và finance test workflow trước khi cấu hình production credentials.