package dashboard import ( "context" "strings" "github.com/shopspring/decimal" ) type Mapper struct { store Store sysOrigins map[string]struct{} unknownCountry string } func NewMapper(store Store, sysOrigins []string, unknownCountry string) *Mapper { origins := make(map[string]struct{}, len(sysOrigins)) for _, origin := range sysOrigins { origins[strings.TrimSpace(origin)] = struct{}{} } return &Mapper{store: store, sysOrigins: origins, unknownCountry: unknownCountry} } func (m *Mapper) Map(ctx context.Context, schema string, table string, action string, row Row) ([]Contribution, error) { switch table { case "user_base_info": return m.mapUser(ctx, schema, table, action, row) case "order_purchase_history": return m.mapOfficialRecharge(ctx, schema, table, action, row) case "order_user_purchase_pay": return m.mapMifapayRecharge(ctx, schema, table, action, row) case "game_lucky_gift_count": return m.mapLuckyGift(ctx, schema, table, action, row) case "game_lucky_box_count": return m.mapLuckyBox(ctx, schema, table, action, row) case "user_freight_balance_running_water": return m.mapDealerRecharge(ctx, schema, table, action, row) case "user_salary_account_running_water", "user_salary_diamond_running_water": return m.mapSalaryExchange(ctx, schema, table, action, row) default: if strings.HasPrefix(table, "wallet_gold_asset_record_") { return m.mapWalletGame(ctx, schema, table, action, row) } return nil, nil } } func (m *Mapper) mapUser(_ context.Context, schema string, table string, action string, row Row) ([]Contribution, error) { user := UserCountryFromRow(row, m.unknownCountry) if !m.allowed(user.SysOrigin) || user.IsDeleted || user.UserID == 0 || user.CreatedAt.IsZero() { return nil, nil } return []Contribution{{ SourceSchema: schema, SourceTable: table, SourcePK: rowPK(row), SourceAction: action, DeltaSign: signForAction(action), SysOrigin: user.SysOrigin, UserID: user.UserID, Country: user.Country, EventTime: user.CreatedAt, CountryNewUser: 1, }}, nil } func (m *Mapper) mapOfficialRecharge(ctx context.Context, schema string, table string, action string, row Row) ([]Contribution, error) { if row.String("evn") != "PROD" || row.Bool("is_trial_period") || row.String("status") != "COMPLETE" { return nil, nil } sysOrigin := row.String("sys_origin") if !m.allowed(sysOrigin) { return nil, nil } user, ok, err := m.user(ctx, row.Int64("user_id")) if err != nil || !ok || user.IsDeleted { return nil, err } if user.SysOrigin != sysOrigin { return nil, nil } amount := row.Decimal("unit_price") payPlatform := row.String("pay_platform") c := m.base(schema, table, action, row, user, row.Time("create_time")) if payPlatform != "MIFA_PAY" { c.OfficialRecharge = amount } if payPlatform == "GOOGLE" { c.GoogleRecharge = amount } c.NewUserRechargeCandidate = amount return []Contribution{c}, nil } func (m *Mapper) mapMifapayRecharge(ctx context.Context, schema string, table string, action string, row Row) ([]Contribution, error) { if row.String("evn") != "PROD" || row.String("factory_code") != "MIFA_PAY" || row.String("pay_status") != "SUCCESSFUL" || row.String("receipt_type") != "PAYMENT" || row.String("refund_status") != "NONE" { return nil, nil } return m.amountContribution(ctx, schema, table, action, row, row.Decimal("compute_usd_amount"), func(c *Contribution, amount decimal.Decimal) { c.MifapayRecharge = amount }) } func (m *Mapper) mapDealerRecharge(ctx context.Context, schema string, table string, action string, row Row) ([]Contribution, error) { if row.String("origin") != "PURCHASE" || row.Int64("type") != 0 || !row.Decimal("amount").GreaterThan(decimal.Zero) { return nil, nil } return m.amountContribution(ctx, schema, table, action, row, row.Decimal("amount"), func(c *Contribution, amount decimal.Decimal) { c.DealerRecharge = amount }) } func (m *Mapper) mapSalaryExchange(ctx context.Context, schema string, table string, action string, row Row) ([]Contribution, error) { if row.Int64("type") != 1 { return nil, nil } event := row.String("salary_event") if event != "SALARY_EXCHANGE" && event != "SALARY_EXCHANGE_GOLD_COINS" && event != "EXCHANGE_GOLD_COINS" && event != "BILL_EXCHANGE_GOLD_COINS" { return nil, nil } return m.amountContribution(ctx, schema, table, action, row, row.Decimal("amount"), func(c *Contribution, amount decimal.Decimal) { c.SalaryExchange = amount }) } func (m *Mapper) mapLuckyGift(ctx context.Context, schema string, table string, action string, row Row) ([]Contribution, error) { return m.amountContribution(ctx, schema, table, action, row, row.Decimal("pay_amount"), func(c *Contribution, amount decimal.Decimal) { c.LuckyGiftTotalFlow = amount c.LuckyGiftPayout = row.Decimal("award_amount") c.LuckyGiftUser = true }) } func (m *Mapper) mapLuckyBox(ctx context.Context, schema string, table string, action string, row Row) ([]Contribution, error) { return m.amountContribution(ctx, schema, table, action, row, row.Decimal("pay_amount"), func(c *Contribution, amount decimal.Decimal) { payout := row.Decimal("gift_amount") c.GameTotalFlow = amount c.GamePayout = payout c.GameUser = true c.GameProvider = "INTERNAL" c.GameID = "LUCKY_BOX" c.GameName = "Lucky Box" c.GameConsume = amount c.GamePayoutBy = payout c.GameProfit = amount.Sub(payout) c.GameOrder = 1 }) }