手动领取房间奖励
This commit is contained in:
parent
8c53a64416
commit
6195544950
@ -196,6 +196,11 @@ func (g *Gateways) MapRoomProfiles(ctx context.Context, roomIDs []int64) (map[in
|
|||||||
return g.Room.MapRoomProfiles(ctx, roomIDs)
|
return g.Room.MapRoomProfiles(ctx, roomIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkRoomTurnoverRewardCoinsSent 透传到房间流水奖励标记接口。
|
||||||
|
func (g *Gateways) MarkRoomTurnoverRewardCoinsSent(ctx context.Context, id string) (bool, error) {
|
||||||
|
return g.Room.MarkRoomTurnoverRewardCoinsSent(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
// GetTeamPolicyRelease 透传到团队政策网关。
|
// GetTeamPolicyRelease 透传到团队政策网关。
|
||||||
func (g *Gateways) GetTeamPolicyRelease(ctx context.Context, query TeamPolicyReleaseQuery) (TeamPolicyRelease, error) {
|
func (g *Gateways) GetTeamPolicyRelease(ctx context.Context, query TeamPolicyReleaseQuery) (TeamPolicyRelease, error) {
|
||||||
return g.Team.GetTeamPolicyRelease(ctx, query)
|
return g.Team.GetTeamPolicyRelease(ctx, query)
|
||||||
@ -445,6 +450,11 @@ func (g *RoomGateway) MapRoomProfiles(ctx context.Context, roomIDs []int64) (map
|
|||||||
return g.client.MapRoomProfiles(ctx, roomIDs)
|
return g.client.MapRoomProfiles(ctx, roomIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkRoomTurnoverRewardCoinsSent 标记 Java 房间流水统计记录已经发奖。
|
||||||
|
func (g *RoomGateway) MarkRoomTurnoverRewardCoinsSent(ctx context.Context, id string) (bool, error) {
|
||||||
|
return g.client.MarkRoomTurnoverRewardCoinsSent(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
// TeamGateway 负责团队政策相关接口。
|
// TeamGateway 负责团队政策相关接口。
|
||||||
type TeamGateway struct {
|
type TeamGateway struct {
|
||||||
client *Client
|
client *Client
|
||||||
|
|||||||
@ -1030,6 +1030,19 @@ func (c *Client) GetCurrentWeekRoomContribution(ctx context.Context, roomID int6
|
|||||||
return resp.Body, nil
|
return resp.Body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) MarkRoomTurnoverRewardCoinsSent(ctx context.Context, id string) (bool, error) {
|
||||||
|
id = strings.TrimSpace(id)
|
||||||
|
if id == "" {
|
||||||
|
return false, fmt.Errorf("empty room contribution id")
|
||||||
|
}
|
||||||
|
endpoint := c.cfg.Java.OtherBaseURL + "/room-contribution-activity-count/client/rewardCoinsSent?id=" + url.QueryEscape(id)
|
||||||
|
var resp resultResponse[bool]
|
||||||
|
if err := c.postJSON(ctx, endpoint, nil, nil, &resp); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return resp.Body, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) GetRoomProfileByUserID(ctx context.Context, userID int64) (RoomProfile, error) {
|
func (c *Client) GetRoomProfileByUserID(ctx context.Context, userID int64) (RoomProfile, error) {
|
||||||
if userID <= 0 {
|
if userID <= 0 {
|
||||||
return RoomProfile{}, nil
|
return RoomProfile{}, nil
|
||||||
|
|||||||
@ -4,12 +4,13 @@ import "time"
|
|||||||
|
|
||||||
// RoomTurnoverRewardConfig 保存房间流水奖励的系统级配置。
|
// RoomTurnoverRewardConfig 保存房间流水奖励的系统级配置。
|
||||||
type RoomTurnoverRewardConfig struct {
|
type RoomTurnoverRewardConfig struct {
|
||||||
ID int64 `gorm:"column:id;primaryKey"`
|
ID int64 `gorm:"column:id;primaryKey"`
|
||||||
SysOrigin string `gorm:"column:sys_origin;size:32;uniqueIndex:uk_room_turnover_reward_sys_origin"`
|
SysOrigin string `gorm:"column:sys_origin;size:32;uniqueIndex:uk_room_turnover_reward_sys_origin"`
|
||||||
Enabled bool `gorm:"column:enabled;index:idx_room_turnover_reward_enabled"`
|
Enabled bool `gorm:"column:enabled;index:idx_room_turnover_reward_enabled"`
|
||||||
Timezone string `gorm:"column:timezone;size:64"`
|
AutoRewardEnabled bool `gorm:"column:auto_reward_enabled"`
|
||||||
CreateTime time.Time `gorm:"column:create_time"`
|
Timezone string `gorm:"column:timezone;size:64"`
|
||||||
UpdateTime time.Time `gorm:"column:update_time"`
|
CreateTime time.Time `gorm:"column:create_time"`
|
||||||
|
UpdateTime time.Time `gorm:"column:update_time"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (RoomTurnoverRewardConfig) TableName() string { return "room_turnover_reward_config" }
|
func (RoomTurnoverRewardConfig) TableName() string { return "room_turnover_reward_config" }
|
||||||
@ -48,6 +49,7 @@ type RoomTurnoverRewardRecord struct {
|
|||||||
TurnoverThreshold int64 `gorm:"column:turnover_threshold"`
|
TurnoverThreshold int64 `gorm:"column:turnover_threshold"`
|
||||||
RewardGold int64 `gorm:"column:reward_gold"`
|
RewardGold int64 `gorm:"column:reward_gold"`
|
||||||
TrackID string `gorm:"column:track_id;size:128;uniqueIndex:uk_room_turnover_reward_track"`
|
TrackID string `gorm:"column:track_id;size:128;uniqueIndex:uk_room_turnover_reward_track"`
|
||||||
|
SourceID string `gorm:"column:source_id;size:128"`
|
||||||
Status string `gorm:"column:status;size:32;index:idx_room_turnover_reward_record_status"`
|
Status string `gorm:"column:status;size:32;index:idx_room_turnover_reward_record_status"`
|
||||||
RetryCount int `gorm:"column:retry_count"`
|
RetryCount int `gorm:"column:retry_count"`
|
||||||
LastError string `gorm:"column:last_error;size:1024"`
|
LastError string `gorm:"column:last_error;size:1024"`
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -35,6 +37,32 @@ func registerRoomTurnoverRewardRoutes(engine *gin.Engine, javaClient authGateway
|
|||||||
}
|
}
|
||||||
writeOK(c, resp)
|
writeOK(c, resp)
|
||||||
})
|
})
|
||||||
|
appGroup.GET("/reward/claim/status", func(c *gin.Context) {
|
||||||
|
resp, err := service.GetClaimStatus(c.Request.Context(), mustAuthUser(c))
|
||||||
|
if err != nil {
|
||||||
|
writeError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeOK(c, resp)
|
||||||
|
})
|
||||||
|
appGroup.POST("/reward/claim", func(c *gin.Context) {
|
||||||
|
var req roomturnoverreward.RoomTurnoverRewardClaimRequest
|
||||||
|
if c.Request.ContentLength != 0 {
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
writeError(c, roomturnoverreward.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if err := c.ShouldBindJSON(&req); err != nil && !errors.Is(err, io.EOF) {
|
||||||
|
writeError(c, roomturnoverreward.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, err := service.ClaimReward(c.Request.Context(), mustAuthUser(c), req)
|
||||||
|
if err != nil {
|
||||||
|
writeError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeOK(c, resp)
|
||||||
|
})
|
||||||
|
|
||||||
group := engine.Group("/resident-activity/room-turnover-reward")
|
group := engine.Group("/resident-activity/room-turnover-reward")
|
||||||
group.Use(consoleAuthMiddleware(javaClient))
|
group.Use(consoleAuthMiddleware(javaClient))
|
||||||
|
|||||||
254
internal/service/roomturnoverreward/claim.go
Normal file
254
internal/service/roomturnoverreward/claim.go
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
package roomturnoverreward
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"chatapp3-golang/internal/common"
|
||||||
|
"chatapp3-golang/internal/integration"
|
||||||
|
"chatapp3-golang/internal/model"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetClaimStatus 返回当前用户是否存在可手动领取的房间流水奖励。
|
||||||
|
func (s *Service) GetClaimStatus(ctx context.Context, user common.AuthUser) (*RoomTurnoverRewardClaimStatusResponse, error) {
|
||||||
|
if user.UserID <= 0 {
|
||||||
|
return nil, NewAppError(http.StatusUnauthorized, "invalid_user", "user is required")
|
||||||
|
}
|
||||||
|
sysOrigin := s.normalizeSysOrigin(user.SysOrigin)
|
||||||
|
resp := &RoomTurnoverRewardClaimStatusResponse{
|
||||||
|
CanClaim: false,
|
||||||
|
Reason: "no_claimable_reward",
|
||||||
|
SysOrigin: sysOrigin,
|
||||||
|
AutoRewardEnabled: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
configRow, ok, err := s.loadConfigRow(ctx, sysOrigin)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
resp.Reason = "config_not_found"
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
resp.AutoRewardEnabled = configRow.AutoRewardEnabled
|
||||||
|
if configRow.AutoRewardEnabled {
|
||||||
|
resp.Reason = "auto_reward_enabled"
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
record, ok, err := s.findClaimableRewardRecord(ctx, sysOrigin, user.UserID, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
view := toRecordView(record)
|
||||||
|
resp.CanClaim = true
|
||||||
|
resp.Reason = "available"
|
||||||
|
resp.Record = &view
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClaimReward 手动领取一条已结算但未发放的房间流水奖励。
|
||||||
|
func (s *Service) ClaimReward(ctx context.Context, user common.AuthUser, req RoomTurnoverRewardClaimRequest) (*RoomTurnoverRewardClaimResponse, error) {
|
||||||
|
if s.repo.Java == nil {
|
||||||
|
return nil, NewAppError(http.StatusServiceUnavailable, "java_gateway_unavailable", "java gateway is unavailable")
|
||||||
|
}
|
||||||
|
if user.UserID <= 0 {
|
||||||
|
return nil, NewAppError(http.StatusUnauthorized, "invalid_user", "user is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
sysOrigin := s.normalizeSysOrigin(user.SysOrigin)
|
||||||
|
configRow, ok, err := s.loadConfigRow(ctx, sysOrigin)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil, NewAppError(http.StatusNotFound, "room_turnover_reward_config_not_found", "config not found")
|
||||||
|
}
|
||||||
|
if configRow.AutoRewardEnabled {
|
||||||
|
return nil, NewAppError(http.StatusConflict, "manual_claim_disabled", "manual claim is disabled when auto reward is enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
recordID := req.RecordID.Int64()
|
||||||
|
var saved model.RoomTurnoverRewardRecord
|
||||||
|
claimed := false
|
||||||
|
var dispatchErr error
|
||||||
|
|
||||||
|
err = s.repo.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||||
|
record, found, findErr := s.lockRewardRecord(ctx, tx, sysOrigin, user.UserID, recordID)
|
||||||
|
if findErr != nil {
|
||||||
|
return findErr
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return NewAppError(http.StatusNotFound, "no_claimable_reward", "no claimable reward")
|
||||||
|
}
|
||||||
|
if record.Status == roomTurnoverRewardStatusSuccess {
|
||||||
|
saved = record
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if record.Status != roomTurnoverRewardStatusPending && record.Status != roomTurnoverRewardStatusFailed {
|
||||||
|
return NewAppError(http.StatusConflict, "reward_not_claimable", "reward is not claimable")
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchErr = s.dispatchRewardRecord(ctx, &record)
|
||||||
|
now := time.Now()
|
||||||
|
if dispatchErr != nil {
|
||||||
|
retryCount := record.RetryCount + 1
|
||||||
|
updates := map[string]any{
|
||||||
|
"status": roomTurnoverRewardStatusFailed,
|
||||||
|
"retry_count": retryCount,
|
||||||
|
"last_error": truncateString(dispatchErr.Error(), 1024),
|
||||||
|
"update_time": now,
|
||||||
|
}
|
||||||
|
if err := tx.Model(&model.RoomTurnoverRewardRecord{}).
|
||||||
|
Where("id = ?", record.ID).
|
||||||
|
Updates(updates).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
record.Status = roomTurnoverRewardStatusFailed
|
||||||
|
record.RetryCount = retryCount
|
||||||
|
record.LastError = truncateString(dispatchErr.Error(), 1024)
|
||||||
|
record.UpdateTime = now
|
||||||
|
saved = record
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
retryCount := record.RetryCount
|
||||||
|
if record.Status == roomTurnoverRewardStatusFailed {
|
||||||
|
retryCount++
|
||||||
|
}
|
||||||
|
if err := tx.Model(&model.RoomTurnoverRewardRecord{}).
|
||||||
|
Where("id = ?", record.ID).
|
||||||
|
Updates(map[string]any{
|
||||||
|
"status": roomTurnoverRewardStatusSuccess,
|
||||||
|
"retry_count": retryCount,
|
||||||
|
"last_error": "",
|
||||||
|
"sent_at": now,
|
||||||
|
"update_time": now,
|
||||||
|
}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
record.Status = roomTurnoverRewardStatusSuccess
|
||||||
|
record.RetryCount = retryCount
|
||||||
|
record.LastError = ""
|
||||||
|
record.SentAt = &now
|
||||||
|
record.UpdateTime = now
|
||||||
|
saved = record
|
||||||
|
claimed = true
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if dispatchErr != nil {
|
||||||
|
return nil, NewAppError(http.StatusBadGateway, "room_turnover_reward_claim_failed", dispatchErr.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if claimed {
|
||||||
|
s.markSourceSent(ctx, saved)
|
||||||
|
}
|
||||||
|
return &RoomTurnoverRewardClaimResponse{
|
||||||
|
Claimed: claimed,
|
||||||
|
Record: toRecordView(saved),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) dispatchRewardRecord(ctx context.Context, record *model.RoomTurnoverRewardRecord) error {
|
||||||
|
if record == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return s.repo.Java.ChangeGoldBalance(ctx, integration.GoldReceiptCommand{
|
||||||
|
ReceiptType: "INCOME",
|
||||||
|
UserID: record.OwnerUserID,
|
||||||
|
SysOrigin: record.SysOrigin,
|
||||||
|
EventID: record.TrackID,
|
||||||
|
Origin: roomTurnoverRewardGoldOrigin,
|
||||||
|
Remark: fmt.Sprintf("room turnover reward %s room %d", record.CycleKey, record.RoomID),
|
||||||
|
Amount: integration.NewPennyAmountPayloadFromDollar(record.RewardGold),
|
||||||
|
CloseDelayAsset: false,
|
||||||
|
OpUserType: "APP",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) markSourceSent(ctx context.Context, record model.RoomTurnoverRewardRecord) {
|
||||||
|
sourceID := strings.TrimSpace(record.SourceID)
|
||||||
|
if sourceID == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
marked, err := s.repo.Java.MarkRoomTurnoverRewardCoinsSent(ctx, sourceID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("mark room turnover reward source failed after manual claim. recordId=%d sourceId=%s err=%v", record.ID, sourceID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !marked {
|
||||||
|
log.Printf("room turnover reward source was not modified after manual claim. recordId=%d sourceId=%s", record.ID, sourceID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) loadConfigRow(ctx context.Context, sysOrigin string) (model.RoomTurnoverRewardConfig, bool, error) {
|
||||||
|
var row model.RoomTurnoverRewardConfig
|
||||||
|
err := s.repo.DB.WithContext(ctx).
|
||||||
|
Where("sys_origin = ?", s.normalizeSysOrigin(sysOrigin)).
|
||||||
|
First(&row).Error
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return model.RoomTurnoverRewardConfig{}, false, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return model.RoomTurnoverRewardConfig{}, false, err
|
||||||
|
}
|
||||||
|
return row, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) findClaimableRewardRecord(ctx context.Context, sysOrigin string, userID int64, recordID int64) (model.RoomTurnoverRewardRecord, bool, error) {
|
||||||
|
query := s.repo.DB.WithContext(ctx).
|
||||||
|
Where("sys_origin = ? AND owner_user_id = ?", s.normalizeSysOrigin(sysOrigin), userID).
|
||||||
|
Where("status IN ?", []string{roomTurnoverRewardStatusPending, roomTurnoverRewardStatusFailed})
|
||||||
|
if recordID > 0 {
|
||||||
|
query = query.Where("id = ?", recordID)
|
||||||
|
}
|
||||||
|
var record model.RoomTurnoverRewardRecord
|
||||||
|
err := query.
|
||||||
|
Order("period_end_at desc").
|
||||||
|
Order("id desc").
|
||||||
|
First(&record).Error
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return model.RoomTurnoverRewardRecord{}, false, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return model.RoomTurnoverRewardRecord{}, false, err
|
||||||
|
}
|
||||||
|
return record, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) lockRewardRecord(ctx context.Context, tx *gorm.DB, sysOrigin string, userID int64, recordID int64) (model.RoomTurnoverRewardRecord, bool, error) {
|
||||||
|
query := tx.WithContext(ctx).
|
||||||
|
Clauses(clause.Locking{Strength: "UPDATE"}).
|
||||||
|
Where("sys_origin = ? AND owner_user_id = ?", s.normalizeSysOrigin(sysOrigin), userID)
|
||||||
|
if recordID > 0 {
|
||||||
|
query = query.Where("id = ?", recordID)
|
||||||
|
} else {
|
||||||
|
query = query.Where("status IN ?", []string{roomTurnoverRewardStatusPending, roomTurnoverRewardStatusFailed})
|
||||||
|
}
|
||||||
|
var record model.RoomTurnoverRewardRecord
|
||||||
|
err := query.
|
||||||
|
Order("period_end_at desc").
|
||||||
|
Order("id desc").
|
||||||
|
First(&record).Error
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return model.RoomTurnoverRewardRecord{}, false, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return model.RoomTurnoverRewardRecord{}, false, err
|
||||||
|
}
|
||||||
|
return record, true, nil
|
||||||
|
}
|
||||||
140
internal/service/roomturnoverreward/claim_test.go
Normal file
140
internal/service/roomturnoverreward/claim_test.go
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package roomturnoverreward
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"chatapp3-golang/internal/common"
|
||||||
|
"chatapp3-golang/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetClaimStatusReturnsClaimableRecordWhenAutoRewardDisabled(t *testing.T) {
|
||||||
|
service, db := newTestService(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
autoRewardEnabled := false
|
||||||
|
configResp, err := service.SaveConfig(ctx, SaveRoomTurnoverRewardConfigRequest{
|
||||||
|
SysOrigin: "LIKEI",
|
||||||
|
Enabled: true,
|
||||||
|
AutoRewardEnabled: &autoRewardEnabled,
|
||||||
|
Timezone: "Asia/Riyadh",
|
||||||
|
LevelConfigs: []RoomTurnoverRewardLevelInput{
|
||||||
|
{Level: 1, TurnoverThreshold: 100000, RewardGold: 2000, Enabled: true},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SaveConfig() error = %v", err)
|
||||||
|
}
|
||||||
|
record := seedRoomTurnoverRewardRecord(t, db, configResp.ID, roomTurnoverRewardStatusPending)
|
||||||
|
|
||||||
|
resp, err := service.GetClaimStatus(ctx, common.AuthUser{UserID: record.OwnerUserID, SysOrigin: "LIKEI"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetClaimStatus() error = %v", err)
|
||||||
|
}
|
||||||
|
if !resp.CanClaim || resp.Reason != "available" || resp.Record == nil || resp.Record.ID != record.ID {
|
||||||
|
t.Fatalf("claim status = %+v", resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetClaimStatusDisablesButtonWhenAutoRewardEnabled(t *testing.T) {
|
||||||
|
service, db := newTestService(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
configResp, err := service.SaveConfig(ctx, SaveRoomTurnoverRewardConfigRequest{
|
||||||
|
SysOrigin: "LIKEI",
|
||||||
|
Enabled: true,
|
||||||
|
Timezone: "Asia/Riyadh",
|
||||||
|
LevelConfigs: []RoomTurnoverRewardLevelInput{
|
||||||
|
{Level: 1, TurnoverThreshold: 100000, RewardGold: 2000, Enabled: true},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SaveConfig() error = %v", err)
|
||||||
|
}
|
||||||
|
record := seedRoomTurnoverRewardRecord(t, db, configResp.ID, roomTurnoverRewardStatusPending)
|
||||||
|
|
||||||
|
resp, err := service.GetClaimStatus(ctx, common.AuthUser{UserID: record.OwnerUserID, SysOrigin: "LIKEI"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetClaimStatus() error = %v", err)
|
||||||
|
}
|
||||||
|
if resp.CanClaim || resp.Reason != "auto_reward_enabled" {
|
||||||
|
t.Fatalf("claim status = %+v", resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClaimRewardDispatchesGoldAndMarksRecordSuccess(t *testing.T) {
|
||||||
|
service, db := newTestService(t)
|
||||||
|
gateway := &stubRoomTurnoverRewardJavaGateway{}
|
||||||
|
service.repo.Java = gateway
|
||||||
|
ctx := context.Background()
|
||||||
|
autoRewardEnabled := false
|
||||||
|
configResp, err := service.SaveConfig(ctx, SaveRoomTurnoverRewardConfigRequest{
|
||||||
|
SysOrigin: "LIKEI",
|
||||||
|
Enabled: true,
|
||||||
|
AutoRewardEnabled: &autoRewardEnabled,
|
||||||
|
Timezone: "Asia/Riyadh",
|
||||||
|
LevelConfigs: []RoomTurnoverRewardLevelInput{
|
||||||
|
{Level: 1, TurnoverThreshold: 100000, RewardGold: 2000, Enabled: true},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SaveConfig() error = %v", err)
|
||||||
|
}
|
||||||
|
record := seedRoomTurnoverRewardRecord(t, db, configResp.ID, roomTurnoverRewardStatusPending)
|
||||||
|
|
||||||
|
resp, err := service.ClaimReward(ctx, common.AuthUser{UserID: record.OwnerUserID, SysOrigin: "LIKEI"}, RoomTurnoverRewardClaimRequest{
|
||||||
|
RecordID: flexibleInt64(record.ID),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ClaimReward() error = %v", err)
|
||||||
|
}
|
||||||
|
if !resp.Claimed || resp.Record.Status != roomTurnoverRewardStatusSuccess || resp.Record.SentAt == "" {
|
||||||
|
t.Fatalf("claim response = %+v", resp)
|
||||||
|
}
|
||||||
|
if len(gateway.changed) != 1 {
|
||||||
|
t.Fatalf("wallet change count = %d, want 1", len(gateway.changed))
|
||||||
|
}
|
||||||
|
if got := gateway.changed[0]; got.EventID != record.TrackID || got.UserID != record.OwnerUserID || got.Amount.DollarAmount != record.RewardGold {
|
||||||
|
t.Fatalf("wallet command = %+v", got)
|
||||||
|
}
|
||||||
|
if len(gateway.markedIDs) != 1 || gateway.markedIDs[0] != record.SourceID {
|
||||||
|
t.Fatalf("marked IDs = %+v", gateway.markedIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
var saved model.RoomTurnoverRewardRecord
|
||||||
|
if err := db.Where("id = ?", record.ID).First(&saved).Error; err != nil {
|
||||||
|
t.Fatalf("load saved record: %v", err)
|
||||||
|
}
|
||||||
|
if saved.Status != roomTurnoverRewardStatusSuccess || saved.SentAt == nil {
|
||||||
|
t.Fatalf("saved record = %+v", saved)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func seedRoomTurnoverRewardRecord(t *testing.T, db roomTurnoverRewardDB, configID int64, status string) model.RoomTurnoverRewardRecord {
|
||||||
|
t.Helper()
|
||||||
|
now := time.Now()
|
||||||
|
record := model.RoomTurnoverRewardRecord{
|
||||||
|
ID: now.UnixNano(),
|
||||||
|
ConfigID: configID,
|
||||||
|
SysOrigin: "LIKEI",
|
||||||
|
CycleKey: "20260511",
|
||||||
|
PeriodStartAt: now.AddDate(0, 0, -7),
|
||||||
|
PeriodEndAt: now,
|
||||||
|
RoomID: 101,
|
||||||
|
RoomAccount: "R101",
|
||||||
|
RoomName: "Owner room",
|
||||||
|
OwnerUserID: 9001,
|
||||||
|
TurnoverAmount: 120000,
|
||||||
|
Level: 1,
|
||||||
|
TurnoverThreshold: 100000,
|
||||||
|
RewardGold: 2000,
|
||||||
|
TrackID: "room-turnover:LIKEI:20260511:101",
|
||||||
|
SourceID: "source-101",
|
||||||
|
Status: status,
|
||||||
|
CreateTime: now,
|
||||||
|
UpdateTime: now,
|
||||||
|
}
|
||||||
|
if err := db.WithContext(context.Background()).Create(&record).Error; err != nil {
|
||||||
|
t.Fatalf("seed reward record: %v", err)
|
||||||
|
}
|
||||||
|
return record
|
||||||
|
}
|
||||||
@ -24,11 +24,12 @@ func (s *Service) GetConfig(ctx context.Context, sysOrigin string) (*RoomTurnove
|
|||||||
First(&configRow).Error
|
First(&configRow).Error
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return &RoomTurnoverRewardConfigResponse{
|
return &RoomTurnoverRewardConfigResponse{
|
||||||
Configured: false,
|
Configured: false,
|
||||||
SysOrigin: sysOrigin,
|
SysOrigin: sysOrigin,
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
Timezone: s.defaultTimezone(),
|
AutoRewardEnabled: true,
|
||||||
LevelConfigs: defaultLevelPayloads(),
|
Timezone: s.defaultTimezone(),
|
||||||
|
LevelConfigs: defaultLevelPayloads(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -40,13 +41,14 @@ func (s *Service) GetConfig(ctx context.Context, sysOrigin string) (*RoomTurnove
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &RoomTurnoverRewardConfigResponse{
|
return &RoomTurnoverRewardConfigResponse{
|
||||||
Configured: true,
|
Configured: true,
|
||||||
ID: configRow.ID,
|
ID: configRow.ID,
|
||||||
SysOrigin: configRow.SysOrigin,
|
SysOrigin: configRow.SysOrigin,
|
||||||
Enabled: configRow.Enabled,
|
Enabled: configRow.Enabled,
|
||||||
Timezone: configRow.Timezone,
|
AutoRewardEnabled: configRow.AutoRewardEnabled,
|
||||||
UpdateTime: formatDateTime(configRow.UpdateTime),
|
Timezone: configRow.Timezone,
|
||||||
LevelConfigs: buildLevelPayloads(levels),
|
UpdateTime: formatDateTime(configRow.UpdateTime),
|
||||||
|
LevelConfigs: buildLevelPayloads(levels),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +85,7 @@ func (s *Service) SaveConfig(ctx context.Context, req SaveRoomTurnoverRewardConf
|
|||||||
if err := s.repo.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
if err := s.repo.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
var configRow model.RoomTurnoverRewardConfig
|
var configRow model.RoomTurnoverRewardConfig
|
||||||
|
creatingConfig := false
|
||||||
if requestID > 0 {
|
if requestID > 0 {
|
||||||
err := tx.Where("id = ?", requestID).First(&configRow).Error
|
err := tx.Where("id = ?", requestID).First(&configRow).Error
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
@ -102,10 +105,12 @@ func (s *Service) SaveConfig(ctx context.Context, req SaveRoomTurnoverRewardConf
|
|||||||
return idErr
|
return idErr
|
||||||
}
|
}
|
||||||
configRow = model.RoomTurnoverRewardConfig{
|
configRow = model.RoomTurnoverRewardConfig{
|
||||||
ID: configID,
|
ID: configID,
|
||||||
SysOrigin: sysOrigin,
|
SysOrigin: sysOrigin,
|
||||||
CreateTime: now,
|
AutoRewardEnabled: true,
|
||||||
|
CreateTime: now,
|
||||||
}
|
}
|
||||||
|
creatingConfig = true
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -113,6 +118,7 @@ func (s *Service) SaveConfig(ctx context.Context, req SaveRoomTurnoverRewardConf
|
|||||||
|
|
||||||
configRow.SysOrigin = sysOrigin
|
configRow.SysOrigin = sysOrigin
|
||||||
configRow.Enabled = req.Enabled
|
configRow.Enabled = req.Enabled
|
||||||
|
configRow.AutoRewardEnabled = resolveAutoRewardEnabled(req.AutoRewardEnabled, configRow.AutoRewardEnabled, creatingConfig)
|
||||||
configRow.Timezone = timezone
|
configRow.Timezone = timezone
|
||||||
configRow.UpdateTime = now
|
configRow.UpdateTime = now
|
||||||
if configRow.CreateTime.IsZero() {
|
if configRow.CreateTime.IsZero() {
|
||||||
@ -142,6 +148,16 @@ func (s *Service) SaveConfig(ctx context.Context, req SaveRoomTurnoverRewardConf
|
|||||||
return s.GetConfig(ctx, sysOriginBySavedID(ctx, s.repo.DB, savedConfigID, sysOrigin))
|
return s.GetConfig(ctx, sysOriginBySavedID(ctx, s.repo.DB, savedConfigID, sysOrigin))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resolveAutoRewardEnabled(value *bool, current bool, creating bool) bool {
|
||||||
|
if value != nil {
|
||||||
|
return *value
|
||||||
|
}
|
||||||
|
if creating {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) normalizeLevelInputs(inputs []RoomTurnoverRewardLevelInput) ([]model.RoomTurnoverRewardLevel, error) {
|
func (s *Service) normalizeLevelInputs(inputs []RoomTurnoverRewardLevelInput) ([]model.RoomTurnoverRewardLevel, error) {
|
||||||
if len(inputs) == 0 {
|
if len(inputs) == 0 {
|
||||||
return nil, NewAppError(http.StatusBadRequest, "invalid_level_configs", "levelConfigs is required")
|
return nil, NewAppError(http.StatusBadRequest, "invalid_level_configs", "levelConfigs is required")
|
||||||
|
|||||||
@ -43,6 +43,9 @@ func TestGetConfigReturnsDefaultLevelsWhenMissing(t *testing.T) {
|
|||||||
if resp.Configured || resp.Enabled {
|
if resp.Configured || resp.Enabled {
|
||||||
t.Fatalf("GetConfig() configured/enabled = %v/%v, want false/false", resp.Configured, resp.Enabled)
|
t.Fatalf("GetConfig() configured/enabled = %v/%v, want false/false", resp.Configured, resp.Enabled)
|
||||||
}
|
}
|
||||||
|
if !resp.AutoRewardEnabled {
|
||||||
|
t.Fatalf("GetConfig() autoRewardEnabled = false, want true")
|
||||||
|
}
|
||||||
if resp.SysOrigin != "LIKEI" || resp.Timezone != "Asia/Riyadh" {
|
if resp.SysOrigin != "LIKEI" || resp.Timezone != "Asia/Riyadh" {
|
||||||
t.Fatalf("GetConfig() sys/timezone = %q/%q", resp.SysOrigin, resp.Timezone)
|
t.Fatalf("GetConfig() sys/timezone = %q/%q", resp.SysOrigin, resp.Timezone)
|
||||||
}
|
}
|
||||||
@ -103,4 +106,28 @@ func TestSaveConfigUpsertsBySysOrigin(t *testing.T) {
|
|||||||
if got := second.LevelConfigs[0]; got.TurnoverThreshold != 200000 || got.RewardGold != 5000 {
|
if got := second.LevelConfigs[0]; got.TurnoverThreshold != 200000 || got.RewardGold != 5000 {
|
||||||
t.Fatalf("upserted level = %+v", got)
|
t.Fatalf("upserted level = %+v", got)
|
||||||
}
|
}
|
||||||
|
if !second.AutoRewardEnabled {
|
||||||
|
t.Fatalf("autoRewardEnabled = false, want default true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSaveConfigCanDisableAutoReward(t *testing.T) {
|
||||||
|
service, _ := newTestService(t)
|
||||||
|
autoRewardEnabled := false
|
||||||
|
|
||||||
|
resp, err := service.SaveConfig(context.Background(), SaveRoomTurnoverRewardConfigRequest{
|
||||||
|
SysOrigin: "LIKEI",
|
||||||
|
Enabled: true,
|
||||||
|
AutoRewardEnabled: &autoRewardEnabled,
|
||||||
|
Timezone: "Asia/Riyadh",
|
||||||
|
LevelConfigs: []RoomTurnoverRewardLevelInput{
|
||||||
|
{Level: 1, TurnoverThreshold: 100000, RewardGold: 2000, Enabled: true},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SaveConfig() error = %v", err)
|
||||||
|
}
|
||||||
|
if resp.AutoRewardEnabled {
|
||||||
|
t.Fatalf("autoRewardEnabled = true, want false")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,9 @@ import (
|
|||||||
type stubRoomTurnoverRewardJavaGateway struct {
|
type stubRoomTurnoverRewardJavaGateway struct {
|
||||||
contributions []integration.RoomContributionActivityCount
|
contributions []integration.RoomContributionActivityCount
|
||||||
current integration.RoomContributionActivityCount
|
current integration.RoomContributionActivityCount
|
||||||
|
changeErr error
|
||||||
|
changed []integration.GoldReceiptCommand
|
||||||
|
markedIDs []string
|
||||||
userProfile integration.UserProfile
|
userProfile integration.UserProfile
|
||||||
userRoom integration.RoomProfile
|
userRoom integration.RoomProfile
|
||||||
profiles map[int64]integration.RoomProfile
|
profiles map[int64]integration.RoomProfile
|
||||||
@ -35,9 +38,19 @@ func (s stubRoomTurnoverRewardJavaGateway) MapRoomProfiles(_ context.Context, _
|
|||||||
return s.profiles, nil
|
return s.profiles, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *stubRoomTurnoverRewardJavaGateway) ChangeGoldBalance(_ context.Context, cmd integration.GoldReceiptCommand) error {
|
||||||
|
s.changed = append(s.changed, cmd)
|
||||||
|
return s.changeErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stubRoomTurnoverRewardJavaGateway) MarkRoomTurnoverRewardCoinsSent(_ context.Context, id string) (bool, error) {
|
||||||
|
s.markedIDs = append(s.markedIDs, id)
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestCurrentRoomRankingSortsAndMatchesHighestLevel(t *testing.T) {
|
func TestCurrentRoomRankingSortsAndMatchesHighestLevel(t *testing.T) {
|
||||||
service, _ := newTestService(t)
|
service, _ := newTestService(t)
|
||||||
service.repo.Java = stubRoomTurnoverRewardJavaGateway{
|
service.repo.Java = &stubRoomTurnoverRewardJavaGateway{
|
||||||
contributions: []integration.RoomContributionActivityCount{
|
contributions: []integration.RoomContributionActivityCount{
|
||||||
{RoomID: integration.Int64Value(101), ContributionValue: integration.AmountValue(120000)},
|
{RoomID: integration.Int64Value(101), ContributionValue: integration.AmountValue(120000)},
|
||||||
{RoomID: integration.Int64Value(102), ContributionValue: integration.AmountValue(800000)},
|
{RoomID: integration.Int64Value(102), ContributionValue: integration.AmountValue(800000)},
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
func TestGetHomeReturnsUserRoomTurnoverAndExpectedReward(t *testing.T) {
|
func TestGetHomeReturnsUserRoomTurnoverAndExpectedReward(t *testing.T) {
|
||||||
service, _ := newTestService(t)
|
service, _ := newTestService(t)
|
||||||
service.repo.Java = stubRoomTurnoverRewardJavaGateway{
|
service.repo.Java = &stubRoomTurnoverRewardJavaGateway{
|
||||||
userProfile: integration.UserProfile{
|
userProfile: integration.UserProfile{
|
||||||
ID: integration.Int64Value(9001),
|
ID: integration.Int64Value(9001),
|
||||||
Account: "123456789",
|
Account: "123456789",
|
||||||
@ -60,7 +60,7 @@ func TestGetHomeReturnsUserRoomTurnoverAndExpectedReward(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetHomeReturnsZeroRewardWhenNoRoom(t *testing.T) {
|
func TestGetHomeReturnsZeroRewardWhenNoRoom(t *testing.T) {
|
||||||
service, _ := newTestService(t)
|
service, _ := newTestService(t)
|
||||||
service.repo.Java = stubRoomTurnoverRewardJavaGateway{
|
service.repo.Java = &stubRoomTurnoverRewardJavaGateway{
|
||||||
userProfile: integration.UserProfile{
|
userProfile: integration.UserProfile{
|
||||||
ID: integration.Int64Value(9001),
|
ID: integration.Int64Value(9001),
|
||||||
UserNickname: "Owner",
|
UserNickname: "Owner",
|
||||||
@ -78,7 +78,7 @@ func TestGetHomeReturnsZeroRewardWhenNoRoom(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetHomeMatchesDefaultLevelsWhenConfigDisabled(t *testing.T) {
|
func TestGetHomeMatchesDefaultLevelsWhenConfigDisabled(t *testing.T) {
|
||||||
service, _ := newTestService(t)
|
service, _ := newTestService(t)
|
||||||
service.repo.Java = stubRoomTurnoverRewardJavaGateway{
|
service.repo.Java = &stubRoomTurnoverRewardJavaGateway{
|
||||||
userRoom: integration.RoomProfile{
|
userRoom: integration.RoomProfile{
|
||||||
ID: integration.Int64Value(101),
|
ID: integration.Int64Value(101),
|
||||||
UserID: integration.Int64Value(9001),
|
UserID: integration.Int64Value(9001),
|
||||||
|
|||||||
@ -78,6 +78,7 @@ func toRecordView(row model.RoomTurnoverRewardRecord) RoomTurnoverRewardRecordVi
|
|||||||
TurnoverThreshold: row.TurnoverThreshold,
|
TurnoverThreshold: row.TurnoverThreshold,
|
||||||
RewardGold: row.RewardGold,
|
RewardGold: row.RewardGold,
|
||||||
TrackID: row.TrackID,
|
TrackID: row.TrackID,
|
||||||
|
SourceID: row.SourceID,
|
||||||
Status: row.Status,
|
Status: row.Status,
|
||||||
RetryCount: row.RetryCount,
|
RetryCount: row.RetryCount,
|
||||||
LastError: row.LastError,
|
LastError: row.LastError,
|
||||||
|
|||||||
@ -20,6 +20,8 @@ const (
|
|||||||
roomTurnoverRewardStatusSuccess = "SUCCESS"
|
roomTurnoverRewardStatusSuccess = "SUCCESS"
|
||||||
roomTurnoverRewardStatusFailed = "FAILED"
|
roomTurnoverRewardStatusFailed = "FAILED"
|
||||||
|
|
||||||
|
roomTurnoverRewardGoldOrigin = "ROOM_CONTRIBUTION_REWARD"
|
||||||
|
|
||||||
defaultRoomTurnoverRewardTimezone = "Asia/Riyadh"
|
defaultRoomTurnoverRewardTimezone = "Asia/Riyadh"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -79,22 +81,24 @@ type RoomTurnoverRewardLevelInput struct {
|
|||||||
|
|
||||||
// RoomTurnoverRewardConfigResponse 是房间流水奖励配置读模型。
|
// RoomTurnoverRewardConfigResponse 是房间流水奖励配置读模型。
|
||||||
type RoomTurnoverRewardConfigResponse struct {
|
type RoomTurnoverRewardConfigResponse struct {
|
||||||
Configured bool `json:"configured"`
|
Configured bool `json:"configured"`
|
||||||
ID int64 `json:"id,string"`
|
ID int64 `json:"id,string"`
|
||||||
SysOrigin string `json:"sysOrigin"`
|
SysOrigin string `json:"sysOrigin"`
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Timezone string `json:"timezone"`
|
AutoRewardEnabled bool `json:"autoRewardEnabled"`
|
||||||
UpdateTime string `json:"updateTime"`
|
Timezone string `json:"timezone"`
|
||||||
LevelConfigs []RoomTurnoverRewardLevelPayload `json:"levelConfigs"`
|
UpdateTime string `json:"updateTime"`
|
||||||
|
LevelConfigs []RoomTurnoverRewardLevelPayload `json:"levelConfigs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveRoomTurnoverRewardConfigRequest 是房间流水奖励配置保存入参。
|
// SaveRoomTurnoverRewardConfigRequest 是房间流水奖励配置保存入参。
|
||||||
type SaveRoomTurnoverRewardConfigRequest struct {
|
type SaveRoomTurnoverRewardConfigRequest struct {
|
||||||
ID flexibleInt64 `json:"id"`
|
ID flexibleInt64 `json:"id"`
|
||||||
SysOrigin string `json:"sysOrigin"`
|
SysOrigin string `json:"sysOrigin"`
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Timezone string `json:"timezone"`
|
AutoRewardEnabled *bool `json:"autoRewardEnabled"`
|
||||||
LevelConfigs []RoomTurnoverRewardLevelInput `json:"levelConfigs"`
|
Timezone string `json:"timezone"`
|
||||||
|
LevelConfigs []RoomTurnoverRewardLevelInput `json:"levelConfigs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoomTurnoverRewardRecordView 是后台发奖记录列表项。
|
// RoomTurnoverRewardRecordView 是后台发奖记录列表项。
|
||||||
@ -117,6 +121,7 @@ type RoomTurnoverRewardRecordView struct {
|
|||||||
TurnoverThreshold int64 `json:"turnoverThreshold"`
|
TurnoverThreshold int64 `json:"turnoverThreshold"`
|
||||||
RewardGold int64 `json:"rewardGold"`
|
RewardGold int64 `json:"rewardGold"`
|
||||||
TrackID string `json:"trackId"`
|
TrackID string `json:"trackId"`
|
||||||
|
SourceID string `json:"sourceId"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
RetryCount int `json:"retryCount"`
|
RetryCount int `json:"retryCount"`
|
||||||
LastError string `json:"lastError"`
|
LastError string `json:"lastError"`
|
||||||
@ -195,6 +200,26 @@ type RoomTurnoverRewardHomeResponse struct {
|
|||||||
LevelConfigs []RoomTurnoverRewardLevelPayload `json:"levelConfigs"`
|
LevelConfigs []RoomTurnoverRewardLevelPayload `json:"levelConfigs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RoomTurnoverRewardClaimStatusResponse 是 App 领取按钮判断接口的读模型。
|
||||||
|
type RoomTurnoverRewardClaimStatusResponse struct {
|
||||||
|
CanClaim bool `json:"canClaim"`
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
SysOrigin string `json:"sysOrigin"`
|
||||||
|
AutoRewardEnabled bool `json:"autoRewardEnabled"`
|
||||||
|
Record *RoomTurnoverRewardRecordView `json:"record,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoomTurnoverRewardClaimRequest 是 App 手动领取奖励入参。
|
||||||
|
type RoomTurnoverRewardClaimRequest struct {
|
||||||
|
RecordID flexibleInt64 `json:"recordId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoomTurnoverRewardClaimResponse 是 App 手动领取奖励返回。
|
||||||
|
type RoomTurnoverRewardClaimResponse struct {
|
||||||
|
Claimed bool `json:"claimed"`
|
||||||
|
Record RoomTurnoverRewardRecordView `json:"record"`
|
||||||
|
}
|
||||||
|
|
||||||
type roomTurnoverRewardDB interface {
|
type roomTurnoverRewardDB interface {
|
||||||
WithContext(ctx context.Context) *gorm.DB
|
WithContext(ctx context.Context) *gorm.DB
|
||||||
}
|
}
|
||||||
@ -205,6 +230,8 @@ type roomTurnoverRewardJavaGateway interface {
|
|||||||
GetCurrentWeekRoomContribution(ctx context.Context, roomID int64) (integration.RoomContributionActivityCount, error)
|
GetCurrentWeekRoomContribution(ctx context.Context, roomID int64) (integration.RoomContributionActivityCount, error)
|
||||||
ListCurrentWeekRoomContribution(ctx context.Context, limit int) ([]integration.RoomContributionActivityCount, error)
|
ListCurrentWeekRoomContribution(ctx context.Context, limit int) ([]integration.RoomContributionActivityCount, error)
|
||||||
MapRoomProfiles(ctx context.Context, roomIDs []int64) (map[int64]integration.RoomProfile, error)
|
MapRoomProfiles(ctx context.Context, roomIDs []int64) (map[int64]integration.RoomProfile, error)
|
||||||
|
ChangeGoldBalance(ctx context.Context, cmd integration.GoldReceiptCommand) error
|
||||||
|
MarkRoomTurnoverRewardCoinsSent(ctx context.Context, id string) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type roomTurnoverRewardPorts struct {
|
type roomTurnoverRewardPorts struct {
|
||||||
|
|||||||
31
migrations/044_room_turnover_reward_manual_claim.sql
Normal file
31
migrations/044_room_turnover_reward_manual_claim.sql
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
SET @current_schema := DATABASE();
|
||||||
|
|
||||||
|
SET @add_room_turnover_reward_auto_sql := IF(
|
||||||
|
NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = @current_schema
|
||||||
|
AND table_name = 'room_turnover_reward_config'
|
||||||
|
AND column_name = 'auto_reward_enabled'
|
||||||
|
),
|
||||||
|
'ALTER TABLE `room_turnover_reward_config` ADD COLUMN `auto_reward_enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT ''是否由 cron 自动发放奖励'' AFTER `enabled`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE add_room_turnover_reward_auto_stmt FROM @add_room_turnover_reward_auto_sql;
|
||||||
|
EXECUTE add_room_turnover_reward_auto_stmt;
|
||||||
|
DEALLOCATE PREPARE add_room_turnover_reward_auto_stmt;
|
||||||
|
|
||||||
|
SET @add_room_turnover_reward_source_sql := IF(
|
||||||
|
NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = @current_schema
|
||||||
|
AND table_name = 'room_turnover_reward_record'
|
||||||
|
AND column_name = 'source_id'
|
||||||
|
),
|
||||||
|
'ALTER TABLE `room_turnover_reward_record` ADD COLUMN `source_id` varchar(128) DEFAULT NULL COMMENT ''Java 房间流水统计记录ID'' AFTER `track_id`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE add_room_turnover_reward_source_stmt FROM @add_room_turnover_reward_source_sql;
|
||||||
|
EXECUTE add_room_turnover_reward_source_stmt;
|
||||||
|
DEALLOCATE PREPARE add_room_turnover_reward_source_stmt;
|
||||||
Loading…
x
Reference in New Issue
Block a user