Add Tiers and Game Prize
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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]
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user