135 lines
4.9 KiB
Go
135 lines
4.9 KiB
Go
package payment
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"hyapp-admin-server/internal/appctx"
|
|
"hyapp-admin-server/internal/middleware"
|
|
"hyapp-admin-server/internal/modules/shared"
|
|
"hyapp-admin-server/internal/response"
|
|
walletv1 "hyapp.local/api/proto/wallet/v1"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type rechargeBillDailyBucketDTO struct {
|
|
Date string `json:"date"`
|
|
GoogleUsdMinor int64 `json:"googleUsdMinor"`
|
|
ThirdPartyUsdMinor int64 `json:"thirdPartyUsdMinor"`
|
|
CoinSellerUsdMinor int64 `json:"coinSellerUsdMinor"`
|
|
GoogleCoinAmount int64 `json:"googleCoinAmount"`
|
|
ThirdPartyCoinAmount int64 `json:"thirdPartyCoinAmount"`
|
|
CoinSellerCoinAmount int64 `json:"coinSellerCoinAmount"`
|
|
}
|
|
|
|
type rechargeBillRegionBucketDTO struct {
|
|
RegionID int64 `json:"regionId"`
|
|
Name string `json:"name"`
|
|
BillCount int64 `json:"billCount"`
|
|
UsdMinorAmount int64 `json:"usdMinorAmount"`
|
|
}
|
|
|
|
type rechargeBillGooglePaidStatsDTO struct {
|
|
GoogleBillCount int64 `json:"googleBillCount"`
|
|
SyncedCount int64 `json:"syncedCount"`
|
|
UnsyncedCount int64 `json:"unsyncedCount"`
|
|
CoveredUsdMinor int64 `json:"coveredUsdMinor"`
|
|
EstFeeUsdMinor int64 `json:"estFeeUsdMinor"`
|
|
EstTaxUsdMinor int64 `json:"estTaxUsdMinor"`
|
|
EstNetUsdMinor int64 `json:"estNetUsdMinor"`
|
|
}
|
|
|
|
type rechargeBillOverviewDTO struct {
|
|
Daily []rechargeBillDailyBucketDTO `json:"daily"`
|
|
Regions []rechargeBillRegionBucketDTO `json:"regions"`
|
|
GooglePaid rechargeBillGooglePaidStatsDTO `json:"googlePaid"`
|
|
}
|
|
|
|
// GetRechargeBillOverview 返回财务概览聚合:按日趋势、区域分布与谷歌实付覆盖度;筛选口径与账单列表一致。
|
|
func (h *Handler) GetRechargeBillOverview(c *gin.Context) {
|
|
options := shared.ListOptions(c)
|
|
appCode := appctx.FromContext(c.Request.Context())
|
|
tzOffsetMinutes := int32(queryInt64(c, "tz_offset_minutes", "tzOffsetMinutes"))
|
|
if tzOffsetMinutes == 0 {
|
|
// 财务系统统一按中国时区切日边界。
|
|
tzOffsetMinutes = 480
|
|
}
|
|
if source, ok := h.billSources[appCode]; ok {
|
|
overview, err := source.Overview(c.Request.Context(), legacyRechargeBillQuery{
|
|
Keyword: options.Keyword,
|
|
RechargeType: strings.TrimSpace(firstQuery(c, "recharge_type", "rechargeType")),
|
|
RegionID: queryInt64(c, "region_id", "regionId"),
|
|
StartAtMS: queryInt64(c, "start_at_ms", "startAtMs"),
|
|
EndAtMS: queryInt64(c, "end_at_ms", "endAtMs"),
|
|
}, tzOffsetMinutes)
|
|
if err != nil {
|
|
response.ServerError(c, "获取财务概览失败")
|
|
return
|
|
}
|
|
response.OK(c, overview)
|
|
return
|
|
}
|
|
|
|
resp, err := h.wallet.GetRechargeBillOverview(c.Request.Context(), &walletv1.GetRechargeBillOverviewRequest{
|
|
RequestId: middleware.CurrentRequestID(c),
|
|
AppCode: appCode,
|
|
RegionId: queryInt64(c, "region_id", "regionId"),
|
|
RechargeType: strings.TrimSpace(firstQuery(c, "recharge_type", "rechargeType")),
|
|
Status: options.Status,
|
|
StartAtMs: queryInt64(c, "start_at_ms", "startAtMs"),
|
|
EndAtMs: queryInt64(c, "end_at_ms", "endAtMs"),
|
|
TzOffsetMinutes: tzOffsetMinutes,
|
|
})
|
|
if err != nil {
|
|
writeWalletError(c, err, "获取财务概览失败")
|
|
return
|
|
}
|
|
|
|
overview := rechargeBillOverviewDTO{
|
|
Daily: make([]rechargeBillDailyBucketDTO, 0, len(resp.GetDaily())),
|
|
Regions: make([]rechargeBillRegionBucketDTO, 0, len(resp.GetRegions())),
|
|
}
|
|
for _, bucket := range resp.GetDaily() {
|
|
overview.Daily = append(overview.Daily, rechargeBillDailyBucketDTO{
|
|
Date: bucket.GetDate(),
|
|
GoogleUsdMinor: bucket.GetGoogleUsdMinor(),
|
|
ThirdPartyUsdMinor: bucket.GetThirdPartyUsdMinor(),
|
|
CoinSellerUsdMinor: bucket.GetCoinSellerUsdMinor(),
|
|
GoogleCoinAmount: bucket.GetGoogleCoinAmount(),
|
|
ThirdPartyCoinAmount: bucket.GetThirdPartyCoinAmount(),
|
|
CoinSellerCoinAmount: bucket.GetCoinSellerCoinAmount(),
|
|
})
|
|
}
|
|
// 区域名从后台区域目录补齐;目录缺失时回退区域 ID 文本,避免概览页出现空白区块。
|
|
regionNames := map[int64]string{}
|
|
if regions, err := h.listRechargeBillRegions(c.Request.Context(), appCode); err == nil {
|
|
for _, region := range regions {
|
|
name := region.Name
|
|
if name == "" {
|
|
name = region.RegionCode
|
|
}
|
|
regionNames[region.RegionID] = name
|
|
}
|
|
}
|
|
for _, bucket := range resp.GetRegions() {
|
|
overview.Regions = append(overview.Regions, rechargeBillRegionBucketDTO{
|
|
RegionID: bucket.GetRegionId(),
|
|
Name: regionNames[bucket.GetRegionId()],
|
|
BillCount: bucket.GetBillCount(),
|
|
UsdMinorAmount: bucket.GetUsdMinorAmount(),
|
|
})
|
|
}
|
|
if stats := resp.GetGooglePaid(); stats != nil {
|
|
overview.GooglePaid = rechargeBillGooglePaidStatsDTO{
|
|
GoogleBillCount: stats.GetGoogleBillCount(),
|
|
SyncedCount: stats.GetSyncedCount(),
|
|
UnsyncedCount: stats.GetUnsyncedCount(),
|
|
CoveredUsdMinor: stats.GetCoveredUsdMinor(),
|
|
EstFeeUsdMinor: stats.GetEstFeeUsdMinor(),
|
|
EstTaxUsdMinor: stats.GetEstTaxUsdMinor(),
|
|
EstNetUsdMinor: stats.GetEstNetUsdMinor(),
|
|
}
|
|
}
|
|
response.OK(c, overview)
|
|
}
|