Add Tiers and Game Prize
This commit is contained in:
parent
12ee54390f
commit
201e24041b
@ -94,6 +94,8 @@ func (a *App) Initialize(cfg *config.Config) error {
|
||||
validators.accountValidator,
|
||||
*services.orderIngredientTransactionService,
|
||||
validators.orderIngredientTransactionValidator,
|
||||
services.gamificationService,
|
||||
validators.gamificationValidator,
|
||||
)
|
||||
|
||||
return nil
|
||||
@ -167,6 +169,13 @@ type repositories struct {
|
||||
chartOfAccountRepo *repository.ChartOfAccountRepositoryImpl
|
||||
accountRepo *repository.AccountRepositoryImpl
|
||||
orderIngredientTransactionRepo *repository.OrderIngredientTransactionRepositoryImpl
|
||||
customerPointsRepo *repository.CustomerPointsRepository
|
||||
customerTokensRepo *repository.CustomerTokensRepository
|
||||
tierRepo *repository.TierRepository
|
||||
gameRepo *repository.GameRepository
|
||||
gamePrizeRepo *repository.GamePrizeRepository
|
||||
gamePlayRepo *repository.GamePlayRepository
|
||||
omsetTrackerRepo *repository.OmsetTrackerRepository
|
||||
txManager *repository.TxManager
|
||||
}
|
||||
|
||||
@ -200,7 +209,14 @@ func (a *App) initRepositories() *repositories {
|
||||
chartOfAccountRepo: repository.NewChartOfAccountRepositoryImpl(a.db),
|
||||
accountRepo: repository.NewAccountRepositoryImpl(a.db),
|
||||
orderIngredientTransactionRepo: repository.NewOrderIngredientTransactionRepositoryImpl(a.db).(*repository.OrderIngredientTransactionRepositoryImpl),
|
||||
txManager: repository.NewTxManager(a.db),
|
||||
customerPointsRepo: repository.NewCustomerPointsRepository(a.db),
|
||||
customerTokensRepo: repository.NewCustomerTokensRepository(a.db),
|
||||
tierRepo: repository.NewTierRepository(a.db),
|
||||
gameRepo: repository.NewGameRepository(a.db),
|
||||
gamePrizeRepo: repository.NewGamePrizeRepository(a.db),
|
||||
gamePlayRepo: repository.NewGamePlayRepository(a.db),
|
||||
omsetTrackerRepo: repository.NewOmsetTrackerRepository(a.db),
|
||||
txManager: repository.NewTxManager(a.db),
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,6 +245,13 @@ type processors struct {
|
||||
chartOfAccountProcessor *processor.ChartOfAccountProcessorImpl
|
||||
accountProcessor *processor.AccountProcessorImpl
|
||||
orderIngredientTransactionProcessor *processor.OrderIngredientTransactionProcessorImpl
|
||||
customerPointsProcessor *processor.CustomerPointsProcessor
|
||||
customerTokensProcessor *processor.CustomerTokensProcessor
|
||||
tierProcessor *processor.TierProcessor
|
||||
gameProcessor *processor.GameProcessor
|
||||
gamePrizeProcessor *processor.GamePrizeProcessor
|
||||
gamePlayProcessor *processor.GamePlayProcessor
|
||||
omsetTrackerProcessor *processor.OmsetTrackerProcessor
|
||||
fileClient processor.FileClient
|
||||
inventoryMovementService service.InventoryMovementService
|
||||
}
|
||||
@ -262,6 +285,13 @@ func (a *App) initProcessors(cfg *config.Config, repos *repositories) *processor
|
||||
chartOfAccountProcessor: processor.NewChartOfAccountProcessorImpl(repos.chartOfAccountRepo, repos.chartOfAccountTypeRepo),
|
||||
accountProcessor: processor.NewAccountProcessorImpl(repos.accountRepo, repos.chartOfAccountRepo),
|
||||
orderIngredientTransactionProcessor: processor.NewOrderIngredientTransactionProcessorImpl(repos.orderIngredientTransactionRepo, repos.productRecipeRepo, repos.ingredientRepo, repos.unitRepo).(*processor.OrderIngredientTransactionProcessorImpl),
|
||||
customerPointsProcessor: processor.NewCustomerPointsProcessor(repos.customerPointsRepo),
|
||||
customerTokensProcessor: processor.NewCustomerTokensProcessor(repos.customerTokensRepo),
|
||||
tierProcessor: processor.NewTierProcessor(repos.tierRepo),
|
||||
gameProcessor: processor.NewGameProcessor(repos.gameRepo),
|
||||
gamePrizeProcessor: processor.NewGamePrizeProcessor(repos.gamePrizeRepo),
|
||||
gamePlayProcessor: processor.NewGamePlayProcessor(repos.gamePlayRepo, repos.gameRepo, repos.gamePrizeRepo, repos.customerTokensRepo, repos.customerPointsRepo),
|
||||
omsetTrackerProcessor: processor.NewOmsetTrackerProcessor(repos.omsetTrackerRepo),
|
||||
fileClient: fileClient,
|
||||
inventoryMovementService: inventoryMovementService,
|
||||
}
|
||||
@ -294,6 +324,7 @@ type services struct {
|
||||
chartOfAccountService service.ChartOfAccountService
|
||||
accountService service.AccountService
|
||||
orderIngredientTransactionService *service.OrderIngredientTransactionService
|
||||
gamificationService service.GamificationService
|
||||
}
|
||||
|
||||
func (a *App) initServices(processors *processors, repos *repositories, cfg *config.Config) *services {
|
||||
@ -324,6 +355,7 @@ func (a *App) initServices(processors *processors, repos *repositories, cfg *con
|
||||
chartOfAccountService := service.NewChartOfAccountService(processors.chartOfAccountProcessor)
|
||||
accountService := service.NewAccountService(processors.accountProcessor)
|
||||
orderIngredientTransactionService := service.NewOrderIngredientTransactionService(processors.orderIngredientTransactionProcessor, repos.txManager)
|
||||
gamificationService := service.NewGamificationService(processors.customerPointsProcessor, processors.customerTokensProcessor, processors.tierProcessor, processors.gameProcessor, processors.gamePrizeProcessor, processors.gamePlayProcessor, processors.omsetTrackerProcessor)
|
||||
|
||||
// Update order service with order ingredient transaction service
|
||||
orderService = service.NewOrderServiceImpl(processors.orderProcessor, repos.tableRepo, orderIngredientTransactionService, processors.orderIngredientTransactionProcessor, *repos.productRecipeRepo, repos.txManager)
|
||||
@ -355,6 +387,7 @@ func (a *App) initServices(processors *processors, repos *repositories, cfg *con
|
||||
chartOfAccountService: chartOfAccountService,
|
||||
accountService: accountService,
|
||||
orderIngredientTransactionService: orderIngredientTransactionService,
|
||||
gamificationService: gamificationService,
|
||||
}
|
||||
}
|
||||
|
||||
@ -388,6 +421,7 @@ type validators struct {
|
||||
chartOfAccountValidator *validator.ChartOfAccountValidatorImpl
|
||||
accountValidator *validator.AccountValidatorImpl
|
||||
orderIngredientTransactionValidator *validator.OrderIngredientTransactionValidatorImpl
|
||||
gamificationValidator *validator.GamificationValidatorImpl
|
||||
}
|
||||
|
||||
func (a *App) initValidators() *validators {
|
||||
@ -411,5 +445,6 @@ func (a *App) initValidators() *validators {
|
||||
chartOfAccountValidator: validator.NewChartOfAccountValidator().(*validator.ChartOfAccountValidatorImpl),
|
||||
accountValidator: validator.NewAccountValidator().(*validator.AccountValidatorImpl),
|
||||
orderIngredientTransactionValidator: validator.NewOrderIngredientTransactionValidator().(*validator.OrderIngredientTransactionValidatorImpl),
|
||||
gamificationValidator: validator.NewGamificationValidator(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,6 +42,14 @@ const (
|
||||
PurchaseOrderServiceEntity = "purchase_order_service"
|
||||
IngredientUnitConverterServiceEntity = "ingredient_unit_converter_service"
|
||||
TableEntity = "table"
|
||||
// Gamification entities
|
||||
CustomerPointsEntity = "customer_points"
|
||||
CustomerTokensEntity = "customer_tokens"
|
||||
TierEntity = "tier"
|
||||
GameEntity = "game"
|
||||
GamePrizeEntity = "game_prize"
|
||||
GamePlayEntity = "game_play"
|
||||
OmsetTrackerEntity = "omset_tracker"
|
||||
)
|
||||
|
||||
var HttpErrorMap = map[string]int{
|
||||
|
||||
49
internal/contract/customer_points_contract.go
Normal file
49
internal/contract/customer_points_contract.go
Normal file
@ -0,0 +1,49 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateCustomerPointsRequest struct {
|
||||
CustomerID uuid.UUID `json:"customer_id" validate:"required"`
|
||||
Balance int64 `json:"balance" validate:"min=0"`
|
||||
}
|
||||
|
||||
type UpdateCustomerPointsRequest struct {
|
||||
Balance int64 `json:"balance" validate:"min=0"`
|
||||
}
|
||||
|
||||
type AddCustomerPointsRequest struct {
|
||||
Points int64 `json:"points" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type DeductCustomerPointsRequest struct {
|
||||
Points int64 `json:"points" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type CustomerPointsResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
CustomerID uuid.UUID `json:"customer_id"`
|
||||
Balance int64 `json:"balance"`
|
||||
Customer *CustomerResponse `json:"customer,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListCustomerPointsRequest struct {
|
||||
Page int `json:"page" validate:"min=1"`
|
||||
Limit int `json:"limit" validate:"min=1,max=100"`
|
||||
Search string `json:"search"`
|
||||
SortBy string `json:"sort_by" validate:"omitempty,oneof=balance created_at updated_at"`
|
||||
SortOrder string `json:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
|
||||
type PaginatedCustomerPointsResponse struct {
|
||||
Data []CustomerPointsResponse `json:"data"`
|
||||
TotalCount int `json:"total_count"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
}
|
||||
52
internal/contract/customer_tokens_contract.go
Normal file
52
internal/contract/customer_tokens_contract.go
Normal file
@ -0,0 +1,52 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateCustomerTokensRequest struct {
|
||||
CustomerID uuid.UUID `json:"customer_id" validate:"required"`
|
||||
TokenType string `json:"token_type" validate:"required,oneof=SPIN RAFFLE MINIGAME"`
|
||||
Balance int64 `json:"balance" validate:"min=0"`
|
||||
}
|
||||
|
||||
type UpdateCustomerTokensRequest struct {
|
||||
Balance int64 `json:"balance" validate:"min=0"`
|
||||
}
|
||||
|
||||
type AddCustomerTokensRequest struct {
|
||||
Tokens int64 `json:"tokens" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type DeductCustomerTokensRequest struct {
|
||||
Tokens int64 `json:"tokens" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type CustomerTokensResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
CustomerID uuid.UUID `json:"customer_id"`
|
||||
TokenType string `json:"token_type"`
|
||||
Balance int64 `json:"balance"`
|
||||
Customer *CustomerResponse `json:"customer,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListCustomerTokensRequest struct {
|
||||
Page int `json:"page" validate:"min=1"`
|
||||
Limit int `json:"limit" validate:"min=1,max=100"`
|
||||
Search string `json:"search"`
|
||||
TokenType string `json:"token_type" validate:"omitempty,oneof=SPIN RAFFLE MINIGAME"`
|
||||
SortBy string `json:"sort_by" validate:"omitempty,oneof=balance token_type created_at updated_at"`
|
||||
SortOrder string `json:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
|
||||
type PaginatedCustomerTokensResponse struct {
|
||||
Data []CustomerTokensResponse `json:"data"`
|
||||
TotalCount int `json:"total_count"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
}
|
||||
49
internal/contract/game_contract.go
Normal file
49
internal/contract/game_contract.go
Normal file
@ -0,0 +1,49 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateGameRequest struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=SPIN RAFFLE MINIGAME"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
}
|
||||
|
||||
type UpdateGameRequest struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,required"`
|
||||
Type *string `json:"type,omitempty" validate:"omitempty,oneof=SPIN RAFFLE MINIGAME"`
|
||||
IsActive *bool `json:"is_active,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type GameResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListGamesRequest struct {
|
||||
Page int `json:"page" form:"page" validate:"min=1"`
|
||||
Limit int `json:"limit" form:"limit" validate:"min=1,max=100"`
|
||||
Search string `json:"search" form:"search"`
|
||||
Type string `json:"type" form:"type" validate:"omitempty,oneof=SPIN RAFFLE MINIGAME"`
|
||||
IsActive *bool `json:"is_active" form:"is_active"`
|
||||
SortBy string `json:"sort_by" form:"sort_by" validate:"omitempty,oneof=name type created_at updated_at"`
|
||||
SortOrder string `json:"sort_order" form:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
|
||||
type PaginatedGamesResponse struct {
|
||||
Data []GameResponse `json:"data"`
|
||||
TotalCount int `json:"total_count"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
}
|
||||
58
internal/contract/game_play_contract.go
Normal file
58
internal/contract/game_play_contract.go
Normal file
@ -0,0 +1,58 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateGamePlayRequest struct {
|
||||
GameID uuid.UUID `json:"game_id" validate:"required"`
|
||||
CustomerID uuid.UUID `json:"customer_id" validate:"required"`
|
||||
TokenUsed int `json:"token_used" validate:"min=0"`
|
||||
RandomSeed *string `json:"random_seed,omitempty"`
|
||||
}
|
||||
|
||||
type GamePlayResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
GameID uuid.UUID `json:"game_id"`
|
||||
CustomerID uuid.UUID `json:"customer_id"`
|
||||
PrizeID *uuid.UUID `json:"prize_id,omitempty"`
|
||||
TokenUsed int `json:"token_used"`
|
||||
RandomSeed *string `json:"random_seed,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Game *GameResponse `json:"game,omitempty"`
|
||||
Customer *CustomerResponse `json:"customer,omitempty"`
|
||||
Prize *GamePrizeResponse `json:"prize,omitempty"`
|
||||
}
|
||||
|
||||
type ListGamePlaysRequest struct {
|
||||
Page int `json:"page" validate:"min=1"`
|
||||
Limit int `json:"limit" validate:"min=1,max=100"`
|
||||
Search string `json:"search"`
|
||||
GameID *uuid.UUID `json:"game_id"`
|
||||
CustomerID *uuid.UUID `json:"customer_id"`
|
||||
PrizeID *uuid.UUID `json:"prize_id"`
|
||||
SortBy string `json:"sort_by" validate:"omitempty,oneof=created_at token_used"`
|
||||
SortOrder string `json:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
|
||||
type PaginatedGamePlaysResponse struct {
|
||||
Data []GamePlayResponse `json:"data"`
|
||||
TotalCount int `json:"total_count"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
}
|
||||
|
||||
type PlayGameRequest struct {
|
||||
GameID uuid.UUID `json:"game_id" validate:"required"`
|
||||
CustomerID uuid.UUID `json:"customer_id" validate:"required"`
|
||||
TokenUsed int `json:"token_used" validate:"min=0"`
|
||||
}
|
||||
|
||||
type PlayGameResponse struct {
|
||||
GamePlay GamePlayResponse `json:"game_play"`
|
||||
PrizeWon *GamePrizeResponse `json:"prize_won,omitempty"`
|
||||
TokensRemaining int64 `json:"tokens_remaining"`
|
||||
}
|
||||
61
internal/contract/game_prize_contract.go
Normal file
61
internal/contract/game_prize_contract.go
Normal file
@ -0,0 +1,61 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateGamePrizeRequest struct {
|
||||
GameID uuid.UUID `json:"game_id" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Weight int `json:"weight" validate:"min=1"`
|
||||
Stock int `json:"stock" validate:"min=0"`
|
||||
MaxStock *int `json:"max_stock,omitempty"`
|
||||
Threshold *int64 `json:"threshold,omitempty"`
|
||||
FallbackPrizeID *uuid.UUID `json:"fallback_prize_id,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
}
|
||||
|
||||
type UpdateGamePrizeRequest struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,required"`
|
||||
Weight *int `json:"weight,omitempty" validate:"omitempty,min=1"`
|
||||
Stock *int `json:"stock,omitempty" validate:"omitempty,min=0"`
|
||||
MaxStock *int `json:"max_stock,omitempty"`
|
||||
Threshold *int64 `json:"threshold,omitempty"`
|
||||
FallbackPrizeID *uuid.UUID `json:"fallback_prize_id,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type GamePrizeResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
GameID uuid.UUID `json:"game_id"`
|
||||
Name string `json:"name"`
|
||||
Weight int `json:"weight"`
|
||||
Stock int `json:"stock"`
|
||||
MaxStock *int `json:"max_stock,omitempty"`
|
||||
Threshold *int64 `json:"threshold,omitempty"`
|
||||
FallbackPrizeID *uuid.UUID `json:"fallback_prize_id,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
Game *GameResponse `json:"game,omitempty"`
|
||||
FallbackPrize *GamePrizeResponse `json:"fallback_prize,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListGamePrizesRequest struct {
|
||||
Page int `json:"page" form:"page" validate:"min=1"`
|
||||
Limit int `json:"limit" form:"limit" validate:"min=1,max=100"`
|
||||
Search string `json:"search" form:"search"`
|
||||
GameID *uuid.UUID `json:"game_id" form:"game_id"`
|
||||
SortBy string `json:"sort_by" form:"sort_by" validate:"omitempty,oneof=name weight stock created_at updated_at"`
|
||||
SortOrder string `json:"sort_order" form:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
|
||||
type PaginatedGamePrizesResponse struct {
|
||||
Data []GamePrizeResponse `json:"data"`
|
||||
TotalCount int `json:"total_count"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
}
|
||||
59
internal/contract/omset_tracker_contract.go
Normal file
59
internal/contract/omset_tracker_contract.go
Normal file
@ -0,0 +1,59 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateOmsetTrackerRequest struct {
|
||||
PeriodType string `json:"period_type" validate:"required,oneof=DAILY WEEKLY MONTHLY TOTAL"`
|
||||
PeriodStart time.Time `json:"period_start" validate:"required"`
|
||||
PeriodEnd time.Time `json:"period_end" validate:"required"`
|
||||
Total int64 `json:"total" validate:"min=0"`
|
||||
GameID *uuid.UUID `json:"game_id,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateOmsetTrackerRequest struct {
|
||||
PeriodType *string `json:"period_type,omitempty" validate:"omitempty,oneof=DAILY WEEKLY MONTHLY TOTAL"`
|
||||
PeriodStart *time.Time `json:"period_start,omitempty"`
|
||||
PeriodEnd *time.Time `json:"period_end,omitempty"`
|
||||
Total *int64 `json:"total,omitempty" validate:"omitempty,min=0"`
|
||||
GameID *uuid.UUID `json:"game_id,omitempty"`
|
||||
}
|
||||
|
||||
type AddOmsetRequest struct {
|
||||
Amount int64 `json:"amount" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type OmsetTrackerResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
PeriodType string `json:"period_type"`
|
||||
PeriodStart time.Time `json:"period_start"`
|
||||
PeriodEnd time.Time `json:"period_end"`
|
||||
Total int64 `json:"total"`
|
||||
GameID *uuid.UUID `json:"game_id,omitempty"`
|
||||
Game *GameResponse `json:"game,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListOmsetTrackerRequest struct {
|
||||
Page int `json:"page" validate:"min=1"`
|
||||
Limit int `json:"limit" validate:"min=1,max=100"`
|
||||
Search string `json:"search"`
|
||||
PeriodType string `json:"period_type" validate:"omitempty,oneof=DAILY WEEKLY MONTHLY TOTAL"`
|
||||
GameID *uuid.UUID `json:"game_id"`
|
||||
From *time.Time `json:"from"`
|
||||
To *time.Time `json:"to"`
|
||||
SortBy string `json:"sort_by" validate:"omitempty,oneof=period_type period_start total created_at updated_at"`
|
||||
SortOrder string `json:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
|
||||
type PaginatedOmsetTrackerResponse struct {
|
||||
Data []OmsetTrackerResponse `json:"data"`
|
||||
TotalCount int `json:"total_count"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
}
|
||||
44
internal/contract/tier_contract.go
Normal file
44
internal/contract/tier_contract.go
Normal file
@ -0,0 +1,44 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateTierRequest struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
MinPoints int64 `json:"min_points" validate:"min=0"`
|
||||
Benefits map[string]interface{} `json:"benefits"`
|
||||
}
|
||||
|
||||
type UpdateTierRequest struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,required"`
|
||||
MinPoints *int64 `json:"min_points,omitempty" validate:"omitempty,min=0"`
|
||||
Benefits map[string]interface{} `json:"benefits,omitempty"`
|
||||
}
|
||||
|
||||
type TierResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
MinPoints int64 `json:"min_points"`
|
||||
Benefits map[string]interface{} `json:"benefits"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListTiersRequest struct {
|
||||
Page int `form:"page" validate:"min=1"`
|
||||
Limit int `form:"limit" validate:"min=1,max=100"`
|
||||
Search string `form:"search"`
|
||||
SortBy string `form:"sort_by" validate:"omitempty,oneof=name min_points created_at updated_at"`
|
||||
SortOrder string `form:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
|
||||
type PaginatedTiersResponse struct {
|
||||
Data []TierResponse `json:"data"`
|
||||
TotalCount int `json:"total_count"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
}
|
||||
29
internal/entities/customer_points.go
Normal file
29
internal/entities/customer_points.go
Normal file
@ -0,0 +1,29 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type CustomerPoints struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
CustomerID uuid.UUID `gorm:"type:uuid;not null;index" json:"customer_id" validate:"required"`
|
||||
Balance int64 `gorm:"not null;default:0" json:"balance" validate:"min=0"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
Customer Customer `gorm:"foreignKey:CustomerID" json:"customer,omitempty"`
|
||||
}
|
||||
|
||||
func (cp *CustomerPoints) BeforeCreate(tx *gorm.DB) error {
|
||||
if cp.ID == uuid.Nil {
|
||||
cp.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (CustomerPoints) TableName() string {
|
||||
return "customer_points"
|
||||
}
|
||||
38
internal/entities/customer_tokens.go
Normal file
38
internal/entities/customer_tokens.go
Normal file
@ -0,0 +1,38 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type TokenType string
|
||||
|
||||
const (
|
||||
TokenTypeSpin TokenType = "SPIN"
|
||||
TokenTypeRaffle TokenType = "RAFFLE"
|
||||
TokenTypeMinigame TokenType = "MINIGAME"
|
||||
)
|
||||
|
||||
type CustomerTokens struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
CustomerID uuid.UUID `gorm:"type:uuid;not null;index" json:"customer_id" validate:"required"`
|
||||
TokenType TokenType `gorm:"type:varchar(50);not null" json:"token_type" validate:"required,oneof=SPIN RAFFLE MINIGAME"`
|
||||
Balance int64 `gorm:"not null;default:0" json:"balance" validate:"min=0"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
Customer Customer `gorm:"foreignKey:CustomerID" json:"customer,omitempty"`
|
||||
}
|
||||
|
||||
func (ct *CustomerTokens) BeforeCreate(tx *gorm.DB) error {
|
||||
if ct.ID == uuid.Nil {
|
||||
ct.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (CustomerTokens) TableName() string {
|
||||
return "customer_tokens"
|
||||
}
|
||||
@ -23,6 +23,14 @@ func GetAllEntities() []interface{} {
|
||||
&PurchaseOrderItem{},
|
||||
&PurchaseOrderAttachment{},
|
||||
&IngredientUnitConverter{},
|
||||
// Gamification entities
|
||||
&CustomerPoints{},
|
||||
&CustomerTokens{},
|
||||
&Tier{},
|
||||
&Game{},
|
||||
&GamePrize{},
|
||||
&GamePlay{},
|
||||
&OmsetTracker{},
|
||||
// Analytics entities are not database tables, they are query results
|
||||
}
|
||||
}
|
||||
|
||||
40
internal/entities/game.go
Normal file
40
internal/entities/game.go
Normal file
@ -0,0 +1,40 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type GameType string
|
||||
|
||||
const (
|
||||
GameTypeSpin GameType = "SPIN"
|
||||
GameTypeRaffle GameType = "RAFFLE"
|
||||
GameTypeMinigame GameType = "MINIGAME"
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
Name string `gorm:"type:varchar(255);not null" json:"name" validate:"required"`
|
||||
Type GameType `gorm:"type:varchar(50);not null" json:"type" validate:"required,oneof=SPIN RAFFLE MINIGAME"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
Prizes []GamePrize `gorm:"foreignKey:GameID" json:"prizes,omitempty"`
|
||||
Plays []GamePlay `gorm:"foreignKey:GameID" json:"plays,omitempty"`
|
||||
}
|
||||
|
||||
func (g *Game) BeforeCreate(tx *gorm.DB) error {
|
||||
if g.ID == uuid.Nil {
|
||||
g.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Game) TableName() string {
|
||||
return "games"
|
||||
}
|
||||
33
internal/entities/game_play.go
Normal file
33
internal/entities/game_play.go
Normal file
@ -0,0 +1,33 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type GamePlay struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
GameID uuid.UUID `gorm:"type:uuid;not null;index" json:"game_id" validate:"required"`
|
||||
CustomerID uuid.UUID `gorm:"type:uuid;not null;index" json:"customer_id" validate:"required"`
|
||||
PrizeID *uuid.UUID `gorm:"type:uuid" json:"prize_id,omitempty"`
|
||||
TokenUsed int `gorm:"default:0" json:"token_used" validate:"min=0"`
|
||||
RandomSeed *string `gorm:"type:varchar(255)" json:"random_seed,omitempty"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
|
||||
Game Game `gorm:"foreignKey:GameID" json:"game,omitempty"`
|
||||
Customer Customer `gorm:"foreignKey:CustomerID" json:"customer,omitempty"`
|
||||
Prize *GamePrize `gorm:"foreignKey:PrizeID" json:"prize,omitempty"`
|
||||
}
|
||||
|
||||
func (gp *GamePlay) BeforeCreate(tx *gorm.DB) error {
|
||||
if gp.ID == uuid.Nil {
|
||||
gp.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (GamePlay) TableName() string {
|
||||
return "game_plays"
|
||||
}
|
||||
37
internal/entities/game_prize.go
Normal file
37
internal/entities/game_prize.go
Normal file
@ -0,0 +1,37 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type GamePrize struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
GameID uuid.UUID `gorm:"type:uuid;not null;index" json:"game_id" validate:"required"`
|
||||
Name string `gorm:"type:varchar(255);not null" json:"name" validate:"required"`
|
||||
Weight int `gorm:"not null" json:"weight" validate:"min=1"`
|
||||
Stock int `gorm:"default:0" json:"stock" validate:"min=0"`
|
||||
MaxStock *int `gorm:"" json:"max_stock,omitempty"`
|
||||
Threshold *int64 `gorm:"" json:"threshold,omitempty"`
|
||||
FallbackPrizeID *uuid.UUID `gorm:"type:uuid" json:"fallback_prize_id,omitempty"`
|
||||
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
Game Game `gorm:"foreignKey:GameID" json:"game,omitempty"`
|
||||
FallbackPrize *GamePrize `gorm:"foreignKey:FallbackPrizeID" json:"fallback_prize,omitempty"`
|
||||
Plays []GamePlay `gorm:"foreignKey:PrizeID" json:"plays,omitempty"`
|
||||
}
|
||||
|
||||
func (gp *GamePrize) BeforeCreate(tx *gorm.DB) error {
|
||||
if gp.ID == uuid.Nil {
|
||||
gp.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (GamePrize) TableName() string {
|
||||
return "game_prizes"
|
||||
}
|
||||
41
internal/entities/omset_tracker.go
Normal file
41
internal/entities/omset_tracker.go
Normal file
@ -0,0 +1,41 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type PeriodType string
|
||||
|
||||
const (
|
||||
PeriodTypeDaily PeriodType = "DAILY"
|
||||
PeriodTypeWeekly PeriodType = "WEEKLY"
|
||||
PeriodTypeMonthly PeriodType = "MONTHLY"
|
||||
PeriodTypeTotal PeriodType = "TOTAL"
|
||||
)
|
||||
|
||||
type OmsetTracker struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
PeriodType PeriodType `gorm:"type:varchar(20);not null" json:"period_type" validate:"required,oneof=DAILY WEEKLY MONTHLY TOTAL"`
|
||||
PeriodStart time.Time `gorm:"type:date;not null" json:"period_start" validate:"required"`
|
||||
PeriodEnd time.Time `gorm:"type:date;not null" json:"period_end" validate:"required"`
|
||||
Total int64 `gorm:"not null;default:0" json:"total" validate:"min=0"`
|
||||
GameID *uuid.UUID `gorm:"type:uuid" json:"game_id,omitempty"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
Game *Game `gorm:"foreignKey:GameID" json:"game,omitempty"`
|
||||
}
|
||||
|
||||
func (ot *OmsetTracker) BeforeCreate(tx *gorm.DB) error {
|
||||
if ot.ID == uuid.Nil {
|
||||
ot.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (OmsetTracker) TableName() string {
|
||||
return "omset_tracker"
|
||||
}
|
||||
28
internal/entities/tier.go
Normal file
28
internal/entities/tier.go
Normal file
@ -0,0 +1,28 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Tier struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
Name string `gorm:"type:varchar(100);not null;unique" json:"name" validate:"required"`
|
||||
MinPoints int64 `gorm:"not null" json:"min_points" validate:"min=0"`
|
||||
Benefits Metadata `gorm:"type:jsonb;default:'{}'" json:"benefits"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (t *Tier) BeforeCreate(tx *gorm.DB) error {
|
||||
if t.ID == uuid.Nil {
|
||||
t.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Tier) TableName() string {
|
||||
return "tiers"
|
||||
}
|
||||
527
internal/handler/gamification_handler.go
Normal file
527
internal/handler/gamification_handler.go
Normal file
@ -0,0 +1,527 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/constants"
|
||||
"apskel-pos-be/internal/contract"
|
||||
"apskel-pos-be/internal/logger"
|
||||
"apskel-pos-be/internal/service"
|
||||
"apskel-pos-be/internal/util"
|
||||
"apskel-pos-be/internal/validator"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type GamificationHandler struct {
|
||||
gamificationService service.GamificationService
|
||||
gamificationValidator validator.GamificationValidator
|
||||
}
|
||||
|
||||
func NewGamificationHandler(
|
||||
gamificationService service.GamificationService,
|
||||
gamificationValidator validator.GamificationValidator,
|
||||
) *GamificationHandler {
|
||||
return &GamificationHandler{
|
||||
gamificationService: gamificationService,
|
||||
gamificationValidator: gamificationValidator,
|
||||
}
|
||||
}
|
||||
|
||||
// Customer Points Handlers
|
||||
func (h *GamificationHandler) CreateCustomerPoints(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.CreateCustomerPointsRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateCustomerPoints -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateCreateCustomerPointsRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::CreateCustomerPoints -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.CreateCustomerPoints(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateCustomerPoints -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerPointsEntity, err.Error())}), "GamificationHandler::CreateCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::CreateCustomerPoints")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) GetCustomerPoints(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetCustomerPoints -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.CustomerPointsEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::GetCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.GetCustomerPoints(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetCustomerPoints -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerPointsEntity, err.Error())}), "GamificationHandler::GetCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::GetCustomerPoints")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) GetCustomerPointsByCustomerID(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
customerIDStr := c.Param("customer_id")
|
||||
customerID, err := uuid.Parse(customerIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetCustomerPointsByCustomerID -> invalid customer ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.CustomerPointsEntity, "Invalid customer ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::GetCustomerPointsByCustomerID")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.GetCustomerPointsByCustomerID(ctx, customerID)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetCustomerPointsByCustomerID -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerPointsEntity, err.Error())}), "GamificationHandler::GetCustomerPointsByCustomerID")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::GetCustomerPointsByCustomerID")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) ListCustomerPoints(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.ListCustomerPointsRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListCustomerPoints -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateListCustomerPointsRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::ListCustomerPoints -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.ListCustomerPoints(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListCustomerPoints -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerPointsEntity, err.Error())}), "GamificationHandler::ListCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::ListCustomerPoints")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) UpdateCustomerPoints(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateCustomerPoints -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.CustomerPointsEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.UpdateCustomerPointsRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateCustomerPoints -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateUpdateCustomerPointsRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::UpdateCustomerPoints -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.UpdateCustomerPoints(ctx, id, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateCustomerPoints -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerPointsEntity, err.Error())}), "GamificationHandler::UpdateCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::UpdateCustomerPoints")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) DeleteCustomerPoints(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeleteCustomerPoints -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.CustomerPointsEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::DeleteCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.gamificationService.DeleteCustomerPoints(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeleteCustomerPoints -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerPointsEntity, err.Error())}), "GamificationHandler::DeleteCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(nil), "GamificationHandler::DeleteCustomerPoints")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) AddCustomerPoints(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
customerIDStr := c.Param("customer_id")
|
||||
customerID, err := uuid.Parse(customerIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::AddCustomerPoints -> invalid customer ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.CustomerPointsEntity, "Invalid customer ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::AddCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.AddCustomerPointsRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::AddCustomerPoints -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::AddCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateAddCustomerPointsRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::AddCustomerPoints -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::AddCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.AddCustomerPoints(ctx, customerID, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::AddCustomerPoints -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerPointsEntity, err.Error())}), "GamificationHandler::AddCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::AddCustomerPoints")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) DeductCustomerPoints(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
customerIDStr := c.Param("customer_id")
|
||||
customerID, err := uuid.Parse(customerIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeductCustomerPoints -> invalid customer ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.CustomerPointsEntity, "Invalid customer ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::DeductCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.DeductCustomerPointsRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeductCustomerPoints -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::DeductCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateDeductCustomerPointsRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::DeductCustomerPoints -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::DeductCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.DeductCustomerPoints(ctx, customerID, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeductCustomerPoints -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerPointsEntity, err.Error())}), "GamificationHandler::DeductCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::DeductCustomerPoints")
|
||||
}
|
||||
|
||||
// Play Game Handler
|
||||
func (h *GamificationHandler) PlayGame(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.PlayGameRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::PlayGame -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::PlayGame")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidatePlayGameRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::PlayGame -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::PlayGame")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.PlayGame(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::PlayGame -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GameEntity, err.Error())}), "GamificationHandler::PlayGame")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::PlayGame")
|
||||
}
|
||||
|
||||
// Additional handler methods for other gamification features
|
||||
func (h *GamificationHandler) CreateCustomerTokens(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.CreateCustomerTokensRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateCustomerTokens -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateCreateCustomerTokensRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::CreateCustomerTokens -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.CreateCustomerTokens(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateCustomerTokens -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerTokensEntity, err.Error())}), "GamificationHandler::CreateCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::CreateCustomerTokens")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) GetCustomerTokens(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetCustomerTokens -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.CustomerTokensEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::GetCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.GetCustomerTokens(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetCustomerTokens -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerTokensEntity, err.Error())}), "GamificationHandler::GetCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::GetCustomerTokens")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) GetCustomerTokensByCustomerIDAndType(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
customerIDStr := c.Param("customer_id")
|
||||
customerID, err := uuid.Parse(customerIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetCustomerTokensByCustomerIDAndType -> invalid customer ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.CustomerTokensEntity, "Invalid customer ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::GetCustomerTokensByCustomerIDAndType")
|
||||
return
|
||||
}
|
||||
|
||||
tokenType := c.Param("token_type")
|
||||
|
||||
response, err := h.gamificationService.GetCustomerTokensByCustomerIDAndType(ctx, customerID, tokenType)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetCustomerTokensByCustomerIDAndType -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerTokensEntity, err.Error())}), "GamificationHandler::GetCustomerTokensByCustomerIDAndType")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::GetCustomerTokensByCustomerIDAndType")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) ListCustomerTokens(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.ListCustomerTokensRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListCustomerTokens -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateListCustomerTokensRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::ListCustomerTokens -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.ListCustomerTokens(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListCustomerTokens -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerTokensEntity, err.Error())}), "GamificationHandler::ListCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::ListCustomerTokens")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) UpdateCustomerTokens(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateCustomerTokens -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.CustomerTokensEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.UpdateCustomerTokensRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateCustomerTokens -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateUpdateCustomerTokensRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::UpdateCustomerTokens -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.UpdateCustomerTokens(ctx, id, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateCustomerTokens -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerTokensEntity, err.Error())}), "GamificationHandler::UpdateCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::UpdateCustomerTokens")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) DeleteCustomerTokens(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeleteCustomerTokens -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.CustomerTokensEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::DeleteCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.gamificationService.DeleteCustomerTokens(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeleteCustomerTokens -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerTokensEntity, err.Error())}), "GamificationHandler::DeleteCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(nil), "GamificationHandler::DeleteCustomerTokens")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) AddCustomerTokens(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
customerIDStr := c.Param("customer_id")
|
||||
customerID, err := uuid.Parse(customerIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::AddCustomerTokens -> invalid customer ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.CustomerTokensEntity, "Invalid customer ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::AddCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
tokenType := c.Param("token_type")
|
||||
|
||||
var req contract.AddCustomerTokensRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::AddCustomerTokens -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::AddCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateAddCustomerTokensRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::AddCustomerTokens -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::AddCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.AddCustomerTokens(ctx, customerID, tokenType, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::AddCustomerTokens -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerTokensEntity, err.Error())}), "GamificationHandler::AddCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::AddCustomerTokens")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) DeductCustomerTokens(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
customerIDStr := c.Param("customer_id")
|
||||
customerID, err := uuid.Parse(customerIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeductCustomerTokens -> invalid customer ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.CustomerTokensEntity, "Invalid customer ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::DeductCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
tokenType := c.Param("token_type")
|
||||
|
||||
var req contract.DeductCustomerTokensRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeductCustomerTokens -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::DeductCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateDeductCustomerTokensRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::DeductCustomerTokens -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::DeductCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.DeductCustomerTokens(ctx, customerID, tokenType, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeductCustomerTokens -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerTokensEntity, err.Error())}), "GamificationHandler::DeductCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::DeductCustomerTokens")
|
||||
}
|
||||
709
internal/handler/gamification_handler_additional.go
Normal file
709
internal/handler/gamification_handler_additional.go
Normal file
@ -0,0 +1,709 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/constants"
|
||||
"apskel-pos-be/internal/contract"
|
||||
"apskel-pos-be/internal/logger"
|
||||
"apskel-pos-be/internal/util"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Tier Handlers
|
||||
func (h *GamificationHandler) CreateTier(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.CreateTierRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateTier -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateTier")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateCreateTierRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::CreateTier -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateTier")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.CreateTier(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateTier -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.TierEntity, err.Error())}), "GamificationHandler::CreateTier")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::CreateTier")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) GetTier(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetTier -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.TierEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::GetTier")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.GetTier(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetTier -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.TierEntity, err.Error())}), "GamificationHandler::GetTier")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::GetTier")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) ListTiers(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.ListTiersRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListTiers -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListTiers")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateListTiersRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::ListTiers -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListTiers")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.ListTiers(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListTiers -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.TierEntity, err.Error())}), "GamificationHandler::ListTiers")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::ListTiers")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) UpdateTier(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateTier -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.TierEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateTier")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.UpdateTierRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateTier -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateTier")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateUpdateTierRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::UpdateTier -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateTier")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.UpdateTier(ctx, id, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateTier -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.TierEntity, err.Error())}), "GamificationHandler::UpdateTier")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::UpdateTier")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) DeleteTier(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeleteTier -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.TierEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::DeleteTier")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.gamificationService.DeleteTier(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeleteTier -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.TierEntity, err.Error())}), "GamificationHandler::DeleteTier")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(nil), "GamificationHandler::DeleteTier")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) GetTierByPoints(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
pointsStr := c.Param("points")
|
||||
points, err := strconv.ParseInt(pointsStr, 10, 64)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetTierByPoints -> invalid points")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.TierEntity, "Invalid points format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::GetTierByPoints")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.GetTierByPoints(ctx, points)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetTierByPoints -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.TierEntity, err.Error())}), "GamificationHandler::GetTierByPoints")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::GetTierByPoints")
|
||||
}
|
||||
|
||||
// Game Handlers
|
||||
func (h *GamificationHandler) CreateGame(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.CreateGameRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateGame -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateGame")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateCreateGameRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::CreateGame -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateGame")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.CreateGame(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateGame -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GameEntity, err.Error())}), "GamificationHandler::CreateGame")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::CreateGame")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) GetGame(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetGame -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.GameEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::GetGame")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.GetGame(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetGame -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GameEntity, err.Error())}), "GamificationHandler::GetGame")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::GetGame")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) ListGames(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.ListGamesRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListGames -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListGames")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateListGamesRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::ListGames -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListGames")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.ListGames(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListGames -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GameEntity, err.Error())}), "GamificationHandler::ListGames")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::ListGames")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) GetActiveGames(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
response, err := h.gamificationService.GetActiveGames(ctx)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetActiveGames -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GameEntity, err.Error())}), "GamificationHandler::GetActiveGames")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::GetActiveGames")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) UpdateGame(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateGame -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.GameEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateGame")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.UpdateGameRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateGame -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateGame")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateUpdateGameRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::UpdateGame -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateGame")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.UpdateGame(ctx, id, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateGame -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GameEntity, err.Error())}), "GamificationHandler::UpdateGame")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::UpdateGame")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) DeleteGame(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeleteGame -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.GameEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::DeleteGame")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.gamificationService.DeleteGame(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeleteGame -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GameEntity, err.Error())}), "GamificationHandler::DeleteGame")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(nil), "GamificationHandler::DeleteGame")
|
||||
}
|
||||
|
||||
// Game Prize Handlers
|
||||
func (h *GamificationHandler) CreateGamePrize(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.CreateGamePrizeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateGamePrize -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateGamePrize")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateCreateGamePrizeRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::CreateGamePrize -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateGamePrize")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.CreateGamePrize(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateGamePrize -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GamePrizeEntity, err.Error())}), "GamificationHandler::CreateGamePrize")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::CreateGamePrize")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) GetGamePrize(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetGamePrize -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.GamePrizeEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::GetGamePrize")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.GetGamePrize(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetGamePrize -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GamePrizeEntity, err.Error())}), "GamificationHandler::GetGamePrize")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::GetGamePrize")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) ListGamePrizes(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.ListGamePrizesRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListGamePrizes -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListGamePrizes")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateListGamePrizesRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::ListGamePrizes -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListGamePrizes")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.ListGamePrizes(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListGamePrizes -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GamePrizeEntity, err.Error())}), "GamificationHandler::ListGamePrizes")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::ListGamePrizes")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) UpdateGamePrize(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateGamePrize -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.GamePrizeEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateGamePrize")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.UpdateGamePrizeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateGamePrize -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateGamePrize")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateUpdateGamePrizeRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::UpdateGamePrize -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateGamePrize")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.UpdateGamePrize(ctx, id, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateGamePrize -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GamePrizeEntity, err.Error())}), "GamificationHandler::UpdateGamePrize")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::UpdateGamePrize")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) DeleteGamePrize(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeleteGamePrize -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.GamePrizeEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::DeleteGamePrize")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.gamificationService.DeleteGamePrize(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeleteGamePrize -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GamePrizeEntity, err.Error())}), "GamificationHandler::DeleteGamePrize")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(nil), "GamificationHandler::DeleteGamePrize")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) GetGamePrizesByGameID(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
gameIDStr := c.Param("game_id")
|
||||
gameID, err := uuid.Parse(gameIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetGamePrizesByGameID -> invalid game ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.GamePrizeEntity, "Invalid game ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::GetGamePrizesByGameID")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.GetGamePrizesByGameID(ctx, gameID)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetGamePrizesByGameID -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GamePrizeEntity, err.Error())}), "GamificationHandler::GetGamePrizesByGameID")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::GetGamePrizesByGameID")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) GetAvailablePrizes(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
gameIDStr := c.Param("game_id")
|
||||
gameID, err := uuid.Parse(gameIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetAvailablePrizes -> invalid game ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.GamePrizeEntity, "Invalid game ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::GetAvailablePrizes")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.GetAvailablePrizes(ctx, gameID)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetAvailablePrizes -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GamePrizeEntity, err.Error())}), "GamificationHandler::GetAvailablePrizes")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::GetAvailablePrizes")
|
||||
}
|
||||
|
||||
// Game Play Handlers
|
||||
func (h *GamificationHandler) CreateGamePlay(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.CreateGamePlayRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateGamePlay -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateGamePlay")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateCreateGamePlayRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::CreateGamePlay -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateGamePlay")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.CreateGamePlay(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateGamePlay -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GamePlayEntity, err.Error())}), "GamificationHandler::CreateGamePlay")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::CreateGamePlay")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) GetGamePlay(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetGamePlay -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.GamePlayEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::GetGamePlay")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.GetGamePlay(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetGamePlay -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GamePlayEntity, err.Error())}), "GamificationHandler::GetGamePlay")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::GetGamePlay")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) ListGamePlays(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.ListGamePlaysRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListGamePlays -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListGamePlays")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateListGamePlaysRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::ListGamePlays -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListGamePlays")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.ListGamePlays(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListGamePlays -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.GamePlayEntity, err.Error())}), "GamificationHandler::ListGamePlays")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::ListGamePlays")
|
||||
}
|
||||
|
||||
// Omset Tracker Handlers
|
||||
func (h *GamificationHandler) CreateOmsetTracker(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.CreateOmsetTrackerRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateOmsetTracker -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateOmsetTracker")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateCreateOmsetTrackerRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::CreateOmsetTracker -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::CreateOmsetTracker")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.CreateOmsetTracker(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::CreateOmsetTracker -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.OmsetTrackerEntity, err.Error())}), "GamificationHandler::CreateOmsetTracker")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::CreateOmsetTracker")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) GetOmsetTracker(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetOmsetTracker -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.OmsetTrackerEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::GetOmsetTracker")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.GetOmsetTracker(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::GetOmsetTracker -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.OmsetTrackerEntity, err.Error())}), "GamificationHandler::GetOmsetTracker")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::GetOmsetTracker")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) ListOmsetTrackers(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
var req contract.ListOmsetTrackerRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListOmsetTrackers -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListOmsetTrackers")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateListOmsetTrackerRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::ListOmsetTrackers -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::ListOmsetTrackers")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.ListOmsetTrackers(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::ListOmsetTrackers -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.OmsetTrackerEntity, err.Error())}), "GamificationHandler::ListOmsetTrackers")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::ListOmsetTrackers")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) UpdateOmsetTracker(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateOmsetTracker -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.OmsetTrackerEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateOmsetTracker")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.UpdateOmsetTrackerRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateOmsetTracker -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateOmsetTracker")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.gamificationValidator.ValidateUpdateOmsetTrackerRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("GamificationHandler::UpdateOmsetTracker -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::UpdateOmsetTracker")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.gamificationService.UpdateOmsetTracker(ctx, id, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::UpdateOmsetTracker -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.OmsetTrackerEntity, err.Error())}), "GamificationHandler::UpdateOmsetTracker")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "GamificationHandler::UpdateOmsetTracker")
|
||||
}
|
||||
|
||||
func (h *GamificationHandler) DeleteOmsetTracker(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeleteOmsetTracker -> invalid ID")
|
||||
validationResponseError := contract.NewResponseError(constants.InvalidFieldErrorCode, constants.OmsetTrackerEntity, "Invalid ID format")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "GamificationHandler::DeleteOmsetTracker")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.gamificationService.DeleteOmsetTracker(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("GamificationHandler::DeleteOmsetTracker -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.OmsetTrackerEntity, err.Error())}), "GamificationHandler::DeleteOmsetTracker")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(nil), "GamificationHandler::DeleteOmsetTracker")
|
||||
}
|
||||
46
internal/mappers/customer_points_mapper.go
Normal file
46
internal/mappers/customer_points_mapper.go
Normal file
@ -0,0 +1,46 @@
|
||||
package mappers
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"apskel-pos-be/internal/models"
|
||||
)
|
||||
|
||||
// ToCustomerPointsResponse converts a customer points entity to a customer points response
|
||||
func ToCustomerPointsResponse(customerPoints *entities.CustomerPoints) *models.CustomerPointsResponse {
|
||||
if customerPoints == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &models.CustomerPointsResponse{
|
||||
ID: customerPoints.ID,
|
||||
CustomerID: customerPoints.CustomerID,
|
||||
Balance: customerPoints.Balance,
|
||||
Customer: ToCustomerResponse(&customerPoints.Customer),
|
||||
CreatedAt: customerPoints.CreatedAt,
|
||||
UpdatedAt: customerPoints.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
// ToCustomerPointsResponses converts a slice of customer points entities to customer points responses
|
||||
func ToCustomerPointsResponses(customerPoints []entities.CustomerPoints) []models.CustomerPointsResponse {
|
||||
responses := make([]models.CustomerPointsResponse, len(customerPoints))
|
||||
for i, cp := range customerPoints {
|
||||
responses[i] = *ToCustomerPointsResponse(&cp)
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
// ToCustomerPointsEntity converts a create customer points request to a customer points entity
|
||||
func ToCustomerPointsEntity(req *models.CreateCustomerPointsRequest) *entities.CustomerPoints {
|
||||
return &entities.CustomerPoints{
|
||||
CustomerID: req.CustomerID,
|
||||
Balance: req.Balance,
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateCustomerPointsEntity updates a customer points entity with update request data
|
||||
func UpdateCustomerPointsEntity(customerPoints *entities.CustomerPoints, req *models.UpdateCustomerPointsRequest) {
|
||||
if req.Balance >= 0 {
|
||||
customerPoints.Balance = req.Balance
|
||||
}
|
||||
}
|
||||
48
internal/mappers/customer_tokens_mapper.go
Normal file
48
internal/mappers/customer_tokens_mapper.go
Normal file
@ -0,0 +1,48 @@
|
||||
package mappers
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"apskel-pos-be/internal/models"
|
||||
)
|
||||
|
||||
// ToCustomerTokensResponse converts a customer tokens entity to a customer tokens response
|
||||
func ToCustomerTokensResponse(customerTokens *entities.CustomerTokens) *models.CustomerTokensResponse {
|
||||
if customerTokens == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &models.CustomerTokensResponse{
|
||||
ID: customerTokens.ID,
|
||||
CustomerID: customerTokens.CustomerID,
|
||||
TokenType: string(customerTokens.TokenType),
|
||||
Balance: customerTokens.Balance,
|
||||
Customer: ToCustomerResponse(&customerTokens.Customer),
|
||||
CreatedAt: customerTokens.CreatedAt,
|
||||
UpdatedAt: customerTokens.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
// ToCustomerTokensResponses converts a slice of customer tokens entities to customer tokens responses
|
||||
func ToCustomerTokensResponses(customerTokens []entities.CustomerTokens) []models.CustomerTokensResponse {
|
||||
responses := make([]models.CustomerTokensResponse, len(customerTokens))
|
||||
for i, ct := range customerTokens {
|
||||
responses[i] = *ToCustomerTokensResponse(&ct)
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
// ToCustomerTokensEntity converts a create customer tokens request to a customer tokens entity
|
||||
func ToCustomerTokensEntity(req *models.CreateCustomerTokensRequest) *entities.CustomerTokens {
|
||||
return &entities.CustomerTokens{
|
||||
CustomerID: req.CustomerID,
|
||||
TokenType: entities.TokenType(req.TokenType),
|
||||
Balance: req.Balance,
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateCustomerTokensEntity updates a customer tokens entity with update request data
|
||||
func UpdateCustomerTokensEntity(customerTokens *entities.CustomerTokens, req *models.UpdateCustomerTokensRequest) {
|
||||
if req.Balance >= 0 {
|
||||
customerTokens.Balance = req.Balance
|
||||
}
|
||||
}
|
||||
58
internal/mappers/game_mapper.go
Normal file
58
internal/mappers/game_mapper.go
Normal file
@ -0,0 +1,58 @@
|
||||
package mappers
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"apskel-pos-be/internal/models"
|
||||
)
|
||||
|
||||
// ToGameResponse converts a game entity to a game response
|
||||
func ToGameResponse(game *entities.Game) *models.GameResponse {
|
||||
if game == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &models.GameResponse{
|
||||
ID: game.ID,
|
||||
Name: game.Name,
|
||||
Type: string(game.Type),
|
||||
IsActive: game.IsActive,
|
||||
Metadata: game.Metadata,
|
||||
CreatedAt: game.CreatedAt,
|
||||
UpdatedAt: game.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
// ToGameResponses converts a slice of game entities to game responses
|
||||
func ToGameResponses(games []entities.Game) []models.GameResponse {
|
||||
responses := make([]models.GameResponse, len(games))
|
||||
for i, game := range games {
|
||||
responses[i] = *ToGameResponse(&game)
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
// ToGameEntity converts a create game request to a game entity
|
||||
func ToGameEntity(req *models.CreateGameRequest) *entities.Game {
|
||||
return &entities.Game{
|
||||
Name: req.Name,
|
||||
Type: entities.GameType(req.Type),
|
||||
IsActive: req.IsActive,
|
||||
Metadata: req.Metadata,
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateGameEntity updates a game entity with update request data
|
||||
func UpdateGameEntity(game *entities.Game, req *models.UpdateGameRequest) {
|
||||
if req.Name != nil {
|
||||
game.Name = *req.Name
|
||||
}
|
||||
if req.Type != nil {
|
||||
game.Type = entities.GameType(*req.Type)
|
||||
}
|
||||
if req.IsActive != nil {
|
||||
game.IsActive = *req.IsActive
|
||||
}
|
||||
if req.Metadata != nil {
|
||||
game.Metadata = req.Metadata
|
||||
}
|
||||
}
|
||||
45
internal/mappers/game_play_mapper.go
Normal file
45
internal/mappers/game_play_mapper.go
Normal file
@ -0,0 +1,45 @@
|
||||
package mappers
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"apskel-pos-be/internal/models"
|
||||
)
|
||||
|
||||
// ToGamePlayResponse converts a game play entity to a game play response
|
||||
func ToGamePlayResponse(gamePlay *entities.GamePlay) *models.GamePlayResponse {
|
||||
if gamePlay == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &models.GamePlayResponse{
|
||||
ID: gamePlay.ID,
|
||||
GameID: gamePlay.GameID,
|
||||
CustomerID: gamePlay.CustomerID,
|
||||
PrizeID: gamePlay.PrizeID,
|
||||
TokenUsed: gamePlay.TokenUsed,
|
||||
RandomSeed: gamePlay.RandomSeed,
|
||||
CreatedAt: gamePlay.CreatedAt,
|
||||
Game: ToGameResponse(&gamePlay.Game),
|
||||
Customer: ToCustomerResponse(&gamePlay.Customer),
|
||||
Prize: ToGamePrizeResponse(gamePlay.Prize),
|
||||
}
|
||||
}
|
||||
|
||||
// ToGamePlayResponses converts a slice of game play entities to game play responses
|
||||
func ToGamePlayResponses(gamePlays []entities.GamePlay) []models.GamePlayResponse {
|
||||
responses := make([]models.GamePlayResponse, len(gamePlays))
|
||||
for i, gp := range gamePlays {
|
||||
responses[i] = *ToGamePlayResponse(&gp)
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
// ToGamePlayEntity converts a create game play request to a game play entity
|
||||
func ToGamePlayEntity(req *models.CreateGamePlayRequest) *entities.GamePlay {
|
||||
return &entities.GamePlay{
|
||||
GameID: req.GameID,
|
||||
CustomerID: req.CustomerID,
|
||||
TokenUsed: req.TokenUsed,
|
||||
RandomSeed: req.RandomSeed,
|
||||
}
|
||||
}
|
||||
77
internal/mappers/game_prize_mapper.go
Normal file
77
internal/mappers/game_prize_mapper.go
Normal file
@ -0,0 +1,77 @@
|
||||
package mappers
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"apskel-pos-be/internal/models"
|
||||
)
|
||||
|
||||
// ToGamePrizeResponse converts a game prize entity to a game prize response
|
||||
func ToGamePrizeResponse(gamePrize *entities.GamePrize) *models.GamePrizeResponse {
|
||||
if gamePrize == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &models.GamePrizeResponse{
|
||||
ID: gamePrize.ID,
|
||||
GameID: gamePrize.GameID,
|
||||
Name: gamePrize.Name,
|
||||
Weight: gamePrize.Weight,
|
||||
Stock: gamePrize.Stock,
|
||||
MaxStock: gamePrize.MaxStock,
|
||||
Threshold: gamePrize.Threshold,
|
||||
FallbackPrizeID: gamePrize.FallbackPrizeID,
|
||||
Metadata: gamePrize.Metadata,
|
||||
Game: ToGameResponse(&gamePrize.Game),
|
||||
FallbackPrize: ToGamePrizeResponse(gamePrize.FallbackPrize),
|
||||
CreatedAt: gamePrize.CreatedAt,
|
||||
UpdatedAt: gamePrize.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
// ToGamePrizeResponses converts a slice of game prize entities to game prize responses
|
||||
func ToGamePrizeResponses(gamePrizes []entities.GamePrize) []models.GamePrizeResponse {
|
||||
responses := make([]models.GamePrizeResponse, len(gamePrizes))
|
||||
for i, gp := range gamePrizes {
|
||||
responses[i] = *ToGamePrizeResponse(&gp)
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
// ToGamePrizeEntity converts a create game prize request to a game prize entity
|
||||
func ToGamePrizeEntity(req *models.CreateGamePrizeRequest) *entities.GamePrize {
|
||||
return &entities.GamePrize{
|
||||
GameID: req.GameID,
|
||||
Name: req.Name,
|
||||
Weight: req.Weight,
|
||||
Stock: req.Stock,
|
||||
MaxStock: req.MaxStock,
|
||||
Threshold: req.Threshold,
|
||||
FallbackPrizeID: req.FallbackPrizeID,
|
||||
Metadata: req.Metadata,
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateGamePrizeEntity updates a game prize entity with update request data
|
||||
func UpdateGamePrizeEntity(gamePrize *entities.GamePrize, req *models.UpdateGamePrizeRequest) {
|
||||
if req.Name != nil {
|
||||
gamePrize.Name = *req.Name
|
||||
}
|
||||
if req.Weight != nil {
|
||||
gamePrize.Weight = *req.Weight
|
||||
}
|
||||
if req.Stock != nil {
|
||||
gamePrize.Stock = *req.Stock
|
||||
}
|
||||
if req.MaxStock != nil {
|
||||
gamePrize.MaxStock = req.MaxStock
|
||||
}
|
||||
if req.Threshold != nil {
|
||||
gamePrize.Threshold = req.Threshold
|
||||
}
|
||||
if req.FallbackPrizeID != nil {
|
||||
gamePrize.FallbackPrizeID = req.FallbackPrizeID
|
||||
}
|
||||
if req.Metadata != nil {
|
||||
gamePrize.Metadata = req.Metadata
|
||||
}
|
||||
}
|
||||
64
internal/mappers/omset_tracker_mapper.go
Normal file
64
internal/mappers/omset_tracker_mapper.go
Normal file
@ -0,0 +1,64 @@
|
||||
package mappers
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"apskel-pos-be/internal/models"
|
||||
)
|
||||
|
||||
// ToOmsetTrackerResponse converts an omset tracker entity to an omset tracker response
|
||||
func ToOmsetTrackerResponse(omsetTracker *entities.OmsetTracker) *models.OmsetTrackerResponse {
|
||||
if omsetTracker == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &models.OmsetTrackerResponse{
|
||||
ID: omsetTracker.ID,
|
||||
PeriodType: string(omsetTracker.PeriodType),
|
||||
PeriodStart: omsetTracker.PeriodStart,
|
||||
PeriodEnd: omsetTracker.PeriodEnd,
|
||||
Total: omsetTracker.Total,
|
||||
GameID: omsetTracker.GameID,
|
||||
Game: ToGameResponse(omsetTracker.Game),
|
||||
CreatedAt: omsetTracker.CreatedAt,
|
||||
UpdatedAt: omsetTracker.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
// ToOmsetTrackerResponses converts a slice of omset tracker entities to omset tracker responses
|
||||
func ToOmsetTrackerResponses(omsetTrackers []entities.OmsetTracker) []models.OmsetTrackerResponse {
|
||||
responses := make([]models.OmsetTrackerResponse, len(omsetTrackers))
|
||||
for i, ot := range omsetTrackers {
|
||||
responses[i] = *ToOmsetTrackerResponse(&ot)
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
// ToOmsetTrackerEntity converts a create omset tracker request to an omset tracker entity
|
||||
func ToOmsetTrackerEntity(req *models.CreateOmsetTrackerRequest) *entities.OmsetTracker {
|
||||
return &entities.OmsetTracker{
|
||||
PeriodType: entities.PeriodType(req.PeriodType),
|
||||
PeriodStart: req.PeriodStart,
|
||||
PeriodEnd: req.PeriodEnd,
|
||||
Total: req.Total,
|
||||
GameID: req.GameID,
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateOmsetTrackerEntity updates an omset tracker entity with update request data
|
||||
func UpdateOmsetTrackerEntity(omsetTracker *entities.OmsetTracker, req *models.UpdateOmsetTrackerRequest) {
|
||||
if req.PeriodType != nil {
|
||||
omsetTracker.PeriodType = entities.PeriodType(*req.PeriodType)
|
||||
}
|
||||
if req.PeriodStart != nil {
|
||||
omsetTracker.PeriodStart = *req.PeriodStart
|
||||
}
|
||||
if req.PeriodEnd != nil {
|
||||
omsetTracker.PeriodEnd = *req.PeriodEnd
|
||||
}
|
||||
if req.Total != nil {
|
||||
omsetTracker.Total = *req.Total
|
||||
}
|
||||
if req.GameID != nil {
|
||||
omsetTracker.GameID = req.GameID
|
||||
}
|
||||
}
|
||||
53
internal/mappers/tier_mapper.go
Normal file
53
internal/mappers/tier_mapper.go
Normal file
@ -0,0 +1,53 @@
|
||||
package mappers
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"apskel-pos-be/internal/models"
|
||||
)
|
||||
|
||||
// ToTierResponse converts a tier entity to a tier response
|
||||
func ToTierResponse(tier *entities.Tier) *models.TierResponse {
|
||||
if tier == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &models.TierResponse{
|
||||
ID: tier.ID,
|
||||
Name: tier.Name,
|
||||
MinPoints: tier.MinPoints,
|
||||
Benefits: tier.Benefits,
|
||||
CreatedAt: tier.CreatedAt,
|
||||
UpdatedAt: tier.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
// ToTierResponses converts a slice of tier entities to tier responses
|
||||
func ToTierResponses(tiers []entities.Tier) []models.TierResponse {
|
||||
responses := make([]models.TierResponse, len(tiers))
|
||||
for i, tier := range tiers {
|
||||
responses[i] = *ToTierResponse(&tier)
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
// ToTierEntity converts a create tier request to a tier entity
|
||||
func ToTierEntity(req *models.CreateTierRequest) *entities.Tier {
|
||||
return &entities.Tier{
|
||||
Name: req.Name,
|
||||
MinPoints: req.MinPoints,
|
||||
Benefits: req.Benefits,
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateTierEntity updates a tier entity with update request data
|
||||
func UpdateTierEntity(tier *entities.Tier, req *models.UpdateTierRequest) {
|
||||
if req.Name != nil {
|
||||
tier.Name = *req.Name
|
||||
}
|
||||
if req.MinPoints != nil {
|
||||
tier.MinPoints = *req.MinPoints
|
||||
}
|
||||
if req.Benefits != nil {
|
||||
tier.Benefits = req.Benefits
|
||||
}
|
||||
}
|
||||
41
internal/models/customer_points.go
Normal file
41
internal/models/customer_points.go
Normal file
@ -0,0 +1,41 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateCustomerPointsRequest struct {
|
||||
CustomerID uuid.UUID `json:"customer_id" validate:"required"`
|
||||
Balance int64 `json:"balance" validate:"min=0"`
|
||||
}
|
||||
|
||||
type UpdateCustomerPointsRequest struct {
|
||||
Balance int64 `json:"balance" validate:"min=0"`
|
||||
}
|
||||
|
||||
type AddCustomerPointsRequest struct {
|
||||
Points int64 `json:"points" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type DeductCustomerPointsRequest struct {
|
||||
Points int64 `json:"points" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type CustomerPointsResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
CustomerID uuid.UUID `json:"customer_id"`
|
||||
Balance int64 `json:"balance"`
|
||||
Customer *CustomerResponse `json:"customer,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListCustomerPointsQuery struct {
|
||||
Page int `query:"page" validate:"min=1"`
|
||||
Limit int `query:"limit" validate:"min=1,max=100"`
|
||||
Search string `query:"search"`
|
||||
SortBy string `query:"sort_by" validate:"omitempty,oneof=balance created_at updated_at"`
|
||||
SortOrder string `query:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
44
internal/models/customer_tokens.go
Normal file
44
internal/models/customer_tokens.go
Normal file
@ -0,0 +1,44 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateCustomerTokensRequest struct {
|
||||
CustomerID uuid.UUID `json:"customer_id" validate:"required"`
|
||||
TokenType string `json:"token_type" validate:"required,oneof=SPIN RAFFLE MINIGAME"`
|
||||
Balance int64 `json:"balance" validate:"min=0"`
|
||||
}
|
||||
|
||||
type UpdateCustomerTokensRequest struct {
|
||||
Balance int64 `json:"balance" validate:"min=0"`
|
||||
}
|
||||
|
||||
type AddCustomerTokensRequest struct {
|
||||
Tokens int64 `json:"tokens" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type DeductCustomerTokensRequest struct {
|
||||
Tokens int64 `json:"tokens" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type CustomerTokensResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
CustomerID uuid.UUID `json:"customer_id"`
|
||||
TokenType string `json:"token_type"`
|
||||
Balance int64 `json:"balance"`
|
||||
Customer *CustomerResponse `json:"customer,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListCustomerTokensQuery struct {
|
||||
Page int `query:"page" validate:"min=1"`
|
||||
Limit int `query:"limit" validate:"min=1,max=100"`
|
||||
Search string `query:"search"`
|
||||
TokenType string `query:"token_type" validate:"omitempty,oneof=SPIN RAFFLE MINIGAME"`
|
||||
SortBy string `query:"sort_by" validate:"omitempty,oneof=balance token_type created_at updated_at"`
|
||||
SortOrder string `query:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
41
internal/models/game.go
Normal file
41
internal/models/game.go
Normal file
@ -0,0 +1,41 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateGameRequest struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=SPIN RAFFLE MINIGAME"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
}
|
||||
|
||||
type UpdateGameRequest struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,required"`
|
||||
Type *string `json:"type,omitempty" validate:"omitempty,oneof=SPIN RAFFLE MINIGAME"`
|
||||
IsActive *bool `json:"is_active,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type GameResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListGamesQuery struct {
|
||||
Page int `query:"page" validate:"min=1"`
|
||||
Limit int `query:"limit" validate:"min=1,max=100"`
|
||||
Search string `query:"search"`
|
||||
Type string `query:"type" validate:"omitempty,oneof=SPIN RAFFLE MINIGAME"`
|
||||
IsActive *bool `query:"is_active"`
|
||||
SortBy string `query:"sort_by" validate:"omitempty,oneof=name type created_at updated_at"`
|
||||
SortOrder string `query:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
50
internal/models/game_play.go
Normal file
50
internal/models/game_play.go
Normal file
@ -0,0 +1,50 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateGamePlayRequest struct {
|
||||
GameID uuid.UUID `json:"game_id" validate:"required"`
|
||||
CustomerID uuid.UUID `json:"customer_id" validate:"required"`
|
||||
TokenUsed int `json:"token_used" validate:"min=0"`
|
||||
RandomSeed *string `json:"random_seed,omitempty"`
|
||||
}
|
||||
|
||||
type GamePlayResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
GameID uuid.UUID `json:"game_id"`
|
||||
CustomerID uuid.UUID `json:"customer_id"`
|
||||
PrizeID *uuid.UUID `json:"prize_id,omitempty"`
|
||||
TokenUsed int `json:"token_used"`
|
||||
RandomSeed *string `json:"random_seed,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Game *GameResponse `json:"game,omitempty"`
|
||||
Customer *CustomerResponse `json:"customer,omitempty"`
|
||||
Prize *GamePrizeResponse `json:"prize,omitempty"`
|
||||
}
|
||||
|
||||
type ListGamePlaysQuery struct {
|
||||
Page int `query:"page" validate:"min=1"`
|
||||
Limit int `query:"limit" validate:"min=1,max=100"`
|
||||
Search string `query:"search"`
|
||||
GameID *uuid.UUID `query:"game_id"`
|
||||
CustomerID *uuid.UUID `query:"customer_id"`
|
||||
PrizeID *uuid.UUID `query:"prize_id"`
|
||||
SortBy string `query:"sort_by" validate:"omitempty,oneof=created_at token_used"`
|
||||
SortOrder string `query:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
|
||||
type PlayGameRequest struct {
|
||||
GameID uuid.UUID `json:"game_id" validate:"required"`
|
||||
CustomerID uuid.UUID `json:"customer_id" validate:"required"`
|
||||
TokenUsed int `json:"token_used" validate:"min=0"`
|
||||
}
|
||||
|
||||
type PlayGameResponse struct {
|
||||
GamePlay GamePlayResponse `json:"game_play"`
|
||||
PrizeWon *GamePrizeResponse `json:"prize_won,omitempty"`
|
||||
TokensRemaining int64 `json:"tokens_remaining"`
|
||||
}
|
||||
53
internal/models/game_prize.go
Normal file
53
internal/models/game_prize.go
Normal file
@ -0,0 +1,53 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateGamePrizeRequest struct {
|
||||
GameID uuid.UUID `json:"game_id" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Weight int `json:"weight" validate:"min=1"`
|
||||
Stock int `json:"stock" validate:"min=0"`
|
||||
MaxStock *int `json:"max_stock,omitempty"`
|
||||
Threshold *int64 `json:"threshold,omitempty"`
|
||||
FallbackPrizeID *uuid.UUID `json:"fallback_prize_id,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
}
|
||||
|
||||
type UpdateGamePrizeRequest struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,required"`
|
||||
Weight *int `json:"weight,omitempty" validate:"omitempty,min=1"`
|
||||
Stock *int `json:"stock,omitempty" validate:"omitempty,min=0"`
|
||||
MaxStock *int `json:"max_stock,omitempty"`
|
||||
Threshold *int64 `json:"threshold,omitempty"`
|
||||
FallbackPrizeID *uuid.UUID `json:"fallback_prize_id,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type GamePrizeResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
GameID uuid.UUID `json:"game_id"`
|
||||
Name string `json:"name"`
|
||||
Weight int `json:"weight"`
|
||||
Stock int `json:"stock"`
|
||||
MaxStock *int `json:"max_stock,omitempty"`
|
||||
Threshold *int64 `json:"threshold,omitempty"`
|
||||
FallbackPrizeID *uuid.UUID `json:"fallback_prize_id,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
Game *GameResponse `json:"game,omitempty"`
|
||||
FallbackPrize *GamePrizeResponse `json:"fallback_prize,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListGamePrizesQuery struct {
|
||||
Page int `query:"page" validate:"min=1"`
|
||||
Limit int `query:"limit" validate:"min=1,max=100"`
|
||||
Search string `query:"search"`
|
||||
GameID *uuid.UUID `query:"game_id"`
|
||||
SortBy string `query:"sort_by" validate:"omitempty,oneof=name weight stock created_at updated_at"`
|
||||
SortOrder string `query:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
51
internal/models/omset_tracker.go
Normal file
51
internal/models/omset_tracker.go
Normal file
@ -0,0 +1,51 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateOmsetTrackerRequest struct {
|
||||
PeriodType string `json:"period_type" validate:"required,oneof=DAILY WEEKLY MONTHLY TOTAL"`
|
||||
PeriodStart time.Time `json:"period_start" validate:"required"`
|
||||
PeriodEnd time.Time `json:"period_end" validate:"required"`
|
||||
Total int64 `json:"total" validate:"min=0"`
|
||||
GameID *uuid.UUID `json:"game_id,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateOmsetTrackerRequest struct {
|
||||
PeriodType *string `json:"period_type,omitempty" validate:"omitempty,oneof=DAILY WEEKLY MONTHLY TOTAL"`
|
||||
PeriodStart *time.Time `json:"period_start,omitempty"`
|
||||
PeriodEnd *time.Time `json:"period_end,omitempty"`
|
||||
Total *int64 `json:"total,omitempty" validate:"omitempty,min=0"`
|
||||
GameID *uuid.UUID `json:"game_id,omitempty"`
|
||||
}
|
||||
|
||||
type AddOmsetRequest struct {
|
||||
Amount int64 `json:"amount" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type OmsetTrackerResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
PeriodType string `json:"period_type"`
|
||||
PeriodStart time.Time `json:"period_start"`
|
||||
PeriodEnd time.Time `json:"period_end"`
|
||||
Total int64 `json:"total"`
|
||||
GameID *uuid.UUID `json:"game_id,omitempty"`
|
||||
Game *GameResponse `json:"game,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListOmsetTrackerQuery struct {
|
||||
Page int `query:"page" validate:"min=1"`
|
||||
Limit int `query:"limit" validate:"min=1,max=100"`
|
||||
Search string `query:"search"`
|
||||
PeriodType string `query:"period_type" validate:"omitempty,oneof=DAILY WEEKLY MONTHLY TOTAL"`
|
||||
GameID *uuid.UUID `query:"game_id"`
|
||||
From *time.Time `query:"from"`
|
||||
To *time.Time `query:"to"`
|
||||
SortBy string `query:"sort_by" validate:"omitempty,oneof=period_type period_start total created_at updated_at"`
|
||||
SortOrder string `query:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
36
internal/models/tier.go
Normal file
36
internal/models/tier.go
Normal file
@ -0,0 +1,36 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateTierRequest struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
MinPoints int64 `json:"min_points" validate:"min=0"`
|
||||
Benefits map[string]interface{} `json:"benefits"`
|
||||
}
|
||||
|
||||
type UpdateTierRequest struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,required"`
|
||||
MinPoints *int64 `json:"min_points,omitempty" validate:"omitempty,min=0"`
|
||||
Benefits map[string]interface{} `json:"benefits,omitempty"`
|
||||
}
|
||||
|
||||
type TierResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
MinPoints int64 `json:"min_points"`
|
||||
Benefits map[string]interface{} `json:"benefits"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListTiersQuery struct {
|
||||
Page int `query:"page" validate:"min=1"`
|
||||
Limit int `query:"limit" validate:"min=1,max=100"`
|
||||
Search string `query:"search"`
|
||||
SortBy string `query:"sort_by" validate:"omitempty,oneof=name min_points created_at updated_at"`
|
||||
SortOrder string `query:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
}
|
||||
196
internal/processor/customer_points_processor.go
Normal file
196
internal/processor/customer_points_processor.go
Normal file
@ -0,0 +1,196 @@
|
||||
package processor
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/mappers"
|
||||
"apskel-pos-be/internal/models"
|
||||
"apskel-pos-be/internal/repository"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CustomerPointsProcessor struct {
|
||||
customerPointsRepo *repository.CustomerPointsRepository
|
||||
}
|
||||
|
||||
func NewCustomerPointsProcessor(customerPointsRepo *repository.CustomerPointsRepository) *CustomerPointsProcessor {
|
||||
return &CustomerPointsProcessor{
|
||||
customerPointsRepo: customerPointsRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateCustomerPoints creates a new customer points record
|
||||
func (p *CustomerPointsProcessor) CreateCustomerPoints(ctx context.Context, req *models.CreateCustomerPointsRequest) (*models.CustomerPointsResponse, error) {
|
||||
// Convert request to entity
|
||||
customerPoints := mappers.ToCustomerPointsEntity(req)
|
||||
|
||||
// Create customer points
|
||||
err := p.customerPointsRepo.Create(ctx, customerPoints)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create customer points: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToCustomerPointsResponse(customerPoints), nil
|
||||
}
|
||||
|
||||
// GetCustomerPoints retrieves customer points by ID
|
||||
func (p *CustomerPointsProcessor) GetCustomerPoints(ctx context.Context, id uuid.UUID) (*models.CustomerPointsResponse, error) {
|
||||
customerPoints, err := p.customerPointsRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("customer points not found: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToCustomerPointsResponse(customerPoints), nil
|
||||
}
|
||||
|
||||
// GetCustomerPointsByCustomerID retrieves customer points by customer ID
|
||||
func (p *CustomerPointsProcessor) GetCustomerPointsByCustomerID(ctx context.Context, customerID uuid.UUID) (*models.CustomerPointsResponse, error) {
|
||||
customerPoints, err := p.customerPointsRepo.EnsureCustomerPoints(ctx, customerID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get customer points: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToCustomerPointsResponse(customerPoints), nil
|
||||
}
|
||||
|
||||
// ListCustomerPoints retrieves customer points with pagination and filtering
|
||||
func (p *CustomerPointsProcessor) ListCustomerPoints(ctx context.Context, query *models.ListCustomerPointsQuery) (*models.PaginatedResponse[models.CustomerPointsResponse], error) {
|
||||
// Set default values
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.Limit <= 0 {
|
||||
query.Limit = 10
|
||||
}
|
||||
if query.Limit > 100 {
|
||||
query.Limit = 100
|
||||
}
|
||||
|
||||
offset := (query.Page - 1) * query.Limit
|
||||
|
||||
// Get customer points from repository
|
||||
customerPoints, total, err := p.customerPointsRepo.List(
|
||||
ctx,
|
||||
offset,
|
||||
query.Limit,
|
||||
query.Search,
|
||||
query.SortBy,
|
||||
query.SortOrder,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list customer points: %w", err)
|
||||
}
|
||||
|
||||
// Convert to responses
|
||||
responses := mappers.ToCustomerPointsResponses(customerPoints)
|
||||
|
||||
// Calculate pagination info
|
||||
totalPages := int((total + int64(query.Limit) - 1) / int64(query.Limit))
|
||||
|
||||
return &models.PaginatedResponse[models.CustomerPointsResponse]{
|
||||
Data: responses,
|
||||
Pagination: models.Pagination{
|
||||
Page: query.Page,
|
||||
Limit: query.Limit,
|
||||
Total: total,
|
||||
TotalPages: totalPages,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateCustomerPoints updates an existing customer points record
|
||||
func (p *CustomerPointsProcessor) UpdateCustomerPoints(ctx context.Context, id uuid.UUID, req *models.UpdateCustomerPointsRequest) (*models.CustomerPointsResponse, error) {
|
||||
// Get existing customer points
|
||||
customerPoints, err := p.customerPointsRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("customer points not found: %w", err)
|
||||
}
|
||||
|
||||
// Update customer points fields
|
||||
mappers.UpdateCustomerPointsEntity(customerPoints, req)
|
||||
|
||||
// Save updated customer points
|
||||
err = p.customerPointsRepo.Update(ctx, customerPoints)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update customer points: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToCustomerPointsResponse(customerPoints), nil
|
||||
}
|
||||
|
||||
// DeleteCustomerPoints deletes a customer points record
|
||||
func (p *CustomerPointsProcessor) DeleteCustomerPoints(ctx context.Context, id uuid.UUID) error {
|
||||
// Get existing customer points
|
||||
_, err := p.customerPointsRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("customer points not found: %w", err)
|
||||
}
|
||||
|
||||
// Delete customer points
|
||||
err = p.customerPointsRepo.Delete(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete customer points: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddPoints adds points to a customer's balance
|
||||
func (p *CustomerPointsProcessor) AddPoints(ctx context.Context, customerID uuid.UUID, points int64) (*models.CustomerPointsResponse, error) {
|
||||
if points <= 0 {
|
||||
return nil, errors.New("points must be greater than 0")
|
||||
}
|
||||
|
||||
// Ensure customer points record exists
|
||||
_, err := p.customerPointsRepo.EnsureCustomerPoints(ctx, customerID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to ensure customer points: %w", err)
|
||||
}
|
||||
|
||||
// Add points
|
||||
err = p.customerPointsRepo.AddPoints(ctx, customerID, points)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add points: %w", err)
|
||||
}
|
||||
|
||||
// Get updated customer points
|
||||
customerPoints, err := p.customerPointsRepo.GetByCustomerID(ctx, customerID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get updated customer points: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToCustomerPointsResponse(customerPoints), nil
|
||||
}
|
||||
|
||||
// DeductPoints deducts points from a customer's balance
|
||||
func (p *CustomerPointsProcessor) DeductPoints(ctx context.Context, customerID uuid.UUID, points int64) (*models.CustomerPointsResponse, error) {
|
||||
if points <= 0 {
|
||||
return nil, errors.New("points must be greater than 0")
|
||||
}
|
||||
|
||||
// Get current customer points
|
||||
customerPoints, err := p.customerPointsRepo.GetByCustomerID(ctx, customerID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("customer points not found: %w", err)
|
||||
}
|
||||
|
||||
if customerPoints.Balance < points {
|
||||
return nil, errors.New("insufficient points balance")
|
||||
}
|
||||
|
||||
// Deduct points
|
||||
err = p.customerPointsRepo.DeductPoints(ctx, customerID, points)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to deduct points: %w", err)
|
||||
}
|
||||
|
||||
// Get updated customer points
|
||||
updatedCustomerPoints, err := p.customerPointsRepo.GetByCustomerID(ctx, customerID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get updated customer points: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToCustomerPointsResponse(updatedCustomerPoints), nil
|
||||
}
|
||||
198
internal/processor/customer_tokens_processor.go
Normal file
198
internal/processor/customer_tokens_processor.go
Normal file
@ -0,0 +1,198 @@
|
||||
package processor
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"apskel-pos-be/internal/mappers"
|
||||
"apskel-pos-be/internal/models"
|
||||
"apskel-pos-be/internal/repository"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CustomerTokensProcessor struct {
|
||||
customerTokensRepo *repository.CustomerTokensRepository
|
||||
}
|
||||
|
||||
func NewCustomerTokensProcessor(customerTokensRepo *repository.CustomerTokensRepository) *CustomerTokensProcessor {
|
||||
return &CustomerTokensProcessor{
|
||||
customerTokensRepo: customerTokensRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateCustomerTokens creates a new customer tokens record
|
||||
func (p *CustomerTokensProcessor) CreateCustomerTokens(ctx context.Context, req *models.CreateCustomerTokensRequest) (*models.CustomerTokensResponse, error) {
|
||||
// Convert request to entity
|
||||
customerTokens := mappers.ToCustomerTokensEntity(req)
|
||||
|
||||
// Create customer tokens
|
||||
err := p.customerTokensRepo.Create(ctx, customerTokens)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create customer tokens: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToCustomerTokensResponse(customerTokens), nil
|
||||
}
|
||||
|
||||
// GetCustomerTokens retrieves customer tokens by ID
|
||||
func (p *CustomerTokensProcessor) GetCustomerTokens(ctx context.Context, id uuid.UUID) (*models.CustomerTokensResponse, error) {
|
||||
customerTokens, err := p.customerTokensRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("customer tokens not found: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToCustomerTokensResponse(customerTokens), nil
|
||||
}
|
||||
|
||||
// GetCustomerTokensByCustomerIDAndType retrieves customer tokens by customer ID and token type
|
||||
func (p *CustomerTokensProcessor) GetCustomerTokensByCustomerIDAndType(ctx context.Context, customerID uuid.UUID, tokenType string) (*models.CustomerTokensResponse, error) {
|
||||
customerTokens, err := p.customerTokensRepo.EnsureCustomerTokens(ctx, customerID, entities.TokenType(tokenType))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get customer tokens: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToCustomerTokensResponse(customerTokens), nil
|
||||
}
|
||||
|
||||
// ListCustomerTokens retrieves customer tokens with pagination and filtering
|
||||
func (p *CustomerTokensProcessor) ListCustomerTokens(ctx context.Context, query *models.ListCustomerTokensQuery) (*models.PaginatedResponse[models.CustomerTokensResponse], error) {
|
||||
// Set default values
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.Limit <= 0 {
|
||||
query.Limit = 10
|
||||
}
|
||||
if query.Limit > 100 {
|
||||
query.Limit = 100
|
||||
}
|
||||
|
||||
offset := (query.Page - 1) * query.Limit
|
||||
|
||||
// Get customer tokens from repository
|
||||
customerTokens, total, err := p.customerTokensRepo.List(
|
||||
ctx,
|
||||
offset,
|
||||
query.Limit,
|
||||
query.Search,
|
||||
query.TokenType,
|
||||
query.SortBy,
|
||||
query.SortOrder,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list customer tokens: %w", err)
|
||||
}
|
||||
|
||||
// Convert to responses
|
||||
responses := mappers.ToCustomerTokensResponses(customerTokens)
|
||||
|
||||
// Calculate pagination info
|
||||
totalPages := int((total + int64(query.Limit) - 1) / int64(query.Limit))
|
||||
|
||||
return &models.PaginatedResponse[models.CustomerTokensResponse]{
|
||||
Data: responses,
|
||||
Pagination: models.Pagination{
|
||||
Page: query.Page,
|
||||
Limit: query.Limit,
|
||||
Total: total,
|
||||
TotalPages: totalPages,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateCustomerTokens updates an existing customer tokens record
|
||||
func (p *CustomerTokensProcessor) UpdateCustomerTokens(ctx context.Context, id uuid.UUID, req *models.UpdateCustomerTokensRequest) (*models.CustomerTokensResponse, error) {
|
||||
// Get existing customer tokens
|
||||
customerTokens, err := p.customerTokensRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("customer tokens not found: %w", err)
|
||||
}
|
||||
|
||||
// Update customer tokens fields
|
||||
mappers.UpdateCustomerTokensEntity(customerTokens, req)
|
||||
|
||||
// Save updated customer tokens
|
||||
err = p.customerTokensRepo.Update(ctx, customerTokens)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update customer tokens: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToCustomerTokensResponse(customerTokens), nil
|
||||
}
|
||||
|
||||
// DeleteCustomerTokens deletes a customer tokens record
|
||||
func (p *CustomerTokensProcessor) DeleteCustomerTokens(ctx context.Context, id uuid.UUID) error {
|
||||
// Get existing customer tokens
|
||||
_, err := p.customerTokensRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("customer tokens not found: %w", err)
|
||||
}
|
||||
|
||||
// Delete customer tokens
|
||||
err = p.customerTokensRepo.Delete(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete customer tokens: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddTokens adds tokens to a customer's balance
|
||||
func (p *CustomerTokensProcessor) AddTokens(ctx context.Context, customerID uuid.UUID, tokenType string, tokens int64) (*models.CustomerTokensResponse, error) {
|
||||
if tokens <= 0 {
|
||||
return nil, errors.New("tokens must be greater than 0")
|
||||
}
|
||||
|
||||
// Ensure customer tokens record exists
|
||||
_, err := p.customerTokensRepo.EnsureCustomerTokens(ctx, customerID, entities.TokenType(tokenType))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to ensure customer tokens: %w", err)
|
||||
}
|
||||
|
||||
// Add tokens
|
||||
err = p.customerTokensRepo.AddTokens(ctx, customerID, entities.TokenType(tokenType), tokens)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add tokens: %w", err)
|
||||
}
|
||||
|
||||
// Get updated customer tokens
|
||||
customerTokens, err := p.customerTokensRepo.GetByCustomerIDAndType(ctx, customerID, entities.TokenType(tokenType))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get updated customer tokens: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToCustomerTokensResponse(customerTokens), nil
|
||||
}
|
||||
|
||||
// DeductTokens deducts tokens from a customer's balance
|
||||
func (p *CustomerTokensProcessor) DeductTokens(ctx context.Context, customerID uuid.UUID, tokenType string, tokens int64) (*models.CustomerTokensResponse, error) {
|
||||
if tokens <= 0 {
|
||||
return nil, errors.New("tokens must be greater than 0")
|
||||
}
|
||||
|
||||
// Get current customer tokens
|
||||
customerTokens, err := p.customerTokensRepo.GetByCustomerIDAndType(ctx, customerID, entities.TokenType(tokenType))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("customer tokens not found: %w", err)
|
||||
}
|
||||
|
||||
if customerTokens.Balance < tokens {
|
||||
return nil, errors.New("insufficient tokens balance")
|
||||
}
|
||||
|
||||
// Deduct tokens
|
||||
err = p.customerTokensRepo.DeductTokens(ctx, customerID, entities.TokenType(tokenType), tokens)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to deduct tokens: %w", err)
|
||||
}
|
||||
|
||||
// Get updated customer tokens
|
||||
updatedCustomerTokens, err := p.customerTokensRepo.GetByCustomerIDAndType(ctx, customerID, entities.TokenType(tokenType))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get updated customer tokens: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToCustomerTokensResponse(updatedCustomerTokens), nil
|
||||
}
|
||||
239
internal/processor/game_play_processor.go
Normal file
239
internal/processor/game_play_processor.go
Normal file
@ -0,0 +1,239 @@
|
||||
package processor
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"apskel-pos-be/internal/mappers"
|
||||
"apskel-pos-be/internal/models"
|
||||
"apskel-pos-be/internal/repository"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type GamePlayProcessor struct {
|
||||
gamePlayRepo *repository.GamePlayRepository
|
||||
gameRepo *repository.GameRepository
|
||||
gamePrizeRepo *repository.GamePrizeRepository
|
||||
customerTokensRepo *repository.CustomerTokensRepository
|
||||
customerPointsRepo *repository.CustomerPointsRepository
|
||||
}
|
||||
|
||||
func NewGamePlayProcessor(
|
||||
gamePlayRepo *repository.GamePlayRepository,
|
||||
gameRepo *repository.GameRepository,
|
||||
gamePrizeRepo *repository.GamePrizeRepository,
|
||||
customerTokensRepo *repository.CustomerTokensRepository,
|
||||
customerPointsRepo *repository.CustomerPointsRepository,
|
||||
) *GamePlayProcessor {
|
||||
return &GamePlayProcessor{
|
||||
gamePlayRepo: gamePlayRepo,
|
||||
gameRepo: gameRepo,
|
||||
gamePrizeRepo: gamePrizeRepo,
|
||||
customerTokensRepo: customerTokensRepo,
|
||||
customerPointsRepo: customerPointsRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateGamePlay creates a new game play record
|
||||
func (p *GamePlayProcessor) CreateGamePlay(ctx context.Context, req *models.CreateGamePlayRequest) (*models.GamePlayResponse, error) {
|
||||
// Convert request to entity
|
||||
gamePlay := mappers.ToGamePlayEntity(req)
|
||||
|
||||
// Create game play
|
||||
err := p.gamePlayRepo.Create(ctx, gamePlay)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create game play: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToGamePlayResponse(gamePlay), nil
|
||||
}
|
||||
|
||||
// GetGamePlay retrieves a game play by ID
|
||||
func (p *GamePlayProcessor) GetGamePlay(ctx context.Context, id uuid.UUID) (*models.GamePlayResponse, error) {
|
||||
gamePlay, err := p.gamePlayRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("game play not found: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToGamePlayResponse(gamePlay), nil
|
||||
}
|
||||
|
||||
// ListGamePlays retrieves game plays with pagination and filtering
|
||||
func (p *GamePlayProcessor) ListGamePlays(ctx context.Context, query *models.ListGamePlaysQuery) (*models.PaginatedResponse[models.GamePlayResponse], error) {
|
||||
// Set default values
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.Limit <= 0 {
|
||||
query.Limit = 10
|
||||
}
|
||||
if query.Limit > 100 {
|
||||
query.Limit = 100
|
||||
}
|
||||
|
||||
offset := (query.Page - 1) * query.Limit
|
||||
|
||||
// Get game plays from repository
|
||||
gamePlays, total, err := p.gamePlayRepo.List(
|
||||
ctx,
|
||||
offset,
|
||||
query.Limit,
|
||||
query.Search,
|
||||
query.GameID,
|
||||
query.CustomerID,
|
||||
query.PrizeID,
|
||||
query.SortBy,
|
||||
query.SortOrder,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list game plays: %w", err)
|
||||
}
|
||||
|
||||
// Convert to responses
|
||||
responses := mappers.ToGamePlayResponses(gamePlays)
|
||||
|
||||
// Calculate pagination info
|
||||
totalPages := int((total + int64(query.Limit) - 1) / int64(query.Limit))
|
||||
|
||||
return &models.PaginatedResponse[models.GamePlayResponse]{
|
||||
Data: responses,
|
||||
Pagination: models.Pagination{
|
||||
Page: query.Page,
|
||||
Limit: query.Limit,
|
||||
Total: total,
|
||||
TotalPages: totalPages,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// PlayGame handles the game playing logic
|
||||
func (p *GamePlayProcessor) PlayGame(ctx context.Context, req *models.PlayGameRequest) (*models.PlayGameResponse, error) {
|
||||
// Verify game exists and is active
|
||||
game, err := p.gameRepo.GetByID(ctx, req.GameID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("game not found: %w", err)
|
||||
}
|
||||
|
||||
if !game.IsActive {
|
||||
return nil, errors.New("game is not active")
|
||||
}
|
||||
|
||||
// Convert GameType to TokenType
|
||||
tokenType := entities.TokenType(game.Type)
|
||||
|
||||
// Check if customer has enough tokens
|
||||
customerTokens, err := p.customerTokensRepo.GetByCustomerIDAndType(ctx, req.CustomerID, tokenType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("customer tokens not found: %w", err)
|
||||
}
|
||||
|
||||
if customerTokens.Balance < int64(req.TokenUsed) {
|
||||
return nil, errors.New("insufficient tokens")
|
||||
}
|
||||
|
||||
// Deduct tokens
|
||||
err = p.customerTokensRepo.DeductTokens(ctx, req.CustomerID, tokenType, int64(req.TokenUsed))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to deduct tokens: %w", err)
|
||||
}
|
||||
|
||||
// Get available prizes
|
||||
availablePrizes, err := p.gamePrizeRepo.GetAvailablePrizes(ctx, req.GameID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get available prizes: %w", err)
|
||||
}
|
||||
|
||||
if len(availablePrizes) == 0 {
|
||||
return nil, errors.New("no prizes available")
|
||||
}
|
||||
|
||||
// Convert entities to models for prize selection
|
||||
prizeResponses := make([]models.GamePrizeResponse, len(availablePrizes))
|
||||
for i, prize := range availablePrizes {
|
||||
prizeResponses[i] = *mappers.ToGamePrizeResponse(&prize)
|
||||
}
|
||||
|
||||
// Select prize based on weight
|
||||
selectedPrize := p.selectPrizeByWeight(prizeResponses)
|
||||
|
||||
// Generate random seed for audit
|
||||
randomSeed := fmt.Sprintf("%d", time.Now().UnixNano())
|
||||
|
||||
// Create game play record
|
||||
gamePlay := &models.CreateGamePlayRequest{
|
||||
GameID: req.GameID,
|
||||
CustomerID: req.CustomerID,
|
||||
TokenUsed: req.TokenUsed,
|
||||
RandomSeed: &randomSeed,
|
||||
}
|
||||
|
||||
gamePlayEntity := mappers.ToGamePlayEntity(gamePlay)
|
||||
if selectedPrize != nil {
|
||||
gamePlayEntity.PrizeID = &selectedPrize.ID
|
||||
}
|
||||
|
||||
err = p.gamePlayRepo.Create(ctx, gamePlayEntity)
|
||||
if err != nil {
|
||||
// Rollback token deduction
|
||||
p.customerTokensRepo.AddTokens(ctx, req.CustomerID, tokenType, int64(req.TokenUsed))
|
||||
return nil, fmt.Errorf("failed to create game play: %w", err)
|
||||
}
|
||||
|
||||
// Decrease prize stock if prize was won
|
||||
if selectedPrize != nil {
|
||||
err = p.gamePrizeRepo.DecreaseStock(ctx, selectedPrize.ID, 1)
|
||||
if err != nil {
|
||||
// Log error but don't fail the transaction
|
||||
fmt.Printf("Warning: failed to decrease prize stock: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Get updated token balance
|
||||
updatedTokens, err := p.customerTokensRepo.GetByCustomerIDAndType(ctx, req.CustomerID, tokenType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get updated token balance: %w", err)
|
||||
}
|
||||
|
||||
return &models.PlayGameResponse{
|
||||
GamePlay: *mappers.ToGamePlayResponse(gamePlayEntity),
|
||||
PrizeWon: selectedPrize,
|
||||
TokensRemaining: updatedTokens.Balance,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// selectPrizeByWeight selects a prize based on weight distribution
|
||||
func (p *GamePlayProcessor) selectPrizeByWeight(prizes []models.GamePrizeResponse) *models.GamePrizeResponse {
|
||||
if len(prizes) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Calculate total weight
|
||||
totalWeight := 0
|
||||
for _, prize := range prizes {
|
||||
totalWeight += prize.Weight
|
||||
}
|
||||
|
||||
if totalWeight == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generate random number
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
randomNumber := rand.Intn(totalWeight)
|
||||
|
||||
// Select prize based on cumulative weight
|
||||
currentWeight := 0
|
||||
for _, prize := range prizes {
|
||||
currentWeight += prize.Weight
|
||||
if randomNumber < currentWeight {
|
||||
return &prize
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to last prize
|
||||
return &prizes[len(prizes)-1]
|
||||
}
|
||||
148
internal/processor/game_prize_processor.go
Normal file
148
internal/processor/game_prize_processor.go
Normal file
@ -0,0 +1,148 @@
|
||||
package processor
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/mappers"
|
||||
"apskel-pos-be/internal/models"
|
||||
"apskel-pos-be/internal/repository"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type GamePrizeProcessor struct {
|
||||
gamePrizeRepo *repository.GamePrizeRepository
|
||||
}
|
||||
|
||||
func NewGamePrizeProcessor(gamePrizeRepo *repository.GamePrizeRepository) *GamePrizeProcessor {
|
||||
return &GamePrizeProcessor{
|
||||
gamePrizeRepo: gamePrizeRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateGamePrize creates a new game prize
|
||||
func (p *GamePrizeProcessor) CreateGamePrize(ctx context.Context, req *models.CreateGamePrizeRequest) (*models.GamePrizeResponse, error) {
|
||||
// Convert request to entity
|
||||
gamePrize := mappers.ToGamePrizeEntity(req)
|
||||
|
||||
// Create game prize
|
||||
err := p.gamePrizeRepo.Create(ctx, gamePrize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create game prize: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToGamePrizeResponse(gamePrize), nil
|
||||
}
|
||||
|
||||
// GetGamePrize retrieves a game prize by ID
|
||||
func (p *GamePrizeProcessor) GetGamePrize(ctx context.Context, id uuid.UUID) (*models.GamePrizeResponse, error) {
|
||||
gamePrize, err := p.gamePrizeRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("game prize not found: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToGamePrizeResponse(gamePrize), nil
|
||||
}
|
||||
|
||||
// GetGamePrizesByGameID retrieves all prizes for a specific game
|
||||
func (p *GamePrizeProcessor) GetGamePrizesByGameID(ctx context.Context, gameID uuid.UUID) ([]models.GamePrizeResponse, error) {
|
||||
gamePrizes, err := p.gamePrizeRepo.GetByGameID(ctx, gameID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get game prizes: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToGamePrizeResponses(gamePrizes), nil
|
||||
}
|
||||
|
||||
// ListGamePrizes retrieves game prizes with pagination and filtering
|
||||
func (p *GamePrizeProcessor) ListGamePrizes(ctx context.Context, query *models.ListGamePrizesQuery) (*models.PaginatedResponse[models.GamePrizeResponse], error) {
|
||||
// Set default values
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.Limit <= 0 {
|
||||
query.Limit = 10
|
||||
}
|
||||
if query.Limit > 100 {
|
||||
query.Limit = 100
|
||||
}
|
||||
|
||||
offset := (query.Page - 1) * query.Limit
|
||||
|
||||
// Get game prizes from repository
|
||||
gamePrizes, total, err := p.gamePrizeRepo.List(
|
||||
ctx,
|
||||
offset,
|
||||
query.Limit,
|
||||
query.Search,
|
||||
query.GameID,
|
||||
query.SortBy,
|
||||
query.SortOrder,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list game prizes: %w", err)
|
||||
}
|
||||
|
||||
// Convert to responses
|
||||
responses := mappers.ToGamePrizeResponses(gamePrizes)
|
||||
|
||||
// Calculate pagination info
|
||||
totalPages := int((total + int64(query.Limit) - 1) / int64(query.Limit))
|
||||
|
||||
return &models.PaginatedResponse[models.GamePrizeResponse]{
|
||||
Data: responses,
|
||||
Pagination: models.Pagination{
|
||||
Page: query.Page,
|
||||
Limit: query.Limit,
|
||||
Total: total,
|
||||
TotalPages: totalPages,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateGamePrize updates an existing game prize
|
||||
func (p *GamePrizeProcessor) UpdateGamePrize(ctx context.Context, id uuid.UUID, req *models.UpdateGamePrizeRequest) (*models.GamePrizeResponse, error) {
|
||||
// Get existing game prize
|
||||
gamePrize, err := p.gamePrizeRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("game prize not found: %w", err)
|
||||
}
|
||||
|
||||
// Update game prize fields
|
||||
mappers.UpdateGamePrizeEntity(gamePrize, req)
|
||||
|
||||
// Save updated game prize
|
||||
err = p.gamePrizeRepo.Update(ctx, gamePrize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update game prize: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToGamePrizeResponse(gamePrize), nil
|
||||
}
|
||||
|
||||
// DeleteGamePrize deletes a game prize
|
||||
func (p *GamePrizeProcessor) DeleteGamePrize(ctx context.Context, id uuid.UUID) error {
|
||||
// Get existing game prize
|
||||
_, err := p.gamePrizeRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("game prize not found: %w", err)
|
||||
}
|
||||
|
||||
// Delete game prize
|
||||
err = p.gamePrizeRepo.Delete(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete game prize: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAvailablePrizes gets all available prizes for a game (with stock > 0)
|
||||
func (p *GamePrizeProcessor) GetAvailablePrizes(ctx context.Context, gameID uuid.UUID) ([]models.GamePrizeResponse, error) {
|
||||
gamePrizes, err := p.gamePrizeRepo.GetAvailablePrizes(ctx, gameID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get available prizes: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToGamePrizeResponses(gamePrizes), nil
|
||||
}
|
||||
139
internal/processor/game_processor.go
Normal file
139
internal/processor/game_processor.go
Normal file
@ -0,0 +1,139 @@
|
||||
package processor
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/mappers"
|
||||
"apskel-pos-be/internal/models"
|
||||
"apskel-pos-be/internal/repository"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type GameProcessor struct {
|
||||
gameRepo *repository.GameRepository
|
||||
}
|
||||
|
||||
func NewGameProcessor(gameRepo *repository.GameRepository) *GameProcessor {
|
||||
return &GameProcessor{
|
||||
gameRepo: gameRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateGame creates a new game
|
||||
func (p *GameProcessor) CreateGame(ctx context.Context, req *models.CreateGameRequest) (*models.GameResponse, error) {
|
||||
// Convert request to entity
|
||||
game := mappers.ToGameEntity(req)
|
||||
|
||||
// Create game
|
||||
err := p.gameRepo.Create(ctx, game)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create game: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToGameResponse(game), nil
|
||||
}
|
||||
|
||||
// GetGame retrieves a game by ID
|
||||
func (p *GameProcessor) GetGame(ctx context.Context, id uuid.UUID) (*models.GameResponse, error) {
|
||||
game, err := p.gameRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("game not found: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToGameResponse(game), nil
|
||||
}
|
||||
|
||||
// ListGames retrieves games with pagination and filtering
|
||||
func (p *GameProcessor) ListGames(ctx context.Context, query *models.ListGamesQuery) (*models.PaginatedResponse[models.GameResponse], error) {
|
||||
// Set default values
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.Limit <= 0 {
|
||||
query.Limit = 10
|
||||
}
|
||||
if query.Limit > 100 {
|
||||
query.Limit = 100
|
||||
}
|
||||
|
||||
offset := (query.Page - 1) * query.Limit
|
||||
|
||||
// Get games from repository
|
||||
games, total, err := p.gameRepo.List(
|
||||
ctx,
|
||||
offset,
|
||||
query.Limit,
|
||||
query.Search,
|
||||
query.Type,
|
||||
query.IsActive,
|
||||
query.SortBy,
|
||||
query.SortOrder,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list games: %w", err)
|
||||
}
|
||||
|
||||
// Convert to responses
|
||||
responses := mappers.ToGameResponses(games)
|
||||
|
||||
// Calculate pagination info
|
||||
totalPages := int((total + int64(query.Limit) - 1) / int64(query.Limit))
|
||||
|
||||
return &models.PaginatedResponse[models.GameResponse]{
|
||||
Data: responses,
|
||||
Pagination: models.Pagination{
|
||||
Page: query.Page,
|
||||
Limit: query.Limit,
|
||||
Total: total,
|
||||
TotalPages: totalPages,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateGame updates an existing game
|
||||
func (p *GameProcessor) UpdateGame(ctx context.Context, id uuid.UUID, req *models.UpdateGameRequest) (*models.GameResponse, error) {
|
||||
// Get existing game
|
||||
game, err := p.gameRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("game not found: %w", err)
|
||||
}
|
||||
|
||||
// Update game fields
|
||||
mappers.UpdateGameEntity(game, req)
|
||||
|
||||
// Save updated game
|
||||
err = p.gameRepo.Update(ctx, game)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update game: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToGameResponse(game), nil
|
||||
}
|
||||
|
||||
// DeleteGame deletes a game
|
||||
func (p *GameProcessor) DeleteGame(ctx context.Context, id uuid.UUID) error {
|
||||
// Get existing game
|
||||
_, err := p.gameRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("game not found: %w", err)
|
||||
}
|
||||
|
||||
// Delete game
|
||||
err = p.gameRepo.Delete(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete game: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetActiveGames gets all active games
|
||||
func (p *GameProcessor) GetActiveGames(ctx context.Context) ([]models.GameResponse, error) {
|
||||
games, err := p.gameRepo.GetActiveGames(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get active games: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToGameResponses(games), nil
|
||||
}
|
||||
163
internal/processor/omset_tracker_processor.go
Normal file
163
internal/processor/omset_tracker_processor.go
Normal file
@ -0,0 +1,163 @@
|
||||
package processor
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"apskel-pos-be/internal/mappers"
|
||||
"apskel-pos-be/internal/models"
|
||||
"apskel-pos-be/internal/repository"
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type OmsetTrackerProcessor struct {
|
||||
omsetTrackerRepo *repository.OmsetTrackerRepository
|
||||
}
|
||||
|
||||
func NewOmsetTrackerProcessor(omsetTrackerRepo *repository.OmsetTrackerRepository) *OmsetTrackerProcessor {
|
||||
return &OmsetTrackerProcessor{
|
||||
omsetTrackerRepo: omsetTrackerRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateOmsetTracker creates a new omset tracker record
|
||||
func (p *OmsetTrackerProcessor) CreateOmsetTracker(ctx context.Context, req *models.CreateOmsetTrackerRequest) (*models.OmsetTrackerResponse, error) {
|
||||
// Convert request to entity
|
||||
omsetTracker := mappers.ToOmsetTrackerEntity(req)
|
||||
|
||||
// Create omset tracker
|
||||
err := p.omsetTrackerRepo.Create(ctx, omsetTracker)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create omset tracker: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToOmsetTrackerResponse(omsetTracker), nil
|
||||
}
|
||||
|
||||
// GetOmsetTracker retrieves an omset tracker by ID
|
||||
func (p *OmsetTrackerProcessor) GetOmsetTracker(ctx context.Context, id uuid.UUID) (*models.OmsetTrackerResponse, error) {
|
||||
omsetTracker, err := p.omsetTrackerRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("omset tracker not found: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToOmsetTrackerResponse(omsetTracker), nil
|
||||
}
|
||||
|
||||
// ListOmsetTrackers retrieves omset trackers with pagination and filtering
|
||||
func (p *OmsetTrackerProcessor) ListOmsetTrackers(ctx context.Context, query *models.ListOmsetTrackerQuery) (*models.PaginatedResponse[models.OmsetTrackerResponse], error) {
|
||||
// Set default values
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.Limit <= 0 {
|
||||
query.Limit = 10
|
||||
}
|
||||
if query.Limit > 100 {
|
||||
query.Limit = 100
|
||||
}
|
||||
|
||||
offset := (query.Page - 1) * query.Limit
|
||||
|
||||
// Get omset trackers from repository
|
||||
omsetTrackers, total, err := p.omsetTrackerRepo.List(
|
||||
ctx,
|
||||
offset,
|
||||
query.Limit,
|
||||
query.Search,
|
||||
query.PeriodType,
|
||||
query.GameID,
|
||||
query.From,
|
||||
query.To,
|
||||
query.SortBy,
|
||||
query.SortOrder,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list omset trackers: %w", err)
|
||||
}
|
||||
|
||||
// Convert to responses
|
||||
responses := mappers.ToOmsetTrackerResponses(omsetTrackers)
|
||||
|
||||
// Calculate pagination info
|
||||
totalPages := int((total + int64(query.Limit) - 1) / int64(query.Limit))
|
||||
|
||||
return &models.PaginatedResponse[models.OmsetTrackerResponse]{
|
||||
Data: responses,
|
||||
Pagination: models.Pagination{
|
||||
Page: query.Page,
|
||||
Limit: query.Limit,
|
||||
Total: total,
|
||||
TotalPages: totalPages,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateOmsetTracker updates an existing omset tracker
|
||||
func (p *OmsetTrackerProcessor) UpdateOmsetTracker(ctx context.Context, id uuid.UUID, req *models.UpdateOmsetTrackerRequest) (*models.OmsetTrackerResponse, error) {
|
||||
// Get existing omset tracker
|
||||
omsetTracker, err := p.omsetTrackerRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("omset tracker not found: %w", err)
|
||||
}
|
||||
|
||||
// Update omset tracker fields
|
||||
mappers.UpdateOmsetTrackerEntity(omsetTracker, req)
|
||||
|
||||
// Save updated omset tracker
|
||||
err = p.omsetTrackerRepo.Update(ctx, omsetTracker)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update omset tracker: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToOmsetTrackerResponse(omsetTracker), nil
|
||||
}
|
||||
|
||||
// DeleteOmsetTracker deletes an omset tracker
|
||||
func (p *OmsetTrackerProcessor) DeleteOmsetTracker(ctx context.Context, id uuid.UUID) error {
|
||||
// Get existing omset tracker
|
||||
_, err := p.omsetTrackerRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("omset tracker not found: %w", err)
|
||||
}
|
||||
|
||||
// Delete omset tracker
|
||||
err = p.omsetTrackerRepo.Delete(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete omset tracker: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddOmset adds omset to a specific period
|
||||
func (p *OmsetTrackerProcessor) AddOmset(ctx context.Context, periodType string, periodStart, periodEnd time.Time, amount int64, gameID *uuid.UUID) (*models.OmsetTrackerResponse, error) {
|
||||
if amount <= 0 {
|
||||
return nil, fmt.Errorf("amount must be greater than 0")
|
||||
}
|
||||
|
||||
// Convert string to PeriodType
|
||||
periodTypeEnum := entities.PeriodType(periodType)
|
||||
|
||||
// Get or create period tracker
|
||||
omsetTracker, err := p.omsetTrackerRepo.GetOrCreatePeriod(ctx, periodTypeEnum, periodStart, periodEnd, gameID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get or create period tracker: %w", err)
|
||||
}
|
||||
|
||||
// Add omset
|
||||
err = p.omsetTrackerRepo.AddOmset(ctx, periodTypeEnum, periodStart, periodEnd, amount, gameID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add omset: %w", err)
|
||||
}
|
||||
|
||||
// Get updated tracker
|
||||
updatedTracker, err := p.omsetTrackerRepo.GetByID(ctx, omsetTracker.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get updated tracker: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToOmsetTrackerResponse(updatedTracker), nil
|
||||
}
|
||||
137
internal/processor/tier_processor.go
Normal file
137
internal/processor/tier_processor.go
Normal file
@ -0,0 +1,137 @@
|
||||
package processor
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/mappers"
|
||||
"apskel-pos-be/internal/models"
|
||||
"apskel-pos-be/internal/repository"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type TierProcessor struct {
|
||||
tierRepo *repository.TierRepository
|
||||
}
|
||||
|
||||
func NewTierProcessor(tierRepo *repository.TierRepository) *TierProcessor {
|
||||
return &TierProcessor{
|
||||
tierRepo: tierRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateTier creates a new tier
|
||||
func (p *TierProcessor) CreateTier(ctx context.Context, req *models.CreateTierRequest) (*models.TierResponse, error) {
|
||||
// Convert request to entity
|
||||
tier := mappers.ToTierEntity(req)
|
||||
|
||||
// Create tier
|
||||
err := p.tierRepo.Create(ctx, tier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create tier: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToTierResponse(tier), nil
|
||||
}
|
||||
|
||||
// GetTier retrieves a tier by ID
|
||||
func (p *TierProcessor) GetTier(ctx context.Context, id uuid.UUID) (*models.TierResponse, error) {
|
||||
tier, err := p.tierRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tier not found: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToTierResponse(tier), nil
|
||||
}
|
||||
|
||||
// ListTiers retrieves tiers with pagination and filtering
|
||||
func (p *TierProcessor) ListTiers(ctx context.Context, query *models.ListTiersQuery) (*models.PaginatedResponse[models.TierResponse], error) {
|
||||
// Set default values
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.Limit <= 0 {
|
||||
query.Limit = 10
|
||||
}
|
||||
if query.Limit > 100 {
|
||||
query.Limit = 100
|
||||
}
|
||||
|
||||
offset := (query.Page - 1) * query.Limit
|
||||
|
||||
// Get tiers from repository
|
||||
tiers, total, err := p.tierRepo.List(
|
||||
ctx,
|
||||
offset,
|
||||
query.Limit,
|
||||
query.Search,
|
||||
query.SortBy,
|
||||
query.SortOrder,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list tiers: %w", err)
|
||||
}
|
||||
|
||||
// Convert to responses
|
||||
responses := mappers.ToTierResponses(tiers)
|
||||
|
||||
// Calculate pagination info
|
||||
totalPages := int((total + int64(query.Limit) - 1) / int64(query.Limit))
|
||||
|
||||
return &models.PaginatedResponse[models.TierResponse]{
|
||||
Data: responses,
|
||||
Pagination: models.Pagination{
|
||||
Page: query.Page,
|
||||
Limit: query.Limit,
|
||||
Total: total,
|
||||
TotalPages: totalPages,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateTier updates an existing tier
|
||||
func (p *TierProcessor) UpdateTier(ctx context.Context, id uuid.UUID, req *models.UpdateTierRequest) (*models.TierResponse, error) {
|
||||
// Get existing tier
|
||||
tier, err := p.tierRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tier not found: %w", err)
|
||||
}
|
||||
|
||||
// Update tier fields
|
||||
mappers.UpdateTierEntity(tier, req)
|
||||
|
||||
// Save updated tier
|
||||
err = p.tierRepo.Update(ctx, tier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update tier: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToTierResponse(tier), nil
|
||||
}
|
||||
|
||||
// DeleteTier deletes a tier
|
||||
func (p *TierProcessor) DeleteTier(ctx context.Context, id uuid.UUID) error {
|
||||
// Get existing tier
|
||||
_, err := p.tierRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("tier not found: %w", err)
|
||||
}
|
||||
|
||||
// Delete tier
|
||||
err = p.tierRepo.Delete(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete tier: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTierByPoints gets the appropriate tier for a given point amount
|
||||
func (p *TierProcessor) GetTierByPoints(ctx context.Context, points int64) (*models.TierResponse, error) {
|
||||
tier, err := p.tierRepo.GetTierByPoints(ctx, points)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tier not found for points: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ToTierResponse(tier), nil
|
||||
}
|
||||
117
internal/repository/customer_points_repository.go
Normal file
117
internal/repository/customer_points_repository.go
Normal file
@ -0,0 +1,117 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type CustomerPointsRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewCustomerPointsRepository(db *gorm.DB) *CustomerPointsRepository {
|
||||
return &CustomerPointsRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *CustomerPointsRepository) Create(ctx context.Context, customerPoints *entities.CustomerPoints) error {
|
||||
return r.db.WithContext(ctx).Create(customerPoints).Error
|
||||
}
|
||||
|
||||
func (r *CustomerPointsRepository) GetByID(ctx context.Context, id uuid.UUID) (*entities.CustomerPoints, error) {
|
||||
var customerPoints entities.CustomerPoints
|
||||
err := r.db.WithContext(ctx).Preload("Customer").Where("id = ?", id).First(&customerPoints).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &customerPoints, nil
|
||||
}
|
||||
|
||||
func (r *CustomerPointsRepository) GetByCustomerID(ctx context.Context, customerID uuid.UUID) (*entities.CustomerPoints, error) {
|
||||
var customerPoints entities.CustomerPoints
|
||||
err := r.db.WithContext(ctx).Preload("Customer").Where("customer_id = ?", customerID).First(&customerPoints).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &customerPoints, nil
|
||||
}
|
||||
|
||||
func (r *CustomerPointsRepository) List(ctx context.Context, offset, limit int, search string, sortBy, sortOrder string) ([]entities.CustomerPoints, int64, error) {
|
||||
var customerPoints []entities.CustomerPoints
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Preload("Customer")
|
||||
|
||||
if search != "" {
|
||||
searchTerm := "%" + search + "%"
|
||||
query = query.Joins("JOIN customers ON customer_points.customer_id = customers.id").
|
||||
Where("customers.name ILIKE ? OR customers.email ILIKE ?", searchTerm, searchTerm)
|
||||
}
|
||||
|
||||
if err := query.Model(&entities.CustomerPoints{}).Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if sortBy != "" {
|
||||
if sortOrder == "" {
|
||||
sortOrder = "asc"
|
||||
}
|
||||
query = query.Order(fmt.Sprintf("customer_points.%s %s", sortBy, sortOrder))
|
||||
} else {
|
||||
query = query.Order("customer_points.created_at DESC")
|
||||
}
|
||||
|
||||
err := query.Offset(offset).Limit(limit).Find(&customerPoints).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return customerPoints, total, nil
|
||||
}
|
||||
|
||||
func (r *CustomerPointsRepository) Update(ctx context.Context, customerPoints *entities.CustomerPoints) error {
|
||||
return r.db.WithContext(ctx).Save(customerPoints).Error
|
||||
}
|
||||
|
||||
func (r *CustomerPointsRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
return r.db.WithContext(ctx).Delete(&entities.CustomerPoints{}, id).Error
|
||||
}
|
||||
|
||||
func (r *CustomerPointsRepository) AddPoints(ctx context.Context, customerID uuid.UUID, points int64) error {
|
||||
return r.db.WithContext(ctx).Model(&entities.CustomerPoints{}).
|
||||
Where("customer_id = ?", customerID).
|
||||
Update("balance", gorm.Expr("balance + ?", points)).Error
|
||||
}
|
||||
|
||||
func (r *CustomerPointsRepository) DeductPoints(ctx context.Context, customerID uuid.UUID, points int64) error {
|
||||
return r.db.WithContext(ctx).Model(&entities.CustomerPoints{}).
|
||||
Where("customer_id = ? AND balance >= ?", customerID, points).
|
||||
Update("balance", gorm.Expr("balance - ?", points)).Error
|
||||
}
|
||||
|
||||
func (r *CustomerPointsRepository) EnsureCustomerPoints(ctx context.Context, customerID uuid.UUID) (*entities.CustomerPoints, error) {
|
||||
customerPoints, err := r.GetByCustomerID(ctx, customerID)
|
||||
if err == nil {
|
||||
return customerPoints, nil
|
||||
}
|
||||
|
||||
if err != gorm.ErrRecordNotFound {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create new customer points record
|
||||
newCustomerPoints := &entities.CustomerPoints{
|
||||
CustomerID: customerID,
|
||||
Balance: 0,
|
||||
}
|
||||
|
||||
err = r.Create(ctx, newCustomerPoints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newCustomerPoints, nil
|
||||
}
|
||||
131
internal/repository/customer_tokens_repository.go
Normal file
131
internal/repository/customer_tokens_repository.go
Normal file
@ -0,0 +1,131 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type CustomerTokensRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewCustomerTokensRepository(db *gorm.DB) *CustomerTokensRepository {
|
||||
return &CustomerTokensRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *CustomerTokensRepository) Create(ctx context.Context, customerTokens *entities.CustomerTokens) error {
|
||||
return r.db.WithContext(ctx).Create(customerTokens).Error
|
||||
}
|
||||
|
||||
func (r *CustomerTokensRepository) GetByID(ctx context.Context, id uuid.UUID) (*entities.CustomerTokens, error) {
|
||||
var customerTokens entities.CustomerTokens
|
||||
err := r.db.WithContext(ctx).Preload("Customer").Where("id = ?", id).First(&customerTokens).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &customerTokens, nil
|
||||
}
|
||||
|
||||
func (r *CustomerTokensRepository) GetByCustomerIDAndType(ctx context.Context, customerID uuid.UUID, tokenType entities.TokenType) (*entities.CustomerTokens, error) {
|
||||
var customerTokens entities.CustomerTokens
|
||||
err := r.db.WithContext(ctx).Preload("Customer").Where("customer_id = ? AND token_type = ?", customerID, tokenType).First(&customerTokens).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &customerTokens, nil
|
||||
}
|
||||
|
||||
func (r *CustomerTokensRepository) GetByCustomerID(ctx context.Context, customerID uuid.UUID) ([]entities.CustomerTokens, error) {
|
||||
var customerTokens []entities.CustomerTokens
|
||||
err := r.db.WithContext(ctx).Preload("Customer").Where("customer_id = ?", customerID).Find(&customerTokens).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return customerTokens, nil
|
||||
}
|
||||
|
||||
func (r *CustomerTokensRepository) List(ctx context.Context, offset, limit int, search, tokenType string, sortBy, sortOrder string) ([]entities.CustomerTokens, int64, error) {
|
||||
var customerTokens []entities.CustomerTokens
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Preload("Customer")
|
||||
|
||||
if search != "" {
|
||||
searchTerm := "%" + search + "%"
|
||||
query = query.Joins("JOIN customers ON customer_tokens.customer_id = customers.id").
|
||||
Where("customers.name ILIKE ? OR customers.email ILIKE ?", searchTerm, searchTerm)
|
||||
}
|
||||
|
||||
if tokenType != "" {
|
||||
query = query.Where("token_type = ?", tokenType)
|
||||
}
|
||||
|
||||
if err := query.Model(&entities.CustomerTokens{}).Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if sortBy != "" {
|
||||
if sortOrder == "" {
|
||||
sortOrder = "asc"
|
||||
}
|
||||
query = query.Order(fmt.Sprintf("customer_tokens.%s %s", sortBy, sortOrder))
|
||||
} else {
|
||||
query = query.Order("customer_tokens.created_at DESC")
|
||||
}
|
||||
|
||||
err := query.Offset(offset).Limit(limit).Find(&customerTokens).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return customerTokens, total, nil
|
||||
}
|
||||
|
||||
func (r *CustomerTokensRepository) Update(ctx context.Context, customerTokens *entities.CustomerTokens) error {
|
||||
return r.db.WithContext(ctx).Save(customerTokens).Error
|
||||
}
|
||||
|
||||
func (r *CustomerTokensRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
return r.db.WithContext(ctx).Delete(&entities.CustomerTokens{}, id).Error
|
||||
}
|
||||
|
||||
func (r *CustomerTokensRepository) AddTokens(ctx context.Context, customerID uuid.UUID, tokenType entities.TokenType, tokens int64) error {
|
||||
return r.db.WithContext(ctx).Model(&entities.CustomerTokens{}).
|
||||
Where("customer_id = ? AND token_type = ?", customerID, tokenType).
|
||||
Update("balance", gorm.Expr("balance + ?", tokens)).Error
|
||||
}
|
||||
|
||||
func (r *CustomerTokensRepository) DeductTokens(ctx context.Context, customerID uuid.UUID, tokenType entities.TokenType, tokens int64) error {
|
||||
return r.db.WithContext(ctx).Model(&entities.CustomerTokens{}).
|
||||
Where("customer_id = ? AND token_type = ? AND balance >= ?", customerID, tokenType, tokens).
|
||||
Update("balance", gorm.Expr("balance - ?", tokens)).Error
|
||||
}
|
||||
|
||||
func (r *CustomerTokensRepository) EnsureCustomerTokens(ctx context.Context, customerID uuid.UUID, tokenType entities.TokenType) (*entities.CustomerTokens, error) {
|
||||
customerTokens, err := r.GetByCustomerIDAndType(ctx, customerID, tokenType)
|
||||
if err == nil {
|
||||
return customerTokens, nil
|
||||
}
|
||||
|
||||
if err != gorm.ErrRecordNotFound {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create new customer tokens record
|
||||
newCustomerTokens := &entities.CustomerTokens{
|
||||
CustomerID: customerID,
|
||||
TokenType: tokenType,
|
||||
Balance: 0,
|
||||
}
|
||||
|
||||
err = r.Create(ctx, newCustomerTokens)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newCustomerTokens, nil
|
||||
}
|
||||
111
internal/repository/game_play_repository.go
Normal file
111
internal/repository/game_play_repository.go
Normal file
@ -0,0 +1,111 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type GamePlayRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewGamePlayRepository(db *gorm.DB) *GamePlayRepository {
|
||||
return &GamePlayRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *GamePlayRepository) Create(ctx context.Context, gamePlay *entities.GamePlay) error {
|
||||
return r.db.WithContext(ctx).Create(gamePlay).Error
|
||||
}
|
||||
|
||||
func (r *GamePlayRepository) GetByID(ctx context.Context, id uuid.UUID) (*entities.GamePlay, error) {
|
||||
var gamePlay entities.GamePlay
|
||||
err := r.db.WithContext(ctx).Preload("Game").Preload("Customer").Preload("Prize").Where("id = ?", id).First(&gamePlay).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &gamePlay, nil
|
||||
}
|
||||
|
||||
func (r *GamePlayRepository) List(ctx context.Context, offset, limit int, search string, gameID, customerID, prizeID *uuid.UUID, sortBy, sortOrder string) ([]entities.GamePlay, int64, error) {
|
||||
var gamePlays []entities.GamePlay
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Preload("Game").Preload("Customer").Preload("Prize")
|
||||
|
||||
if search != "" {
|
||||
searchTerm := "%" + search + "%"
|
||||
query = query.Joins("JOIN customers ON game_plays.customer_id = customers.id").
|
||||
Where("customers.name ILIKE ? OR customers.email ILIKE ?", searchTerm, searchTerm)
|
||||
}
|
||||
|
||||
if gameID != nil {
|
||||
query = query.Where("game_id = ?", *gameID)
|
||||
}
|
||||
|
||||
if customerID != nil {
|
||||
query = query.Where("customer_id = ?", *customerID)
|
||||
}
|
||||
|
||||
if prizeID != nil {
|
||||
query = query.Where("prize_id = ?", *prizeID)
|
||||
}
|
||||
|
||||
if err := query.Model(&entities.GamePlay{}).Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if sortBy != "" {
|
||||
if sortOrder == "" {
|
||||
sortOrder = "asc"
|
||||
}
|
||||
query = query.Order(fmt.Sprintf("game_plays.%s %s", sortBy, sortOrder))
|
||||
} else {
|
||||
query = query.Order("game_plays.created_at DESC")
|
||||
}
|
||||
|
||||
err := query.Offset(offset).Limit(limit).Find(&gamePlays).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return gamePlays, total, nil
|
||||
}
|
||||
|
||||
func (r *GamePlayRepository) Update(ctx context.Context, gamePlay *entities.GamePlay) error {
|
||||
return r.db.WithContext(ctx).Save(gamePlay).Error
|
||||
}
|
||||
|
||||
func (r *GamePlayRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
return r.db.WithContext(ctx).Delete(&entities.GamePlay{}, id).Error
|
||||
}
|
||||
|
||||
func (r *GamePlayRepository) GetCustomerPlays(ctx context.Context, customerID uuid.UUID, limit int) ([]entities.GamePlay, error) {
|
||||
var gamePlays []entities.GamePlay
|
||||
err := r.db.WithContext(ctx).Preload("Game").Preload("Prize").
|
||||
Where("customer_id = ?", customerID).
|
||||
Order("created_at DESC").
|
||||
Limit(limit).
|
||||
Find(&gamePlays).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gamePlays, nil
|
||||
}
|
||||
|
||||
func (r *GamePlayRepository) GetGameStats(ctx context.Context, gameID uuid.UUID) (map[string]interface{}, error) {
|
||||
var stats map[string]interface{}
|
||||
|
||||
err := r.db.WithContext(ctx).Model(&entities.GamePlay{}).
|
||||
Select("COUNT(*) as total_plays, SUM(token_used) as total_tokens_used").
|
||||
Where("game_id = ?", gameID).
|
||||
Scan(&stats).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
102
internal/repository/game_prize_repository.go
Normal file
102
internal/repository/game_prize_repository.go
Normal file
@ -0,0 +1,102 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type GamePrizeRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewGamePrizeRepository(db *gorm.DB) *GamePrizeRepository {
|
||||
return &GamePrizeRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *GamePrizeRepository) Create(ctx context.Context, gamePrize *entities.GamePrize) error {
|
||||
return r.db.WithContext(ctx).Create(gamePrize).Error
|
||||
}
|
||||
|
||||
func (r *GamePrizeRepository) GetByID(ctx context.Context, id uuid.UUID) (*entities.GamePrize, error) {
|
||||
var gamePrize entities.GamePrize
|
||||
err := r.db.WithContext(ctx).Preload("Game").Preload("FallbackPrize").Where("id = ?", id).First(&gamePrize).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &gamePrize, nil
|
||||
}
|
||||
|
||||
func (r *GamePrizeRepository) GetByGameID(ctx context.Context, gameID uuid.UUID) ([]entities.GamePrize, error) {
|
||||
var gamePrizes []entities.GamePrize
|
||||
err := r.db.WithContext(ctx).Preload("Game").Preload("FallbackPrize").Where("game_id = ?", gameID).Find(&gamePrizes).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gamePrizes, nil
|
||||
}
|
||||
|
||||
func (r *GamePrizeRepository) List(ctx context.Context, offset, limit int, search string, gameID *uuid.UUID, sortBy, sortOrder string) ([]entities.GamePrize, int64, error) {
|
||||
var gamePrizes []entities.GamePrize
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Preload("Game").Preload("FallbackPrize")
|
||||
|
||||
if search != "" {
|
||||
searchTerm := "%" + search + "%"
|
||||
query = query.Where("name ILIKE ?", searchTerm)
|
||||
}
|
||||
|
||||
if gameID != nil {
|
||||
query = query.Where("game_id = ?", *gameID)
|
||||
}
|
||||
|
||||
if err := query.Model(&entities.GamePrize{}).Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if sortBy != "" {
|
||||
if sortOrder == "" {
|
||||
sortOrder = "asc"
|
||||
}
|
||||
query = query.Order(fmt.Sprintf("game_prizes.%s %s", sortBy, sortOrder))
|
||||
} else {
|
||||
query = query.Order("game_prizes.weight DESC")
|
||||
}
|
||||
|
||||
err := query.Offset(offset).Limit(limit).Find(&gamePrizes).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return gamePrizes, total, nil
|
||||
}
|
||||
|
||||
func (r *GamePrizeRepository) Update(ctx context.Context, gamePrize *entities.GamePrize) error {
|
||||
return r.db.WithContext(ctx).Save(gamePrize).Error
|
||||
}
|
||||
|
||||
func (r *GamePrizeRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
return r.db.WithContext(ctx).Delete(&entities.GamePrize{}, id).Error
|
||||
}
|
||||
|
||||
func (r *GamePrizeRepository) DecreaseStock(ctx context.Context, id uuid.UUID, amount int) error {
|
||||
return r.db.WithContext(ctx).Model(&entities.GamePrize{}).
|
||||
Where("id = ? AND stock >= ?", id, amount).
|
||||
Update("stock", gorm.Expr("stock - ?", amount)).Error
|
||||
}
|
||||
|
||||
func (r *GamePrizeRepository) GetAvailablePrizes(ctx context.Context, gameID uuid.UUID) ([]entities.GamePrize, error) {
|
||||
var gamePrizes []entities.GamePrize
|
||||
err := r.db.WithContext(ctx).Preload("Game").Preload("FallbackPrize").
|
||||
Where("game_id = ? AND stock > 0", gameID).
|
||||
Order("weight DESC").
|
||||
Find(&gamePrizes).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gamePrizes, nil
|
||||
}
|
||||
88
internal/repository/game_repository.go
Normal file
88
internal/repository/game_repository.go
Normal file
@ -0,0 +1,88 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type GameRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewGameRepository(db *gorm.DB) *GameRepository {
|
||||
return &GameRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *GameRepository) Create(ctx context.Context, game *entities.Game) error {
|
||||
return r.db.WithContext(ctx).Create(game).Error
|
||||
}
|
||||
|
||||
func (r *GameRepository) GetByID(ctx context.Context, id uuid.UUID) (*entities.Game, error) {
|
||||
var game entities.Game
|
||||
err := r.db.WithContext(ctx).Preload("Prizes").Where("id = ?", id).First(&game).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &game, nil
|
||||
}
|
||||
|
||||
func (r *GameRepository) List(ctx context.Context, offset, limit int, search, gameType string, isActive *bool, sortBy, sortOrder string) ([]entities.Game, int64, error) {
|
||||
var games []entities.Game
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Preload("Prizes")
|
||||
|
||||
if search != "" {
|
||||
searchTerm := "%" + search + "%"
|
||||
query = query.Where("name ILIKE ?", searchTerm)
|
||||
}
|
||||
|
||||
if gameType != "" {
|
||||
query = query.Where("type = ?", gameType)
|
||||
}
|
||||
|
||||
if isActive != nil {
|
||||
query = query.Where("is_active = ?", *isActive)
|
||||
}
|
||||
|
||||
if err := query.Model(&entities.Game{}).Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if sortBy != "" {
|
||||
if sortOrder == "" {
|
||||
sortOrder = "asc"
|
||||
}
|
||||
query = query.Order(fmt.Sprintf("%s %s", sortBy, sortOrder))
|
||||
} else {
|
||||
query = query.Order("created_at DESC")
|
||||
}
|
||||
|
||||
err := query.Offset(offset).Limit(limit).Find(&games).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return games, total, nil
|
||||
}
|
||||
|
||||
func (r *GameRepository) Update(ctx context.Context, game *entities.Game) error {
|
||||
return r.db.WithContext(ctx).Save(game).Error
|
||||
}
|
||||
|
||||
func (r *GameRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
return r.db.WithContext(ctx).Delete(&entities.Game{}, id).Error
|
||||
}
|
||||
|
||||
func (r *GameRepository) GetActiveGames(ctx context.Context) ([]entities.Game, error) {
|
||||
var games []entities.Game
|
||||
err := r.db.WithContext(ctx).Preload("Prizes").Where("is_active = ?", true).Find(&games).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return games, nil
|
||||
}
|
||||
150
internal/repository/omset_tracker_repository.go
Normal file
150
internal/repository/omset_tracker_repository.go
Normal file
@ -0,0 +1,150 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type OmsetTrackerRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewOmsetTrackerRepository(db *gorm.DB) *OmsetTrackerRepository {
|
||||
return &OmsetTrackerRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *OmsetTrackerRepository) Create(ctx context.Context, omsetTracker *entities.OmsetTracker) error {
|
||||
return r.db.WithContext(ctx).Create(omsetTracker).Error
|
||||
}
|
||||
|
||||
func (r *OmsetTrackerRepository) GetByID(ctx context.Context, id uuid.UUID) (*entities.OmsetTracker, error) {
|
||||
var omsetTracker entities.OmsetTracker
|
||||
err := r.db.WithContext(ctx).Preload("Game").Where("id = ?", id).First(&omsetTracker).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &omsetTracker, nil
|
||||
}
|
||||
|
||||
func (r *OmsetTrackerRepository) List(ctx context.Context, offset, limit int, search, periodType string, gameID *uuid.UUID, from, to *time.Time, sortBy, sortOrder string) ([]entities.OmsetTracker, int64, error) {
|
||||
var omsetTrackers []entities.OmsetTracker
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Preload("Game")
|
||||
|
||||
if search != "" {
|
||||
searchTerm := "%" + search + "%"
|
||||
query = query.Joins("LEFT JOIN games ON omset_tracker.game_id = games.id").
|
||||
Where("games.name ILIKE ?", searchTerm)
|
||||
}
|
||||
|
||||
if periodType != "" {
|
||||
query = query.Where("period_type = ?", periodType)
|
||||
}
|
||||
|
||||
if gameID != nil {
|
||||
query = query.Where("game_id = ?", *gameID)
|
||||
}
|
||||
|
||||
if from != nil {
|
||||
query = query.Where("period_start >= ?", *from)
|
||||
}
|
||||
|
||||
if to != nil {
|
||||
query = query.Where("period_end <= ?", *to)
|
||||
}
|
||||
|
||||
if err := query.Model(&entities.OmsetTracker{}).Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if sortBy != "" {
|
||||
if sortOrder == "" {
|
||||
sortOrder = "asc"
|
||||
}
|
||||
query = query.Order(fmt.Sprintf("omset_tracker.%s %s", sortBy, sortOrder))
|
||||
} else {
|
||||
query = query.Order("omset_tracker.period_start DESC")
|
||||
}
|
||||
|
||||
err := query.Offset(offset).Limit(limit).Find(&omsetTrackers).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return omsetTrackers, total, nil
|
||||
}
|
||||
|
||||
func (r *OmsetTrackerRepository) Update(ctx context.Context, omsetTracker *entities.OmsetTracker) error {
|
||||
return r.db.WithContext(ctx).Save(omsetTracker).Error
|
||||
}
|
||||
|
||||
func (r *OmsetTrackerRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
return r.db.WithContext(ctx).Delete(&entities.OmsetTracker{}, id).Error
|
||||
}
|
||||
|
||||
func (r *OmsetTrackerRepository) AddOmset(ctx context.Context, periodType entities.PeriodType, periodStart, periodEnd time.Time, amount int64, gameID *uuid.UUID) error {
|
||||
return r.db.WithContext(ctx).Model(&entities.OmsetTracker{}).
|
||||
Where("period_type = ? AND period_start = ? AND period_end = ? AND game_id = ?", periodType, periodStart, periodEnd, gameID).
|
||||
Update("total", gorm.Expr("total + ?", amount)).Error
|
||||
}
|
||||
|
||||
func (r *OmsetTrackerRepository) GetOrCreatePeriod(ctx context.Context, periodType entities.PeriodType, periodStart, periodEnd time.Time, gameID *uuid.UUID) (*entities.OmsetTracker, error) {
|
||||
var omsetTracker entities.OmsetTracker
|
||||
|
||||
err := r.db.WithContext(ctx).Preload("Game").
|
||||
Where("period_type = ? AND period_start = ? AND period_end = ? AND game_id = ?", periodType, periodStart, periodEnd, gameID).
|
||||
First(&omsetTracker).Error
|
||||
|
||||
if err == nil {
|
||||
return &omsetTracker, nil
|
||||
}
|
||||
|
||||
if err != gorm.ErrRecordNotFound {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create new period
|
||||
newOmsetTracker := &entities.OmsetTracker{
|
||||
PeriodType: periodType,
|
||||
PeriodStart: periodStart,
|
||||
PeriodEnd: periodEnd,
|
||||
Total: 0,
|
||||
GameID: gameID,
|
||||
}
|
||||
|
||||
err = r.Create(ctx, newOmsetTracker)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newOmsetTracker, nil
|
||||
}
|
||||
|
||||
func (r *OmsetTrackerRepository) GetPeriodSummary(ctx context.Context, periodType entities.PeriodType, from, to time.Time) (map[string]interface{}, error) {
|
||||
var summary map[string]interface{}
|
||||
|
||||
query := r.db.WithContext(ctx).Model(&entities.OmsetTracker{}).
|
||||
Select("SUM(total) as total_omset, COUNT(*) as period_count").
|
||||
Where("period_type = ?", periodType)
|
||||
|
||||
if !from.IsZero() {
|
||||
query = query.Where("period_start >= ?", from)
|
||||
}
|
||||
|
||||
if !to.IsZero() {
|
||||
query = query.Where("period_end <= ?", to)
|
||||
}
|
||||
|
||||
err := query.Scan(&summary).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return summary, nil
|
||||
}
|
||||
89
internal/repository/tier_repository.go
Normal file
89
internal/repository/tier_repository.go
Normal file
@ -0,0 +1,89 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/entities"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type TierRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewTierRepository(db *gorm.DB) *TierRepository {
|
||||
return &TierRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *TierRepository) Create(ctx context.Context, tier *entities.Tier) error {
|
||||
return r.db.WithContext(ctx).Create(tier).Error
|
||||
}
|
||||
|
||||
func (r *TierRepository) GetByID(ctx context.Context, id uuid.UUID) (*entities.Tier, error) {
|
||||
var tier entities.Tier
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&tier).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tier, nil
|
||||
}
|
||||
|
||||
func (r *TierRepository) GetByName(ctx context.Context, name string) (*entities.Tier, error) {
|
||||
var tier entities.Tier
|
||||
err := r.db.WithContext(ctx).Where("name = ?", name).First(&tier).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tier, nil
|
||||
}
|
||||
|
||||
func (r *TierRepository) List(ctx context.Context, offset, limit int, search string, sortBy, sortOrder string) ([]entities.Tier, int64, error) {
|
||||
var tiers []entities.Tier
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx)
|
||||
|
||||
if search != "" {
|
||||
searchTerm := "%" + search + "%"
|
||||
query = query.Where("name ILIKE ?", searchTerm)
|
||||
}
|
||||
|
||||
if err := query.Model(&entities.Tier{}).Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if sortBy != "" {
|
||||
if sortOrder == "" {
|
||||
sortOrder = "asc"
|
||||
}
|
||||
query = query.Order(fmt.Sprintf("%s %s", sortBy, sortOrder))
|
||||
} else {
|
||||
query = query.Order("min_points ASC")
|
||||
}
|
||||
|
||||
err := query.Offset(offset).Limit(limit).Find(&tiers).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return tiers, total, nil
|
||||
}
|
||||
|
||||
func (r *TierRepository) Update(ctx context.Context, tier *entities.Tier) error {
|
||||
return r.db.WithContext(ctx).Save(tier).Error
|
||||
}
|
||||
|
||||
func (r *TierRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
return r.db.WithContext(ctx).Delete(&entities.Tier{}, id).Error
|
||||
}
|
||||
|
||||
func (r *TierRepository) GetTierByPoints(ctx context.Context, points int64) (*entities.Tier, error) {
|
||||
var tier entities.Tier
|
||||
err := r.db.WithContext(ctx).Where("min_points <= ?", points).Order("min_points DESC").First(&tier).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tier, nil
|
||||
}
|
||||
@ -40,6 +40,7 @@ type Router struct {
|
||||
chartOfAccountHandler *handler.ChartOfAccountHandler
|
||||
accountHandler *handler.AccountHandler
|
||||
orderIngredientTransactionHandler *handler.OrderIngredientTransactionHandler
|
||||
gamificationHandler *handler.GamificationHandler
|
||||
authMiddleware *middleware.AuthMiddleware
|
||||
}
|
||||
|
||||
@ -90,7 +91,9 @@ func NewRouter(cfg *config.Config,
|
||||
accountService service.AccountService,
|
||||
accountValidator validator.AccountValidator,
|
||||
orderIngredientTransactionService service.OrderIngredientTransactionService,
|
||||
orderIngredientTransactionValidator validator.OrderIngredientTransactionValidator) *Router {
|
||||
orderIngredientTransactionValidator validator.OrderIngredientTransactionValidator,
|
||||
gamificationService service.GamificationService,
|
||||
gamificationValidator validator.GamificationValidator) *Router {
|
||||
|
||||
return &Router{
|
||||
config: cfg,
|
||||
@ -120,6 +123,7 @@ func NewRouter(cfg *config.Config,
|
||||
chartOfAccountHandler: handler.NewChartOfAccountHandler(chartOfAccountService, chartOfAccountValidator),
|
||||
accountHandler: handler.NewAccountHandler(accountService, accountValidator),
|
||||
orderIngredientTransactionHandler: handler.NewOrderIngredientTransactionHandler(&orderIngredientTransactionService, orderIngredientTransactionValidator),
|
||||
gamificationHandler: handler.NewGamificationHandler(gamificationService, gamificationValidator),
|
||||
authMiddleware: authMiddleware,
|
||||
}
|
||||
}
|
||||
@ -426,6 +430,88 @@ func (r *Router) addAppRoutes(rg *gin.Engine) {
|
||||
orderIngredientTransactions.POST("/bulk", r.orderIngredientTransactionHandler.BulkCreateOrderIngredientTransactions)
|
||||
}
|
||||
|
||||
gamification := protected.Group("/marketing")
|
||||
gamification.Use(r.authMiddleware.RequireAdminOrManager())
|
||||
{
|
||||
//customerPoints := gamification.Group("/customer-points")
|
||||
//{
|
||||
// customerPoints.POST("", r.gamificationHandler.CreateCustomerPoints)
|
||||
// customerPoints.GET("", r.gamificationHandler.ListCustomerPoints)
|
||||
// customerPoints.GET("/:id", r.gamificationHandler.GetCustomerPoints)
|
||||
// customerPoints.PUT("/:id", r.gamificationHandler.UpdateCustomerPoints)
|
||||
// customerPoints.DELETE("/:id", r.gamificationHandler.DeleteCustomerPoints)
|
||||
// customerPoints.GET("/customer/:customer_id", r.gamificationHandler.GetCustomerPointsByCustomerID)
|
||||
// customerPoints.POST("/customer/:customer_id/add", r.gamificationHandler.AddCustomerPoints)
|
||||
// customerPoints.POST("/customer/:customer_id/deduct", r.gamificationHandler.DeductCustomerPoints)
|
||||
//}
|
||||
|
||||
// Customer Tokens
|
||||
//customerTokens := gamification.Group("/customer-tokens")
|
||||
//{
|
||||
// customerTokens.POST("", r.gamificationHandler.CreateCustomerTokens)
|
||||
// customerTokens.GET("", r.gamificationHandler.ListCustomerTokens)
|
||||
// customerTokens.GET("/:id", r.gamificationHandler.GetCustomerTokens)
|
||||
// customerTokens.PUT("/:id", r.gamificationHandler.UpdateCustomerTokens)
|
||||
// customerTokens.DELETE("/:id", r.gamificationHandler.DeleteCustomerTokens)
|
||||
// customerTokens.GET("/customer/:customer_id/type/:token_type", r.gamificationHandler.GetCustomerTokensByCustomerIDAndType)
|
||||
// customerTokens.POST("/customer/:customer_id/type/:token_type/add", r.gamificationHandler.AddCustomerTokens)
|
||||
// customerTokens.POST("/customer/:customer_id/type/:token_type/deduct", r.gamificationHandler.DeductCustomerTokens)
|
||||
//}
|
||||
|
||||
// Tiers
|
||||
tiers := gamification.Group("/tiers")
|
||||
{
|
||||
tiers.POST("", r.gamificationHandler.CreateTier)
|
||||
tiers.GET("", r.gamificationHandler.ListTiers)
|
||||
tiers.GET("/:id", r.gamificationHandler.GetTier)
|
||||
tiers.PUT("/:id", r.gamificationHandler.UpdateTier)
|
||||
tiers.DELETE("/:id", r.gamificationHandler.DeleteTier)
|
||||
tiers.GET("/by-points/:points", r.gamificationHandler.GetTierByPoints)
|
||||
}
|
||||
|
||||
// Games
|
||||
games := gamification.Group("/games")
|
||||
{
|
||||
games.POST("", r.gamificationHandler.CreateGame)
|
||||
games.GET("", r.gamificationHandler.ListGames)
|
||||
games.GET("/active", r.gamificationHandler.GetActiveGames)
|
||||
games.GET("/:id", r.gamificationHandler.GetGame)
|
||||
games.PUT("/:id", r.gamificationHandler.UpdateGame)
|
||||
games.DELETE("/:id", r.gamificationHandler.DeleteGame)
|
||||
}
|
||||
|
||||
// Game Prizes
|
||||
gamePrizes := gamification.Group("/game-prizes")
|
||||
{
|
||||
gamePrizes.POST("", r.gamificationHandler.CreateGamePrize)
|
||||
gamePrizes.GET("", r.gamificationHandler.ListGamePrizes)
|
||||
gamePrizes.GET("/:id", r.gamificationHandler.GetGamePrize)
|
||||
gamePrizes.PUT("/:id", r.gamificationHandler.UpdateGamePrize)
|
||||
gamePrizes.DELETE("/:id", r.gamificationHandler.DeleteGamePrize)
|
||||
gamePrizes.GET("/game/:game_id", r.gamificationHandler.GetGamePrizesByGameID)
|
||||
gamePrizes.GET("/game/:game_id/available", r.gamificationHandler.GetAvailablePrizes)
|
||||
}
|
||||
|
||||
//// Game Plays
|
||||
//gamePlays := gamification.Group("/game-plays")
|
||||
//{
|
||||
// gamePlays.POST("", r.gamificationHandler.CreateGamePlay)
|
||||
// gamePlays.GET("", r.gamificationHandler.ListGamePlays)
|
||||
// gamePlays.GET("/:id", r.gamificationHandler.GetGamePlay)
|
||||
// gamePlays.POST("/play", r.gamificationHandler.PlayGame)
|
||||
//}
|
||||
|
||||
// Omset Tracker
|
||||
//omsetTracker := gamification.Group("/omset-tracker")
|
||||
//{
|
||||
// omsetTracker.POST("", r.gamificationHandler.CreateOmsetTracker)
|
||||
// omsetTracker.GET("", r.gamificationHandler.ListOmsetTrackers)
|
||||
// omsetTracker.GET("/:id", r.gamificationHandler.GetOmsetTracker)
|
||||
// omsetTracker.PUT("/:id", r.gamificationHandler.UpdateOmsetTracker)
|
||||
// omsetTracker.DELETE("/:id", r.gamificationHandler.DeleteOmsetTracker)
|
||||
//}
|
||||
}
|
||||
|
||||
outlets := protected.Group("/outlets")
|
||||
outlets.Use(r.authMiddleware.RequireAdminOrManager())
|
||||
{
|
||||
|
||||
466
internal/service/gamification_service.go
Normal file
466
internal/service/gamification_service.go
Normal file
@ -0,0 +1,466 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/contract"
|
||||
"apskel-pos-be/internal/processor"
|
||||
"apskel-pos-be/internal/transformer"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type GamificationService interface {
|
||||
// Customer Points
|
||||
CreateCustomerPoints(ctx context.Context, req *contract.CreateCustomerPointsRequest) (*contract.CustomerPointsResponse, error)
|
||||
GetCustomerPoints(ctx context.Context, id uuid.UUID) (*contract.CustomerPointsResponse, error)
|
||||
GetCustomerPointsByCustomerID(ctx context.Context, customerID uuid.UUID) (*contract.CustomerPointsResponse, error)
|
||||
ListCustomerPoints(ctx context.Context, query *contract.ListCustomerPointsRequest) (*contract.PaginatedCustomerPointsResponse, error)
|
||||
UpdateCustomerPoints(ctx context.Context, id uuid.UUID, req *contract.UpdateCustomerPointsRequest) (*contract.CustomerPointsResponse, error)
|
||||
DeleteCustomerPoints(ctx context.Context, id uuid.UUID) error
|
||||
AddCustomerPoints(ctx context.Context, customerID uuid.UUID, req *contract.AddCustomerPointsRequest) (*contract.CustomerPointsResponse, error)
|
||||
DeductCustomerPoints(ctx context.Context, customerID uuid.UUID, req *contract.DeductCustomerPointsRequest) (*contract.CustomerPointsResponse, error)
|
||||
|
||||
// Customer Tokens
|
||||
CreateCustomerTokens(ctx context.Context, req *contract.CreateCustomerTokensRequest) (*contract.CustomerTokensResponse, error)
|
||||
GetCustomerTokens(ctx context.Context, id uuid.UUID) (*contract.CustomerTokensResponse, error)
|
||||
GetCustomerTokensByCustomerIDAndType(ctx context.Context, customerID uuid.UUID, tokenType string) (*contract.CustomerTokensResponse, error)
|
||||
ListCustomerTokens(ctx context.Context, query *contract.ListCustomerTokensRequest) (*contract.PaginatedCustomerTokensResponse, error)
|
||||
UpdateCustomerTokens(ctx context.Context, id uuid.UUID, req *contract.UpdateCustomerTokensRequest) (*contract.CustomerTokensResponse, error)
|
||||
DeleteCustomerTokens(ctx context.Context, id uuid.UUID) error
|
||||
AddCustomerTokens(ctx context.Context, customerID uuid.UUID, tokenType string, req *contract.AddCustomerTokensRequest) (*contract.CustomerTokensResponse, error)
|
||||
DeductCustomerTokens(ctx context.Context, customerID uuid.UUID, tokenType string, req *contract.DeductCustomerTokensRequest) (*contract.CustomerTokensResponse, error)
|
||||
|
||||
// Tiers
|
||||
CreateTier(ctx context.Context, req *contract.CreateTierRequest) (*contract.TierResponse, error)
|
||||
GetTier(ctx context.Context, id uuid.UUID) (*contract.TierResponse, error)
|
||||
ListTiers(ctx context.Context, query *contract.ListTiersRequest) (*contract.PaginatedTiersResponse, error)
|
||||
UpdateTier(ctx context.Context, id uuid.UUID, req *contract.UpdateTierRequest) (*contract.TierResponse, error)
|
||||
DeleteTier(ctx context.Context, id uuid.UUID) error
|
||||
GetTierByPoints(ctx context.Context, points int64) (*contract.TierResponse, error)
|
||||
|
||||
// Games
|
||||
CreateGame(ctx context.Context, req *contract.CreateGameRequest) (*contract.GameResponse, error)
|
||||
GetGame(ctx context.Context, id uuid.UUID) (*contract.GameResponse, error)
|
||||
ListGames(ctx context.Context, query *contract.ListGamesRequest) (*contract.PaginatedGamesResponse, error)
|
||||
UpdateGame(ctx context.Context, id uuid.UUID, req *contract.UpdateGameRequest) (*contract.GameResponse, error)
|
||||
DeleteGame(ctx context.Context, id uuid.UUID) error
|
||||
GetActiveGames(ctx context.Context) ([]contract.GameResponse, error)
|
||||
|
||||
// Game Prizes
|
||||
CreateGamePrize(ctx context.Context, req *contract.CreateGamePrizeRequest) (*contract.GamePrizeResponse, error)
|
||||
GetGamePrize(ctx context.Context, id uuid.UUID) (*contract.GamePrizeResponse, error)
|
||||
GetGamePrizesByGameID(ctx context.Context, gameID uuid.UUID) ([]contract.GamePrizeResponse, error)
|
||||
ListGamePrizes(ctx context.Context, query *contract.ListGamePrizesRequest) (*contract.PaginatedGamePrizesResponse, error)
|
||||
UpdateGamePrize(ctx context.Context, id uuid.UUID, req *contract.UpdateGamePrizeRequest) (*contract.GamePrizeResponse, error)
|
||||
DeleteGamePrize(ctx context.Context, id uuid.UUID) error
|
||||
GetAvailablePrizes(ctx context.Context, gameID uuid.UUID) ([]contract.GamePrizeResponse, error)
|
||||
|
||||
// Game Plays
|
||||
CreateGamePlay(ctx context.Context, req *contract.CreateGamePlayRequest) (*contract.GamePlayResponse, error)
|
||||
GetGamePlay(ctx context.Context, id uuid.UUID) (*contract.GamePlayResponse, error)
|
||||
ListGamePlays(ctx context.Context, query *contract.ListGamePlaysRequest) (*contract.PaginatedGamePlaysResponse, error)
|
||||
PlayGame(ctx context.Context, req *contract.PlayGameRequest) (*contract.PlayGameResponse, error)
|
||||
|
||||
// Omset Tracker
|
||||
CreateOmsetTracker(ctx context.Context, req *contract.CreateOmsetTrackerRequest) (*contract.OmsetTrackerResponse, error)
|
||||
GetOmsetTracker(ctx context.Context, id uuid.UUID) (*contract.OmsetTrackerResponse, error)
|
||||
ListOmsetTrackers(ctx context.Context, query *contract.ListOmsetTrackerRequest) (*contract.PaginatedOmsetTrackerResponse, error)
|
||||
UpdateOmsetTracker(ctx context.Context, id uuid.UUID, req *contract.UpdateOmsetTrackerRequest) (*contract.OmsetTrackerResponse, error)
|
||||
DeleteOmsetTracker(ctx context.Context, id uuid.UUID) error
|
||||
AddOmset(ctx context.Context, periodType string, periodStart, periodEnd time.Time, amount int64, gameID *uuid.UUID) (*contract.OmsetTrackerResponse, error)
|
||||
}
|
||||
|
||||
type GamificationServiceImpl struct {
|
||||
customerPointsProcessor *processor.CustomerPointsProcessor
|
||||
customerTokensProcessor *processor.CustomerTokensProcessor
|
||||
tierProcessor *processor.TierProcessor
|
||||
gameProcessor *processor.GameProcessor
|
||||
gamePrizeProcessor *processor.GamePrizeProcessor
|
||||
gamePlayProcessor *processor.GamePlayProcessor
|
||||
omsetTrackerProcessor *processor.OmsetTrackerProcessor
|
||||
}
|
||||
|
||||
func NewGamificationService(
|
||||
customerPointsProcessor *processor.CustomerPointsProcessor,
|
||||
customerTokensProcessor *processor.CustomerTokensProcessor,
|
||||
tierProcessor *processor.TierProcessor,
|
||||
gameProcessor *processor.GameProcessor,
|
||||
gamePrizeProcessor *processor.GamePrizeProcessor,
|
||||
gamePlayProcessor *processor.GamePlayProcessor,
|
||||
omsetTrackerProcessor *processor.OmsetTrackerProcessor,
|
||||
) *GamificationServiceImpl {
|
||||
return &GamificationServiceImpl{
|
||||
customerPointsProcessor: customerPointsProcessor,
|
||||
customerTokensProcessor: customerTokensProcessor,
|
||||
tierProcessor: tierProcessor,
|
||||
gameProcessor: gameProcessor,
|
||||
gamePrizeProcessor: gamePrizeProcessor,
|
||||
gamePlayProcessor: gamePlayProcessor,
|
||||
omsetTrackerProcessor: omsetTrackerProcessor,
|
||||
}
|
||||
}
|
||||
|
||||
// Customer Points Service Methods
|
||||
func (s *GamificationServiceImpl) CreateCustomerPoints(ctx context.Context, req *contract.CreateCustomerPointsRequest) (*contract.CustomerPointsResponse, error) {
|
||||
modelReq := transformer.CreateCustomerPointsRequestToModel(req)
|
||||
response, err := s.customerPointsProcessor.CreateCustomerPoints(ctx, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.CustomerPointsModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) GetCustomerPoints(ctx context.Context, id uuid.UUID) (*contract.CustomerPointsResponse, error) {
|
||||
response, err := s.customerPointsProcessor.GetCustomerPoints(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.CustomerPointsModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) GetCustomerPointsByCustomerID(ctx context.Context, customerID uuid.UUID) (*contract.CustomerPointsResponse, error) {
|
||||
response, err := s.customerPointsProcessor.GetCustomerPointsByCustomerID(ctx, customerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.CustomerPointsModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) ListCustomerPoints(ctx context.Context, query *contract.ListCustomerPointsRequest) (*contract.PaginatedCustomerPointsResponse, error) {
|
||||
modelQuery := transformer.ListCustomerPointsRequestToModel(query)
|
||||
response, err := s.customerPointsProcessor.ListCustomerPoints(ctx, modelQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.PaginatedCustomerPointsResponseToContract(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) UpdateCustomerPoints(ctx context.Context, id uuid.UUID, req *contract.UpdateCustomerPointsRequest) (*contract.CustomerPointsResponse, error) {
|
||||
modelReq := transformer.UpdateCustomerPointsRequestToModel(req)
|
||||
response, err := s.customerPointsProcessor.UpdateCustomerPoints(ctx, id, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.CustomerPointsModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) DeleteCustomerPoints(ctx context.Context, id uuid.UUID) error {
|
||||
return s.customerPointsProcessor.DeleteCustomerPoints(ctx, id)
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) AddCustomerPoints(ctx context.Context, customerID uuid.UUID, req *contract.AddCustomerPointsRequest) (*contract.CustomerPointsResponse, error) {
|
||||
response, err := s.customerPointsProcessor.AddPoints(ctx, customerID, req.Points)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.CustomerPointsModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) DeductCustomerPoints(ctx context.Context, customerID uuid.UUID, req *contract.DeductCustomerPointsRequest) (*contract.CustomerPointsResponse, error) {
|
||||
response, err := s.customerPointsProcessor.DeductPoints(ctx, customerID, req.Points)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.CustomerPointsModelToResponse(response), nil
|
||||
}
|
||||
|
||||
// Customer Tokens Service Methods
|
||||
func (s *GamificationServiceImpl) CreateCustomerTokens(ctx context.Context, req *contract.CreateCustomerTokensRequest) (*contract.CustomerTokensResponse, error) {
|
||||
modelReq := transformer.CreateCustomerTokensRequestToModel(req)
|
||||
response, err := s.customerTokensProcessor.CreateCustomerTokens(ctx, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.CustomerTokensModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) GetCustomerTokens(ctx context.Context, id uuid.UUID) (*contract.CustomerTokensResponse, error) {
|
||||
response, err := s.customerTokensProcessor.GetCustomerTokens(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.CustomerTokensModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) GetCustomerTokensByCustomerIDAndType(ctx context.Context, customerID uuid.UUID, tokenType string) (*contract.CustomerTokensResponse, error) {
|
||||
response, err := s.customerTokensProcessor.GetCustomerTokensByCustomerIDAndType(ctx, customerID, tokenType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.CustomerTokensModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) ListCustomerTokens(ctx context.Context, query *contract.ListCustomerTokensRequest) (*contract.PaginatedCustomerTokensResponse, error) {
|
||||
modelQuery := transformer.ListCustomerTokensRequestToModel(query)
|
||||
response, err := s.customerTokensProcessor.ListCustomerTokens(ctx, modelQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.PaginatedCustomerTokensResponseToContract(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) UpdateCustomerTokens(ctx context.Context, id uuid.UUID, req *contract.UpdateCustomerTokensRequest) (*contract.CustomerTokensResponse, error) {
|
||||
modelReq := transformer.UpdateCustomerTokensRequestToModel(req)
|
||||
response, err := s.customerTokensProcessor.UpdateCustomerTokens(ctx, id, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.CustomerTokensModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) DeleteCustomerTokens(ctx context.Context, id uuid.UUID) error {
|
||||
return s.customerTokensProcessor.DeleteCustomerTokens(ctx, id)
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) AddCustomerTokens(ctx context.Context, customerID uuid.UUID, tokenType string, req *contract.AddCustomerTokensRequest) (*contract.CustomerTokensResponse, error) {
|
||||
response, err := s.customerTokensProcessor.AddTokens(ctx, customerID, tokenType, req.Tokens)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.CustomerTokensModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) DeductCustomerTokens(ctx context.Context, customerID uuid.UUID, tokenType string, req *contract.DeductCustomerTokensRequest) (*contract.CustomerTokensResponse, error) {
|
||||
response, err := s.customerTokensProcessor.DeductTokens(ctx, customerID, tokenType, req.Tokens)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.CustomerTokensModelToResponse(response), nil
|
||||
}
|
||||
|
||||
// Tier Service Methods
|
||||
func (s *GamificationServiceImpl) CreateTier(ctx context.Context, req *contract.CreateTierRequest) (*contract.TierResponse, error) {
|
||||
modelReq := transformer.CreateTierRequestToModel(req)
|
||||
response, err := s.tierProcessor.CreateTier(ctx, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.TierModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) GetTier(ctx context.Context, id uuid.UUID) (*contract.TierResponse, error) {
|
||||
response, err := s.tierProcessor.GetTier(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.TierModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) ListTiers(ctx context.Context, query *contract.ListTiersRequest) (*contract.PaginatedTiersResponse, error) {
|
||||
modelQuery := transformer.ListTiersRequestToModel(query)
|
||||
response, err := s.tierProcessor.ListTiers(ctx, modelQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.PaginatedTiersResponseToContract(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) UpdateTier(ctx context.Context, id uuid.UUID, req *contract.UpdateTierRequest) (*contract.TierResponse, error) {
|
||||
modelReq := transformer.UpdateTierRequestToModel(req)
|
||||
response, err := s.tierProcessor.UpdateTier(ctx, id, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.TierModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) DeleteTier(ctx context.Context, id uuid.UUID) error {
|
||||
return s.tierProcessor.DeleteTier(ctx, id)
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) GetTierByPoints(ctx context.Context, points int64) (*contract.TierResponse, error) {
|
||||
response, err := s.tierProcessor.GetTierByPoints(ctx, points)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.TierModelToResponse(response), nil
|
||||
}
|
||||
|
||||
// Game Service Methods
|
||||
func (s *GamificationServiceImpl) CreateGame(ctx context.Context, req *contract.CreateGameRequest) (*contract.GameResponse, error) {
|
||||
modelReq := transformer.CreateGameRequestToModel(req)
|
||||
response, err := s.gameProcessor.CreateGame(ctx, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.GameModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) GetGame(ctx context.Context, id uuid.UUID) (*contract.GameResponse, error) {
|
||||
response, err := s.gameProcessor.GetGame(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.GameModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) ListGames(ctx context.Context, query *contract.ListGamesRequest) (*contract.PaginatedGamesResponse, error) {
|
||||
modelQuery := transformer.ListGamesRequestToModel(query)
|
||||
response, err := s.gameProcessor.ListGames(ctx, modelQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.PaginatedGamesResponseToContract(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) UpdateGame(ctx context.Context, id uuid.UUID, req *contract.UpdateGameRequest) (*contract.GameResponse, error) {
|
||||
modelReq := transformer.UpdateGameRequestToModel(req)
|
||||
response, err := s.gameProcessor.UpdateGame(ctx, id, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.GameModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) DeleteGame(ctx context.Context, id uuid.UUID) error {
|
||||
return s.gameProcessor.DeleteGame(ctx, id)
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) GetActiveGames(ctx context.Context) ([]contract.GameResponse, error) {
|
||||
response, err := s.gameProcessor.GetActiveGames(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.GameModelsToResponses(response), nil
|
||||
}
|
||||
|
||||
// Game Prize Service Methods
|
||||
func (s *GamificationServiceImpl) CreateGamePrize(ctx context.Context, req *contract.CreateGamePrizeRequest) (*contract.GamePrizeResponse, error) {
|
||||
modelReq := transformer.CreateGamePrizeRequestToModel(req)
|
||||
response, err := s.gamePrizeProcessor.CreateGamePrize(ctx, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.GamePrizeModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) GetGamePrize(ctx context.Context, id uuid.UUID) (*contract.GamePrizeResponse, error) {
|
||||
response, err := s.gamePrizeProcessor.GetGamePrize(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.GamePrizeModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) GetGamePrizesByGameID(ctx context.Context, gameID uuid.UUID) ([]contract.GamePrizeResponse, error) {
|
||||
response, err := s.gamePrizeProcessor.GetGamePrizesByGameID(ctx, gameID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.GamePrizeModelsToResponses(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) ListGamePrizes(ctx context.Context, query *contract.ListGamePrizesRequest) (*contract.PaginatedGamePrizesResponse, error) {
|
||||
modelQuery := transformer.ListGamePrizesRequestToModel(query)
|
||||
response, err := s.gamePrizeProcessor.ListGamePrizes(ctx, modelQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.PaginatedGamePrizesResponseToContract(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) UpdateGamePrize(ctx context.Context, id uuid.UUID, req *contract.UpdateGamePrizeRequest) (*contract.GamePrizeResponse, error) {
|
||||
modelReq := transformer.UpdateGamePrizeRequestToModel(req)
|
||||
response, err := s.gamePrizeProcessor.UpdateGamePrize(ctx, id, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.GamePrizeModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) DeleteGamePrize(ctx context.Context, id uuid.UUID) error {
|
||||
return s.gamePrizeProcessor.DeleteGamePrize(ctx, id)
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) GetAvailablePrizes(ctx context.Context, gameID uuid.UUID) ([]contract.GamePrizeResponse, error) {
|
||||
response, err := s.gamePrizeProcessor.GetAvailablePrizes(ctx, gameID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.GamePrizeModelsToResponses(response), nil
|
||||
}
|
||||
|
||||
// Game Play Service Methods
|
||||
func (s *GamificationServiceImpl) CreateGamePlay(ctx context.Context, req *contract.CreateGamePlayRequest) (*contract.GamePlayResponse, error) {
|
||||
modelReq := transformer.CreateGamePlayRequestToModel(req)
|
||||
response, err := s.gamePlayProcessor.CreateGamePlay(ctx, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.GamePlayModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) GetGamePlay(ctx context.Context, id uuid.UUID) (*contract.GamePlayResponse, error) {
|
||||
response, err := s.gamePlayProcessor.GetGamePlay(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.GamePlayModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) ListGamePlays(ctx context.Context, query *contract.ListGamePlaysRequest) (*contract.PaginatedGamePlaysResponse, error) {
|
||||
modelQuery := transformer.ListGamePlaysRequestToModel(query)
|
||||
response, err := s.gamePlayProcessor.ListGamePlays(ctx, modelQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.PaginatedGamePlaysResponseToContract(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) PlayGame(ctx context.Context, req *contract.PlayGameRequest) (*contract.PlayGameResponse, error) {
|
||||
modelReq := transformer.PlayGameRequestToModel(req)
|
||||
response, err := s.gamePlayProcessor.PlayGame(ctx, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.PlayGameModelToResponse(response), nil
|
||||
}
|
||||
|
||||
// Omset Tracker Service Methods
|
||||
func (s *GamificationServiceImpl) CreateOmsetTracker(ctx context.Context, req *contract.CreateOmsetTrackerRequest) (*contract.OmsetTrackerResponse, error) {
|
||||
modelReq := transformer.CreateOmsetTrackerRequestToModel(req)
|
||||
response, err := s.omsetTrackerProcessor.CreateOmsetTracker(ctx, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.OmsetTrackerModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) GetOmsetTracker(ctx context.Context, id uuid.UUID) (*contract.OmsetTrackerResponse, error) {
|
||||
response, err := s.omsetTrackerProcessor.GetOmsetTracker(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.OmsetTrackerModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) ListOmsetTrackers(ctx context.Context, query *contract.ListOmsetTrackerRequest) (*contract.PaginatedOmsetTrackerResponse, error) {
|
||||
modelQuery := transformer.ListOmsetTrackerRequestToModel(query)
|
||||
response, err := s.omsetTrackerProcessor.ListOmsetTrackers(ctx, modelQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.PaginatedOmsetTrackerResponseToContract(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) UpdateOmsetTracker(ctx context.Context, id uuid.UUID, req *contract.UpdateOmsetTrackerRequest) (*contract.OmsetTrackerResponse, error) {
|
||||
modelReq := transformer.UpdateOmsetTrackerRequestToModel(req)
|
||||
response, err := s.omsetTrackerProcessor.UpdateOmsetTracker(ctx, id, modelReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.OmsetTrackerModelToResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) DeleteOmsetTracker(ctx context.Context, id uuid.UUID) error {
|
||||
return s.omsetTrackerProcessor.DeleteOmsetTracker(ctx, id)
|
||||
}
|
||||
|
||||
func (s *GamificationServiceImpl) AddOmset(ctx context.Context, periodType string, periodStart, periodEnd time.Time, amount int64, gameID *uuid.UUID) (*contract.OmsetTrackerResponse, error) {
|
||||
response, err := s.omsetTrackerProcessor.AddOmset(ctx, periodType, periodStart, periodEnd, amount, gameID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transformer.OmsetTrackerModelToResponse(response), nil
|
||||
}
|
||||
439
internal/transformer/gamification_transformer.go
Normal file
439
internal/transformer/gamification_transformer.go
Normal file
@ -0,0 +1,439 @@
|
||||
package transformer
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/contract"
|
||||
"apskel-pos-be/internal/models"
|
||||
)
|
||||
|
||||
// Customer Points Transformers
|
||||
func CreateCustomerPointsRequestToModel(req *contract.CreateCustomerPointsRequest) *models.CreateCustomerPointsRequest {
|
||||
return &models.CreateCustomerPointsRequest{
|
||||
CustomerID: req.CustomerID,
|
||||
Balance: req.Balance,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateCustomerPointsRequestToModel(req *contract.UpdateCustomerPointsRequest) *models.UpdateCustomerPointsRequest {
|
||||
return &models.UpdateCustomerPointsRequest{
|
||||
Balance: req.Balance,
|
||||
}
|
||||
}
|
||||
|
||||
func ListCustomerPointsRequestToModel(req *contract.ListCustomerPointsRequest) *models.ListCustomerPointsQuery {
|
||||
return &models.ListCustomerPointsQuery{
|
||||
Page: req.Page,
|
||||
Limit: req.Limit,
|
||||
Search: req.Search,
|
||||
SortBy: req.SortBy,
|
||||
SortOrder: req.SortOrder,
|
||||
}
|
||||
}
|
||||
|
||||
func CustomerPointsModelToResponse(model *models.CustomerPointsResponse) *contract.CustomerPointsResponse {
|
||||
return &contract.CustomerPointsResponse{
|
||||
ID: model.ID,
|
||||
CustomerID: model.CustomerID,
|
||||
Balance: model.Balance,
|
||||
Customer: CustomerModelToResponse(model.Customer),
|
||||
CreatedAt: model.CreatedAt,
|
||||
UpdatedAt: model.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func PaginatedCustomerPointsResponseToContract(model *models.PaginatedResponse[models.CustomerPointsResponse]) *contract.PaginatedCustomerPointsResponse {
|
||||
responses := make([]contract.CustomerPointsResponse, len(model.Data))
|
||||
for i, item := range model.Data {
|
||||
responses[i] = *CustomerPointsModelToResponse(&item)
|
||||
}
|
||||
|
||||
return &contract.PaginatedCustomerPointsResponse{
|
||||
Data: responses,
|
||||
TotalCount: int(model.Pagination.Total),
|
||||
Page: model.Pagination.Page,
|
||||
Limit: model.Pagination.Limit,
|
||||
TotalPages: model.Pagination.TotalPages,
|
||||
}
|
||||
}
|
||||
|
||||
// Customer Tokens Transformers
|
||||
func CreateCustomerTokensRequestToModel(req *contract.CreateCustomerTokensRequest) *models.CreateCustomerTokensRequest {
|
||||
return &models.CreateCustomerTokensRequest{
|
||||
CustomerID: req.CustomerID,
|
||||
TokenType: req.TokenType,
|
||||
Balance: req.Balance,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateCustomerTokensRequestToModel(req *contract.UpdateCustomerTokensRequest) *models.UpdateCustomerTokensRequest {
|
||||
return &models.UpdateCustomerTokensRequest{
|
||||
Balance: req.Balance,
|
||||
}
|
||||
}
|
||||
|
||||
func ListCustomerTokensRequestToModel(req *contract.ListCustomerTokensRequest) *models.ListCustomerTokensQuery {
|
||||
return &models.ListCustomerTokensQuery{
|
||||
Page: req.Page,
|
||||
Limit: req.Limit,
|
||||
Search: req.Search,
|
||||
TokenType: req.TokenType,
|
||||
SortBy: req.SortBy,
|
||||
SortOrder: req.SortOrder,
|
||||
}
|
||||
}
|
||||
|
||||
func CustomerTokensModelToResponse(model *models.CustomerTokensResponse) *contract.CustomerTokensResponse {
|
||||
return &contract.CustomerTokensResponse{
|
||||
ID: model.ID,
|
||||
CustomerID: model.CustomerID,
|
||||
TokenType: model.TokenType,
|
||||
Balance: model.Balance,
|
||||
Customer: CustomerModelToResponse(model.Customer),
|
||||
CreatedAt: model.CreatedAt,
|
||||
UpdatedAt: model.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func PaginatedCustomerTokensResponseToContract(model *models.PaginatedResponse[models.CustomerTokensResponse]) *contract.PaginatedCustomerTokensResponse {
|
||||
responses := make([]contract.CustomerTokensResponse, len(model.Data))
|
||||
for i, item := range model.Data {
|
||||
responses[i] = *CustomerTokensModelToResponse(&item)
|
||||
}
|
||||
|
||||
return &contract.PaginatedCustomerTokensResponse{
|
||||
Data: responses,
|
||||
TotalCount: int(model.Pagination.Total),
|
||||
Page: model.Pagination.Page,
|
||||
Limit: model.Pagination.Limit,
|
||||
TotalPages: model.Pagination.TotalPages,
|
||||
}
|
||||
}
|
||||
|
||||
// Tier Transformers
|
||||
func CreateTierRequestToModel(req *contract.CreateTierRequest) *models.CreateTierRequest {
|
||||
return &models.CreateTierRequest{
|
||||
Name: req.Name,
|
||||
MinPoints: req.MinPoints,
|
||||
Benefits: req.Benefits,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateTierRequestToModel(req *contract.UpdateTierRequest) *models.UpdateTierRequest {
|
||||
return &models.UpdateTierRequest{
|
||||
Name: req.Name,
|
||||
MinPoints: req.MinPoints,
|
||||
Benefits: req.Benefits,
|
||||
}
|
||||
}
|
||||
|
||||
func ListTiersRequestToModel(req *contract.ListTiersRequest) *models.ListTiersQuery {
|
||||
return &models.ListTiersQuery{
|
||||
Page: req.Page,
|
||||
Limit: req.Limit,
|
||||
Search: req.Search,
|
||||
SortBy: req.SortBy,
|
||||
SortOrder: req.SortOrder,
|
||||
}
|
||||
}
|
||||
|
||||
func TierModelToResponse(model *models.TierResponse) *contract.TierResponse {
|
||||
return &contract.TierResponse{
|
||||
ID: model.ID,
|
||||
Name: model.Name,
|
||||
MinPoints: model.MinPoints,
|
||||
Benefits: model.Benefits,
|
||||
CreatedAt: model.CreatedAt,
|
||||
UpdatedAt: model.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func PaginatedTiersResponseToContract(model *models.PaginatedResponse[models.TierResponse]) *contract.PaginatedTiersResponse {
|
||||
responses := make([]contract.TierResponse, len(model.Data))
|
||||
for i, item := range model.Data {
|
||||
responses[i] = *TierModelToResponse(&item)
|
||||
}
|
||||
|
||||
return &contract.PaginatedTiersResponse{
|
||||
Data: responses,
|
||||
TotalCount: int(model.Pagination.Total),
|
||||
Page: model.Pagination.Page,
|
||||
Limit: model.Pagination.Limit,
|
||||
TotalPages: model.Pagination.TotalPages,
|
||||
}
|
||||
}
|
||||
|
||||
// Game Transformers
|
||||
func CreateGameRequestToModel(req *contract.CreateGameRequest) *models.CreateGameRequest {
|
||||
return &models.CreateGameRequest{
|
||||
Name: req.Name,
|
||||
Type: req.Type,
|
||||
IsActive: req.IsActive,
|
||||
Metadata: req.Metadata,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateGameRequestToModel(req *contract.UpdateGameRequest) *models.UpdateGameRequest {
|
||||
return &models.UpdateGameRequest{
|
||||
Name: req.Name,
|
||||
Type: req.Type,
|
||||
IsActive: req.IsActive,
|
||||
Metadata: req.Metadata,
|
||||
}
|
||||
}
|
||||
|
||||
func ListGamesRequestToModel(req *contract.ListGamesRequest) *models.ListGamesQuery {
|
||||
return &models.ListGamesQuery{
|
||||
Page: req.Page,
|
||||
Limit: req.Limit,
|
||||
Search: req.Search,
|
||||
Type: req.Type,
|
||||
IsActive: req.IsActive,
|
||||
SortBy: req.SortBy,
|
||||
SortOrder: req.SortOrder,
|
||||
}
|
||||
}
|
||||
|
||||
func GameModelToResponse(model *models.GameResponse) *contract.GameResponse {
|
||||
return &contract.GameResponse{
|
||||
ID: model.ID,
|
||||
Name: model.Name,
|
||||
Type: model.Type,
|
||||
IsActive: model.IsActive,
|
||||
Metadata: model.Metadata,
|
||||
CreatedAt: model.CreatedAt,
|
||||
UpdatedAt: model.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func GameModelsToResponses(models []models.GameResponse) []contract.GameResponse {
|
||||
responses := make([]contract.GameResponse, len(models))
|
||||
for i, model := range models {
|
||||
responses[i] = *GameModelToResponse(&model)
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
func PaginatedGamesResponseToContract(model *models.PaginatedResponse[models.GameResponse]) *contract.PaginatedGamesResponse {
|
||||
responses := make([]contract.GameResponse, len(model.Data))
|
||||
for i, item := range model.Data {
|
||||
responses[i] = *GameModelToResponse(&item)
|
||||
}
|
||||
|
||||
return &contract.PaginatedGamesResponse{
|
||||
Data: responses,
|
||||
TotalCount: int(model.Pagination.Total),
|
||||
Page: model.Pagination.Page,
|
||||
Limit: model.Pagination.Limit,
|
||||
TotalPages: model.Pagination.TotalPages,
|
||||
}
|
||||
}
|
||||
|
||||
// Game Prize Transformers
|
||||
func CreateGamePrizeRequestToModel(req *contract.CreateGamePrizeRequest) *models.CreateGamePrizeRequest {
|
||||
return &models.CreateGamePrizeRequest{
|
||||
GameID: req.GameID,
|
||||
Name: req.Name,
|
||||
Weight: req.Weight,
|
||||
Stock: req.Stock,
|
||||
MaxStock: req.MaxStock,
|
||||
Threshold: req.Threshold,
|
||||
FallbackPrizeID: req.FallbackPrizeID,
|
||||
Metadata: req.Metadata,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateGamePrizeRequestToModel(req *contract.UpdateGamePrizeRequest) *models.UpdateGamePrizeRequest {
|
||||
return &models.UpdateGamePrizeRequest{
|
||||
Name: req.Name,
|
||||
Weight: req.Weight,
|
||||
Stock: req.Stock,
|
||||
MaxStock: req.MaxStock,
|
||||
Threshold: req.Threshold,
|
||||
FallbackPrizeID: req.FallbackPrizeID,
|
||||
Metadata: req.Metadata,
|
||||
}
|
||||
}
|
||||
|
||||
func ListGamePrizesRequestToModel(req *contract.ListGamePrizesRequest) *models.ListGamePrizesQuery {
|
||||
return &models.ListGamePrizesQuery{
|
||||
Page: req.Page,
|
||||
Limit: req.Limit,
|
||||
Search: req.Search,
|
||||
GameID: req.GameID,
|
||||
SortBy: req.SortBy,
|
||||
SortOrder: req.SortOrder,
|
||||
}
|
||||
}
|
||||
|
||||
func GamePrizeModelToResponse(model *models.GamePrizeResponse) *contract.GamePrizeResponse {
|
||||
return &contract.GamePrizeResponse{
|
||||
ID: model.ID,
|
||||
GameID: model.GameID,
|
||||
Name: model.Name,
|
||||
Weight: model.Weight,
|
||||
Stock: model.Stock,
|
||||
MaxStock: model.MaxStock,
|
||||
Threshold: model.Threshold,
|
||||
FallbackPrizeID: model.FallbackPrizeID,
|
||||
Metadata: model.Metadata,
|
||||
Game: GameModelToResponse(model.Game),
|
||||
FallbackPrize: GamePrizeModelToResponse(model.FallbackPrize),
|
||||
CreatedAt: model.CreatedAt,
|
||||
UpdatedAt: model.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func GamePrizeModelsToResponses(models []models.GamePrizeResponse) []contract.GamePrizeResponse {
|
||||
responses := make([]contract.GamePrizeResponse, len(models))
|
||||
for i, model := range models {
|
||||
responses[i] = *GamePrizeModelToResponse(&model)
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
func PaginatedGamePrizesResponseToContract(model *models.PaginatedResponse[models.GamePrizeResponse]) *contract.PaginatedGamePrizesResponse {
|
||||
responses := make([]contract.GamePrizeResponse, len(model.Data))
|
||||
for i, item := range model.Data {
|
||||
responses[i] = *GamePrizeModelToResponse(&item)
|
||||
}
|
||||
|
||||
return &contract.PaginatedGamePrizesResponse{
|
||||
Data: responses,
|
||||
TotalCount: int(model.Pagination.Total),
|
||||
Page: model.Pagination.Page,
|
||||
Limit: model.Pagination.Limit,
|
||||
TotalPages: model.Pagination.TotalPages,
|
||||
}
|
||||
}
|
||||
|
||||
// Game Play Transformers
|
||||
func CreateGamePlayRequestToModel(req *contract.CreateGamePlayRequest) *models.CreateGamePlayRequest {
|
||||
return &models.CreateGamePlayRequest{
|
||||
GameID: req.GameID,
|
||||
CustomerID: req.CustomerID,
|
||||
TokenUsed: req.TokenUsed,
|
||||
RandomSeed: req.RandomSeed,
|
||||
}
|
||||
}
|
||||
|
||||
func PlayGameRequestToModel(req *contract.PlayGameRequest) *models.PlayGameRequest {
|
||||
return &models.PlayGameRequest{
|
||||
GameID: req.GameID,
|
||||
CustomerID: req.CustomerID,
|
||||
TokenUsed: req.TokenUsed,
|
||||
}
|
||||
}
|
||||
|
||||
func ListGamePlaysRequestToModel(req *contract.ListGamePlaysRequest) *models.ListGamePlaysQuery {
|
||||
return &models.ListGamePlaysQuery{
|
||||
Page: req.Page,
|
||||
Limit: req.Limit,
|
||||
Search: req.Search,
|
||||
GameID: req.GameID,
|
||||
CustomerID: req.CustomerID,
|
||||
PrizeID: req.PrizeID,
|
||||
SortBy: req.SortBy,
|
||||
SortOrder: req.SortOrder,
|
||||
}
|
||||
}
|
||||
|
||||
func GamePlayModelToResponse(model *models.GamePlayResponse) *contract.GamePlayResponse {
|
||||
return &contract.GamePlayResponse{
|
||||
ID: model.ID,
|
||||
GameID: model.GameID,
|
||||
CustomerID: model.CustomerID,
|
||||
PrizeID: model.PrizeID,
|
||||
TokenUsed: model.TokenUsed,
|
||||
RandomSeed: model.RandomSeed,
|
||||
CreatedAt: model.CreatedAt,
|
||||
Game: GameModelToResponse(model.Game),
|
||||
Customer: CustomerModelToResponse(model.Customer),
|
||||
Prize: GamePrizeModelToResponse(model.Prize),
|
||||
}
|
||||
}
|
||||
|
||||
func PlayGameModelToResponse(model *models.PlayGameResponse) *contract.PlayGameResponse {
|
||||
return &contract.PlayGameResponse{
|
||||
GamePlay: *GamePlayModelToResponse(&model.GamePlay),
|
||||
PrizeWon: GamePrizeModelToResponse(model.PrizeWon),
|
||||
TokensRemaining: model.TokensRemaining,
|
||||
}
|
||||
}
|
||||
|
||||
func PaginatedGamePlaysResponseToContract(model *models.PaginatedResponse[models.GamePlayResponse]) *contract.PaginatedGamePlaysResponse {
|
||||
responses := make([]contract.GamePlayResponse, len(model.Data))
|
||||
for i, item := range model.Data {
|
||||
responses[i] = *GamePlayModelToResponse(&item)
|
||||
}
|
||||
|
||||
return &contract.PaginatedGamePlaysResponse{
|
||||
Data: responses,
|
||||
TotalCount: int(model.Pagination.Total),
|
||||
Page: model.Pagination.Page,
|
||||
Limit: model.Pagination.Limit,
|
||||
TotalPages: model.Pagination.TotalPages,
|
||||
}
|
||||
}
|
||||
|
||||
// Omset Tracker Transformers
|
||||
func CreateOmsetTrackerRequestToModel(req *contract.CreateOmsetTrackerRequest) *models.CreateOmsetTrackerRequest {
|
||||
return &models.CreateOmsetTrackerRequest{
|
||||
PeriodType: req.PeriodType,
|
||||
PeriodStart: req.PeriodStart,
|
||||
PeriodEnd: req.PeriodEnd,
|
||||
Total: req.Total,
|
||||
GameID: req.GameID,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateOmsetTrackerRequestToModel(req *contract.UpdateOmsetTrackerRequest) *models.UpdateOmsetTrackerRequest {
|
||||
return &models.UpdateOmsetTrackerRequest{
|
||||
PeriodType: req.PeriodType,
|
||||
PeriodStart: req.PeriodStart,
|
||||
PeriodEnd: req.PeriodEnd,
|
||||
Total: req.Total,
|
||||
GameID: req.GameID,
|
||||
}
|
||||
}
|
||||
|
||||
func ListOmsetTrackerRequestToModel(req *contract.ListOmsetTrackerRequest) *models.ListOmsetTrackerQuery {
|
||||
return &models.ListOmsetTrackerQuery{
|
||||
Page: req.Page,
|
||||
Limit: req.Limit,
|
||||
Search: req.Search,
|
||||
PeriodType: req.PeriodType,
|
||||
GameID: req.GameID,
|
||||
From: req.From,
|
||||
To: req.To,
|
||||
SortBy: req.SortBy,
|
||||
SortOrder: req.SortOrder,
|
||||
}
|
||||
}
|
||||
|
||||
func OmsetTrackerModelToResponse(model *models.OmsetTrackerResponse) *contract.OmsetTrackerResponse {
|
||||
return &contract.OmsetTrackerResponse{
|
||||
ID: model.ID,
|
||||
PeriodType: model.PeriodType,
|
||||
PeriodStart: model.PeriodStart,
|
||||
PeriodEnd: model.PeriodEnd,
|
||||
Total: model.Total,
|
||||
GameID: model.GameID,
|
||||
Game: GameModelToResponse(model.Game),
|
||||
CreatedAt: model.CreatedAt,
|
||||
UpdatedAt: model.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func PaginatedOmsetTrackerResponseToContract(model *models.PaginatedResponse[models.OmsetTrackerResponse]) *contract.PaginatedOmsetTrackerResponse {
|
||||
responses := make([]contract.OmsetTrackerResponse, len(model.Data))
|
||||
for i, item := range model.Data {
|
||||
responses[i] = *OmsetTrackerModelToResponse(&item)
|
||||
}
|
||||
|
||||
return &contract.PaginatedOmsetTrackerResponse{
|
||||
Data: responses,
|
||||
TotalCount: int(model.Pagination.Total),
|
||||
Page: model.Pagination.Page,
|
||||
Limit: model.Pagination.Limit,
|
||||
TotalPages: model.Pagination.TotalPages,
|
||||
}
|
||||
}
|
||||
556
internal/validator/gamification_validator.go
Normal file
556
internal/validator/gamification_validator.go
Normal file
@ -0,0 +1,556 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/contract"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
type GamificationValidator interface {
|
||||
// Customer Points
|
||||
ValidateCreateCustomerPointsRequest(req *contract.CreateCustomerPointsRequest) (error, string)
|
||||
ValidateUpdateCustomerPointsRequest(req *contract.UpdateCustomerPointsRequest) (error, string)
|
||||
ValidateListCustomerPointsRequest(req *contract.ListCustomerPointsRequest) (error, string)
|
||||
ValidateAddCustomerPointsRequest(req *contract.AddCustomerPointsRequest) (error, string)
|
||||
ValidateDeductCustomerPointsRequest(req *contract.DeductCustomerPointsRequest) (error, string)
|
||||
|
||||
// Customer Tokens
|
||||
ValidateCreateCustomerTokensRequest(req *contract.CreateCustomerTokensRequest) (error, string)
|
||||
ValidateUpdateCustomerTokensRequest(req *contract.UpdateCustomerTokensRequest) (error, string)
|
||||
ValidateListCustomerTokensRequest(req *contract.ListCustomerTokensRequest) (error, string)
|
||||
ValidateAddCustomerTokensRequest(req *contract.AddCustomerTokensRequest) (error, string)
|
||||
ValidateDeductCustomerTokensRequest(req *contract.DeductCustomerTokensRequest) (error, string)
|
||||
|
||||
// Tiers
|
||||
ValidateCreateTierRequest(req *contract.CreateTierRequest) (error, string)
|
||||
ValidateUpdateTierRequest(req *contract.UpdateTierRequest) (error, string)
|
||||
ValidateListTiersRequest(req *contract.ListTiersRequest) (error, string)
|
||||
|
||||
// Games
|
||||
ValidateCreateGameRequest(req *contract.CreateGameRequest) (error, string)
|
||||
ValidateUpdateGameRequest(req *contract.UpdateGameRequest) (error, string)
|
||||
ValidateListGamesRequest(req *contract.ListGamesRequest) (error, string)
|
||||
|
||||
// Game Prizes
|
||||
ValidateCreateGamePrizeRequest(req *contract.CreateGamePrizeRequest) (error, string)
|
||||
ValidateUpdateGamePrizeRequest(req *contract.UpdateGamePrizeRequest) (error, string)
|
||||
ValidateListGamePrizesRequest(req *contract.ListGamePrizesRequest) (error, string)
|
||||
|
||||
// Game Plays
|
||||
ValidateCreateGamePlayRequest(req *contract.CreateGamePlayRequest) (error, string)
|
||||
ValidateListGamePlaysRequest(req *contract.ListGamePlaysRequest) (error, string)
|
||||
ValidatePlayGameRequest(req *contract.PlayGameRequest) (error, string)
|
||||
|
||||
// Omset Tracker
|
||||
ValidateCreateOmsetTrackerRequest(req *contract.CreateOmsetTrackerRequest) (error, string)
|
||||
ValidateUpdateOmsetTrackerRequest(req *contract.UpdateOmsetTrackerRequest) (error, string)
|
||||
ValidateListOmsetTrackerRequest(req *contract.ListOmsetTrackerRequest) (error, string)
|
||||
ValidateAddOmsetRequest(req *contract.AddOmsetRequest) (error, string)
|
||||
}
|
||||
|
||||
type GamificationValidatorImpl struct {
|
||||
validate *validator.Validate
|
||||
}
|
||||
|
||||
func NewGamificationValidator() *GamificationValidatorImpl {
|
||||
return &GamificationValidatorImpl{
|
||||
validate: validator.New(),
|
||||
}
|
||||
}
|
||||
|
||||
// Customer Points Validators
|
||||
func (v *GamificationValidatorImpl) ValidateCreateCustomerPointsRequest(req *contract.CreateCustomerPointsRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Balance < 0 {
|
||||
return errors.New("balance cannot be negative"), "INVALID_BALANCE"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateUpdateCustomerPointsRequest(req *contract.UpdateCustomerPointsRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Balance < 0 {
|
||||
return errors.New("balance cannot be negative"), "INVALID_BALANCE"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateListCustomerPointsRequest(req *contract.ListCustomerPointsRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Limit <= 0 {
|
||||
req.Limit = 10
|
||||
}
|
||||
if req.Limit > 100 {
|
||||
req.Limit = 100
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateAddCustomerPointsRequest(req *contract.AddCustomerPointsRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Points <= 0 {
|
||||
return errors.New("points must be greater than 0"), "INVALID_POINTS"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateDeductCustomerPointsRequest(req *contract.DeductCustomerPointsRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Points <= 0 {
|
||||
return errors.New("points must be greater than 0"), "INVALID_POINTS"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
// Customer Tokens Validators
|
||||
func (v *GamificationValidatorImpl) ValidateCreateCustomerTokensRequest(req *contract.CreateCustomerTokensRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Balance < 0 {
|
||||
return errors.New("balance cannot be negative"), "INVALID_BALANCE"
|
||||
}
|
||||
|
||||
validTokenTypes := []string{"SPIN", "RAFFLE", "MINIGAME"}
|
||||
if !contains(validTokenTypes, req.TokenType) {
|
||||
return errors.New("invalid token type"), "INVALID_TOKEN_TYPE"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateUpdateCustomerTokensRequest(req *contract.UpdateCustomerTokensRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Balance < 0 {
|
||||
return errors.New("balance cannot be negative"), "INVALID_BALANCE"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateListCustomerTokensRequest(req *contract.ListCustomerTokensRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Limit <= 0 {
|
||||
req.Limit = 10
|
||||
}
|
||||
if req.Limit > 100 {
|
||||
req.Limit = 100
|
||||
}
|
||||
|
||||
if req.TokenType != "" {
|
||||
validTokenTypes := []string{"SPIN", "RAFFLE", "MINIGAME"}
|
||||
if !contains(validTokenTypes, req.TokenType) {
|
||||
return errors.New("invalid token type"), "INVALID_TOKEN_TYPE"
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateAddCustomerTokensRequest(req *contract.AddCustomerTokensRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Tokens <= 0 {
|
||||
return errors.New("tokens must be greater than 0"), "INVALID_TOKENS"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateDeductCustomerTokensRequest(req *contract.DeductCustomerTokensRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Tokens <= 0 {
|
||||
return errors.New("tokens must be greater than 0"), "INVALID_TOKENS"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
// Tier Validators
|
||||
func (v *GamificationValidatorImpl) ValidateCreateTierRequest(req *contract.CreateTierRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Name != "" {
|
||||
req.Name = strings.TrimSpace(req.Name)
|
||||
if req.Name == "" {
|
||||
return errors.New("name cannot be empty or whitespace only"), "INVALID_NAME"
|
||||
}
|
||||
if len(req.Name) > 100 {
|
||||
return errors.New("name cannot exceed 100 characters"), "INVALID_NAME"
|
||||
}
|
||||
}
|
||||
|
||||
if req.MinPoints < 0 {
|
||||
return errors.New("min points cannot be negative"), "INVALID_MIN_POINTS"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateUpdateTierRequest(req *contract.UpdateTierRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Name != nil && *req.Name != "" {
|
||||
*req.Name = strings.TrimSpace(*req.Name)
|
||||
if *req.Name == "" {
|
||||
return errors.New("name cannot be empty or whitespace only"), "INVALID_NAME"
|
||||
}
|
||||
if len(*req.Name) > 100 {
|
||||
return errors.New("name cannot exceed 100 characters"), "INVALID_NAME"
|
||||
}
|
||||
}
|
||||
|
||||
if req.MinPoints != nil && *req.MinPoints < 0 {
|
||||
return errors.New("min points cannot be negative"), "INVALID_MIN_POINTS"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateListTiersRequest(req *contract.ListTiersRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Limit <= 0 {
|
||||
req.Limit = 10
|
||||
}
|
||||
if req.Limit > 100 {
|
||||
req.Limit = 100
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
// Game Validators
|
||||
func (v *GamificationValidatorImpl) ValidateCreateGameRequest(req *contract.CreateGameRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Name != "" {
|
||||
req.Name = strings.TrimSpace(req.Name)
|
||||
if req.Name == "" {
|
||||
return errors.New("name cannot be empty or whitespace only"), "INVALID_NAME"
|
||||
}
|
||||
if len(req.Name) > 255 {
|
||||
return errors.New("name cannot exceed 255 characters"), "INVALID_NAME"
|
||||
}
|
||||
}
|
||||
|
||||
validGameTypes := []string{"SPIN", "RAFFLE", "MINIGAME"}
|
||||
if !contains(validGameTypes, req.Type) {
|
||||
return errors.New("invalid game type"), "INVALID_GAME_TYPE"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateUpdateGameRequest(req *contract.UpdateGameRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Name != nil && *req.Name != "" {
|
||||
*req.Name = strings.TrimSpace(*req.Name)
|
||||
if *req.Name == "" {
|
||||
return errors.New("name cannot be empty or whitespace only"), "INVALID_NAME"
|
||||
}
|
||||
if len(*req.Name) > 255 {
|
||||
return errors.New("name cannot exceed 255 characters"), "INVALID_NAME"
|
||||
}
|
||||
}
|
||||
|
||||
if req.Type != nil {
|
||||
validGameTypes := []string{"SPIN", "RAFFLE", "MINIGAME"}
|
||||
if !contains(validGameTypes, *req.Type) {
|
||||
return errors.New("invalid game type"), "INVALID_GAME_TYPE"
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateListGamesRequest(req *contract.ListGamesRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Limit <= 0 {
|
||||
req.Limit = 10
|
||||
}
|
||||
if req.Limit > 100 {
|
||||
req.Limit = 100
|
||||
}
|
||||
|
||||
if req.Type != "" {
|
||||
validGameTypes := []string{"SPIN", "RAFFLE", "MINIGAME"}
|
||||
if !contains(validGameTypes, req.Type) {
|
||||
return errors.New("invalid game type"), "INVALID_GAME_TYPE"
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
// Game Prize Validators
|
||||
func (v *GamificationValidatorImpl) ValidateCreateGamePrizeRequest(req *contract.CreateGamePrizeRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Name != "" {
|
||||
req.Name = strings.TrimSpace(req.Name)
|
||||
if req.Name == "" {
|
||||
return errors.New("name cannot be empty or whitespace only"), "INVALID_NAME"
|
||||
}
|
||||
if len(req.Name) > 255 {
|
||||
return errors.New("name cannot exceed 255 characters"), "INVALID_NAME"
|
||||
}
|
||||
}
|
||||
|
||||
if req.Weight <= 0 {
|
||||
return errors.New("weight must be greater than 0"), "INVALID_WEIGHT"
|
||||
}
|
||||
|
||||
if req.Stock < 0 {
|
||||
return errors.New("stock cannot be negative"), "INVALID_STOCK"
|
||||
}
|
||||
|
||||
if req.MaxStock != nil && *req.MaxStock <= 0 {
|
||||
return errors.New("max stock must be greater than 0"), "INVALID_MAX_STOCK"
|
||||
}
|
||||
|
||||
if req.Threshold != nil && *req.Threshold < 0 {
|
||||
return errors.New("threshold cannot be negative"), "INVALID_THRESHOLD"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateUpdateGamePrizeRequest(req *contract.UpdateGamePrizeRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Name != nil && *req.Name != "" {
|
||||
*req.Name = strings.TrimSpace(*req.Name)
|
||||
if *req.Name == "" {
|
||||
return errors.New("name cannot be empty or whitespace only"), "INVALID_NAME"
|
||||
}
|
||||
if len(*req.Name) > 255 {
|
||||
return errors.New("name cannot exceed 255 characters"), "INVALID_NAME"
|
||||
}
|
||||
}
|
||||
|
||||
if req.Weight != nil && *req.Weight <= 0 {
|
||||
return errors.New("weight must be greater than 0"), "INVALID_WEIGHT"
|
||||
}
|
||||
|
||||
if req.Stock != nil && *req.Stock < 0 {
|
||||
return errors.New("stock cannot be negative"), "INVALID_STOCK"
|
||||
}
|
||||
|
||||
if req.MaxStock != nil && *req.MaxStock <= 0 {
|
||||
return errors.New("max stock must be greater than 0"), "INVALID_MAX_STOCK"
|
||||
}
|
||||
|
||||
if req.Threshold != nil && *req.Threshold < 0 {
|
||||
return errors.New("threshold cannot be negative"), "INVALID_THRESHOLD"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateListGamePrizesRequest(req *contract.ListGamePrizesRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Limit <= 0 {
|
||||
req.Limit = 10
|
||||
}
|
||||
if req.Limit > 100 {
|
||||
req.Limit = 100
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
// Game Play Validators
|
||||
func (v *GamificationValidatorImpl) ValidateCreateGamePlayRequest(req *contract.CreateGamePlayRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.TokenUsed < 0 {
|
||||
return errors.New("token used cannot be negative"), "INVALID_TOKEN_USED"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateListGamePlaysRequest(req *contract.ListGamePlaysRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Limit <= 0 {
|
||||
req.Limit = 10
|
||||
}
|
||||
if req.Limit > 100 {
|
||||
req.Limit = 100
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidatePlayGameRequest(req *contract.PlayGameRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.TokenUsed < 0 {
|
||||
return errors.New("token used cannot be negative"), "INVALID_TOKEN_USED"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
// Omset Tracker Validators
|
||||
func (v *GamificationValidatorImpl) ValidateCreateOmsetTrackerRequest(req *contract.CreateOmsetTrackerRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
validPeriodTypes := []string{"DAILY", "WEEKLY", "MONTHLY", "TOTAL"}
|
||||
if !contains(validPeriodTypes, req.PeriodType) {
|
||||
return errors.New("invalid period type"), "INVALID_PERIOD_TYPE"
|
||||
}
|
||||
|
||||
if req.Total < 0 {
|
||||
return errors.New("total cannot be negative"), "INVALID_TOTAL"
|
||||
}
|
||||
|
||||
if req.PeriodEnd.Before(req.PeriodStart) {
|
||||
return errors.New("period end must be after period start"), "INVALID_PERIOD"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateUpdateOmsetTrackerRequest(req *contract.UpdateOmsetTrackerRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.PeriodType != nil {
|
||||
validPeriodTypes := []string{"DAILY", "WEEKLY", "MONTHLY", "TOTAL"}
|
||||
if !contains(validPeriodTypes, *req.PeriodType) {
|
||||
return errors.New("invalid period type"), "INVALID_PERIOD_TYPE"
|
||||
}
|
||||
}
|
||||
|
||||
if req.Total != nil && *req.Total < 0 {
|
||||
return errors.New("total cannot be negative"), "INVALID_TOTAL"
|
||||
}
|
||||
|
||||
if req.PeriodStart != nil && req.PeriodEnd != nil && req.PeriodEnd.Before(*req.PeriodStart) {
|
||||
return errors.New("period end must be after period start"), "INVALID_PERIOD"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateListOmsetTrackerRequest(req *contract.ListOmsetTrackerRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Limit <= 0 {
|
||||
req.Limit = 10
|
||||
}
|
||||
if req.Limit > 100 {
|
||||
req.Limit = 100
|
||||
}
|
||||
|
||||
if req.PeriodType != "" {
|
||||
validPeriodTypes := []string{"DAILY", "WEEKLY", "MONTHLY", "TOTAL"}
|
||||
if !contains(validPeriodTypes, req.PeriodType) {
|
||||
return errors.New("invalid period type"), "INVALID_PERIOD_TYPE"
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (v *GamificationValidatorImpl) ValidateAddOmsetRequest(req *contract.AddOmsetRequest) (error, string) {
|
||||
if err := v.validate.Struct(req); err != nil {
|
||||
return err, "VALIDATION_ERROR"
|
||||
}
|
||||
|
||||
if req.Amount <= 0 {
|
||||
return errors.New("amount must be greater than 0"), "INVALID_AMOUNT"
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
1
migrations/000048_create_customer_points_table.down.sql
Normal file
1
migrations/000048_create_customer_points_table.down.sql
Normal file
@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS customer_points;
|
||||
22
migrations/000048_create_customer_points_table.up.sql
Normal file
22
migrations/000048_create_customer_points_table.up.sql
Normal file
@ -0,0 +1,22 @@
|
||||
CREATE TABLE customer_points (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
customer_id UUID NOT NULL,
|
||||
balance BIGINT DEFAULT 0 NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
|
||||
CONSTRAINT fk_customer_points_customer
|
||||
FOREIGN KEY (customer_id)
|
||||
REFERENCES customers(id)
|
||||
ON DELETE CASCADE,
|
||||
|
||||
CONSTRAINT chk_customer_points_balance_non_negative
|
||||
CHECK (balance >= 0)
|
||||
);
|
||||
|
||||
-- Create indexes
|
||||
CREATE INDEX idx_customer_points_customer_id ON customer_points(customer_id);
|
||||
CREATE INDEX idx_customer_points_updated_at ON customer_points(updated_at);
|
||||
|
||||
-- Create unique constraint to ensure one point record per customer
|
||||
CREATE UNIQUE INDEX idx_customer_points_unique_customer ON customer_points(customer_id);
|
||||
1
migrations/000049_create_customer_tokens_table.down.sql
Normal file
1
migrations/000049_create_customer_tokens_table.down.sql
Normal file
@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS customer_tokens;
|
||||
25
migrations/000049_create_customer_tokens_table.up.sql
Normal file
25
migrations/000049_create_customer_tokens_table.up.sql
Normal file
@ -0,0 +1,25 @@
|
||||
CREATE TABLE customer_tokens (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
customer_id UUID NOT NULL,
|
||||
token_type VARCHAR(50) NOT NULL,
|
||||
balance BIGINT DEFAULT 0 NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
|
||||
CONSTRAINT fk_customer_tokens_customer
|
||||
FOREIGN KEY (customer_id)
|
||||
REFERENCES customers(id)
|
||||
ON DELETE CASCADE,
|
||||
|
||||
CONSTRAINT chk_customer_tokens_balance_non_negative
|
||||
CHECK (balance >= 0),
|
||||
|
||||
CONSTRAINT chk_customer_tokens_type_valid
|
||||
CHECK (token_type IN ('SPIN', 'RAFFLE', 'MINIGAME'))
|
||||
);
|
||||
|
||||
CREATE INDEX idx_customer_tokens_customer_id ON customer_tokens(customer_id);
|
||||
CREATE INDEX idx_customer_tokens_token_type ON customer_tokens(token_type);
|
||||
CREATE INDEX idx_customer_tokens_updated_at ON customer_tokens(updated_at);
|
||||
|
||||
CREATE UNIQUE INDEX idx_customer_tokens_unique_customer_type ON customer_tokens(customer_id, token_type);
|
||||
1
migrations/000050_create_tiers_table.down.sql
Normal file
1
migrations/000050_create_tiers_table.down.sql
Normal file
@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS tiers;
|
||||
14
migrations/000050_create_tiers_table.up.sql
Normal file
14
migrations/000050_create_tiers_table.up.sql
Normal file
@ -0,0 +1,14 @@
|
||||
CREATE TABLE tiers (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(100) NOT NULL UNIQUE,
|
||||
min_points BIGINT NOT NULL,
|
||||
benefits JSONB DEFAULT '{}',
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
|
||||
CONSTRAINT chk_tiers_min_points_non_negative
|
||||
CHECK (min_points >= 0)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_tiers_min_points ON tiers(min_points);
|
||||
CREATE INDEX idx_tiers_created_at ON tiers(created_at);
|
||||
1
migrations/000051_create_games_table.down.sql
Normal file
1
migrations/000051_create_games_table.down.sql
Normal file
@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS games;
|
||||
17
migrations/000051_create_games_table.up.sql
Normal file
17
migrations/000051_create_games_table.up.sql
Normal file
@ -0,0 +1,17 @@
|
||||
CREATE TABLE games (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
type VARCHAR(50) NOT NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
metadata JSONB DEFAULT '{}',
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
|
||||
CONSTRAINT chk_games_type_valid
|
||||
CHECK (type IN ('SPIN', 'RAFFLE', 'MINIGAME'))
|
||||
);
|
||||
|
||||
-- Create indexes
|
||||
CREATE INDEX idx_games_type ON games(type);
|
||||
CREATE INDEX idx_games_is_active ON games(is_active);
|
||||
CREATE INDEX idx_games_created_at ON games(created_at);
|
||||
1
migrations/000052_create_game_prizes_table.down.sql
Normal file
1
migrations/000052_create_game_prizes_table.down.sql
Normal file
@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS game_prizes;
|
||||
45
migrations/000052_create_game_prizes_table.up.sql
Normal file
45
migrations/000052_create_game_prizes_table.up.sql
Normal file
@ -0,0 +1,45 @@
|
||||
CREATE TABLE game_prizes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
game_id UUID NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
weight INTEGER NOT NULL,
|
||||
stock INTEGER DEFAULT 0,
|
||||
max_stock INTEGER,
|
||||
threshold BIGINT,
|
||||
fallback_prize_id UUID,
|
||||
metadata JSONB DEFAULT '{}',
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
|
||||
CONSTRAINT fk_game_prizes_game
|
||||
FOREIGN KEY (game_id)
|
||||
REFERENCES games(id)
|
||||
ON DELETE CASCADE,
|
||||
|
||||
CONSTRAINT fk_game_prizes_fallback
|
||||
FOREIGN KEY (fallback_prize_id)
|
||||
REFERENCES game_prizes(id)
|
||||
ON DELETE SET NULL,
|
||||
|
||||
CONSTRAINT chk_game_prizes_weight_positive
|
||||
CHECK (weight > 0),
|
||||
|
||||
CONSTRAINT chk_game_prizes_stock_non_negative
|
||||
CHECK (stock >= 0),
|
||||
|
||||
CONSTRAINT chk_game_prizes_max_stock_positive
|
||||
CHECK (max_stock IS NULL OR max_stock > 0),
|
||||
|
||||
CONSTRAINT chk_game_prizes_threshold_non_negative
|
||||
CHECK (threshold IS NULL OR threshold >= 0),
|
||||
|
||||
CONSTRAINT chk_game_prizes_stock_not_exceed_max
|
||||
CHECK (max_stock IS NULL OR stock <= max_stock)
|
||||
);
|
||||
|
||||
-- Create indexes
|
||||
CREATE INDEX idx_game_prizes_game_id ON game_prizes(game_id);
|
||||
CREATE INDEX idx_game_prizes_weight ON game_prizes(weight);
|
||||
CREATE INDEX idx_game_prizes_stock ON game_prizes(stock);
|
||||
CREATE INDEX idx_game_prizes_fallback_prize_id ON game_prizes(fallback_prize_id);
|
||||
CREATE INDEX idx_game_prizes_created_at ON game_prizes(created_at);
|
||||
1
migrations/000053_create_game_plays_table.down.sql
Normal file
1
migrations/000053_create_game_plays_table.down.sql
Normal file
@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS game_plays;
|
||||
34
migrations/000053_create_game_plays_table.up.sql
Normal file
34
migrations/000053_create_game_plays_table.up.sql
Normal file
@ -0,0 +1,34 @@
|
||||
CREATE TABLE game_plays (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
game_id UUID NOT NULL,
|
||||
customer_id UUID NOT NULL,
|
||||
prize_id UUID,
|
||||
token_used INTEGER DEFAULT 0,
|
||||
random_seed VARCHAR(255),
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
|
||||
CONSTRAINT fk_game_plays_game
|
||||
FOREIGN KEY (game_id)
|
||||
REFERENCES games(id)
|
||||
ON DELETE CASCADE,
|
||||
|
||||
CONSTRAINT fk_game_plays_customer
|
||||
FOREIGN KEY (customer_id)
|
||||
REFERENCES customers(id)
|
||||
ON DELETE CASCADE,
|
||||
|
||||
CONSTRAINT fk_game_plays_prize
|
||||
FOREIGN KEY (prize_id)
|
||||
REFERENCES game_prizes(id)
|
||||
ON DELETE SET NULL,
|
||||
|
||||
CONSTRAINT chk_game_plays_token_used_non_negative
|
||||
CHECK (token_used >= 0)
|
||||
);
|
||||
|
||||
-- Create indexes
|
||||
CREATE INDEX idx_game_plays_game_id ON game_plays(game_id);
|
||||
CREATE INDEX idx_game_plays_customer_id ON game_plays(customer_id);
|
||||
CREATE INDEX idx_game_plays_prize_id ON game_plays(prize_id);
|
||||
CREATE INDEX idx_game_plays_created_at ON game_plays(created_at);
|
||||
CREATE INDEX idx_game_plays_game_customer ON game_plays(game_id, customer_id);
|
||||
1
migrations/000054_create_omset_tracker_table.down.sql
Normal file
1
migrations/000054_create_omset_tracker_table.down.sql
Normal file
@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS omset_tracker;
|
||||
32
migrations/000054_create_omset_tracker_table.up.sql
Normal file
32
migrations/000054_create_omset_tracker_table.up.sql
Normal file
@ -0,0 +1,32 @@
|
||||
CREATE TABLE omset_tracker (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
period_type VARCHAR(20) NOT NULL,
|
||||
period_start DATE NOT NULL,
|
||||
period_end DATE NOT NULL,
|
||||
total BIGINT DEFAULT 0 NOT NULL,
|
||||
game_id UUID,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
|
||||
CONSTRAINT fk_omset_tracker_game
|
||||
FOREIGN KEY (game_id)
|
||||
REFERENCES games(id)
|
||||
ON DELETE SET NULL,
|
||||
|
||||
CONSTRAINT chk_omset_tracker_period_type_valid
|
||||
CHECK (period_type IN ('DAILY', 'WEEKLY', 'MONTHLY', 'TOTAL')),
|
||||
|
||||
CONSTRAINT chk_omset_tracker_total_non_negative
|
||||
CHECK (total >= 0),
|
||||
|
||||
CONSTRAINT chk_omset_tracker_period_valid
|
||||
CHECK (period_end >= period_start)
|
||||
);
|
||||
|
||||
-- Create indexes
|
||||
CREATE INDEX idx_omset_tracker_period_type ON omset_tracker(period_type);
|
||||
CREATE INDEX idx_omset_tracker_period_start ON omset_tracker(period_start);
|
||||
CREATE INDEX idx_omset_tracker_game_id ON omset_tracker(game_id);
|
||||
CREATE INDEX idx_omset_tracker_created_at ON omset_tracker(created_at);
|
||||
CREATE INDEX idx_omset_tracker_period_type_start ON omset_tracker(period_type, period_start);
|
||||
CREATE INDEX idx_omset_tracker_game_period ON omset_tracker(game_id, period_type, period_start);
|
||||
Loading…
x
Reference in New Issue
Block a user