184 lines
6.5 KiB
Go
184 lines
6.5 KiB
Go
package dashboard
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// CoinSellerRechargeBillQuery 是 finance legacy 列表需要的币商进货明细筛选。
|
|
// 它只服务只读展示;金额口径必须与 StatisticsOverview 的 coin_seller_recharge_usd_minor 保持一致。
|
|
type CoinSellerRechargeBillQuery struct {
|
|
Keyword string
|
|
RegionID int64
|
|
StatTZ string
|
|
StartMS int64
|
|
EndMS int64
|
|
Page int
|
|
PageSize int
|
|
}
|
|
|
|
type CoinSellerRechargeBill struct {
|
|
TransactionID string
|
|
Source string
|
|
UserID int64
|
|
CountryCode string
|
|
USDMinorAmount int64
|
|
CreatedAtMS int64
|
|
}
|
|
|
|
type CoinSellerRechargeBillSource interface {
|
|
ListCoinSellerRechargeBills(ctx context.Context, query CoinSellerRechargeBillQuery) ([]CoinSellerRechargeBill, int64, error)
|
|
}
|
|
|
|
func (s *AslanMongoDashboardSource) ListCoinSellerRechargeBills(ctx context.Context, query CoinSellerRechargeBillQuery) ([]CoinSellerRechargeBill, int64, error) {
|
|
if s == nil || s.legacyDB == nil {
|
|
return nil, 0, fmt.Errorf("aslan legacy mysql is not configured")
|
|
}
|
|
countryFilter, err := s.countryFilter(ctx, StatisticsQuery{RegionID: query.RegionID})
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
if countryFilter.Applied && len(countryFilter.Codes) == 0 {
|
|
return []CoinSellerRechargeBill{}, 0, nil
|
|
}
|
|
page := query.Page
|
|
if page < 1 {
|
|
page = 1
|
|
}
|
|
pageSize := query.PageSize
|
|
if pageSize < 1 {
|
|
pageSize = 10
|
|
}
|
|
unionSQL, args := s.coinSellerRechargeBillUnionSQL(query, countryFilter)
|
|
|
|
queryCtx, cancel := context.WithTimeout(ctx, s.requestTimeout)
|
|
defer cancel()
|
|
|
|
var total int64
|
|
if err := s.legacyDB.QueryRowContext(queryCtx, `SELECT COUNT(*) FROM (`+unionSQL+`) bills`, args...).Scan(&total); err != nil {
|
|
return nil, 0, fmt.Errorf("count aslan coin seller recharge bills: %w", err)
|
|
}
|
|
if total == 0 {
|
|
return []CoinSellerRechargeBill{}, 0, nil
|
|
}
|
|
|
|
rows, err := s.legacyDB.QueryContext(queryCtx, `
|
|
SELECT transaction_id, source, user_id, country_code, amount, created_at
|
|
FROM (`+unionSQL+`) bills
|
|
ORDER BY created_at DESC, transaction_id DESC
|
|
LIMIT ? OFFSET ?`, append(args, pageSize, (page-1)*pageSize)...)
|
|
if err != nil {
|
|
return nil, 0, fmt.Errorf("query aslan coin seller recharge bills: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
items := make([]CoinSellerRechargeBill, 0, pageSize)
|
|
for rows.Next() {
|
|
var item CoinSellerRechargeBill
|
|
var amountText string
|
|
var createdAt time.Time
|
|
if err := rows.Scan(&item.TransactionID, &item.Source, &item.UserID, &item.CountryCode, &amountText, &createdAt); err != nil {
|
|
return nil, 0, fmt.Errorf("scan aslan coin seller recharge bill: %w", err)
|
|
}
|
|
amount, err := decimalTextToMinor(amountText)
|
|
if err != nil {
|
|
return nil, 0, fmt.Errorf("parse aslan coin seller recharge bill %s amount: %w", item.TransactionID, err)
|
|
}
|
|
item.CountryCode = aslanMongoCountryCode(item.CountryCode)
|
|
item.USDMinorAmount = amount
|
|
item.CreatedAtMS = createdAt.UnixMilli()
|
|
items = append(items, item)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, 0, fmt.Errorf("iterate aslan coin seller recharge bills: %w", err)
|
|
}
|
|
return items, total, nil
|
|
}
|
|
|
|
func (s *AslanMongoDashboardSource) coinSellerRechargeBillUnionSQL(query CoinSellerRechargeBillQuery, countryFilter externalDashboardCountryFilter) (string, []any) {
|
|
goldWhere := []string{
|
|
"ugcr.sys_origin = ?",
|
|
"ugcr.gold_coin_source = 2",
|
|
"ugcr.recharge_amount > 0",
|
|
"ubi.country_code IS NOT NULL",
|
|
"ubi.country_code != ''",
|
|
}
|
|
goldArgs := []any{s.sysOrigin}
|
|
freightWhere := []string{
|
|
"fbrw.sys_origin = ?",
|
|
"fbrw.origin = 'PURCHASE'",
|
|
"fbrw.type = 0",
|
|
"(COALESCE(fbrw.amount, 0) <> 0 OR COALESCE(fbrw.usd_quantity, 0) <> 0)",
|
|
"ubi.country_code IS NOT NULL",
|
|
"ubi.country_code != ''",
|
|
}
|
|
freightArgs := []any{s.sysOrigin}
|
|
if query.StartMS > 0 {
|
|
start := time.UnixMilli(query.StartMS)
|
|
goldWhere = append(goldWhere, "ugcr.create_time >= ?")
|
|
goldArgs = append(goldArgs, start)
|
|
freightWhere = append(freightWhere, "fbrw.create_time >= ?")
|
|
freightArgs = append(freightArgs, start)
|
|
}
|
|
if query.EndMS > 0 {
|
|
end := time.UnixMilli(query.EndMS)
|
|
goldWhere = append(goldWhere, "ugcr.create_time < ?")
|
|
goldArgs = append(goldArgs, end)
|
|
freightWhere = append(freightWhere, "fbrw.create_time < ?")
|
|
freightArgs = append(freightArgs, end)
|
|
}
|
|
if keyword := strings.TrimSpace(query.Keyword); keyword != "" {
|
|
goldWhere = append(goldWhere, "(CAST(ugcr.id AS CHAR) = ? OR CONCAT('aslan-gold-coin-', ugcr.id) = ? OR CAST(ugcr.user_id AS CHAR) = ?)")
|
|
goldArgs = append(goldArgs, keyword, keyword, keyword)
|
|
freightWhere = append(freightWhere, "(CAST(fbrw.id AS CHAR) = ? OR CONCAT('aslan-freight-purchase-', fbrw.id) = ? OR CAST(fbrw.user_id AS CHAR) = ?)")
|
|
freightArgs = append(freightArgs, keyword, keyword, keyword)
|
|
}
|
|
if countryFilter.Applied {
|
|
placeholders := make([]string, 0, len(countryFilter.Codes))
|
|
for _, code := range countryFilter.Codes {
|
|
normalized := aslanMongoCountryCode(code)
|
|
if normalized == "" {
|
|
continue
|
|
}
|
|
placeholders = append(placeholders, "?")
|
|
goldArgs = append(goldArgs, normalized)
|
|
freightArgs = append(freightArgs, normalized)
|
|
}
|
|
if len(placeholders) == 0 {
|
|
placeholders = append(placeholders, "?")
|
|
goldArgs = append(goldArgs, "__NO_COUNTRY__")
|
|
freightArgs = append(freightArgs, "__NO_COUNTRY__")
|
|
}
|
|
condition := "UPPER(ubi.country_code) IN (" + strings.Join(placeholders, ",") + ")"
|
|
goldWhere = append(goldWhere, condition)
|
|
freightWhere = append(freightWhere, condition)
|
|
}
|
|
walletDatabase := strings.TrimSpace(s.legacyWalletDatabase)
|
|
if walletDatabase == "" {
|
|
walletDatabase = "atyou_wallet"
|
|
}
|
|
unionSQL := `
|
|
SELECT CONCAT('aslan-gold-coin-', ugcr.id) AS transaction_id,
|
|
'gold_coin_recharge' AS source,
|
|
ugcr.user_id,
|
|
UPPER(ubi.country_code) AS country_code,
|
|
CAST(ugcr.recharge_amount AS CHAR) AS amount,
|
|
ugcr.create_time AS created_at
|
|
FROM user_gold_coin_recharge ugcr
|
|
INNER JOIN user_base_info ubi ON ubi.id = ugcr.user_id
|
|
WHERE ` + strings.Join(goldWhere, " AND ") + `
|
|
UNION ALL
|
|
SELECT CONCAT('aslan-freight-purchase-', fbrw.id) AS transaction_id,
|
|
'freight_purchase' AS source,
|
|
fbrw.user_id,
|
|
UPPER(ubi.country_code) AS country_code,
|
|
CAST(CASE WHEN fbrw.amount IS NOT NULL AND fbrw.amount <> 0 THEN fbrw.amount ELSE COALESCE(fbrw.usd_quantity, 0) END AS CHAR) AS amount,
|
|
fbrw.create_time AS created_at
|
|
FROM ` + quoteMySQLIdentifier(walletDatabase) + `.user_freight_balance_running_water fbrw
|
|
INNER JOIN user_base_info ubi ON ubi.id = fbrw.user_id
|
|
WHERE ` + strings.Join(freightWhere, " AND ")
|
|
return unionSQL, append(goldArgs, freightArgs...)
|
|
}
|