212 lines
7.0 KiB
Go
212 lines
7.0 KiB
Go
package financeorder
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"hyapp-admin-server/internal/model"
|
|
"hyapp-admin-server/internal/modules/shared"
|
|
walletv1 "hyapp.local/api/proto/wallet/v1"
|
|
)
|
|
|
|
func TestNormalizeCreateOrderRequiresExplicitUSDTChain(t *testing.T) {
|
|
_, err := normalizeCreateOrderRequest(createCoinSellerRechargeOrderRequest{
|
|
AppCode: "lalu",
|
|
TargetUserID: "10001",
|
|
USDAmount: 12.34,
|
|
CoinAmount: 1200,
|
|
ProviderCode: "usdt",
|
|
ExternalOrderNo: "0xabc",
|
|
})
|
|
if err == nil || !strings.Contains(err.Error(), "必须选择链") {
|
|
t.Fatalf("expected explicit usdt chain error, got %v", err)
|
|
}
|
|
|
|
input, err := normalizeCreateOrderRequest(createCoinSellerRechargeOrderRequest{
|
|
AppCode: "lalu",
|
|
TargetUserID: "10001",
|
|
USDAmount: 12.34,
|
|
CoinAmount: 1200,
|
|
ProviderCode: "usdt",
|
|
Chain: "bsc",
|
|
ExternalOrderNo: "0xabc",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("normalize usdt order failed: %v", err)
|
|
}
|
|
if input.ProviderCode != "usdt" || input.Chain != "BSC" || input.USDMinorAmount != 1234 {
|
|
t.Fatalf("normalized input mismatch: %+v", input)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeCreateOrderDoesNotRequireProviderHints(t *testing.T) {
|
|
for _, providerCode := range []string{"mifapay", "v5pay"} {
|
|
input, err := normalizeCreateOrderRequest(createCoinSellerRechargeOrderRequest{
|
|
AppCode: "lalu",
|
|
TargetUserID: "10001",
|
|
USDAmount: 12.34,
|
|
CoinAmount: 1200,
|
|
ProviderCode: providerCode,
|
|
ExternalOrderNo: providerCode + "-order",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("normalize %s without provider hints failed: %v", providerCode, err)
|
|
}
|
|
if input.ProviderCurrencyCode != "" || input.ProviderCountryCode != "" || input.OrderDateMS != 0 {
|
|
t.Fatalf("provider hints should remain optional for %s: %+v", providerCode, input)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNormalizeCreateOrderAllowsZeroCoinAmount(t *testing.T) {
|
|
input, err := normalizeCreateOrderRequest(createCoinSellerRechargeOrderRequest{
|
|
AppCode: "lalu",
|
|
TargetUserID: "10001",
|
|
USDAmount: 12.34,
|
|
CoinAmount: 0,
|
|
ProviderCode: "mifapay",
|
|
ExternalOrderNo: "MIFA-001",
|
|
Remark: " 补单,不发金币 ",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("zero coin makeup order should be accepted: %v", err)
|
|
}
|
|
if input.CoinAmount != 0 || input.USDMinorAmount != 1234 || input.Remark != "补单,不发金币" {
|
|
t.Fatalf("normalized zero coin order mismatch: %+v", input)
|
|
}
|
|
}
|
|
|
|
func TestExecuteGrantSkipsWalletAndLegacyForZeroCoinMakeupOrder(t *testing.T) {
|
|
service := NewService(nil, nil, nil)
|
|
result, err := service.executeGrant(context.Background(), shared.Actor{UserID: 7}, model.CoinSellerRechargeOrder{
|
|
ID: 42,
|
|
AppCode: "aslan",
|
|
TargetUserID: 10001,
|
|
CoinAmount: 0,
|
|
}, "req-1")
|
|
if err != nil {
|
|
t.Fatalf("zero coin makeup order should not require wallet or legacy writer: %v", err)
|
|
}
|
|
if result.CommandID != "admin-coin-seller-recharge:42" || result.TransactionID != "" || result.AmountDelta != 0 {
|
|
t.Fatalf("zero coin grant result mismatch: %+v", result)
|
|
}
|
|
}
|
|
|
|
func TestVerifyReceiptMatchesOrderAmounts(t *testing.T) {
|
|
order := model.CoinSellerRechargeOrder{
|
|
ExternalOrderNo: "merchant-1",
|
|
USDMinorAmount: 1234,
|
|
ProviderCurrencyCode: "USD",
|
|
ProviderAmountMinor: 0,
|
|
ProviderPayloadJSON: "",
|
|
TargetDisplayUserID: "10001",
|
|
TargetCountryID: 1,
|
|
TargetRegionID: 2,
|
|
ProviderCountryCode: "SA",
|
|
ProviderPayType: "CARD",
|
|
ProviderOrderID: "merchant-1",
|
|
ProviderStatus: "paid",
|
|
WalletTransactionID: "",
|
|
WalletAssetType: "",
|
|
WalletAmountDelta: 0,
|
|
WalletBalanceAfter: 0,
|
|
OperatorName: "ops",
|
|
VerifiedByName: "",
|
|
GrantedByName: "",
|
|
ReceiveAddress: "",
|
|
FailureReason: "",
|
|
WalletCommandID: "",
|
|
TargetUserID: 10001,
|
|
ProviderCode: "mifapay",
|
|
Chain: "",
|
|
USDAmount: "12.34",
|
|
CoinAmount: 1200,
|
|
Status: model.CoinSellerRechargeOrderStatusCreated,
|
|
VerifyStatus: model.CoinSellerRechargeVerifyStatusPending,
|
|
GrantStatus: model.CoinSellerRechargeGrantStatusPending,
|
|
OperatorUserID: 7,
|
|
CreatedAtMS: 1,
|
|
UpdatedAtMS: 1,
|
|
}
|
|
if err := verifyReceiptMatchesOrder(order, &walletv1.VerifyCoinSellerRechargeReceiptResponse{
|
|
ExternalOrderNo: "merchant-1",
|
|
CurrencyCode: "USD",
|
|
ProviderAmountMinor: 1234,
|
|
}); err != nil {
|
|
t.Fatalf("expected USD amount to match: %v", err)
|
|
}
|
|
if err := verifyReceiptMatchesOrder(order, &walletv1.VerifyCoinSellerRechargeReceiptResponse{
|
|
ExternalOrderNo: "merchant-1",
|
|
CurrencyCode: "USD",
|
|
ProviderAmountMinor: 1200,
|
|
}); err == nil {
|
|
t.Fatalf("expected USD amount mismatch")
|
|
}
|
|
}
|
|
|
|
func TestVerifyReceiptMatchesNonUSDProviderAmount(t *testing.T) {
|
|
order := model.CoinSellerRechargeOrder{
|
|
ExternalOrderNo: "v5-1",
|
|
USDMinorAmount: 1000,
|
|
ProviderCurrencyCode: "IDR",
|
|
ProviderAmountMinor: 15000000,
|
|
ProviderCode: "v5pay",
|
|
TargetDisplayUserID: "10001",
|
|
TargetUserID: 10001,
|
|
USDAmount: "10.00",
|
|
CoinAmount: 1000,
|
|
Status: model.CoinSellerRechargeOrderStatusCreated,
|
|
VerifyStatus: model.CoinSellerRechargeVerifyStatusPending,
|
|
GrantStatus: model.CoinSellerRechargeGrantStatusPending,
|
|
OperatorUserID: 7,
|
|
}
|
|
if err := verifyReceiptMatchesOrder(order, &walletv1.VerifyCoinSellerRechargeReceiptResponse{
|
|
ExternalOrderNo: "v5-1",
|
|
CurrencyCode: "IDR",
|
|
ProviderAmountMinor: 15000000,
|
|
}); err != nil {
|
|
t.Fatalf("expected provider amount to match: %v", err)
|
|
}
|
|
order.ProviderAmountMinor = 0
|
|
if err := verifyReceiptMatchesOrder(order, &walletv1.VerifyCoinSellerRechargeReceiptResponse{
|
|
ExternalOrderNo: "v5-1",
|
|
CurrencyCode: "IDR",
|
|
ProviderAmountMinor: 15000000,
|
|
}); err != nil {
|
|
t.Fatalf("non-USD provider amount should be an audit snapshot when operator did not fill local minor amount: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestVerifyReceiptMatchesInputRequiresUSDExactMatch(t *testing.T) {
|
|
input := normalizedCreateOrderInput{
|
|
ExternalOrderNo: "usdt-tx",
|
|
USDMinorAmount: 1234,
|
|
ProviderCode: "usdt",
|
|
Chain: "TRON",
|
|
}
|
|
if err := verifyReceiptMatchesInput(input, coinSellerRechargeReceiptVerificationDTO{
|
|
ExternalOrderNo: "usdt-tx",
|
|
CurrencyCode: "USDT",
|
|
ProviderAmountMinor: 1234,
|
|
}); err != nil {
|
|
t.Fatalf("expected usdt amount to match: %v", err)
|
|
}
|
|
if err := verifyReceiptMatchesInput(input, coinSellerRechargeReceiptVerificationDTO{
|
|
ExternalOrderNo: "usdt-tx",
|
|
CurrencyCode: "USDT",
|
|
ProviderAmountMinor: 1200,
|
|
}); err == nil {
|
|
t.Fatalf("expected usdt amount mismatch")
|
|
}
|
|
}
|
|
|
|
func TestReceiptProviderCodeForUSDTChains(t *testing.T) {
|
|
if got := receiptProviderCode(model.CoinSellerRechargeOrder{ProviderCode: "usdt", Chain: "TRON"}); got != "usdt_trc20" {
|
|
t.Fatalf("tron provider code mismatch: %s", got)
|
|
}
|
|
if got := receiptProviderCode(model.CoinSellerRechargeOrder{ProviderCode: "usdt", Chain: "BSC"}); got != "usdt_bep20" {
|
|
t.Fatalf("bsc provider code mismatch: %s", got)
|
|
}
|
|
}
|