171 lines
5.8 KiB
Go
171 lines
5.8 KiB
Go
package registerreward
|
|
|
|
import (
|
|
"chatapp3-golang/internal/integration"
|
|
"chatapp3-golang/internal/model"
|
|
"chatapp3-golang/internal/utils"
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// resolveRewardConfig 决定本次事件应该发什么奖励,并把解析结果回写日志。
|
|
func (s *RegisterRewardService) resolveRewardConfig(ctx context.Context, logRecord *model.ResidentRegisterRewardLog, event registerRewardEvent) (registerRewardResolvedConfig, bool, error) {
|
|
// 失败重试时优先沿用上一次已经落库的奖励配置,避免配置变更影响补发。
|
|
if logRecord.Status == registerRewardStatusFailed && (logRecord.GoldAmount > 0 || logRecord.RewardGroupID != nil) {
|
|
return registerRewardResolvedConfig{
|
|
GoldAmount: logRecord.GoldAmount,
|
|
RewardGroupID: logRecord.RewardGroupID,
|
|
}, false, nil
|
|
}
|
|
|
|
cfg, err := s.loadRegisterRewardConfig(ctx, event.SysOrigin)
|
|
if err != nil {
|
|
return registerRewardResolvedConfig{}, false, err
|
|
}
|
|
if cfg == nil || !cfg.Enabled {
|
|
err = s.updateLogStatus(
|
|
ctx,
|
|
logRecord.ID,
|
|
registerRewardStatusSkipped,
|
|
"register reward config missing or disabled",
|
|
registerRewardResolvedConfig{},
|
|
)
|
|
return registerRewardResolvedConfig{}, err == nil, err
|
|
}
|
|
|
|
resolved := registerRewardResolvedConfig{
|
|
GoldAmount: cfg.GoldAmount,
|
|
RewardGroupID: cfg.RewardGroupID,
|
|
DailyLimit: cfg.DailyLimit,
|
|
}
|
|
// 配置存在但没有任何奖励内容时,直接标记跳过。
|
|
if resolved.GoldAmount <= 0 && resolved.RewardGroupID == nil {
|
|
err = s.updateLogStatus(
|
|
ctx,
|
|
logRecord.ID,
|
|
registerRewardStatusSkipped,
|
|
"register reward config has no reward payload",
|
|
resolved,
|
|
)
|
|
return registerRewardResolvedConfig{}, err == nil, err
|
|
}
|
|
if err := s.updateLogStatus(ctx, logRecord.ID, registerRewardStatusPending, "", resolved); err != nil {
|
|
return registerRewardResolvedConfig{}, false, err
|
|
}
|
|
return resolved, false, nil
|
|
}
|
|
|
|
// loadRegisterRewardConfig 按系统读取注册奖励配置。
|
|
func (s *RegisterRewardService) loadRegisterRewardConfig(ctx context.Context, sysOrigin string) (*model.ResidentRegisterRewardConfig, error) {
|
|
var cfg model.ResidentRegisterRewardConfig
|
|
err := s.repo.DB.WithContext(ctx).
|
|
Where("sys_origin = ?", strings.ToUpper(strings.TrimSpace(sysOrigin))).
|
|
First(&cfg).Error
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &cfg, nil
|
|
}
|
|
|
|
// dispatchGold 调用钱包接口发放金币奖励。
|
|
func (s *RegisterRewardService) dispatchGold(ctx context.Context, event registerRewardEvent, resolved registerRewardResolvedConfig) error {
|
|
if resolved.GoldAmount <= 0 {
|
|
return nil
|
|
}
|
|
return s.java.ChangeGoldBalance(ctx, integration.GoldReceiptCommand{
|
|
ReceiptType: "INCOME",
|
|
UserID: event.UserID,
|
|
SysOrigin: event.SysOrigin,
|
|
EventID: event.EventID + ":gold",
|
|
Remark: registerRewardGoldDesc,
|
|
Amount: integration.NewPennyAmountPayloadFromDollar(resolved.GoldAmount),
|
|
CloseDelayAsset: false,
|
|
OpUserType: "APP",
|
|
CustomizeOrigin: registerRewardGoldOrigin,
|
|
CustomizeOriginDesc: registerRewardGoldDesc,
|
|
})
|
|
}
|
|
|
|
// dispatchProps 调用 Java 奖励接口发放道具奖励。
|
|
func (s *RegisterRewardService) dispatchProps(ctx context.Context, logID int64, event registerRewardEvent, resolved registerRewardResolvedConfig) error {
|
|
if resolved.RewardGroupID == nil {
|
|
return nil
|
|
}
|
|
return s.java.GrantProps(ctx, integration.GrantPropsRequest{
|
|
TrackID: logID,
|
|
AcceptUserID: event.UserID,
|
|
SysOrigin: event.SysOrigin,
|
|
Origin: registerRewardPropsOrigin,
|
|
SourceGroupID: *resolved.RewardGroupID,
|
|
})
|
|
}
|
|
|
|
// getOrCreateLog 基于事件 ID 做幂等,返回现有日志或新建日志。
|
|
func (s *RegisterRewardService) getOrCreateLog(ctx context.Context, event registerRewardEvent, streamMessageID string) (*model.ResidentRegisterRewardLog, bool, error) {
|
|
var record model.ResidentRegisterRewardLog
|
|
err := s.repo.DB.WithContext(ctx).
|
|
Where("event_id = ?", event.EventID).
|
|
First(&record).Error
|
|
if err == nil {
|
|
if record.StreamMessageID != streamMessageID {
|
|
if updateErr := s.repo.DB.WithContext(ctx).
|
|
Model(&model.ResidentRegisterRewardLog{}).
|
|
Where("id = ?", record.ID).
|
|
Updates(map[string]any{
|
|
"stream_message_id": streamMessageID,
|
|
"update_time": time.Now(),
|
|
}).Error; updateErr == nil {
|
|
record.StreamMessageID = streamMessageID
|
|
}
|
|
}
|
|
return &record, isRegisterRewardTerminalStatus(record.Status), nil
|
|
}
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, false, err
|
|
}
|
|
|
|
id, idErr := utils.NextID()
|
|
if idErr != nil {
|
|
return nil, false, idErr
|
|
}
|
|
now := time.Now()
|
|
record = model.ResidentRegisterRewardLog{
|
|
ID: id,
|
|
EventID: event.EventID,
|
|
StreamMessageID: streamMessageID,
|
|
SysOrigin: event.SysOrigin,
|
|
UserID: event.UserID,
|
|
Status: registerRewardStatusPending,
|
|
CreateTime: now,
|
|
UpdateTime: now,
|
|
}
|
|
if err := s.repo.DB.WithContext(ctx).Create(&record).Error; err != nil {
|
|
if strings.Contains(strings.ToLower(err.Error()), "duplicate") {
|
|
return s.getOrCreateLog(ctx, event, streamMessageID)
|
|
}
|
|
return nil, false, err
|
|
}
|
|
return &record, false, nil
|
|
}
|
|
|
|
// updateLogStatus 回写处理状态、错误信息以及最终奖励内容。
|
|
func (s *RegisterRewardService) updateLogStatus(ctx context.Context, logID int64, status, errorMessage string, resolved registerRewardResolvedConfig) error {
|
|
return s.repo.DB.WithContext(ctx).
|
|
Model(&model.ResidentRegisterRewardLog{}).
|
|
Where("id = ?", logID).
|
|
Updates(map[string]any{
|
|
"status": status,
|
|
"error_message": truncateRegisterRewardMessage(errorMessage),
|
|
"gold_amount": resolved.GoldAmount,
|
|
"reward_group_id": resolved.RewardGroupID,
|
|
"update_time": time.Now(),
|
|
}).Error
|
|
}
|