191 lines
6.2 KiB
Go
191 lines
6.2 KiB
Go
package payment
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"hyapp-admin-server/internal/config"
|
|
|
|
"go.mongodb.org/mongo-driver/v2/bson"
|
|
)
|
|
|
|
func yumiBillSourceConfig() config.FinanceBillSourceConfig {
|
|
return config.FinanceBillSourceConfig{
|
|
Enabled: true,
|
|
AppCode: "yumi",
|
|
AppName: "Yumi",
|
|
SysOrigin: "LIKEI",
|
|
MongoDatabase: "test",
|
|
MongoCollection: "in_app_purchase_details",
|
|
RequestTimeout: time.Second,
|
|
}
|
|
}
|
|
|
|
func TestLegacyRechargeBillDTOMapsGooglePurchase(t *testing.T) {
|
|
amount, err := bson.ParseDecimal128("164.99")
|
|
if err != nil {
|
|
t.Fatalf("parse amount: %v", err)
|
|
}
|
|
amountUSD, err := bson.ParseDecimal128("2.99")
|
|
if err != nil {
|
|
t.Fatalf("parse amount usd: %v", err)
|
|
}
|
|
createTime := time.UnixMilli(1_751_000_000_000).UTC()
|
|
dto := legacyRechargeBillDTO(yumiBillSourceConfig(), legacyPurchaseDocument{
|
|
ID: "175100000000012345",
|
|
OrderID: "GPA.1234-5678-9012-34567",
|
|
AcceptUserID: 42,
|
|
CountryCode: "TR",
|
|
Currency: "try",
|
|
Amount: amount,
|
|
AmountUSD: amountUSD,
|
|
Status: "SUCCESS",
|
|
Factory: legacyPurchaseFactory{Platform: "Android", FactoryCode: "GOOGLE"},
|
|
Products: []legacyPurchaseProduct{
|
|
{Name: "GOLD", Content: "560000"},
|
|
{Name: "PROPS", Content: "AVATAR_FRAME"},
|
|
},
|
|
CreateTime: createTime,
|
|
})
|
|
|
|
if dto.AppCode != "yumi" || dto.TransactionID != "175100000000012345" {
|
|
t.Fatalf("unexpected identity: %+v", dto)
|
|
}
|
|
if dto.RechargeType != "google_play_recharge" || dto.ProviderCode != "google" {
|
|
t.Fatalf("unexpected channel mapping: %+v", dto)
|
|
}
|
|
if dto.Status != "succeeded" || dto.ExternalRef != "GPA.1234-5678-9012-34567" {
|
|
t.Fatalf("unexpected status/external ref: %+v", dto)
|
|
}
|
|
if dto.CoinAmount != 560000 {
|
|
t.Fatalf("coin amount = %d, want 560000", dto.CoinAmount)
|
|
}
|
|
if dto.USDMinorAmount != 299 {
|
|
t.Fatalf("usd minor = %d, want 299", dto.USDMinorAmount)
|
|
}
|
|
if dto.UserPaidCurrencyCode != "TRY" || dto.UserPaidAmountMicro != 164_990_000 {
|
|
t.Fatalf("unexpected user paid: %+v", dto)
|
|
}
|
|
if dto.CreatedAtMS != createTime.UnixMilli() || dto.PaidSyncedAtMS != dto.CreatedAtMS {
|
|
t.Fatalf("unexpected timestamps: %+v", dto)
|
|
}
|
|
}
|
|
|
|
func TestLegacyRechargeTypeMapping(t *testing.T) {
|
|
cases := map[string]string{
|
|
"GOOGLE": "google_play_recharge",
|
|
"APPLE": "apple_recharge",
|
|
"HUAWEI": "huawei_recharge",
|
|
"TELEGRAM": "telegram_recharge",
|
|
"PAYER_MAX": "web_recharge",
|
|
"": "web_recharge",
|
|
}
|
|
for factoryCode, want := range cases {
|
|
if got := legacyRechargeType(factoryCode); got != want {
|
|
t.Fatalf("legacyRechargeType(%q) = %q, want %q", factoryCode, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLegacyDecimalScaledHandlesTypes(t *testing.T) {
|
|
decimal, err := bson.ParseDecimal128("6.99")
|
|
if err != nil {
|
|
t.Fatalf("parse decimal: %v", err)
|
|
}
|
|
if got := legacyDecimalToMinor(decimal); got != 699 {
|
|
t.Fatalf("decimal minor = %d, want 699", got)
|
|
}
|
|
if got := legacyDecimalToMicro("54.99"); got != 54_990_000 {
|
|
t.Fatalf("string micro = %d, want 54990000", got)
|
|
}
|
|
if got := legacyDecimalToMinor(int64(3)); got != 300 {
|
|
t.Fatalf("int64 minor = %d, want 300", got)
|
|
}
|
|
if got := legacyDecimalToMinor(nil); got != 0 {
|
|
t.Fatalf("nil minor = %d, want 0", got)
|
|
}
|
|
if got := legacyDecimalToMinor("not-a-number"); got != 0 {
|
|
t.Fatalf("invalid minor = %d, want 0", got)
|
|
}
|
|
}
|
|
|
|
type staticLegacyRegionResolver struct {
|
|
codes []string
|
|
handled bool
|
|
}
|
|
|
|
func (r staticLegacyRegionResolver) CountryCodesForRegion(context.Context, string, int64) ([]string, bool, error) {
|
|
return r.codes, r.handled, nil
|
|
}
|
|
|
|
func TestLegacyBillFilterBuildsQuery(t *testing.T) {
|
|
source := &MongoRechargeBillSource{
|
|
config: yumiBillSourceConfig(),
|
|
regionResolvers: []legacyRegionCountryResolver{staticLegacyRegionResolver{codes: []string{"tr", "SA"}, handled: true}},
|
|
}
|
|
filter, regionCodes, matchable, err := source.billFilter(context.Background(), legacyRechargeBillQuery{
|
|
Keyword: "GPA.1",
|
|
RegionID: 9_000_000_000_000_000_001,
|
|
StartAtMS: 1_000,
|
|
EndAtMS: 2_000,
|
|
})
|
|
if err != nil || !matchable {
|
|
t.Fatalf("billFilter err=%v matchable=%v", err, matchable)
|
|
}
|
|
if filter["sysOrigin"] != "LIKEI" || filter["status"] != "SUCCESS" {
|
|
t.Fatalf("unexpected base filter: %v", filter)
|
|
}
|
|
timeRange, ok := filter["createTime"].(bson.M)
|
|
if !ok || !timeRange["$gte"].(time.Time).Equal(time.UnixMilli(1_000)) || !timeRange["$lt"].(time.Time).Equal(time.UnixMilli(2_000)) {
|
|
t.Fatalf("unexpected time range: %v", filter["createTime"])
|
|
}
|
|
// likei 账单不带国家码;区域条件必须以国家码清单返回,由聚合阶段按付款用户资料匹配。
|
|
if len(regionCodes) != 2 || regionCodes[0] != "TR" || regionCodes[1] != "SA" {
|
|
t.Fatalf("unexpected region codes: %v", regionCodes)
|
|
}
|
|
if _, ok := filter["countryCode"]; ok {
|
|
t.Fatalf("bill countryCode filter should not be used: %v", filter)
|
|
}
|
|
if _, ok := filter["$or"]; !ok {
|
|
t.Fatalf("keyword filter missing: %v", filter)
|
|
}
|
|
}
|
|
|
|
func TestLegacyBillFilterUnresolvedRegionMatchesNothing(t *testing.T) {
|
|
source := &MongoRechargeBillSource{config: yumiBillSourceConfig()}
|
|
_, _, matchable, err := source.billFilter(context.Background(), legacyRechargeBillQuery{RegionID: 123})
|
|
if err != nil {
|
|
t.Fatalf("billFilter err=%v", err)
|
|
}
|
|
if matchable {
|
|
t.Fatalf("unresolved region should not be matchable")
|
|
}
|
|
}
|
|
|
|
func TestLegacyRegionLookupStages(t *testing.T) {
|
|
if stages := legacyRegionLookupStages(nil); len(stages) != 0 {
|
|
t.Fatalf("empty codes should not add stages: %v", stages)
|
|
}
|
|
stages := legacyRegionLookupStages([]string{"TR", "SA"})
|
|
if len(stages) != 3 {
|
|
t.Fatalf("expected lookup/addFields/match stages, got %d", len(stages))
|
|
}
|
|
lookup, ok := stages[0][0].Value.(bson.M)
|
|
if !ok || lookup["from"] != legacyUserProfileCollection || lookup["localField"] != "acceptUserId" || lookup["foreignField"] != "_id" {
|
|
t.Fatalf("unexpected lookup stage: %v", stages[0])
|
|
}
|
|
match, ok := stages[2][0].Value.(bson.M)
|
|
if !ok {
|
|
t.Fatalf("unexpected match stage: %v", stages[2])
|
|
}
|
|
condition, ok := match["legacyBillCountry"].(bson.M)
|
|
if !ok {
|
|
t.Fatalf("match stage missing country condition: %v", match)
|
|
}
|
|
codes, ok := condition["$in"].([]string)
|
|
if !ok || len(codes) != 2 || codes[0] != "TR" || codes[1] != "SA" {
|
|
t.Fatalf("unexpected region codes in match: %v", condition["$in"])
|
|
}
|
|
}
|