380 lines
15 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package payment
import (
"fmt"
"strconv"
"strings"
walletv1 "hyapp.local/api/proto/wallet/v1"
)
type rechargeBillDTO struct {
AppCode string `json:"appCode"`
TransactionID string `json:"transactionId"`
CommandID string `json:"commandId"`
RechargeType string `json:"rechargeType"`
Status string `json:"status"`
ExternalRef string `json:"externalRef"`
UserID int64 `json:"userId,string"`
SellerUserID int64 `json:"sellerUserId,string"`
SellerRegionID int64 `json:"sellerRegionId"`
TargetRegionID int64 `json:"targetRegionId"`
PolicyID int64 `json:"policyId"`
PolicyVersion string `json:"policyVersion"`
CurrencyCode string `json:"currencyCode"`
CoinAmount int64 `json:"coinAmount"`
USDMinorAmount int64 `json:"usdMinorAmount"`
ExchangeCoinAmount int64 `json:"exchangeCoinAmount"`
ExchangeUSDMinorAmount int64 `json:"exchangeUsdMinorAmount"`
ProviderAmountMinor int64 `json:"providerAmountMinor,omitempty"`
CreatedAtMS int64 `json:"createdAtMs"`
ProviderCode string `json:"providerCode"`
UserPaidCurrencyCode string `json:"userPaidCurrencyCode"`
UserPaidAmountMicro int64 `json:"userPaidAmountMicro"`
ProviderFeeMicro int64 `json:"providerFeeMicro"`
ProviderTaxMicro int64 `json:"providerTaxMicro"`
ProviderNetMicro int64 `json:"providerNetMicro"`
PaidSyncedAtMS int64 `json:"paidSyncedAtMs"`
User rechargeBillUserDTO `json:"user"`
Seller rechargeBillUserDTO `json:"seller"`
}
type rechargeBillUserDTO struct {
UserID string `json:"userId"`
DisplayUserID string `json:"displayUserId"`
Username string `json:"username"`
Avatar string `json:"avatar"`
CountryCode string `json:"countryCode"`
CountryName string `json:"countryName"`
CountryDisplayName string `json:"countryDisplayName"`
}
type rechargeProductDTO struct {
AppCode string `json:"appCode"`
ProductID int64 `json:"productId"`
ProductCode string `json:"productCode"`
ProductName string `json:"productName"`
Description string `json:"description"`
AudienceType string `json:"audienceType"`
Platform string `json:"platform"`
Channel string `json:"channel"`
CurrencyCode string `json:"currencyCode"`
AmountUSDT string `json:"amountUsdt"`
AmountUSDTMicro int64 `json:"amountUsdtMicro"`
AmountMicro int64 `json:"amountMicro"`
AmountMinor int64 `json:"amountMinor"`
CoinAmount int64 `json:"coinAmount"`
PolicyVersion string `json:"policyVersion"`
RegionIDs []int64 `json:"regionIds"`
ResourceAssetType string `json:"resourceAssetType"`
Status string `json:"status"`
Enabled bool `json:"enabled"`
AppVisible bool `json:"appVisible"`
SortOrder int32 `json:"sortOrder"`
CreatedByUserID int64 `json:"createdByUserId"`
UpdatedByUserID int64 `json:"updatedByUserId"`
CreatedAtMS int64 `json:"createdAtMs"`
UpdatedAtMS int64 `json:"updatedAtMs"`
}
type thirdPartyPaymentChannelDTO struct {
AppCode string `json:"appCode"`
ProviderCode string `json:"providerCode"`
ProviderName string `json:"providerName"`
Status string `json:"status"`
SortOrder int32 `json:"sortOrder"`
Methods []thirdPartyPaymentMethodDTO `json:"methods"`
}
type thirdPartyPaymentMethodDTO struct {
MethodID int64 `json:"methodId"`
AppCode string `json:"appCode"`
ProviderCode string `json:"providerCode"`
ProviderName string `json:"providerName"`
CountryCode string `json:"countryCode"`
CountryName string `json:"countryName"`
CurrencyCode string `json:"currencyCode"`
PayWay string `json:"payWay"`
PayType string `json:"payType"`
MethodName string `json:"methodName"`
LogoURL string `json:"logoUrl"`
Status string `json:"status"`
USDToCurrencyRate string `json:"usdToCurrencyRate"`
SortOrder int32 `json:"sortOrder"`
CreatedAtMS int64 `json:"createdAtMs"`
UpdatedAtMS int64 `json:"updatedAtMs"`
}
type thirdPartyPaymentMethodSyncDTO struct {
ProviderCode string `json:"providerCode"`
ScannedCountryCount int32 `json:"scannedCountryCount"`
FetchedCountryCount int32 `json:"fetchedCountryCount"`
CreatedCount int32 `json:"createdCount"`
UpdatedCount int32 `json:"updatedCount"`
SkippedCount int32 `json:"skippedCount"`
FailedCountryCount int `json:"failedCountryCount"`
Issues []thirdPartyPaymentMethodIssueDTO `json:"issues"`
}
type thirdPartyPaymentMethodIssueDTO struct {
CountryCode string `json:"countryCode"`
CurrencyCode string `json:"currencyCode"`
Code string `json:"code"`
Message string `json:"message"`
}
type temporaryPaymentLinkDTO struct {
OrderID string `json:"orderId"`
AppCode string `json:"appCode"`
RegionID int64 `json:"regionId"`
OwnerUserID uint `json:"ownerUserId,omitempty"`
OwnerUsername string `json:"ownerUsername,omitempty"`
OwnerName string `json:"ownerName,omitempty"`
CommandID string `json:"commandId,omitempty"`
AudienceType string `json:"audienceType"`
ProductName string `json:"productName"`
CoinAmount int64 `json:"coinAmount"`
USDMinorAmount int64 `json:"usdMinorAmount"`
ProviderCode string `json:"providerCode"`
PaymentMethodID int64 `json:"paymentMethodId"`
CountryCode string `json:"countryCode"`
CurrencyCode string `json:"currencyCode"`
ProviderAmountMinor int64 `json:"providerAmountMinor"`
PayWay string `json:"payWay"`
PayType string `json:"payType"`
PayURL string `json:"payUrl"`
ProviderOrderID string `json:"providerOrderId"`
TxHash string `json:"txHash"`
Status string `json:"status"`
FailureReason string `json:"failureReason"`
TransactionID string `json:"transactionId"`
CreatedAtMS int64 `json:"createdAtMs"`
UpdatedAtMS int64 `json:"updatedAtMs"`
}
func rechargeBillFromProto(item *walletv1.RechargeBill) rechargeBillDTO {
if item == nil {
return rechargeBillDTO{}
}
return rechargeBillDTO{
AppCode: item.GetAppCode(),
TransactionID: item.GetTransactionId(),
CommandID: item.GetCommandId(),
RechargeType: item.GetRechargeType(),
Status: item.GetStatus(),
ExternalRef: item.GetExternalRef(),
UserID: item.GetUserId(),
SellerUserID: item.GetSellerUserId(),
SellerRegionID: item.GetSellerRegionId(),
TargetRegionID: item.GetTargetRegionId(),
PolicyID: item.GetPolicyId(),
PolicyVersion: item.GetPolicyVersion(),
CurrencyCode: item.GetCurrencyCode(),
CoinAmount: item.GetCoinAmount(),
USDMinorAmount: item.GetUsdMinorAmount(),
ExchangeCoinAmount: item.GetExchangeCoinAmount(),
ExchangeUSDMinorAmount: item.GetExchangeUsdMinorAmount(),
ProviderAmountMinor: item.GetProviderAmountMinor(),
CreatedAtMS: item.GetCreatedAtMs(),
ProviderCode: item.GetProviderCode(),
UserPaidCurrencyCode: item.GetUserPaidCurrencyCode(),
UserPaidAmountMicro: item.GetUserPaidAmountMicro(),
ProviderFeeMicro: item.GetProviderFeeMicro(),
ProviderTaxMicro: item.GetProviderTaxMicro(),
ProviderNetMicro: item.GetProviderNetMicro(),
PaidSyncedAtMS: item.GetPaidSyncedAtMs(),
}
}
// collectRechargeBillUserIDs 把付款用户和币商用户放进同一个去重列表;后续只查一次 users 表即可覆盖两列展示。
func collectRechargeBillUserIDs(items []rechargeBillDTO) []int64 {
seen := make(map[int64]struct{}, len(items)*2)
userIDs := make([]int64, 0, len(items)*2)
for _, item := range items {
for _, userID := range []int64{item.UserID, item.SellerUserID} {
if userID <= 0 {
continue
}
if _, ok := seen[userID]; ok {
continue
}
seen[userID] = struct{}{}
userIDs = append(userIDs, userID)
}
}
return userIDs
}
// rechargeBillUserOrFallback 保证用户资料缺失时仍返回长 ID列表和导出不会因为历史用户资料缺失而显示空白。
func rechargeBillUserOrFallback(profile rechargeBillUserDTO, userID int64) rechargeBillUserDTO {
if userID <= 0 {
return rechargeBillUserDTO{}
}
if profile.UserID != "" {
return profile
}
return rechargeBillUserDTO{UserID: strconv.FormatInt(userID, 10)}
}
// int64Args 将用户 ID 列表转换为 database/sql 可展开的参数切片,避免为 IN 条件拼接原始数值。
func int64Args(values []int64) []any {
args := make([]any, 0, len(values))
for _, value := range values {
args = append(args, value)
}
return args
}
// placeholders 只生成固定数量的问号占位符;实际用户 ID 仍通过参数绑定传入,避免 SQL 注入。
func placeholders(count int) string {
if count <= 0 {
return ""
}
items := make([]string, count)
for index := range items {
items[index] = "?"
}
return strings.Join(items, ",")
}
func rechargeProductFromProto(item *walletv1.RechargeProduct) rechargeProductDTO {
if item == nil {
return rechargeProductDTO{}
}
return rechargeProductDTO{
AppCode: item.GetAppCode(),
ProductID: item.GetProductId(),
ProductCode: item.GetProductCode(),
ProductName: item.GetProductName(),
Description: item.GetDescription(),
AudienceType: item.GetAudienceType(),
Platform: item.GetPlatform(),
Channel: item.GetChannel(),
CurrencyCode: item.GetCurrencyCode(),
AmountUSDT: formatUSDTMicro(item.GetAmountMicro()),
AmountUSDTMicro: item.GetAmountMicro(),
AmountMicro: item.GetAmountMicro(),
AmountMinor: item.GetAmountMinor(),
CoinAmount: item.GetCoinAmount(),
PolicyVersion: item.GetPolicyVersion(),
RegionIDs: append([]int64(nil), item.GetRegionIds()...),
ResourceAssetType: item.GetResourceAssetType(),
Status: item.GetStatus(),
Enabled: item.GetEnabled(),
AppVisible: item.GetAppVisible(),
SortOrder: item.GetSortOrder(),
CreatedByUserID: item.GetCreatedByUserId(),
UpdatedByUserID: item.GetUpdatedByUserId(),
CreatedAtMS: item.GetCreatedAtMs(),
UpdatedAtMS: item.GetUpdatedAtMs(),
}
}
func thirdPartyPaymentChannelFromProto(item *walletv1.ThirdPartyPaymentChannel) thirdPartyPaymentChannelDTO {
if item == nil {
return thirdPartyPaymentChannelDTO{}
}
dto := thirdPartyPaymentChannelDTO{
AppCode: item.GetAppCode(),
ProviderCode: item.GetProviderCode(),
ProviderName: item.GetProviderName(),
Status: item.GetStatus(),
SortOrder: item.GetSortOrder(),
Methods: make([]thirdPartyPaymentMethodDTO, 0, len(item.GetMethods())),
}
for _, method := range item.GetMethods() {
dto.Methods = append(dto.Methods, thirdPartyPaymentMethodFromProto(method))
}
return dto
}
func thirdPartyPaymentMethodFromProto(item *walletv1.ThirdPartyPaymentMethod) thirdPartyPaymentMethodDTO {
if item == nil {
return thirdPartyPaymentMethodDTO{}
}
return thirdPartyPaymentMethodDTO{
MethodID: item.GetMethodId(),
AppCode: item.GetAppCode(),
ProviderCode: item.GetProviderCode(),
ProviderName: item.GetProviderName(),
CountryCode: item.GetCountryCode(),
CountryName: item.GetCountryName(),
CurrencyCode: item.GetCurrencyCode(),
PayWay: item.GetPayWay(),
PayType: item.GetPayType(),
MethodName: item.GetMethodName(),
LogoURL: item.GetLogoUrl(),
Status: item.GetStatus(),
USDToCurrencyRate: item.GetUsdToCurrencyRate(),
SortOrder: item.GetSortOrder(),
CreatedAtMS: item.GetCreatedAtMs(),
UpdatedAtMS: item.GetUpdatedAtMs(),
}
}
func thirdPartyPaymentMethodSyncFromProto(item *walletv1.SyncThirdPartyPaymentMethodsResponse) thirdPartyPaymentMethodSyncDTO {
if item == nil {
return thirdPartyPaymentMethodSyncDTO{}
}
dto := thirdPartyPaymentMethodSyncDTO{
ProviderCode: item.GetProviderCode(),
ScannedCountryCount: item.GetScannedCountryCount(),
FetchedCountryCount: item.GetFetchedCountryCount(),
CreatedCount: item.GetCreatedCount(),
UpdatedCount: item.GetUpdatedCount(),
SkippedCount: item.GetSkippedCount(),
FailedCountryCount: len(item.GetIssues()),
Issues: make([]thirdPartyPaymentMethodIssueDTO, 0, len(item.GetIssues())),
}
for _, issue := range item.GetIssues() {
dto.Issues = append(dto.Issues, thirdPartyPaymentMethodIssueDTO{
CountryCode: issue.GetCountryCode(),
CurrencyCode: issue.GetCurrencyCode(),
Code: issue.GetCode(),
Message: issue.GetMessage(),
})
}
return dto
}
func temporaryPaymentLinkFromProto(item *walletv1.ExternalRechargeOrder) temporaryPaymentLinkDTO {
if item == nil {
return temporaryPaymentLinkDTO{}
}
return temporaryPaymentLinkDTO{
OrderID: item.GetOrderId(),
AppCode: item.GetAppCode(),
AudienceType: item.GetAudienceType(),
ProductName: item.GetProductName(),
CoinAmount: item.GetCoinAmount(),
USDMinorAmount: item.GetUsdMinorAmount(),
ProviderCode: item.GetProviderCode(),
PaymentMethodID: item.GetPaymentMethodId(),
CountryCode: item.GetCountryCode(),
CurrencyCode: item.GetCurrencyCode(),
ProviderAmountMinor: item.GetProviderAmountMinor(),
PayWay: item.GetPayWay(),
PayType: item.GetPayType(),
PayURL: item.GetPayUrl(),
ProviderOrderID: item.GetProviderOrderId(),
TxHash: item.GetTxHash(),
Status: item.GetStatus(),
FailureReason: item.GetFailureReason(),
TransactionID: item.GetTransactionId(),
CreatedAtMS: item.GetCreatedAtMs(),
UpdatedAtMS: item.GetUpdatedAtMs(),
}
}
func formatUSDTMicro(amount int64) string {
if amount <= 0 {
return "0"
}
whole := amount / usdtMicroUnit
fraction := amount % usdtMicroUnit
if fraction == 0 {
return strconv.FormatInt(whole, 10)
}
return fmt.Sprintf("%d.%s", whole, strings.TrimRight(fmt.Sprintf("%06d", fraction), "0"))
}