fix campaign rules
This commit is contained in:
@@ -18,15 +18,24 @@ type CampaignService interface {
|
||||
DeleteCampaign(ctx context.Context, id string) error
|
||||
GetActiveCampaigns(ctx context.Context) ([]models.CampaignResponse, error)
|
||||
GetCampaignsForApp(ctx context.Context) ([]models.CampaignResponse, error)
|
||||
// Campaign Rules methods
|
||||
CreateCampaignRule(ctx context.Context, req *contract.CreateCampaignRuleRequest) (*models.CampaignRuleResponse, error)
|
||||
GetCampaignRule(ctx context.Context, id string) (*models.CampaignRuleResponse, error)
|
||||
ListCampaignRules(ctx context.Context, req *contract.ListCampaignRulesRequest) (*models.ListCampaignRulesResponse, error)
|
||||
UpdateCampaignRule(ctx context.Context, req *contract.UpdateCampaignRuleRequest) (*models.CampaignRuleResponse, error)
|
||||
DeleteCampaignRule(ctx context.Context, id string) error
|
||||
GetCampaignRulesByCampaignID(ctx context.Context, campaignID string) ([]models.CampaignRuleResponse, error)
|
||||
}
|
||||
|
||||
type campaignService struct {
|
||||
campaignProcessor processor.CampaignProcessor
|
||||
campaignProcessor processor.CampaignProcessor
|
||||
campaignRuleProcessor processor.CampaignRuleProcessor
|
||||
}
|
||||
|
||||
func NewCampaignService(campaignProcessor processor.CampaignProcessor) CampaignService {
|
||||
func NewCampaignService(campaignProcessor processor.CampaignProcessor, campaignRuleProcessor processor.CampaignRuleProcessor) CampaignService {
|
||||
return &campaignService{
|
||||
campaignProcessor: campaignProcessor,
|
||||
campaignProcessor: campaignProcessor,
|
||||
campaignRuleProcessor: campaignRuleProcessor,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,11 +50,6 @@ func (s *campaignService) CreateCampaign(ctx context.Context, req *contract.Crea
|
||||
return nil, fmt.Errorf("validation failed: %w", err)
|
||||
}
|
||||
|
||||
// Validate rules
|
||||
if err := s.validateCampaignRules(req.Rules); err != nil {
|
||||
return nil, fmt.Errorf("validation failed: %w", err)
|
||||
}
|
||||
|
||||
// Validate position
|
||||
if req.Position < 0 {
|
||||
return nil, fmt.Errorf("position cannot be negative")
|
||||
@@ -115,11 +119,6 @@ func (s *campaignService) UpdateCampaign(ctx context.Context, req *contract.Upda
|
||||
return nil, fmt.Errorf("validation failed: %w", err)
|
||||
}
|
||||
|
||||
// Validate rules
|
||||
if err := s.validateCampaignRules(req.Rules); err != nil {
|
||||
return nil, fmt.Errorf("validation failed: %w", err)
|
||||
}
|
||||
|
||||
// Validate position
|
||||
if req.Position < 0 {
|
||||
return nil, fmt.Errorf("position cannot be negative")
|
||||
@@ -164,6 +163,137 @@ func (s *campaignService) GetCampaignsForApp(ctx context.Context) ([]models.Camp
|
||||
return campaigns, nil
|
||||
}
|
||||
|
||||
// Campaign Rules methods
|
||||
|
||||
func (s *campaignService) CreateCampaignRule(ctx context.Context, req *contract.CreateCampaignRuleRequest) (*models.CampaignRuleResponse, error) {
|
||||
// Validate rule type
|
||||
if err := s.validateRuleType(req.RuleType); err != nil {
|
||||
return nil, fmt.Errorf("validation failed: %w", err)
|
||||
}
|
||||
|
||||
// Validate reward type
|
||||
if err := s.validateRewardType(req.RewardType); err != nil {
|
||||
return nil, fmt.Errorf("validation failed: %w", err)
|
||||
}
|
||||
|
||||
// Validate reward value based on reward type
|
||||
if req.RewardType == "POINTS" || req.RewardType == "TOKENS" {
|
||||
if req.RewardValue == nil || *req.RewardValue <= 0 {
|
||||
return nil, fmt.Errorf("reward value must be positive for %s type", req.RewardType)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate reward reference ID for REWARD type
|
||||
if req.RewardType == "REWARD" {
|
||||
if req.RewardRefID == nil {
|
||||
return nil, fmt.Errorf("reward reference ID is required for REWARD type")
|
||||
}
|
||||
}
|
||||
|
||||
response, err := s.campaignRuleProcessor.CreateCampaignRule(ctx, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create campaign rule: %w", err)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *campaignService) GetCampaignRule(ctx context.Context, id string) (*models.CampaignRuleResponse, error) {
|
||||
if id == "" {
|
||||
return nil, fmt.Errorf("campaign rule ID is required")
|
||||
}
|
||||
|
||||
response, err := s.campaignRuleProcessor.GetCampaignRule(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get campaign rule: %w", err)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *campaignService) ListCampaignRules(ctx context.Context, req *contract.ListCampaignRulesRequest) (*models.ListCampaignRulesResponse, error) {
|
||||
// Set default pagination
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Limit <= 0 {
|
||||
req.Limit = 10
|
||||
}
|
||||
if req.Limit > 100 {
|
||||
req.Limit = 100
|
||||
}
|
||||
|
||||
response, err := s.campaignRuleProcessor.ListCampaignRules(ctx, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list campaign rules: %w", err)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *campaignService) UpdateCampaignRule(ctx context.Context, req *contract.UpdateCampaignRuleRequest) (*models.CampaignRuleResponse, error) {
|
||||
if req.ID.String() == "" {
|
||||
return nil, fmt.Errorf("campaign rule ID is required")
|
||||
}
|
||||
|
||||
// Validate rule type
|
||||
if err := s.validateRuleType(req.RuleType); err != nil {
|
||||
return nil, fmt.Errorf("validation failed: %w", err)
|
||||
}
|
||||
|
||||
// Validate reward type
|
||||
if err := s.validateRewardType(req.RewardType); err != nil {
|
||||
return nil, fmt.Errorf("validation failed: %w", err)
|
||||
}
|
||||
|
||||
// Validate reward value based on reward type
|
||||
if req.RewardType == "POINTS" || req.RewardType == "TOKENS" {
|
||||
if req.RewardValue == nil || *req.RewardValue <= 0 {
|
||||
return nil, fmt.Errorf("reward value must be positive for %s type", req.RewardType)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate reward reference ID for REWARD type
|
||||
if req.RewardType == "REWARD" {
|
||||
if req.RewardRefID == nil {
|
||||
return nil, fmt.Errorf("reward reference ID is required for REWARD type")
|
||||
}
|
||||
}
|
||||
|
||||
response, err := s.campaignRuleProcessor.UpdateCampaignRule(ctx, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update campaign rule: %w", err)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *campaignService) DeleteCampaignRule(ctx context.Context, id string) error {
|
||||
if id == "" {
|
||||
return fmt.Errorf("campaign rule ID is required")
|
||||
}
|
||||
|
||||
err := s.campaignRuleProcessor.DeleteCampaignRule(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete campaign rule: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *campaignService) GetCampaignRulesByCampaignID(ctx context.Context, campaignID string) ([]models.CampaignRuleResponse, error) {
|
||||
if campaignID == "" {
|
||||
return nil, fmt.Errorf("campaign ID is required")
|
||||
}
|
||||
|
||||
rules, err := s.campaignRuleProcessor.GetCampaignRulesByCampaignID(ctx, campaignID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get campaign rules by campaign ID: %w", err)
|
||||
}
|
||||
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func (s *campaignService) validateCampaignType(campaignType string) error {
|
||||
validTypes := []string{"REWARD", "POINTS", "TOKENS", "MIXED"}
|
||||
for _, validType := range validTypes {
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"apskel-pos-be/internal/models"
|
||||
"apskel-pos-be/internal/processor"
|
||||
"apskel-pos-be/internal/repository"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type SpinGameService interface {
|
||||
PlaySpinGame(ctx context.Context, customerID string, req *models.SpinGameRequest) (*models.SpinGameResponse, error)
|
||||
}
|
||||
|
||||
type spinGameService struct {
|
||||
gamePlayProcessor *processor.GamePlayProcessor
|
||||
txManager *repository.TxManager
|
||||
}
|
||||
|
||||
func NewSpinGameService(gamePlayProcessor *processor.GamePlayProcessor, txManager *repository.TxManager) SpinGameService {
|
||||
return &spinGameService{
|
||||
gamePlayProcessor: gamePlayProcessor,
|
||||
txManager: txManager,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *spinGameService) PlaySpinGame(ctx context.Context, customerID string, req *models.SpinGameRequest) (*models.SpinGameResponse, error) {
|
||||
// Validate customer ID
|
||||
if customerID == "" {
|
||||
return nil, fmt.Errorf("customer ID is required")
|
||||
}
|
||||
|
||||
// Parse spin ID to UUID
|
||||
spinID, err := uuid.Parse(req.SpinID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid spin ID format: %w", err)
|
||||
}
|
||||
|
||||
// Parse customer ID to UUID
|
||||
customerUUID, err := uuid.Parse(customerID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid customer ID format: %w", err)
|
||||
}
|
||||
|
||||
// Use transaction to ensure consistency
|
||||
var playResponse *models.PlayGameResponse
|
||||
err = s.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
|
||||
// Create play game request
|
||||
playGameReq := &models.PlayGameRequest{
|
||||
GameID: spinID,
|
||||
CustomerID: customerUUID,
|
||||
TokenUsed: 1, // Default to 1 token per spin
|
||||
}
|
||||
|
||||
// Play the game within transaction
|
||||
var playErr error
|
||||
playResponse, playErr = s.gamePlayProcessor.PlayGame(txCtx, playGameReq)
|
||||
if playErr != nil {
|
||||
return fmt.Errorf("failed to play spin game: %w", playErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Convert prize to customer-facing format
|
||||
var customerPrize *models.CustomerGamePrizeResponse
|
||||
if playResponse.PrizeWon != nil {
|
||||
customerPrize = &models.CustomerGamePrizeResponse{
|
||||
ID: playResponse.PrizeWon.ID,
|
||||
GameID: playResponse.PrizeWon.GameID,
|
||||
Name: playResponse.PrizeWon.Name,
|
||||
Image: playResponse.PrizeWon.Image,
|
||||
Metadata: &playResponse.PrizeWon.Metadata,
|
||||
CreatedAt: playResponse.PrizeWon.CreatedAt,
|
||||
UpdatedAt: playResponse.PrizeWon.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to spin game response
|
||||
response := &models.SpinGameResponse{
|
||||
Status: "SUCCESS",
|
||||
Message: "Spin game completed successfully.",
|
||||
Data: &models.SpinGameResponseData{
|
||||
GamePlay: playResponse.GamePlay,
|
||||
PrizeWon: customerPrize,
|
||||
TokensRemaining: playResponse.TokensRemaining,
|
||||
},
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
Reference in New Issue
Block a user