Compare commits
82
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7022dd4c1 | ||
|
|
3542104050 | ||
|
|
eb95459578 | ||
|
|
1a5ddd2b34 | ||
|
|
0aa280462c | ||
|
|
421475006b | ||
|
|
75fdb8e847 | ||
|
|
8efa644680 | ||
|
|
ce99aef289 | ||
|
|
ba970229a9 | ||
|
|
9b606b4c8b | ||
|
|
d3dddea1c7 | ||
|
|
80a78137a0 | ||
|
|
3826a6b7a9 | ||
|
|
d695bedc97 | ||
|
|
3db4afbce6 | ||
|
|
535e4c84f6 | ||
|
|
f25ec1c06f | ||
|
|
b3359fa6ff | ||
|
|
0c331dce6a | ||
|
|
cd784624c9 | ||
|
|
3e0d75a4d0 | ||
|
|
54dc8662d6 | ||
|
|
27a2535dde | ||
|
|
f55ea1ceb0 | ||
|
|
670a283c7b | ||
|
|
b29677a192 | ||
|
|
26ac7a2752 | ||
|
|
f85929c575 | ||
|
|
9db3dcb472 | ||
|
|
a520d0ed11 | ||
|
|
c7828a5cad | ||
|
|
d3db08fd15 | ||
|
|
67812a1d75 | ||
|
|
be92ec8b23 | ||
|
|
f64fec1fe2 | ||
|
|
259b8a11b5 | ||
|
|
65f61b65cf | ||
|
|
c68b536480 | ||
|
|
155016dec8 | ||
|
|
201e24041b | ||
|
|
12ee54390f | ||
|
|
36c2352cb2 | ||
|
|
b37d21d366 | ||
|
|
afa8782eb2 | ||
|
|
691456af87 | ||
|
|
cfe690a40f | ||
|
|
4f6208e479 | ||
|
|
75ec5274d2 | ||
|
|
91f51d129e | ||
|
|
3a04990ec8 | ||
|
|
efe09c21e4 | ||
|
|
c107733add | ||
|
|
4c6dc5c8b4 | ||
|
|
f91f85202e | ||
|
|
13d8c75be7 | ||
|
|
07b3eda263 | ||
|
|
3a0c262c77 | ||
|
|
7adba2c8f5 | ||
|
|
bb9a81c7c1 | ||
|
|
4a720f439b | ||
|
|
ee7d0e529b | ||
|
|
ccb0458189 | ||
|
|
451697b783 | ||
|
|
1c7f7feb2e | ||
|
|
9e74d415b3 | ||
|
|
58dc92c722 | ||
|
|
4cade376b9 | ||
|
|
82f72fc3eb | ||
|
|
b72ab4ef3d | ||
|
|
265248ba49 | ||
|
|
db7c862fa8 | ||
|
|
835097d381 | ||
|
|
5a42523f0f | ||
|
|
dc23a318cd | ||
|
|
721235e6fe | ||
|
|
8e9c14b860 | ||
|
|
c18e915d1e | ||
|
|
fe4f17b34d | ||
|
|
93a3b29ae9 | ||
|
|
3696451dc6 | ||
|
|
0a44135fb6 |
+7
-86
@@ -1,99 +1,20 @@
|
||||
# Build Stage
|
||||
# 1) Build stage
|
||||
FROM golang:1.21-alpine AS build
|
||||
|
||||
# Install necessary packages including CA certificates
|
||||
RUN apk --no-cache add ca-certificates tzdata git curl
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
# Copy go mod files first for better caching
|
||||
COPY go.mod go.sum ./
|
||||
|
||||
# Download dependencies
|
||||
RUN go mod download
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Build the application
|
||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /app cmd/server/main.go
|
||||
|
||||
# Development Stage
|
||||
FROM golang:1.21-alpine AS development
|
||||
|
||||
# Install air for live reload and other dev tools
|
||||
RUN go install github.com/cosmtrek/air@latest
|
||||
|
||||
# Install necessary packages
|
||||
RUN apk --no-cache add ca-certificates tzdata git curl
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy go mod files
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /out/app ./cmd/server
|
||||
|
||||
# Set timezone
|
||||
ENV TZ=Asia/Jakarta
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3300
|
||||
|
||||
# Use air for live reload in development
|
||||
CMD ["air", "-c", ".air.toml"]
|
||||
|
||||
# Migration Stage
|
||||
FROM build AS migration
|
||||
|
||||
# Install migration tool
|
||||
RUN go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy migration files
|
||||
COPY migrations ./migrations
|
||||
COPY infra ./infra
|
||||
|
||||
# Set the entrypoint for migrations
|
||||
ENTRYPOINT ["migrate"]
|
||||
|
||||
# Production Stage
|
||||
# 2) Production stage
|
||||
FROM debian:bullseye-slim AS production
|
||||
|
||||
# Install minimal runtime dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
ca-certificates \
|
||||
tzdata \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create non-root user for security
|
||||
RUN apt-get update && apt-get install -y ca-certificates tzdata curl && rm -rf /var/lib/apt/lists/*
|
||||
RUN groupadd -r appuser && useradd -r -g appuser appuser
|
||||
|
||||
# Copy the binary
|
||||
COPY --from=build /app /app
|
||||
|
||||
# Copy configuration files
|
||||
COPY --from=build /src/infra /infra
|
||||
|
||||
# Change ownership to non-root user
|
||||
RUN chown -R appuser:appuser /app /infra
|
||||
|
||||
# Set timezone
|
||||
COPY --from=build /out/app /app
|
||||
ENV TZ=Asia/Jakarta
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3300
|
||||
|
||||
# Health check
|
||||
EXPOSE 4000
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||
CMD curl -f http://localhost:3300/health || exit 1
|
||||
|
||||
# Switch to non-root user
|
||||
CMD curl -fsS http://localhost:3300/health || exit 1
|
||||
USER appuser
|
||||
|
||||
# Set the entrypoint
|
||||
ENTRYPOINT ["/app"]
|
||||
|
||||
+17
-2
@@ -29,6 +29,7 @@ type Config struct {
|
||||
Jwt Jwt `mapstructure:"jwt"`
|
||||
Log Log `mapstructure:"log"`
|
||||
S3Config S3Config `mapstructure:"s3"`
|
||||
Fonnte Fonnte `mapstructure:"fonnte"`
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -63,11 +64,21 @@ func LoadConfig() *Config {
|
||||
|
||||
func (c *Config) Auth() *AuthConfig {
|
||||
return &AuthConfig{
|
||||
jwtTokenSecret: c.Jwt.Token.Secret,
|
||||
jwtTokenExpiresTTL: c.Jwt.Token.ExpiresTTL,
|
||||
jwtTokenSecret: c.Jwt.Token.Secret,
|
||||
jwtTokenExpiresTTL: c.Jwt.Token.ExpiresTTL,
|
||||
refreshTokenSecret: c.Jwt.RefreshToken.Secret,
|
||||
refreshTokenExpiresTTL: c.Jwt.RefreshToken.ExpiresTTL,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) GetCustomerJWTSecret() string {
|
||||
return c.Jwt.Customer.Secret
|
||||
}
|
||||
|
||||
func (c *Config) GetCustomerJWTExpiresTTL() int {
|
||||
return c.Jwt.Customer.ExpiresTTL
|
||||
}
|
||||
|
||||
func (c *Config) LogLevel() string {
|
||||
return c.Log.LogLevel
|
||||
}
|
||||
@@ -79,3 +90,7 @@ func (c *Config) Port() string {
|
||||
func (c *Config) LogFormat() string {
|
||||
return c.Log.LogFormat
|
||||
}
|
||||
|
||||
func (c *Config) GetFonnte() *Fonnte {
|
||||
return &c.Fonnte
|
||||
}
|
||||
|
||||
+21
-2
@@ -3,8 +3,10 @@ package config
|
||||
import "time"
|
||||
|
||||
type AuthConfig struct {
|
||||
jwtTokenExpiresTTL int
|
||||
jwtTokenSecret string
|
||||
jwtTokenExpiresTTL int
|
||||
jwtTokenSecret string
|
||||
refreshTokenExpiresTTL int
|
||||
refreshTokenSecret string
|
||||
}
|
||||
|
||||
type JWT struct {
|
||||
@@ -20,3 +22,20 @@ func (c *AuthConfig) AccessTokenExpiresDate() time.Time {
|
||||
duration := time.Duration(c.jwtTokenExpiresTTL)
|
||||
return time.Now().UTC().Add(time.Minute * duration)
|
||||
}
|
||||
|
||||
func (c *AuthConfig) RefreshTokenSecret() string {
|
||||
return c.refreshTokenSecret
|
||||
}
|
||||
|
||||
func (c *AuthConfig) RefreshTokenExpiresDate() time.Time {
|
||||
duration := time.Duration(c.refreshTokenExpiresTTL)
|
||||
return time.Now().UTC().Add(time.Minute * duration)
|
||||
}
|
||||
|
||||
func (c *AuthConfig) AccessTokenTTL() time.Duration {
|
||||
return time.Duration(c.jwtTokenExpiresTTL) * time.Minute
|
||||
}
|
||||
|
||||
func (c *AuthConfig) RefreshTokenTTL() time.Duration {
|
||||
return time.Duration(c.refreshTokenExpiresTTL) * time.Minute
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ type Database struct {
|
||||
}
|
||||
|
||||
func (c Database) DSN() string {
|
||||
return fmt.Sprintf("host=%s port=%s dbname=%s user=%s password=%s sslmode=%s TimeZone=UTC", c.Host, c.Port, c.DB, c.Username, c.Password, c.SslMode)
|
||||
return fmt.Sprintf("host=%s port=%s dbname=%s user=%s password=%s sslmode=%s TimeZone=Asia/Jakarta", c.Host, c.Port, c.DB, c.Username, c.Password, c.SslMode)
|
||||
}
|
||||
|
||||
func (c Database) ConnectionMaxLifetime() time.Duration {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package config
|
||||
|
||||
type Fonnte struct {
|
||||
ApiUrl string `mapstructure:"api_url"`
|
||||
Token string `mapstructure:"token"`
|
||||
Timeout int `mapstructure:"timeout"`
|
||||
}
|
||||
|
||||
func (f *Fonnte) GetApiUrl() string {
|
||||
return f.ApiUrl
|
||||
}
|
||||
|
||||
func (f *Fonnte) GetToken() string {
|
||||
return f.Token
|
||||
}
|
||||
|
||||
func (f *Fonnte) GetTimeout() int {
|
||||
return f.Timeout
|
||||
}
|
||||
+13
-1
@@ -1,10 +1,22 @@
|
||||
package config
|
||||
|
||||
type Jwt struct {
|
||||
Token Token `mapstructure:"token"`
|
||||
Token Token `mapstructure:"token"`
|
||||
RefreshToken RefreshToken `mapstructure:"refresh_token"`
|
||||
Customer Customer `mapstructure:"customer"`
|
||||
}
|
||||
|
||||
type Token struct {
|
||||
ExpiresTTL int `mapstructure:"expires-ttl"`
|
||||
Secret string `mapstructure:"secret"`
|
||||
}
|
||||
|
||||
type RefreshToken struct {
|
||||
ExpiresTTL int `mapstructure:"expires-ttl"`
|
||||
Secret string `mapstructure:"secret"`
|
||||
}
|
||||
|
||||
type Customer struct {
|
||||
ExpiresTTL int `mapstructure:"expires-ttl"`
|
||||
Secret string `mapstructure:"secret"`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
APP_NAME="apskel-pos"
|
||||
PORT="4000"
|
||||
|
||||
echo "🔄 Pulling latest code..."
|
||||
git pull
|
||||
|
||||
echo "🐳 Building Docker image (production target)..."
|
||||
docker build --target production -t $APP_NAME:latest .
|
||||
|
||||
echo "🛑 Stopping and removing old container..."
|
||||
docker rm -f $APP_NAME 2>/dev/null || true
|
||||
|
||||
echo "🚀 Running new container..."
|
||||
docker run -d --name $APP_NAME \
|
||||
-p $PORT:$PORT \
|
||||
-e TZ=Asia/Jakarta \
|
||||
-v "$(pwd)/infra":/infra:ro \
|
||||
-v "$(pwd)/templates":/templates:ro \
|
||||
$APP_NAME:latest
|
||||
|
||||
echo "✅ Deployment complete."
|
||||
+13
-2
@@ -5,8 +5,14 @@ server:
|
||||
|
||||
jwt:
|
||||
token:
|
||||
expires-ttl: 1440
|
||||
expires-ttl: 144000
|
||||
secret: "5Lm25V3Qd7aut8dr4QUxm5PZUrSFs"
|
||||
refresh_token:
|
||||
expires-ttl: 7776000 # 3 months in minutes (90 days * 24 hours * 60 minutes)
|
||||
secret: "R3fr3sh_T0k3n_S3cr3t_K3y_2024_P0S"
|
||||
customer:
|
||||
expires-ttl: 7776000
|
||||
secret: "z8d5TlFCT58Q$i0%S^2M&3WtE$PMgd"
|
||||
|
||||
postgresql:
|
||||
host: 62.72.45.250
|
||||
@@ -31,4 +37,9 @@ s3:
|
||||
|
||||
log:
|
||||
log_format: 'json'
|
||||
log_level: 'debug'
|
||||
log_level: 'debug'
|
||||
|
||||
fonnte:
|
||||
api_url: "https://api.fonnte.com/send"
|
||||
token: "bADQrf9NTXfLZQCK2wGg"
|
||||
timeout: 30
|
||||
+328
-137
@@ -40,9 +40,9 @@ func NewApp(db *gorm.DB) *App {
|
||||
func (a *App) Initialize(cfg *config.Config) error {
|
||||
repos := a.initRepositories()
|
||||
processors := a.initProcessors(cfg, repos)
|
||||
services := a.initServices(processors, cfg)
|
||||
services := a.initServices(processors, repos, cfg)
|
||||
validators := a.initValidators()
|
||||
middleware := a.initMiddleware(services)
|
||||
middleware := a.initMiddleware(services, cfg)
|
||||
healthHandler := handler.NewHealthHandler()
|
||||
|
||||
a.router = router.NewRouter(
|
||||
@@ -74,10 +74,37 @@ func (a *App) Initialize(cfg *config.Config) error {
|
||||
services.paymentMethodService,
|
||||
validators.paymentMethodValidator,
|
||||
services.analyticsService,
|
||||
services.reportService,
|
||||
services.tableService,
|
||||
validators.tableValidator,
|
||||
services.unitService,
|
||||
services.ingredientService,
|
||||
services.productRecipeService,
|
||||
services.vendorService,
|
||||
validators.vendorValidator,
|
||||
services.purchaseOrderService,
|
||||
validators.purchaseOrderValidator,
|
||||
services.unitConverterService,
|
||||
validators.unitConverterValidator,
|
||||
services.chartOfAccountTypeService,
|
||||
validators.chartOfAccountTypeValidator,
|
||||
services.chartOfAccountService,
|
||||
validators.chartOfAccountValidator,
|
||||
services.accountService,
|
||||
validators.accountValidator,
|
||||
*services.orderIngredientTransactionService,
|
||||
validators.orderIngredientTransactionValidator,
|
||||
services.gamificationService,
|
||||
validators.gamificationValidator,
|
||||
services.rewardService,
|
||||
validators.rewardValidator,
|
||||
services.campaignService,
|
||||
validators.campaignValidator,
|
||||
services.customerAuthService,
|
||||
validators.customerAuthValidator,
|
||||
services.customerPointsService,
|
||||
services.spinGameService,
|
||||
middleware.customerAuthMiddleware,
|
||||
)
|
||||
|
||||
return nil
|
||||
@@ -123,117 +150,224 @@ func (a *App) Shutdown() {
|
||||
}
|
||||
|
||||
type repositories struct {
|
||||
userRepo *repository.UserRepositoryImpl
|
||||
organizationRepo *repository.OrganizationRepositoryImpl
|
||||
outletRepo *repository.OutletRepositoryImpl
|
||||
outletSettingRepo *repository.OutletSettingRepositoryImpl
|
||||
categoryRepo *repository.CategoryRepositoryImpl
|
||||
productRepo *repository.ProductRepositoryImpl
|
||||
productVariantRepo *repository.ProductVariantRepositoryImpl
|
||||
inventoryRepo *repository.InventoryRepositoryImpl
|
||||
inventoryMovementRepo *repository.InventoryMovementRepositoryImpl
|
||||
orderRepo *repository.OrderRepositoryImpl
|
||||
orderItemRepo *repository.OrderItemRepositoryImpl
|
||||
paymentRepo *repository.PaymentRepositoryImpl
|
||||
paymentMethodRepo *repository.PaymentMethodRepositoryImpl
|
||||
fileRepo *repository.FileRepositoryImpl
|
||||
customerRepo *repository.CustomerRepository
|
||||
analyticsRepo *repository.AnalyticsRepositoryImpl
|
||||
tableRepo *repository.TableRepository
|
||||
unitRepo *repository.UnitRepository
|
||||
ingredientRepo *repository.IngredientRepository
|
||||
userRepo *repository.UserRepositoryImpl
|
||||
organizationRepo *repository.OrganizationRepositoryImpl
|
||||
outletRepo *repository.OutletRepositoryImpl
|
||||
outletSettingRepo *repository.OutletSettingRepositoryImpl
|
||||
categoryRepo *repository.CategoryRepositoryImpl
|
||||
productRepo *repository.ProductRepositoryImpl
|
||||
productVariantRepo *repository.ProductVariantRepositoryImpl
|
||||
inventoryRepo *repository.InventoryRepositoryImpl
|
||||
inventoryMovementRepo *repository.InventoryMovementRepositoryImpl
|
||||
orderRepo *repository.OrderRepositoryImpl
|
||||
orderItemRepo *repository.OrderItemRepositoryImpl
|
||||
paymentRepo *repository.PaymentRepositoryImpl
|
||||
paymentOrderItemRepo *repository.PaymentOrderItemRepositoryImpl
|
||||
paymentMethodRepo *repository.PaymentMethodRepositoryImpl
|
||||
fileRepo *repository.FileRepositoryImpl
|
||||
customerRepo *repository.CustomerRepository
|
||||
analyticsRepo *repository.AnalyticsRepositoryImpl
|
||||
tableRepo *repository.TableRepository
|
||||
unitRepo *repository.UnitRepository
|
||||
ingredientRepo *repository.IngredientRepository
|
||||
ingredientCompositionRepo *repository.IngredientCompositionRepository
|
||||
productRecipeRepo *repository.ProductRecipeRepository
|
||||
vendorRepo *repository.VendorRepositoryImpl
|
||||
purchaseOrderRepo *repository.PurchaseOrderRepositoryImpl
|
||||
unitConverterRepo *repository.IngredientUnitConverterRepositoryImpl
|
||||
chartOfAccountTypeRepo *repository.ChartOfAccountTypeRepositoryImpl
|
||||
chartOfAccountRepo *repository.ChartOfAccountRepositoryImpl
|
||||
accountRepo *repository.AccountRepositoryImpl
|
||||
orderIngredientTransactionRepo *repository.OrderIngredientTransactionRepositoryImpl
|
||||
customerTokensRepo *repository.CustomerTokensRepository
|
||||
tierRepo *repository.TierRepository
|
||||
gameRepo *repository.GameRepository
|
||||
gamePrizeRepo *repository.GamePrizeRepository
|
||||
gamePlayRepo repository.GamePlayRepository
|
||||
omsetTrackerRepo *repository.OmsetTrackerRepository
|
||||
rewardRepo repository.RewardRepository
|
||||
campaignRepo repository.CampaignRepository
|
||||
campaignRuleRepo repository.CampaignRuleRepository
|
||||
customerAuthRepo repository.CustomerAuthRepository
|
||||
customerPointsRepo repository.CustomerPointsRepository
|
||||
otpRepo repository.OtpRepository
|
||||
txManager *repository.TxManager
|
||||
}
|
||||
|
||||
func (a *App) initRepositories() *repositories {
|
||||
return &repositories{
|
||||
userRepo: repository.NewUserRepository(a.db),
|
||||
organizationRepo: repository.NewOrganizationRepositoryImpl(a.db),
|
||||
outletRepo: repository.NewOutletRepositoryImpl(a.db),
|
||||
outletSettingRepo: repository.NewOutletSettingRepositoryImpl(a.db),
|
||||
categoryRepo: repository.NewCategoryRepositoryImpl(a.db),
|
||||
productRepo: repository.NewProductRepositoryImpl(a.db),
|
||||
productVariantRepo: repository.NewProductVariantRepositoryImpl(a.db),
|
||||
inventoryRepo: repository.NewInventoryRepositoryImpl(a.db),
|
||||
inventoryMovementRepo: repository.NewInventoryMovementRepositoryImpl(a.db),
|
||||
orderRepo: repository.NewOrderRepositoryImpl(a.db),
|
||||
orderItemRepo: repository.NewOrderItemRepositoryImpl(a.db),
|
||||
paymentRepo: repository.NewPaymentRepositoryImpl(a.db),
|
||||
paymentMethodRepo: repository.NewPaymentMethodRepositoryImpl(a.db),
|
||||
fileRepo: repository.NewFileRepositoryImpl(a.db),
|
||||
customerRepo: repository.NewCustomerRepository(a.db),
|
||||
analyticsRepo: repository.NewAnalyticsRepositoryImpl(a.db),
|
||||
tableRepo: repository.NewTableRepository(a.db),
|
||||
unitRepo: repository.NewUnitRepository(a.db),
|
||||
ingredientRepo: repository.NewIngredientRepository(a.db),
|
||||
userRepo: repository.NewUserRepository(a.db),
|
||||
organizationRepo: repository.NewOrganizationRepositoryImpl(a.db),
|
||||
outletRepo: repository.NewOutletRepositoryImpl(a.db),
|
||||
outletSettingRepo: repository.NewOutletSettingRepositoryImpl(a.db),
|
||||
categoryRepo: repository.NewCategoryRepositoryImpl(a.db),
|
||||
productRepo: repository.NewProductRepositoryImpl(a.db),
|
||||
productVariantRepo: repository.NewProductVariantRepositoryImpl(a.db),
|
||||
inventoryRepo: repository.NewInventoryRepositoryImpl(a.db),
|
||||
inventoryMovementRepo: repository.NewInventoryMovementRepositoryImpl(a.db),
|
||||
orderRepo: repository.NewOrderRepositoryImpl(a.db),
|
||||
orderItemRepo: repository.NewOrderItemRepositoryImpl(a.db),
|
||||
paymentRepo: repository.NewPaymentRepositoryImpl(a.db),
|
||||
paymentOrderItemRepo: repository.NewPaymentOrderItemRepositoryImpl(a.db),
|
||||
paymentMethodRepo: repository.NewPaymentMethodRepositoryImpl(a.db),
|
||||
fileRepo: repository.NewFileRepositoryImpl(a.db),
|
||||
customerRepo: repository.NewCustomerRepository(a.db),
|
||||
analyticsRepo: repository.NewAnalyticsRepositoryImpl(a.db),
|
||||
tableRepo: repository.NewTableRepository(a.db),
|
||||
unitRepo: repository.NewUnitRepository(a.db),
|
||||
ingredientRepo: repository.NewIngredientRepository(a.db),
|
||||
ingredientCompositionRepo: repository.NewIngredientCompositionRepository(a.db),
|
||||
productRecipeRepo: repository.NewProductRecipeRepository(a.db),
|
||||
vendorRepo: repository.NewVendorRepositoryImpl(a.db),
|
||||
purchaseOrderRepo: repository.NewPurchaseOrderRepositoryImpl(a.db),
|
||||
unitConverterRepo: repository.NewIngredientUnitConverterRepositoryImpl(a.db).(*repository.IngredientUnitConverterRepositoryImpl),
|
||||
chartOfAccountTypeRepo: repository.NewChartOfAccountTypeRepositoryImpl(a.db),
|
||||
chartOfAccountRepo: repository.NewChartOfAccountRepositoryImpl(a.db),
|
||||
accountRepo: repository.NewAccountRepositoryImpl(a.db),
|
||||
orderIngredientTransactionRepo: repository.NewOrderIngredientTransactionRepositoryImpl(a.db).(*repository.OrderIngredientTransactionRepositoryImpl),
|
||||
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),
|
||||
rewardRepo: repository.NewRewardRepository(a.db),
|
||||
campaignRepo: repository.NewCampaignRepository(a.db),
|
||||
campaignRuleRepo: repository.NewCampaignRuleRepository(a.db),
|
||||
customerAuthRepo: repository.NewCustomerAuthRepository(a.db),
|
||||
customerPointsRepo: repository.NewCustomerPointsRepository(a.db),
|
||||
otpRepo: repository.NewOtpRepository(a.db),
|
||||
txManager: repository.NewTxManager(a.db),
|
||||
}
|
||||
}
|
||||
|
||||
type processors struct {
|
||||
userProcessor *processor.UserProcessorImpl
|
||||
organizationProcessor processor.OrganizationProcessor
|
||||
outletProcessor processor.OutletProcessor
|
||||
outletSettingProcessor *processor.OutletSettingProcessorImpl
|
||||
categoryProcessor processor.CategoryProcessor
|
||||
productProcessor processor.ProductProcessor
|
||||
productVariantProcessor processor.ProductVariantProcessor
|
||||
inventoryProcessor processor.InventoryProcessor
|
||||
orderProcessor processor.OrderProcessor
|
||||
paymentMethodProcessor processor.PaymentMethodProcessor
|
||||
fileProcessor processor.FileProcessor
|
||||
customerProcessor *processor.CustomerProcessor
|
||||
analyticsProcessor *processor.AnalyticsProcessorImpl
|
||||
tableProcessor *processor.TableProcessor
|
||||
unitProcessor *processor.UnitProcessorImpl
|
||||
ingredientProcessor *processor.IngredientProcessorImpl
|
||||
userProcessor *processor.UserProcessorImpl
|
||||
organizationProcessor processor.OrganizationProcessor
|
||||
outletProcessor processor.OutletProcessor
|
||||
outletSettingProcessor *processor.OutletSettingProcessorImpl
|
||||
categoryProcessor processor.CategoryProcessor
|
||||
productProcessor processor.ProductProcessor
|
||||
productVariantProcessor processor.ProductVariantProcessor
|
||||
inventoryProcessor processor.InventoryProcessor
|
||||
orderProcessor processor.OrderProcessor
|
||||
paymentMethodProcessor processor.PaymentMethodProcessor
|
||||
fileProcessor processor.FileProcessor
|
||||
customerProcessor *processor.CustomerProcessor
|
||||
analyticsProcessor *processor.AnalyticsProcessorImpl
|
||||
tableProcessor *processor.TableProcessor
|
||||
unitProcessor *processor.UnitProcessorImpl
|
||||
ingredientProcessor *processor.IngredientProcessorImpl
|
||||
productRecipeProcessor *processor.ProductRecipeProcessorImpl
|
||||
vendorProcessor *processor.VendorProcessorImpl
|
||||
purchaseOrderProcessor *processor.PurchaseOrderProcessorImpl
|
||||
unitConverterProcessor *processor.IngredientUnitConverterProcessorImpl
|
||||
chartOfAccountTypeProcessor *processor.ChartOfAccountTypeProcessorImpl
|
||||
chartOfAccountProcessor *processor.ChartOfAccountProcessorImpl
|
||||
accountProcessor *processor.AccountProcessorImpl
|
||||
orderIngredientTransactionProcessor *processor.OrderIngredientTransactionProcessorImpl
|
||||
customerTokensProcessor *processor.CustomerTokensProcessor
|
||||
tierProcessor *processor.TierProcessor
|
||||
gameProcessor *processor.GameProcessor
|
||||
gamePrizeProcessor *processor.GamePrizeProcessor
|
||||
gamePlayProcessor *processor.GamePlayProcessor
|
||||
omsetTrackerProcessor *processor.OmsetTrackerProcessor
|
||||
rewardProcessor processor.RewardProcessor
|
||||
campaignProcessor processor.CampaignProcessor
|
||||
campaignRuleProcessor processor.CampaignRuleProcessor
|
||||
customerAuthProcessor processor.CustomerAuthProcessor
|
||||
customerPointsProcessor *processor.CustomerPointsProcessor
|
||||
otpProcessor processor.OtpProcessor
|
||||
fileClient processor.FileClient
|
||||
inventoryMovementService service.InventoryMovementService
|
||||
}
|
||||
|
||||
func (a *App) initProcessors(cfg *config.Config, repos *repositories) *processors {
|
||||
fileClient := client.NewFileClient(cfg.S3Config)
|
||||
fonnteClient := client.NewFonnteClient(cfg.GetFonnte())
|
||||
otpProcessor := processor.NewOtpProcessor(fonnteClient, repos.otpRepo)
|
||||
inventoryMovementService := service.NewInventoryMovementService(repos.inventoryMovementRepo, repos.ingredientRepo)
|
||||
|
||||
return &processors{
|
||||
userProcessor: processor.NewUserProcessor(repos.userRepo, repos.organizationRepo, repos.outletRepo),
|
||||
organizationProcessor: processor.NewOrganizationProcessorImpl(repos.organizationRepo, repos.outletRepo, repos.userRepo),
|
||||
outletProcessor: processor.NewOutletProcessorImpl(repos.outletRepo),
|
||||
outletSettingProcessor: processor.NewOutletSettingProcessorImpl(repos.outletSettingRepo, repos.outletRepo),
|
||||
categoryProcessor: processor.NewCategoryProcessorImpl(repos.categoryRepo),
|
||||
productProcessor: processor.NewProductProcessorImpl(repos.productRepo, repos.categoryRepo, repos.productVariantRepo, repos.inventoryRepo, repos.outletRepo),
|
||||
productVariantProcessor: processor.NewProductVariantProcessorImpl(repos.productVariantRepo, repos.productRepo),
|
||||
inventoryProcessor: processor.NewInventoryProcessorImpl(repos.inventoryRepo, repos.productRepo, repos.outletRepo),
|
||||
orderProcessor: processor.NewOrderProcessorImpl(repos.orderRepo, repos.orderItemRepo, repos.paymentRepo, repos.productRepo, repos.paymentMethodRepo, repos.inventoryRepo, repos.inventoryMovementRepo, repos.productVariantRepo, repos.outletRepo, repos.customerRepo),
|
||||
paymentMethodProcessor: processor.NewPaymentMethodProcessorImpl(repos.paymentMethodRepo),
|
||||
fileProcessor: processor.NewFileProcessorImpl(repos.fileRepo, fileClient),
|
||||
customerProcessor: processor.NewCustomerProcessor(repos.customerRepo),
|
||||
analyticsProcessor: processor.NewAnalyticsProcessorImpl(repos.analyticsRepo),
|
||||
tableProcessor: processor.NewTableProcessor(repos.tableRepo, repos.orderRepo),
|
||||
unitProcessor: processor.NewUnitProcessor(repos.unitRepo),
|
||||
ingredientProcessor: processor.NewIngredientProcessor(repos.ingredientRepo, repos.unitRepo),
|
||||
userProcessor: processor.NewUserProcessor(repos.userRepo, repos.organizationRepo, repos.outletRepo),
|
||||
organizationProcessor: processor.NewOrganizationProcessorImpl(repos.organizationRepo, repos.outletRepo, repos.userRepo),
|
||||
outletProcessor: processor.NewOutletProcessorImpl(repos.outletRepo),
|
||||
outletSettingProcessor: processor.NewOutletSettingProcessorImpl(repos.outletSettingRepo, repos.outletRepo),
|
||||
categoryProcessor: processor.NewCategoryProcessorImpl(repos.categoryRepo),
|
||||
productProcessor: processor.NewProductProcessorImpl(repos.productRepo, repos.categoryRepo, repos.productVariantRepo, repos.inventoryRepo, repos.outletRepo),
|
||||
productVariantProcessor: processor.NewProductVariantProcessorImpl(repos.productVariantRepo, repos.productRepo),
|
||||
inventoryProcessor: processor.NewInventoryProcessorImpl(repos.inventoryRepo, repos.productRepo, repos.outletRepo, repos.ingredientRepo, repos.inventoryMovementRepo),
|
||||
orderProcessor: processor.NewOrderProcessorImpl(repos.orderRepo, repos.orderItemRepo, repos.paymentRepo, repos.paymentOrderItemRepo, repos.productRepo, repos.paymentMethodRepo, repos.inventoryRepo, repos.inventoryMovementRepo, repos.productVariantRepo, repos.outletRepo, repos.customerRepo, repos.txManager, repos.productRecipeRepo, repos.ingredientRepo, inventoryMovementService),
|
||||
paymentMethodProcessor: processor.NewPaymentMethodProcessorImpl(repos.paymentMethodRepo),
|
||||
fileProcessor: processor.NewFileProcessorImpl(repos.fileRepo, fileClient),
|
||||
customerProcessor: processor.NewCustomerProcessor(repos.customerRepo),
|
||||
analyticsProcessor: processor.NewAnalyticsProcessorImpl(repos.analyticsRepo),
|
||||
tableProcessor: processor.NewTableProcessor(repos.tableRepo, repos.orderRepo),
|
||||
unitProcessor: processor.NewUnitProcessor(repos.unitRepo),
|
||||
ingredientProcessor: processor.NewIngredientProcessor(repos.ingredientRepo, repos.unitRepo, repos.ingredientCompositionRepo),
|
||||
productRecipeProcessor: processor.NewProductRecipeProcessor(repos.productRecipeRepo, repos.productRepo, repos.ingredientRepo),
|
||||
vendorProcessor: processor.NewVendorProcessorImpl(repos.vendorRepo),
|
||||
purchaseOrderProcessor: processor.NewPurchaseOrderProcessorImpl(repos.purchaseOrderRepo, repos.vendorRepo, repos.ingredientRepo, repos.unitRepo, repos.fileRepo, inventoryMovementService, repos.unitConverterRepo),
|
||||
unitConverterProcessor: processor.NewIngredientUnitConverterProcessorImpl(repos.unitConverterRepo, repos.ingredientRepo, repos.unitRepo),
|
||||
chartOfAccountTypeProcessor: processor.NewChartOfAccountTypeProcessorImpl(repos.chartOfAccountTypeRepo),
|
||||
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),
|
||||
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),
|
||||
rewardProcessor: processor.NewRewardProcessor(repos.rewardRepo),
|
||||
campaignProcessor: processor.NewCampaignProcessor(repos.campaignRepo),
|
||||
campaignRuleProcessor: processor.NewCampaignRuleProcessor(repos.campaignRuleRepo),
|
||||
customerAuthProcessor: processor.NewCustomerAuthProcessor(repos.customerAuthRepo, otpProcessor, repos.otpRepo, cfg.GetCustomerJWTSecret(), cfg.GetCustomerJWTExpiresTTL()),
|
||||
customerPointsProcessor: processor.NewCustomerPointsProcessor(repos.customerPointsRepo, repos.gameRepo),
|
||||
otpProcessor: otpProcessor,
|
||||
fileClient: fileClient,
|
||||
inventoryMovementService: inventoryMovementService,
|
||||
}
|
||||
}
|
||||
|
||||
type services struct {
|
||||
userService *service.UserServiceImpl
|
||||
authService service.AuthService
|
||||
organizationService service.OrganizationService
|
||||
outletService service.OutletService
|
||||
outletSettingService service.OutletSettingService
|
||||
categoryService service.CategoryService
|
||||
productService service.ProductService
|
||||
productVariantService service.ProductVariantService
|
||||
inventoryService service.InventoryService
|
||||
orderService service.OrderService
|
||||
paymentMethodService service.PaymentMethodService
|
||||
fileService service.FileService
|
||||
customerService service.CustomerService
|
||||
analyticsService *service.AnalyticsServiceImpl
|
||||
tableService *service.TableServiceImpl
|
||||
unitService *service.UnitServiceImpl
|
||||
ingredientService *service.IngredientServiceImpl
|
||||
userService *service.UserServiceImpl
|
||||
authService service.AuthService
|
||||
organizationService service.OrganizationService
|
||||
outletService service.OutletService
|
||||
outletSettingService service.OutletSettingService
|
||||
categoryService service.CategoryService
|
||||
productService service.ProductService
|
||||
productVariantService service.ProductVariantService
|
||||
inventoryService service.InventoryService
|
||||
orderService service.OrderService
|
||||
paymentMethodService service.PaymentMethodService
|
||||
fileService service.FileService
|
||||
customerService service.CustomerService
|
||||
analyticsService *service.AnalyticsServiceImpl
|
||||
reportService service.ReportService
|
||||
tableService *service.TableServiceImpl
|
||||
unitService *service.UnitServiceImpl
|
||||
ingredientService *service.IngredientServiceImpl
|
||||
productRecipeService *service.ProductRecipeServiceImpl
|
||||
vendorService *service.VendorServiceImpl
|
||||
purchaseOrderService *service.PurchaseOrderServiceImpl
|
||||
unitConverterService *service.IngredientUnitConverterServiceImpl
|
||||
chartOfAccountTypeService service.ChartOfAccountTypeService
|
||||
chartOfAccountService service.ChartOfAccountService
|
||||
accountService service.AccountService
|
||||
orderIngredientTransactionService *service.OrderIngredientTransactionService
|
||||
gamificationService service.GamificationService
|
||||
rewardService service.RewardService
|
||||
campaignService service.CampaignService
|
||||
customerAuthService service.CustomerAuthService
|
||||
customerPointsService service.CustomerPointsService
|
||||
spinGameService service.SpinGameService
|
||||
}
|
||||
|
||||
func (a *App) initServices(processors *processors, cfg *config.Config) *services {
|
||||
func (a *App) initServices(processors *processors, repos *repositories, cfg *config.Config) *services {
|
||||
authConfig := cfg.Auth()
|
||||
jwtSecret := authConfig.AccessTokenSecret()
|
||||
authService := service.NewAuthService(processors.userProcessor, jwtSecret)
|
||||
authService := service.NewAuthService(processors.userProcessor, authConfig)
|
||||
organizationService := service.NewOrganizationService(processors.organizationProcessor)
|
||||
outletService := service.NewOutletService(processors.outletProcessor)
|
||||
outletSettingService := service.NewOutletSettingService(processors.outletSettingProcessor)
|
||||
@@ -241,74 +375,131 @@ func (a *App) initServices(processors *processors, cfg *config.Config) *services
|
||||
productService := service.NewProductService(processors.productProcessor)
|
||||
productVariantService := service.NewProductVariantService(processors.productVariantProcessor)
|
||||
inventoryService := service.NewInventoryService(processors.inventoryProcessor)
|
||||
orderService := service.NewOrderServiceImpl(processors.orderProcessor)
|
||||
orderService := service.NewOrderServiceImpl(processors.orderProcessor, repos.tableRepo, nil, processors.orderIngredientTransactionProcessor, *repos.productRecipeRepo, repos.txManager) // Will be updated after orderIngredientTransactionService is created
|
||||
paymentMethodService := service.NewPaymentMethodService(processors.paymentMethodProcessor)
|
||||
fileService := service.NewFileServiceImpl(processors.fileProcessor)
|
||||
var customerService service.CustomerService = service.NewCustomerService(processors.customerProcessor)
|
||||
analyticsService := service.NewAnalyticsServiceImpl(processors.analyticsProcessor)
|
||||
reportService := service.NewReportService(analyticsService, repos.organizationRepo, repos.outletRepo, processors.fileClient)
|
||||
tableService := service.NewTableService(processors.tableProcessor, transformer.NewTableTransformer())
|
||||
unitService := service.NewUnitService(processors.unitProcessor)
|
||||
ingredientService := service.NewIngredientService(processors.ingredientProcessor)
|
||||
productRecipeService := service.NewProductRecipeService(processors.productRecipeProcessor)
|
||||
vendorService := service.NewVendorService(processors.vendorProcessor)
|
||||
purchaseOrderService := service.NewPurchaseOrderService(processors.purchaseOrderProcessor)
|
||||
unitConverterService := service.NewIngredientUnitConverterService(processors.unitConverterProcessor)
|
||||
chartOfAccountTypeService := service.NewChartOfAccountTypeService(processors.chartOfAccountTypeProcessor)
|
||||
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)
|
||||
rewardService := service.NewRewardService(processors.rewardProcessor)
|
||||
campaignService := service.NewCampaignService(processors.campaignProcessor, processors.campaignRuleProcessor)
|
||||
customerAuthService := service.NewCustomerAuthService(processors.customerAuthProcessor)
|
||||
customerPointsService := service.NewCustomerPointsService(processors.customerPointsProcessor)
|
||||
spinGameService := service.NewSpinGameService(processors.gamePlayProcessor, repos.txManager)
|
||||
|
||||
// Update order service with order ingredient transaction service
|
||||
orderService = service.NewOrderServiceImpl(processors.orderProcessor, repos.tableRepo, orderIngredientTransactionService, processors.orderIngredientTransactionProcessor, *repos.productRecipeRepo, repos.txManager)
|
||||
|
||||
return &services{
|
||||
userService: service.NewUserService(processors.userProcessor),
|
||||
authService: authService,
|
||||
organizationService: organizationService,
|
||||
outletService: outletService,
|
||||
outletSettingService: outletSettingService,
|
||||
categoryService: categoryService,
|
||||
productService: productService,
|
||||
productVariantService: productVariantService,
|
||||
inventoryService: inventoryService,
|
||||
orderService: orderService,
|
||||
paymentMethodService: paymentMethodService,
|
||||
fileService: fileService,
|
||||
customerService: customerService,
|
||||
analyticsService: analyticsService,
|
||||
tableService: tableService,
|
||||
unitService: unitService,
|
||||
ingredientService: ingredientService,
|
||||
userService: service.NewUserService(processors.userProcessor),
|
||||
authService: authService,
|
||||
organizationService: organizationService,
|
||||
outletService: outletService,
|
||||
outletSettingService: outletSettingService,
|
||||
categoryService: categoryService,
|
||||
productService: productService,
|
||||
productVariantService: productVariantService,
|
||||
inventoryService: inventoryService,
|
||||
orderService: orderService,
|
||||
paymentMethodService: paymentMethodService,
|
||||
fileService: fileService,
|
||||
customerService: customerService,
|
||||
analyticsService: analyticsService,
|
||||
reportService: reportService,
|
||||
tableService: tableService,
|
||||
unitService: unitService,
|
||||
ingredientService: ingredientService,
|
||||
productRecipeService: productRecipeService,
|
||||
vendorService: vendorService,
|
||||
purchaseOrderService: purchaseOrderService,
|
||||
unitConverterService: unitConverterService,
|
||||
chartOfAccountTypeService: chartOfAccountTypeService,
|
||||
chartOfAccountService: chartOfAccountService,
|
||||
accountService: accountService,
|
||||
orderIngredientTransactionService: orderIngredientTransactionService,
|
||||
gamificationService: gamificationService,
|
||||
rewardService: rewardService,
|
||||
campaignService: campaignService,
|
||||
customerAuthService: customerAuthService,
|
||||
customerPointsService: customerPointsService,
|
||||
spinGameService: spinGameService,
|
||||
}
|
||||
}
|
||||
|
||||
type middlewares struct {
|
||||
authMiddleware *middleware.AuthMiddleware
|
||||
authMiddleware *middleware.AuthMiddleware
|
||||
customerAuthMiddleware *middleware.CustomerAuthMiddleware
|
||||
}
|
||||
|
||||
func (a *App) initMiddleware(services *services) *middlewares {
|
||||
func (a *App) initMiddleware(services *services, cfg *config.Config) *middlewares {
|
||||
return &middlewares{
|
||||
authMiddleware: middleware.NewAuthMiddleware(services.authService),
|
||||
authMiddleware: middleware.NewAuthMiddleware(services.authService),
|
||||
customerAuthMiddleware: middleware.NewCustomerAuthMiddleware(cfg.GetCustomerJWTSecret()),
|
||||
}
|
||||
}
|
||||
|
||||
type validators struct {
|
||||
userValidator *validator.UserValidatorImpl
|
||||
organizationValidator validator.OrganizationValidator
|
||||
outletValidator validator.OutletValidator
|
||||
categoryValidator validator.CategoryValidator
|
||||
productValidator validator.ProductValidator
|
||||
productVariantValidator validator.ProductVariantValidator
|
||||
inventoryValidator validator.InventoryValidator
|
||||
orderValidator validator.OrderValidator
|
||||
paymentMethodValidator validator.PaymentMethodValidator
|
||||
fileValidator validator.FileValidator
|
||||
customerValidator validator.CustomerValidator
|
||||
tableValidator *validator.TableValidator
|
||||
userValidator *validator.UserValidatorImpl
|
||||
organizationValidator validator.OrganizationValidator
|
||||
outletValidator validator.OutletValidator
|
||||
categoryValidator validator.CategoryValidator
|
||||
productValidator validator.ProductValidator
|
||||
productVariantValidator validator.ProductVariantValidator
|
||||
inventoryValidator validator.InventoryValidator
|
||||
orderValidator validator.OrderValidator
|
||||
paymentMethodValidator validator.PaymentMethodValidator
|
||||
fileValidator validator.FileValidator
|
||||
customerValidator validator.CustomerValidator
|
||||
tableValidator *validator.TableValidator
|
||||
vendorValidator *validator.VendorValidatorImpl
|
||||
purchaseOrderValidator *validator.PurchaseOrderValidatorImpl
|
||||
unitConverterValidator *validator.IngredientUnitConverterValidatorImpl
|
||||
chartOfAccountTypeValidator *validator.ChartOfAccountTypeValidatorImpl
|
||||
chartOfAccountValidator *validator.ChartOfAccountValidatorImpl
|
||||
accountValidator *validator.AccountValidatorImpl
|
||||
orderIngredientTransactionValidator *validator.OrderIngredientTransactionValidatorImpl
|
||||
gamificationValidator *validator.GamificationValidatorImpl
|
||||
rewardValidator validator.RewardValidator
|
||||
campaignValidator validator.CampaignValidator
|
||||
customerAuthValidator validator.CustomerAuthValidator
|
||||
}
|
||||
|
||||
func (a *App) initValidators() *validators {
|
||||
return &validators{
|
||||
userValidator: validator.NewUserValidator(),
|
||||
organizationValidator: validator.NewOrganizationValidator(),
|
||||
outletValidator: validator.NewOutletValidator(),
|
||||
categoryValidator: validator.NewCategoryValidator(),
|
||||
productValidator: validator.NewProductValidator(),
|
||||
productVariantValidator: validator.NewProductVariantValidator(),
|
||||
inventoryValidator: validator.NewInventoryValidator(),
|
||||
orderValidator: validator.NewOrderValidator(),
|
||||
paymentMethodValidator: validator.NewPaymentMethodValidator(),
|
||||
fileValidator: validator.NewFileValidatorImpl(),
|
||||
customerValidator: validator.NewCustomerValidator(),
|
||||
tableValidator: validator.NewTableValidator(),
|
||||
userValidator: validator.NewUserValidator(),
|
||||
organizationValidator: validator.NewOrganizationValidator(),
|
||||
outletValidator: validator.NewOutletValidator(),
|
||||
categoryValidator: validator.NewCategoryValidator(),
|
||||
productValidator: validator.NewProductValidator(),
|
||||
productVariantValidator: validator.NewProductVariantValidator(),
|
||||
inventoryValidator: validator.NewInventoryValidator(),
|
||||
orderValidator: validator.NewOrderValidator(),
|
||||
paymentMethodValidator: validator.NewPaymentMethodValidator(),
|
||||
fileValidator: validator.NewFileValidatorImpl(),
|
||||
customerValidator: validator.NewCustomerValidator(),
|
||||
tableValidator: validator.NewTableValidator(),
|
||||
vendorValidator: validator.NewVendorValidator(),
|
||||
purchaseOrderValidator: validator.NewPurchaseOrderValidator(),
|
||||
unitConverterValidator: validator.NewIngredientUnitConverterValidator().(*validator.IngredientUnitConverterValidatorImpl),
|
||||
chartOfAccountTypeValidator: validator.NewChartOfAccountTypeValidator().(*validator.ChartOfAccountTypeValidatorImpl),
|
||||
chartOfAccountValidator: validator.NewChartOfAccountValidator().(*validator.ChartOfAccountValidatorImpl),
|
||||
accountValidator: validator.NewAccountValidator().(*validator.AccountValidatorImpl),
|
||||
orderIngredientTransactionValidator: validator.NewOrderIngredientTransactionValidator().(*validator.OrderIngredientTransactionValidatorImpl),
|
||||
gamificationValidator: validator.NewGamificationValidator(),
|
||||
rewardValidator: validator.NewRewardValidator(),
|
||||
campaignValidator: validator.NewCampaignValidator(),
|
||||
customerAuthValidator: validator.NewCustomerAuthValidator(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package appcontext
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -77,5 +78,18 @@ func FromContext(ctx context.Context) *ContextInfo {
|
||||
if info, ok := ctx.Value(ctxKey).(*ContextInfo); ok {
|
||||
return info
|
||||
}
|
||||
return nil
|
||||
// Fallback: construct ContextInfo from individual context values
|
||||
return &ContextInfo{
|
||||
CorrelationID: value(ctx, CorrelationIDKey),
|
||||
UserID: uuidValue(ctx, UserIDKey),
|
||||
OutletID: uuidValue(ctx, OutletIDKey),
|
||||
OrganizationID: uuidValue(ctx, OrganizationIDKey),
|
||||
AppVersion: value(ctx, AppVersionKey),
|
||||
AppID: value(ctx, AppIDKey),
|
||||
AppType: value(ctx, AppTypeKey),
|
||||
Platform: value(ctx, PlatformKey),
|
||||
DeviceOS: value(ctx, DeviceOSKey),
|
||||
UserLocale: value(ctx, UserLocaleKey),
|
||||
UserRole: value(ctx, UserRoleKey),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"apskel-pos-be/config"
|
||||
)
|
||||
|
||||
type FonnteClient interface {
|
||||
SendWhatsAppMessage(target string, message string) error
|
||||
}
|
||||
|
||||
type fonnteClient struct {
|
||||
httpClient *http.Client
|
||||
apiUrl string
|
||||
token string
|
||||
}
|
||||
|
||||
type FonnteResponse struct {
|
||||
Status bool `json:"status"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func NewFonnteClient(cfg *config.Fonnte) FonnteClient {
|
||||
return &fonnteClient{
|
||||
httpClient: &http.Client{
|
||||
Timeout: time.Duration(cfg.GetTimeout()) * time.Second,
|
||||
},
|
||||
apiUrl: cfg.GetApiUrl(),
|
||||
token: cfg.GetToken(),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *fonnteClient) SendWhatsAppMessage(target string, message string) error {
|
||||
// Prepare form data
|
||||
data := url.Values{}
|
||||
data.Set("target", target)
|
||||
data.Set("message", message)
|
||||
|
||||
// Create request
|
||||
req, err := http.NewRequest("POST", c.apiUrl, bytes.NewBufferString(data.Encode()))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
||||
// Set headers
|
||||
req.Header.Set("Authorization", c.token)
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
// Send request
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Read response body
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
// Check HTTP status
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("fonnte API returned status %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
// Log the response for debugging
|
||||
fmt.Printf("Fonnte API response: %s\n", string(body))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
{
|
||||
"chart_of_accounts": [
|
||||
{
|
||||
"name": "Current Assets",
|
||||
"code": "1000",
|
||||
"chart_of_account_type": "ASSET",
|
||||
"parent_code": null,
|
||||
"is_system": true,
|
||||
"accounts": [
|
||||
{
|
||||
"name": "Cash on Hand",
|
||||
"number": "1001",
|
||||
"account_type": "cash",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Physical cash available at the outlet"
|
||||
},
|
||||
{
|
||||
"name": "Petty Cash",
|
||||
"number": "1002",
|
||||
"account_type": "cash",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Small amount of cash for minor expenses"
|
||||
},
|
||||
{
|
||||
"name": "Bank Account - Main",
|
||||
"number": "1003",
|
||||
"account_type": "bank",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Primary business bank account"
|
||||
},
|
||||
{
|
||||
"name": "Digital Wallet",
|
||||
"number": "1004",
|
||||
"account_type": "wallet",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Digital payment wallet"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Inventory",
|
||||
"code": "1100",
|
||||
"chart_of_account_type": "ASSET",
|
||||
"parent_code": "1000",
|
||||
"is_system": true,
|
||||
"accounts": [
|
||||
{
|
||||
"name": "Raw Materials",
|
||||
"number": "1101",
|
||||
"account_type": "asset",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Raw materials and ingredients inventory"
|
||||
},
|
||||
{
|
||||
"name": "Finished Goods",
|
||||
"number": "1102",
|
||||
"account_type": "asset",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Finished products ready for sale"
|
||||
},
|
||||
{
|
||||
"name": "Work in Progress",
|
||||
"number": "1103",
|
||||
"account_type": "asset",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Products in production process"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Fixed Assets",
|
||||
"code": "1500",
|
||||
"chart_of_account_type": "ASSET",
|
||||
"parent_code": null,
|
||||
"is_system": true,
|
||||
"accounts": [
|
||||
{
|
||||
"name": "Equipment",
|
||||
"number": "1501",
|
||||
"account_type": "asset",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Business equipment and machinery"
|
||||
},
|
||||
{
|
||||
"name": "Furniture & Fixtures",
|
||||
"number": "1502",
|
||||
"account_type": "asset",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Furniture and fixtures"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Current Liabilities",
|
||||
"code": "2000",
|
||||
"chart_of_account_type": "LIABILITY",
|
||||
"parent_code": null,
|
||||
"is_system": true,
|
||||
"accounts": [
|
||||
{
|
||||
"name": "Accounts Payable",
|
||||
"number": "2001",
|
||||
"account_type": "liability",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Amounts owed to suppliers and vendors"
|
||||
},
|
||||
{
|
||||
"name": "Accrued Expenses",
|
||||
"number": "2002",
|
||||
"account_type": "liability",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Expenses incurred but not yet paid"
|
||||
},
|
||||
{
|
||||
"name": "Sales Tax Payable",
|
||||
"number": "2003",
|
||||
"account_type": "liability",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Sales tax collected but not yet remitted"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Owner's Equity",
|
||||
"code": "3000",
|
||||
"chart_of_account_type": "EQUITY",
|
||||
"parent_code": null,
|
||||
"is_system": true,
|
||||
"accounts": [
|
||||
{
|
||||
"name": "Owner's Capital",
|
||||
"number": "3001",
|
||||
"account_type": "equity",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Owner's initial investment in the business"
|
||||
},
|
||||
{
|
||||
"name": "Retained Earnings",
|
||||
"number": "3002",
|
||||
"account_type": "equity",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Accumulated profits retained in the business"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Revenue",
|
||||
"code": "4000",
|
||||
"chart_of_account_type": "REVENUE",
|
||||
"parent_code": null,
|
||||
"is_system": true,
|
||||
"accounts": [
|
||||
{
|
||||
"name": "Sales Revenue",
|
||||
"number": "4001",
|
||||
"account_type": "revenue",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Revenue from product sales"
|
||||
},
|
||||
{
|
||||
"name": "Service Revenue",
|
||||
"number": "4002",
|
||||
"account_type": "revenue",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Revenue from services provided"
|
||||
},
|
||||
{
|
||||
"name": "Other Income",
|
||||
"number": "4003",
|
||||
"account_type": "revenue",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Other sources of income"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cost of Goods Sold",
|
||||
"code": "5000",
|
||||
"chart_of_account_type": "EXPENSE",
|
||||
"parent_code": null,
|
||||
"is_system": true,
|
||||
"accounts": [
|
||||
{
|
||||
"name": "Raw Materials Cost",
|
||||
"number": "5001",
|
||||
"account_type": "expense",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Cost of raw materials used in production"
|
||||
},
|
||||
{
|
||||
"name": "Direct Labor Cost",
|
||||
"number": "5002",
|
||||
"account_type": "expense",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Direct labor costs for production"
|
||||
},
|
||||
{
|
||||
"name": "Manufacturing Overhead",
|
||||
"number": "5003",
|
||||
"account_type": "expense",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Manufacturing overhead costs"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Operating Expenses",
|
||||
"code": "6000",
|
||||
"chart_of_account_type": "EXPENSE",
|
||||
"parent_code": null,
|
||||
"is_system": true,
|
||||
"accounts": [
|
||||
{
|
||||
"name": "Rent Expense",
|
||||
"number": "6001",
|
||||
"account_type": "expense",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Rent for business premises"
|
||||
},
|
||||
{
|
||||
"name": "Utilities Expense",
|
||||
"number": "6002",
|
||||
"account_type": "expense",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Electricity, water, and other utilities"
|
||||
},
|
||||
{
|
||||
"name": "Salaries & Wages",
|
||||
"number": "6003",
|
||||
"account_type": "expense",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Employee salaries and wages"
|
||||
},
|
||||
{
|
||||
"name": "Marketing Expense",
|
||||
"number": "6004",
|
||||
"account_type": "expense",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Marketing and advertising expenses"
|
||||
},
|
||||
{
|
||||
"name": "Office Supplies",
|
||||
"number": "6005",
|
||||
"account_type": "expense",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Office supplies and stationery"
|
||||
},
|
||||
{
|
||||
"name": "Professional Services",
|
||||
"number": "6006",
|
||||
"account_type": "expense",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Legal, accounting, and consulting fees"
|
||||
},
|
||||
{
|
||||
"name": "Insurance Expense",
|
||||
"number": "6007",
|
||||
"account_type": "expense",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Business insurance premiums"
|
||||
},
|
||||
{
|
||||
"name": "Depreciation Expense",
|
||||
"number": "6008",
|
||||
"account_type": "expense",
|
||||
"opening_balance": 0.00,
|
||||
"description": "Depreciation of fixed assets"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+41
-24
@@ -15,30 +15,47 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
RequestEntity = "request"
|
||||
UserServiceEntity = "user_service"
|
||||
OrganizationServiceEntity = "organization_service"
|
||||
CategoryServiceEntity = "category_service"
|
||||
ProductServiceEntity = "product_service"
|
||||
ProductVariantServiceEntity = "product_variant_service"
|
||||
InventoryServiceEntity = "inventory_service"
|
||||
OrderServiceEntity = "order_service"
|
||||
CustomerServiceEntity = "customer_service"
|
||||
UserValidatorEntity = "user_validator"
|
||||
AuthHandlerEntity = "auth_handler"
|
||||
UserHandlerEntity = "user_handler"
|
||||
CategoryHandlerEntity = "category_handler"
|
||||
ProductHandlerEntity = "product_handler"
|
||||
ProductVariantHandlerEntity = "product_variant_handler"
|
||||
InventoryHandlerEntity = "inventory_handler"
|
||||
OrderValidatorEntity = "order_validator"
|
||||
OrderHandlerEntity = "order_handler"
|
||||
OrganizationValidatorEntity = "organization_validator"
|
||||
OrgHandlerEntity = "organization_handler"
|
||||
PaymentMethodValidatorEntity = "payment_method_validator"
|
||||
PaymentMethodHandlerEntity = "payment_method_handler"
|
||||
OutletServiceEntity = "outlet_service"
|
||||
TableEntity = "table"
|
||||
RequestEntity = "request"
|
||||
UserServiceEntity = "user_service"
|
||||
OrganizationServiceEntity = "organization_service"
|
||||
CategoryServiceEntity = "category_service"
|
||||
ProductServiceEntity = "product_service"
|
||||
ProductVariantServiceEntity = "product_variant_service"
|
||||
InventoryServiceEntity = "inventory_service"
|
||||
OrderServiceEntity = "order_service"
|
||||
CustomerServiceEntity = "customer_service"
|
||||
UserValidatorEntity = "user_validator"
|
||||
AuthHandlerEntity = "auth_handler"
|
||||
UserHandlerEntity = "user_handler"
|
||||
CategoryHandlerEntity = "category_handler"
|
||||
ProductHandlerEntity = "product_handler"
|
||||
ProductVariantHandlerEntity = "product_variant_handler"
|
||||
InventoryHandlerEntity = "inventory_handler"
|
||||
OrderValidatorEntity = "order_validator"
|
||||
OrderHandlerEntity = "order_handler"
|
||||
OrganizationValidatorEntity = "organization_validator"
|
||||
OrgHandlerEntity = "organization_handler"
|
||||
PaymentMethodValidatorEntity = "payment_method_validator"
|
||||
PaymentMethodHandlerEntity = "payment_method_handler"
|
||||
OutletServiceEntity = "outlet_service"
|
||||
VendorServiceEntity = "vendor_service"
|
||||
PurchaseOrderServiceEntity = "purchase_order_service"
|
||||
IngredientUnitConverterServiceEntity = "ingredient_unit_converter_service"
|
||||
IngredientCompositionServiceEntity = "ingredient_composition_service"
|
||||
TableEntity = "table"
|
||||
// Gamification entities
|
||||
CustomerPointsEntity = "customer_points"
|
||||
CustomerTokensEntity = "customer_tokens"
|
||||
TierEntity = "tier"
|
||||
GameEntity = "game"
|
||||
GamePrizeEntity = "game_prize"
|
||||
GamePlayEntity = "game_play"
|
||||
OmsetTrackerEntity = "omset_tracker"
|
||||
RewardEntity = "reward"
|
||||
CampaignEntity = "campaign"
|
||||
CampaignRuleEntity = "campaign_rule"
|
||||
CustomerEntity = "customer"
|
||||
SpinGameHandlerEntity = "spin_game_handler"
|
||||
)
|
||||
|
||||
var HttpErrorMap = map[string]int{
|
||||
|
||||
@@ -28,6 +28,7 @@ const (
|
||||
OrderItemStatusServed OrderItemStatus = "served"
|
||||
OrderItemStatusCancelled OrderItemStatus = "cancelled"
|
||||
OrderItemStatusCompleted OrderItemStatus = "completed"
|
||||
OrderItemStatusPaid OrderItemStatus = "paid"
|
||||
)
|
||||
|
||||
func GetAllOrderTypes() []OrderType {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type AccountContract interface {
|
||||
CreateAccount(ctx context.Context, req *CreateAccountRequest) (*AccountResponse, error)
|
||||
GetAccountByID(ctx context.Context, id uuid.UUID) (*AccountResponse, error)
|
||||
UpdateAccount(ctx context.Context, id uuid.UUID, req *UpdateAccountRequest) (*AccountResponse, error)
|
||||
DeleteAccount(ctx context.Context, id uuid.UUID) error
|
||||
ListAccounts(ctx context.Context, req *ListAccountsRequest) ([]AccountResponse, int, error)
|
||||
GetAccountsByOrganization(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]AccountResponse, error)
|
||||
GetAccountsByChartOfAccount(ctx context.Context, chartOfAccountID uuid.UUID) ([]AccountResponse, error)
|
||||
UpdateAccountBalance(ctx context.Context, id uuid.UUID, req *UpdateAccountBalanceRequest) error
|
||||
GetAccountBalance(ctx context.Context, id uuid.UUID) (float64, error)
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateAccountRequest struct {
|
||||
ChartOfAccountID uuid.UUID `json:"chart_of_account_id" validate:"required"`
|
||||
Name string `json:"name" validate:"required,min=1,max=255"`
|
||||
Number string `json:"number" validate:"required,min=1,max=50"`
|
||||
AccountType string `json:"account_type" validate:"required,oneof=cash wallet bank credit debit asset liability equity revenue expense"`
|
||||
OpeningBalance float64 `json:"opening_balance"`
|
||||
Description *string `json:"description"`
|
||||
}
|
||||
|
||||
type UpdateAccountRequest struct {
|
||||
ChartOfAccountID *uuid.UUID `json:"chart_of_account_id"`
|
||||
Name *string `json:"name" validate:"omitempty,min=1,max=255"`
|
||||
Number *string `json:"number" validate:"omitempty,min=1,max=50"`
|
||||
AccountType *string `json:"account_type" validate:"omitempty,oneof=cash wallet bank credit debit asset liability equity revenue expense"`
|
||||
OpeningBalance *float64 `json:"opening_balance"`
|
||||
Description *string `json:"description"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
}
|
||||
|
||||
type AccountResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
OutletID *uuid.UUID `json:"outlet_id"`
|
||||
ChartOfAccountID uuid.UUID `json:"chart_of_account_id"`
|
||||
Name string `json:"name"`
|
||||
Number string `json:"number"`
|
||||
AccountType string `json:"account_type"`
|
||||
OpeningBalance float64 `json:"opening_balance"`
|
||||
CurrentBalance float64 `json:"current_balance"`
|
||||
Description *string `json:"description"`
|
||||
IsActive bool `json:"is_active"`
|
||||
IsSystem bool `json:"is_system"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
ChartOfAccount *ChartOfAccountResponse `json:"chart_of_account,omitempty"`
|
||||
}
|
||||
|
||||
type ListAccountsRequest struct {
|
||||
OrganizationID *uuid.UUID `form:"organization_id"`
|
||||
OutletID *uuid.UUID `form:"outlet_id"`
|
||||
ChartOfAccountID *uuid.UUID `form:"chart_of_account_id"`
|
||||
AccountType *string `form:"account_type"`
|
||||
IsActive *bool `form:"is_active"`
|
||||
IsSystem *bool `form:"is_system"`
|
||||
Page int `form:"page,default=1"`
|
||||
Limit int `form:"limit,default=10"`
|
||||
}
|
||||
|
||||
type UpdateAccountBalanceRequest struct {
|
||||
Amount float64 `json:"amount" binding:"required"`
|
||||
}
|
||||
@@ -89,7 +89,7 @@ type ProductAnalyticsRequest struct {
|
||||
OutletID *uuid.UUID `form:"outlet_id,omitempty"`
|
||||
DateFrom string `form:"date_from" validate:"required"`
|
||||
DateTo string `form:"date_to" validate:"required"`
|
||||
Limit int `form:"limit,default=10" validate:"min=1,max=100"`
|
||||
Limit int `form:"limit,default=1000" validate:"min=1,max=1000"`
|
||||
}
|
||||
|
||||
// ProductAnalyticsResponse represents the response for product analytics
|
||||
@@ -101,16 +101,52 @@ type ProductAnalyticsResponse struct {
|
||||
Data []ProductAnalyticsData `json:"data"`
|
||||
}
|
||||
|
||||
// ProductAnalyticsData represents individual product analytics data
|
||||
type ProductAnalyticsData struct {
|
||||
ProductID uuid.UUID `json:"product_id"`
|
||||
ProductName string `json:"product_name"`
|
||||
CategoryID uuid.UUID `json:"category_id"`
|
||||
CategoryName string `json:"category_name"`
|
||||
QuantitySold int64 `json:"quantity_sold"`
|
||||
Revenue float64 `json:"revenue"`
|
||||
AveragePrice float64 `json:"average_price"`
|
||||
OrderCount int64 `json:"order_count"`
|
||||
ProductID uuid.UUID `json:"product_id"`
|
||||
ProductName string `json:"product_name"`
|
||||
ProductSku string `json:"product_sku"`
|
||||
CategoryID uuid.UUID `json:"category_id"`
|
||||
CategoryName string `json:"category_name"`
|
||||
CategoryOrder int `json:"category_order"`
|
||||
QuantitySold int64 `json:"quantity_sold"`
|
||||
Revenue float64 `json:"revenue"`
|
||||
AveragePrice float64 `json:"average_price"`
|
||||
OrderCount int64 `json:"order_count"`
|
||||
StandardHppPerUnit float64 `json:"standard_hpp_per_unit"`
|
||||
StandardHppTotal float64 `json:"standard_hpp_total"`
|
||||
FifoHppPerUnit float64 `json:"fifo_hpp_per_unit"`
|
||||
FifoHppTotal float64 `json:"fifo_hpp_total"`
|
||||
MovingAverageHppPerUnit float64 `json:"moving_average_hpp_per_unit"`
|
||||
MovingAverageHppTotal float64 `json:"moving_average_hpp_total"`
|
||||
}
|
||||
|
||||
// ProductAnalyticsPerCategoryRequest represents the request for product analytics per category
|
||||
type ProductAnalyticsPerCategoryRequest struct {
|
||||
OrganizationID uuid.UUID
|
||||
OutletID *uuid.UUID `form:"outlet_id,omitempty"`
|
||||
DateFrom string `form:"date_from" validate:"required"`
|
||||
DateTo string `form:"date_to" validate:"required"`
|
||||
}
|
||||
|
||||
// ProductAnalyticsPerCategoryResponse represents the response for product analytics per category
|
||||
type ProductAnalyticsPerCategoryResponse struct {
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
OutletID *uuid.UUID `json:"outlet_id,omitempty"`
|
||||
DateFrom time.Time `json:"date_from"`
|
||||
DateTo time.Time `json:"date_to"`
|
||||
Data []ProductAnalyticsPerCategoryData `json:"data"`
|
||||
}
|
||||
|
||||
type ProductAnalyticsPerCategoryData struct {
|
||||
CategoryID uuid.UUID `json:"category_id"`
|
||||
CategoryName string `json:"category_name"`
|
||||
TotalRevenue float64 `json:"total_revenue"`
|
||||
TotalQuantity int64 `json:"total_quantity"`
|
||||
ProductCount int64 `json:"product_count"`
|
||||
OrderCount int64 `json:"order_count"`
|
||||
TotalStandardHpp float64 `json:"total_standard_hpp"`
|
||||
TotalFifoHpp float64 `json:"total_fifo_hpp"`
|
||||
TotalMovingAverageHpp float64 `json:"total_moving_average_hpp"`
|
||||
}
|
||||
|
||||
// DashboardAnalyticsRequest represents the request for dashboard analytics
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"apskel-pos-be/internal/entities"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Request Contracts
|
||||
type CreateCampaignRequest struct {
|
||||
Name string `json:"name" binding:"required,min=1,max=150"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Type string `json:"type" binding:"required,oneof=REWARD POINTS TOKENS MIXED"`
|
||||
StartDate time.Time `json:"start_date" binding:"required"`
|
||||
EndDate time.Time `json:"end_date" binding:"required"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ShowOnApp bool `json:"show_on_app"`
|
||||
Position int `json:"position" binding:"min=0"`
|
||||
Metadata *entities.Metadata `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateCampaignRequest struct {
|
||||
ID uuid.UUID `json:"id" binding:"required"`
|
||||
Name string `json:"name" binding:"required,min=1,max=150"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Type string `json:"type" binding:"required,oneof=REWARD POINTS TOKENS MIXED"`
|
||||
StartDate time.Time `json:"start_date" binding:"required"`
|
||||
EndDate time.Time `json:"end_date" binding:"required"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ShowOnApp bool `json:"show_on_app"`
|
||||
Position int `json:"position" binding:"min=0"`
|
||||
Metadata *entities.Metadata `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type ListCampaignsRequest struct {
|
||||
Page int `form:"page" binding:"min=1"`
|
||||
Limit int `form:"limit" binding:"min=1,max=100"`
|
||||
Search string `form:"search"`
|
||||
Type string `form:"type"`
|
||||
IsActive *bool `form:"is_active"`
|
||||
ShowOnApp *bool `form:"show_on_app"`
|
||||
StartDate *time.Time `form:"start_date"`
|
||||
EndDate *time.Time `form:"end_date"`
|
||||
}
|
||||
|
||||
type GetCampaignRequest struct {
|
||||
ID uuid.UUID `uri:"id" binding:"required"`
|
||||
}
|
||||
|
||||
type DeleteCampaignRequest struct {
|
||||
ID uuid.UUID `uri:"id" binding:"required"`
|
||||
}
|
||||
|
||||
// Campaign Rule Request Contracts
|
||||
type CreateCampaignRuleRequest struct {
|
||||
CampaignID uuid.UUID `json:"campaign_id" binding:"required"`
|
||||
RuleType string `json:"rule_type" binding:"required,oneof=TIER SPEND PRODUCT CATEGORY DAY LOCATION"`
|
||||
ConditionValue *string `json:"condition_value,omitempty"`
|
||||
RewardType string `json:"reward_type" binding:"required,oneof=POINTS TOKENS REWARD"`
|
||||
RewardValue *int64 `json:"reward_value,omitempty"`
|
||||
RewardSubtype *string `json:"reward_subtype,omitempty"`
|
||||
RewardRefID *uuid.UUID `json:"reward_ref_id,omitempty"`
|
||||
Metadata *entities.Metadata `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateCampaignRuleRequest struct {
|
||||
ID uuid.UUID `json:"id" binding:"required"`
|
||||
CampaignID uuid.UUID `json:"campaign_id" binding:"required"`
|
||||
RuleType string `json:"rule_type" binding:"required,oneof=TIER SPEND PRODUCT CATEGORY DAY LOCATION"`
|
||||
ConditionValue *string `json:"condition_value,omitempty"`
|
||||
RewardType string `json:"reward_type" binding:"required,oneof=POINTS TOKENS REWARD"`
|
||||
RewardValue *int64 `json:"reward_value,omitempty"`
|
||||
RewardSubtype *string `json:"reward_subtype,omitempty"`
|
||||
RewardRefID *uuid.UUID `json:"reward_ref_id,omitempty"`
|
||||
Metadata *entities.Metadata `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type ListCampaignRulesRequest struct {
|
||||
Page int `form:"page" binding:"min=1"`
|
||||
Limit int `form:"limit" binding:"min=1,max=100"`
|
||||
CampaignID string `form:"campaign_id"`
|
||||
RuleType string `form:"rule_type"`
|
||||
RewardType string `form:"reward_type"`
|
||||
}
|
||||
|
||||
type GetCampaignRuleRequest struct {
|
||||
ID uuid.UUID `uri:"id" binding:"required"`
|
||||
}
|
||||
|
||||
type DeleteCampaignRuleRequest struct {
|
||||
ID uuid.UUID `uri:"id" binding:"required"`
|
||||
}
|
||||
|
||||
// Response Contracts
|
||||
type CampaignResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Type string `json:"type"`
|
||||
StartDate time.Time `json:"start_date"`
|
||||
EndDate time.Time `json:"end_date"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ShowOnApp bool `json:"show_on_app"`
|
||||
Position int `json:"position"`
|
||||
Metadata *entities.Metadata `json:"metadata,omitempty"`
|
||||
Rules []CampaignRuleResponse `json:"rules,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type CampaignRuleResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
CampaignID uuid.UUID `json:"campaign_id"`
|
||||
RuleType string `json:"rule_type"`
|
||||
ConditionValue *string `json:"condition_value,omitempty"`
|
||||
RewardType string `json:"reward_type"`
|
||||
RewardValue *int64 `json:"reward_value,omitempty"`
|
||||
RewardSubtype *string `json:"reward_subtype,omitempty"`
|
||||
RewardRefID *uuid.UUID `json:"reward_ref_id,omitempty"`
|
||||
Metadata *entities.Metadata `json:"metadata,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListCampaignsResponse struct {
|
||||
Campaigns []CampaignResponse `json:"campaigns"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
}
|
||||
|
||||
type ListCampaignRulesResponse struct {
|
||||
Rules []CampaignRuleResponse `json:"rules"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
}
|
||||
|
||||
// Helper structs
|
||||
type CampaignRuleStruct struct {
|
||||
RuleType string `json:"rule_type" binding:"required,oneof=TIER SPEND PRODUCT CATEGORY DAY LOCATION"`
|
||||
ConditionValue *string `json:"condition_value,omitempty"`
|
||||
RewardType string `json:"reward_type" binding:"required,oneof=POINTS TOKENS REWARD"`
|
||||
RewardValue *int64 `json:"reward_value,omitempty"`
|
||||
RewardSubtype *string `json:"reward_subtype,omitempty"`
|
||||
RewardRefID *uuid.UUID `json:"reward_ref_id,omitempty"`
|
||||
Metadata *entities.Metadata `json:"metadata,omitempty"`
|
||||
}
|
||||
@@ -10,6 +10,7 @@ type CreateCategoryRequest struct {
|
||||
Name string `json:"name" validate:"required,min=1,max=255"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
BusinessType *string `json:"business_type,omitempty"`
|
||||
Order *int `json:"order,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
@@ -17,6 +18,7 @@ type UpdateCategoryRequest struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,min=1,max=255"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
BusinessType *string `json:"business_type,omitempty"`
|
||||
Order *int `json:"order,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
@@ -35,6 +37,7 @@ type CategoryResponse struct {
|
||||
Name string `json:"name"`
|
||||
Description *string `json:"description"`
|
||||
BusinessType string `json:"business_type"`
|
||||
Order int `json:"order"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ChartOfAccountContract interface {
|
||||
CreateChartOfAccount(ctx context.Context, req *CreateChartOfAccountRequest) (*ChartOfAccountResponse, error)
|
||||
GetChartOfAccountByID(ctx context.Context, id uuid.UUID) (*ChartOfAccountResponse, error)
|
||||
UpdateChartOfAccount(ctx context.Context, id uuid.UUID, req *UpdateChartOfAccountRequest) (*ChartOfAccountResponse, error)
|
||||
DeleteChartOfAccount(ctx context.Context, id uuid.UUID) error
|
||||
ListChartOfAccounts(ctx context.Context, req *ListChartOfAccountsRequest) ([]ChartOfAccountResponse, int, error)
|
||||
GetChartOfAccountsByOrganization(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]ChartOfAccountResponse, error)
|
||||
GetChartOfAccountsByType(ctx context.Context, organizationID uuid.UUID, chartOfAccountTypeID uuid.UUID, outletID *uuid.UUID) ([]ChartOfAccountResponse, error)
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateChartOfAccountRequest struct {
|
||||
ChartOfAccountTypeID uuid.UUID `json:"chart_of_account_type_id" validate:"required"`
|
||||
ParentID *uuid.UUID `json:"parent_id"`
|
||||
Name string `json:"name" validate:"required,min=1,max=255"`
|
||||
Code string `json:"code" validate:"required,min=1,max=20"`
|
||||
Description *string `json:"description"`
|
||||
}
|
||||
|
||||
type UpdateChartOfAccountRequest struct {
|
||||
ChartOfAccountTypeID *uuid.UUID `json:"chart_of_account_type_id"`
|
||||
ParentID *uuid.UUID `json:"parent_id"`
|
||||
Name *string `json:"name" validate:"omitempty,min=1,max=255"`
|
||||
Code *string `json:"code" validate:"omitempty,min=1,max=20"`
|
||||
Description *string `json:"description"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
}
|
||||
|
||||
type ChartOfAccountResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
OutletID *uuid.UUID `json:"outlet_id"`
|
||||
ChartOfAccountTypeID uuid.UUID `json:"chart_of_account_type_id"`
|
||||
ParentID *uuid.UUID `json:"parent_id"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
Description *string `json:"description"`
|
||||
IsActive bool `json:"is_active"`
|
||||
IsSystem bool `json:"is_system"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
ChartOfAccountType *ChartOfAccountTypeResponse `json:"chart_of_account_type,omitempty"`
|
||||
Parent *ChartOfAccountResponse `json:"parent,omitempty"`
|
||||
Children []ChartOfAccountResponse `json:"children,omitempty"`
|
||||
}
|
||||
|
||||
type ListChartOfAccountsRequest struct {
|
||||
ChartOfAccountTypeID *uuid.UUID `form:"chart_of_account_type_id"`
|
||||
ParentID *uuid.UUID `form:"parent_id"`
|
||||
IsActive *bool `form:"is_active"`
|
||||
IsSystem *bool `form:"is_system"`
|
||||
Page int `form:"page,default=1"`
|
||||
Limit int `form:"limit,default=10"`
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ChartOfAccountTypeContract interface {
|
||||
CreateChartOfAccountType(ctx context.Context, req *CreateChartOfAccountTypeRequest) (*ChartOfAccountTypeResponse, error)
|
||||
GetChartOfAccountTypeByID(ctx context.Context, id uuid.UUID) (*ChartOfAccountTypeResponse, error)
|
||||
UpdateChartOfAccountType(ctx context.Context, id uuid.UUID, req *UpdateChartOfAccountTypeRequest) (*ChartOfAccountTypeResponse, error)
|
||||
DeleteChartOfAccountType(ctx context.Context, id uuid.UUID) error
|
||||
ListChartOfAccountTypes(ctx context.Context, filters map[string]interface{}, page, limit int) ([]ChartOfAccountTypeResponse, int, error)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateChartOfAccountTypeRequest struct {
|
||||
Name string `json:"name" validate:"required,min=1,max=100"`
|
||||
Code string `json:"code" validate:"required,min=1,max=10"`
|
||||
Description *string `json:"description"`
|
||||
}
|
||||
|
||||
type UpdateChartOfAccountTypeRequest struct {
|
||||
Name *string `json:"name" validate:"omitempty,min=1,max=100"`
|
||||
Code *string `json:"code" validate:"omitempty,min=1,max=10"`
|
||||
Description *string `json:"description"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
}
|
||||
|
||||
type ChartOfAccountTypeResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
Description *string `json:"description"`
|
||||
IsActive bool `json:"is_active"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Request Contracts
|
||||
type CheckPhoneRequest struct {
|
||||
PhoneNumber string `json:"phone_number" binding:"required"`
|
||||
Password string `json:"password,omitempty"` // Optional - only required if user exists
|
||||
}
|
||||
|
||||
type RegisterStartRequest struct {
|
||||
PhoneNumber string `json:"phone_number" binding:"required"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
BirthDate string `json:"birth_date" binding:"required"`
|
||||
}
|
||||
|
||||
type RegisterVerifyOtpRequest struct {
|
||||
RegistrationToken string `json:"registration_token" binding:"required"`
|
||||
OtpCode string `json:"otp_code" binding:"required"`
|
||||
}
|
||||
|
||||
type RegisterSetPasswordRequest struct {
|
||||
RegistrationToken string `json:"registration_token" binding:"required"`
|
||||
Password string `json:"password" binding:"required,min=8"`
|
||||
ConfirmPassword string `json:"confirm_password" binding:"required"`
|
||||
}
|
||||
|
||||
type CustomerLoginRequest struct {
|
||||
PhoneNumber string `json:"phone_number" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
}
|
||||
|
||||
type ResendOtpRequest struct {
|
||||
PhoneNumber string `json:"phone_number" binding:"required"`
|
||||
Purpose string `json:"purpose" binding:"required,oneof=login registration"`
|
||||
}
|
||||
|
||||
// Response Contracts
|
||||
type CheckPhoneResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data *CheckPhoneResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type CheckPhoneResponseData struct {
|
||||
// For NOT_REGISTERED status
|
||||
PhoneNumber string `json:"phone_number,omitempty"`
|
||||
|
||||
// For PASSWORD_REQUIRED status
|
||||
AccessToken string `json:"access_token,omitempty"`
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
User *CustomerUserData `json:"user,omitempty"`
|
||||
|
||||
// For OTP_REQUIRED status (if password doesn't exist)
|
||||
OtpToken string `json:"otp_token,omitempty"`
|
||||
ExpiresIn int `json:"expires_in,omitempty"`
|
||||
}
|
||||
|
||||
type RegisterStartResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data *RegisterStartResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type RegisterStartResponseData struct {
|
||||
RegistrationToken string `json:"registration_token"`
|
||||
OtpToken string `json:"otp_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
}
|
||||
|
||||
type RegisterVerifyOtpResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data *RegisterVerifyOtpResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type RegisterVerifyOtpResponseData struct {
|
||||
RegistrationToken string `json:"registration_token"`
|
||||
}
|
||||
|
||||
type RegisterSetPasswordResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data *RegisterSetPasswordResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type RegisterSetPasswordResponseData struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
User *CustomerUserData `json:"user"`
|
||||
}
|
||||
|
||||
type CustomerUserData struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
BirthDate string `json:"birth_date"`
|
||||
}
|
||||
|
||||
type CustomerLoginResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data *CustomerLoginResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type CustomerLoginResponseData struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
User *CustomerUserData `json:"user"`
|
||||
}
|
||||
|
||||
type ResendOtpResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data *ResendOtpResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type ResendOtpResponseData struct {
|
||||
OtpToken string `json:"otp_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
NextResendIn int `json:"next_resend_in"` // Seconds until next resend is allowed
|
||||
}
|
||||
|
||||
// Internal structures for OTP and registration tokens
|
||||
type OtpSession struct {
|
||||
Token string `json:"token"`
|
||||
Code string `json:"code"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
Purpose string `json:"purpose"` // "login" or "registration"
|
||||
}
|
||||
|
||||
type RegistrationSession struct {
|
||||
Token string `json:"token"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
Name string `json:"name"`
|
||||
BirthDate string `json:"birth_date"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
Step string `json:"step"` // "otp_sent", "otp_verified", "password_set"
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Request Contracts
|
||||
type GetCustomerGamesRequest struct {
|
||||
// No additional fields needed - customer ID comes from JWT token
|
||||
}
|
||||
|
||||
// Response Contracts
|
||||
type GetCustomerGamesResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data *GetCustomerGamesResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type GetCustomerGamesResponseData struct {
|
||||
Games []CustomerGameResponse `json:"games"`
|
||||
}
|
||||
|
||||
type CustomerGameResponse 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,omitempty"`
|
||||
Prizes []CustomerGamePrizeResponse `json:"prizes,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type CustomerGamePrizeResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
GameID uuid.UUID `json:"game_id"`
|
||||
Name string `json:"name"`
|
||||
Image *string `json:"image,omitempty"`
|
||||
Metadata *map[string]interface{} `json:"metadata,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Ferris Wheel Game Contracts
|
||||
type GetFerrisWheelGameRequest struct {
|
||||
// No additional fields needed - customer ID comes from JWT token
|
||||
}
|
||||
|
||||
type GetFerrisWheelGameResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data *GetFerrisWheelGameResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type GetFerrisWheelGameResponseData struct {
|
||||
Game CustomerGameResponse `json:"game"`
|
||||
Prizes []CustomerGamePrizeResponse `json:"prizes"`
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Existing gamification contracts
|
||||
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"`
|
||||
}
|
||||
|
||||
// New customer API contracts
|
||||
type GetCustomerPointsRequest struct {
|
||||
// No additional fields needed - customer ID comes from JWT token
|
||||
}
|
||||
|
||||
type GetCustomerTokensRequest struct {
|
||||
// No additional fields needed - customer ID comes from JWT token
|
||||
}
|
||||
|
||||
type GetCustomerWalletRequest struct {
|
||||
// No additional fields needed - customer ID comes from JWT token
|
||||
}
|
||||
|
||||
// Response Contracts
|
||||
type GetCustomerPointsResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data *GetCustomerPointsResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type GetCustomerPointsResponseData struct {
|
||||
TotalPoints int64 `json:"total_points"`
|
||||
PointsHistory []PointsHistoryItem `json:"points_history,omitempty"`
|
||||
LastUpdated time.Time `json:"last_updated"`
|
||||
}
|
||||
|
||||
type PointsHistoryItem struct {
|
||||
ID string `json:"id"`
|
||||
Points int64 `json:"points"`
|
||||
Type string `json:"type"` // EARNED, REDEEMED, EXPIRED
|
||||
Description string `json:"description"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type GetCustomerTokensResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data *GetCustomerTokensResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type GetCustomerTokensResponseData struct {
|
||||
TotalTokens int64 `json:"total_tokens"`
|
||||
TokensHistory []TokensHistoryItem `json:"tokens_history,omitempty"`
|
||||
LastUpdated time.Time `json:"last_updated"`
|
||||
}
|
||||
|
||||
type TokensHistoryItem struct {
|
||||
ID string `json:"id"`
|
||||
Tokens int64 `json:"tokens"`
|
||||
Type string `json:"type"` // EARNED, REDEEMED, EXPIRED
|
||||
Description string `json:"description"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type GetCustomerWalletResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data *GetCustomerWalletResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type GetCustomerWalletResponseData struct {
|
||||
TotalPoints int64 `json:"total_points"`
|
||||
TotalTokens int64 `json:"total_tokens"`
|
||||
PointsHistory []PointsHistoryItem `json:"points_history,omitempty"`
|
||||
TokensHistory []TokensHistoryItem `json:"tokens_history,omitempty"`
|
||||
LastUpdated time.Time `json:"last_updated"`
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
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"`
|
||||
Image *string `json:"image,omitempty" validate:"omitempty,max=500"`
|
||||
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"`
|
||||
Image *string `json:"image,omitempty" validate:"omitempty,max=500"`
|
||||
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"`
|
||||
Image *string `json:"image,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"`
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/models"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type IngredientCompositionContract interface {
|
||||
Create(request *models.CreateIngredientCompositionRequest, organizationID uuid.UUID) (*models.IngredientCompositionResponse, error)
|
||||
GetByID(id uuid.UUID, organizationID uuid.UUID) (*models.IngredientCompositionResponse, error)
|
||||
GetByParentIngredientID(parentIngredientID uuid.UUID, organizationID uuid.UUID) ([]*models.IngredientCompositionResponse, error)
|
||||
GetByChildIngredientID(childIngredientID uuid.UUID, organizationID uuid.UUID) ([]*models.IngredientCompositionResponse, error)
|
||||
Update(id uuid.UUID, request *models.UpdateIngredientCompositionRequest, organizationID uuid.UUID) (*models.IngredientCompositionResponse, error)
|
||||
Delete(id uuid.UUID, organizationID uuid.UUID) error
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Request DTOs
|
||||
type CreateIngredientUnitConverterRequest struct {
|
||||
IngredientID uuid.UUID `json:"ingredient_id" validate:"required"`
|
||||
FromUnitID uuid.UUID `json:"from_unit_id" validate:"required"`
|
||||
ToUnitID uuid.UUID `json:"to_unit_id" validate:"required"`
|
||||
ConversionFactor float64 `json:"conversion_factor" validate:"required,gt=0"`
|
||||
IsActive *bool `json:"is_active,omitempty" validate:"omitempty"`
|
||||
}
|
||||
|
||||
type UpdateIngredientUnitConverterRequest struct {
|
||||
FromUnitID *uuid.UUID `json:"from_unit_id,omitempty" validate:"omitempty"`
|
||||
ToUnitID *uuid.UUID `json:"to_unit_id,omitempty" validate:"omitempty"`
|
||||
ConversionFactor *float64 `json:"conversion_factor,omitempty" validate:"omitempty,gt=0"`
|
||||
IsActive *bool `json:"is_active,omitempty" validate:"omitempty"`
|
||||
}
|
||||
|
||||
type ListIngredientUnitConvertersRequest struct {
|
||||
IngredientID *uuid.UUID `json:"ingredient_id,omitempty"`
|
||||
FromUnitID *uuid.UUID `json:"from_unit_id,omitempty"`
|
||||
ToUnitID *uuid.UUID `json:"to_unit_id,omitempty"`
|
||||
IsActive *bool `json:"is_active,omitempty"`
|
||||
Search string `json:"search,omitempty"`
|
||||
Page int `json:"page" validate:"required,min=1"`
|
||||
Limit int `json:"limit" validate:"required,min=1,max=100"`
|
||||
}
|
||||
|
||||
type ConvertUnitRequest struct {
|
||||
IngredientID uuid.UUID `json:"ingredient_id" validate:"required"`
|
||||
FromUnitID uuid.UUID `json:"from_unit_id" validate:"required"`
|
||||
ToUnitID uuid.UUID `json:"to_unit_id" validate:"required"`
|
||||
Quantity float64 `json:"quantity" validate:"required,gt=0"`
|
||||
}
|
||||
|
||||
// Response DTOs
|
||||
type IngredientUnitConverterResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
IngredientID uuid.UUID `json:"ingredient_id"`
|
||||
FromUnitID uuid.UUID `json:"from_unit_id"`
|
||||
ToUnitID uuid.UUID `json:"to_unit_id"`
|
||||
ConversionFactor float64 `json:"conversion_factor"`
|
||||
IsActive bool `json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
CreatedBy uuid.UUID `json:"created_by"`
|
||||
UpdatedBy uuid.UUID `json:"updated_by"`
|
||||
Ingredient *IngredientResponse `json:"ingredient,omitempty"`
|
||||
FromUnit *UnitResponse `json:"from_unit,omitempty"`
|
||||
ToUnit *UnitResponse `json:"to_unit,omitempty"`
|
||||
}
|
||||
|
||||
type ConvertUnitResponse struct {
|
||||
FromQuantity float64 `json:"from_quantity"`
|
||||
FromUnit *UnitResponse `json:"from_unit"`
|
||||
ToQuantity float64 `json:"to_quantity"`
|
||||
ToUnit *UnitResponse `json:"to_unit"`
|
||||
ConversionFactor float64 `json:"conversion_factor"`
|
||||
Ingredient *IngredientResponse `json:"ingredient,omitempty"`
|
||||
}
|
||||
|
||||
type ListIngredientUnitConvertersResponse struct {
|
||||
Converters []IngredientUnitConverterResponse `json:"converters"`
|
||||
TotalCount int `json:"total_count"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
}
|
||||
|
||||
type IngredientUnitsResponse struct {
|
||||
IngredientID uuid.UUID `json:"ingredient_id"`
|
||||
IngredientName string `json:"ingredient_name"`
|
||||
BaseUnitID uuid.UUID `json:"base_unit_id"`
|
||||
BaseUnitName string `json:"base_unit_name"`
|
||||
Units []*UnitResponse `json:"units"`
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateInventoryRequest struct {
|
||||
@@ -24,6 +25,18 @@ type AdjustInventoryRequest struct {
|
||||
Reason string `json:"reason" validate:"required,min=1,max=255"`
|
||||
}
|
||||
|
||||
type RestockInventoryRequest struct {
|
||||
OutletID uuid.UUID `json:"outlet_id" validate:"required"`
|
||||
Items []RestockItem `json:"items" validate:"required,min=1,dive"`
|
||||
Reason string `json:"reason" validate:"required,min=1,max=255"`
|
||||
}
|
||||
|
||||
type RestockItem struct {
|
||||
ItemID uuid.UUID `json:"item_id" validate:"required"`
|
||||
ItemType string `json:"item_type" validate:"required,oneof=PRODUCT INGREDIENT"`
|
||||
Quantity int `json:"quantity" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type ListInventoryRequest struct {
|
||||
OutletID *uuid.UUID `json:"outlet_id,omitempty"`
|
||||
ProductID *uuid.UUID `json:"product_id,omitempty"`
|
||||
@@ -67,3 +80,75 @@ type InventoryAdjustmentResponse struct {
|
||||
Reason string `json:"reason"`
|
||||
AdjustedAt time.Time `json:"adjusted_at"`
|
||||
}
|
||||
|
||||
type RestockInventoryResponse struct {
|
||||
OutletID uuid.UUID `json:"outlet_id"`
|
||||
Items []RestockItemResult `json:"items"`
|
||||
Reason string `json:"reason"`
|
||||
RestockedAt time.Time `json:"restocked_at"`
|
||||
}
|
||||
|
||||
type RestockItemResult struct {
|
||||
ItemID uuid.UUID `json:"item_id"`
|
||||
ItemType string `json:"item_type"`
|
||||
ItemName string `json:"item_name"`
|
||||
PreviousQty int `json:"previous_quantity"`
|
||||
NewQty int `json:"new_quantity"`
|
||||
AddedQty int `json:"added_quantity"`
|
||||
Success bool `json:"success"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// Inventory Report Contracts
|
||||
type InventoryReportSummaryResponse struct {
|
||||
TotalProducts int `json:"total_products"`
|
||||
TotalIngredients int `json:"total_ingredients"`
|
||||
TotalValue float64 `json:"total_value"`
|
||||
LowStockProducts int `json:"low_stock_products"`
|
||||
LowStockIngredients int `json:"low_stock_ingredients"`
|
||||
ZeroStockProducts int `json:"zero_stock_products"`
|
||||
ZeroStockIngredients int `json:"zero_stock_ingredients"`
|
||||
TotalSoldProducts float64 `json:"total_sold_products"`
|
||||
TotalSoldIngredients float64 `json:"total_sold_ingredients"`
|
||||
OutletID string `json:"outlet_id"`
|
||||
OutletName string `json:"outlet_name"`
|
||||
GeneratedAt string `json:"generated_at"`
|
||||
}
|
||||
|
||||
type InventoryReportDetailResponse struct {
|
||||
Summary *InventoryReportSummaryResponse `json:"summary"`
|
||||
Products []*InventoryProductDetailResponse `json:"products"`
|
||||
Ingredients []*InventoryIngredientDetailResponse `json:"ingredients"`
|
||||
}
|
||||
|
||||
type InventoryProductDetailResponse struct {
|
||||
ID string `json:"id"`
|
||||
ProductID string `json:"product_id"`
|
||||
ProductName string `json:"product_name"`
|
||||
CategoryName string `json:"category_name"`
|
||||
Quantity int `json:"quantity"`
|
||||
ReorderLevel int `json:"reorder_level"`
|
||||
UnitCost float64 `json:"unit_cost"`
|
||||
TotalValue float64 `json:"total_value"`
|
||||
TotalIn float64 `json:"total_in"`
|
||||
TotalOut float64 `json:"total_out"`
|
||||
IsLowStock bool `json:"is_low_stock"`
|
||||
IsZeroStock bool `json:"is_zero_stock"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
type InventoryIngredientDetailResponse struct {
|
||||
ID string `json:"id"`
|
||||
IngredientID string `json:"ingredient_id"`
|
||||
IngredientName string `json:"ingredient_name"`
|
||||
UnitName string `json:"unit_name"`
|
||||
Quantity int `json:"quantity"`
|
||||
ReorderLevel int `json:"reorder_level"`
|
||||
UnitCost float64 `json:"unit_cost"`
|
||||
TotalValue float64 `json:"total_value"`
|
||||
TotalIn float64 `json:"total_in"`
|
||||
TotalOut float64 `json:"total_out"`
|
||||
IsLowStock bool `json:"is_low_stock"`
|
||||
IsZeroStock bool `json:"is_zero_stock"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -10,6 +10,7 @@ type CreateOrderRequest struct {
|
||||
OutletID uuid.UUID `json:"outlet_id" validate:"required"`
|
||||
UserID uuid.UUID `json:"user_id" validate:"required"`
|
||||
CustomerID *uuid.UUID `json:"customer_id"`
|
||||
TableID *uuid.UUID `json:"table_id,omitempty" validate:"omitempty"`
|
||||
TableNumber *string `json:"table_number,omitempty" validate:"omitempty,max=50"`
|
||||
OrderType string `json:"order_type" validate:"required,oneof=dine_in takeaway delivery"`
|
||||
Notes *string `json:"notes,omitempty" validate:"omitempty,max=1000"`
|
||||
@@ -56,23 +57,38 @@ type UpdateOrderItemRequest struct {
|
||||
}
|
||||
|
||||
type OrderResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
OrderNumber string `json:"order_number"`
|
||||
OutletID uuid.UUID `json:"outlet_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
TableNumber *string `json:"table_number"`
|
||||
OrderType string `json:"order_type"`
|
||||
Status string `json:"status"`
|
||||
Subtotal float64 `json:"subtotal"`
|
||||
TaxAmount float64 `json:"tax_amount"`
|
||||
DiscountAmount float64 `json:"discount_amount"`
|
||||
TotalAmount float64 `json:"total_amount"`
|
||||
Notes *string `json:"notes"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
OrderItems []OrderItemResponse `json:"order_items,omitempty"`
|
||||
IsRefund bool `json:"is_refund"`
|
||||
ID uuid.UUID `json:"id"`
|
||||
OrderNumber string `json:"order_number"`
|
||||
OutletID uuid.UUID `json:"outlet_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
TableNumber *string `json:"table_number"`
|
||||
OrderType string `json:"order_type"`
|
||||
Status string `json:"status"`
|
||||
Subtotal float64 `json:"subtotal"`
|
||||
TaxAmount float64 `json:"tax_amount"`
|
||||
DiscountAmount float64 `json:"discount_amount"`
|
||||
TotalAmount float64 `json:"total_amount"`
|
||||
TotalCost float64 `json:"total_cost"`
|
||||
RemainingAmount float64 `json:"remaining_amount"`
|
||||
PaymentStatus string `json:"payment_status"`
|
||||
RefundAmount float64 `json:"refund_amount"`
|
||||
IsVoid bool `json:"is_void"`
|
||||
IsRefund bool `json:"is_refund"`
|
||||
VoidReason *string `json:"void_reason,omitempty"`
|
||||
VoidedAt *time.Time `json:"voided_at,omitempty"`
|
||||
VoidedBy *uuid.UUID `json:"voided_by,omitempty"`
|
||||
RefundReason *string `json:"refund_reason,omitempty"`
|
||||
RefundedAt *time.Time `json:"refunded_at,omitempty"`
|
||||
RefundedBy *uuid.UUID `json:"refunded_by,omitempty"`
|
||||
Notes *string `json:"notes"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
OrderItems []OrderItemResponse `json:"order_items,omitempty"`
|
||||
Payments []PaymentResponse `json:"payments,omitempty"`
|
||||
TotalPaid float64 `json:"total_paid"`
|
||||
PaymentCount int `json:"payment_count"`
|
||||
SplitType *string `json:"split_type,omitempty"`
|
||||
}
|
||||
|
||||
type OrderItemResponse struct {
|
||||
@@ -92,6 +108,7 @@ type OrderItemResponse struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
PrinterType string `json:"printer_type"`
|
||||
PaidQuantity int `json:"paid_quantity"`
|
||||
}
|
||||
|
||||
type ListOrdersQuery struct {
|
||||
@@ -123,11 +140,12 @@ type ListOrdersRequest struct {
|
||||
}
|
||||
|
||||
type ListOrdersResponse struct {
|
||||
Orders []OrderResponse `json:"orders"`
|
||||
TotalCount int `json:"total_count"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
Orders []OrderResponse `json:"orders"`
|
||||
Payments []PaymentResponse `json:"payments"`
|
||||
TotalCount int `json:"total_count"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
}
|
||||
|
||||
type VoidOrderRequest struct {
|
||||
@@ -152,7 +170,6 @@ type SetOrderCustomerResponse struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Payment-related contracts
|
||||
type CreatePaymentRequest struct {
|
||||
OrderID uuid.UUID `json:"order_id" validate:"required"`
|
||||
PaymentMethodID uuid.UUID `json:"payment_method_id" validate:"required"`
|
||||
@@ -160,6 +177,7 @@ type CreatePaymentRequest struct {
|
||||
TransactionID *string `json:"transaction_id,omitempty" validate:"omitempty"`
|
||||
SplitNumber int `json:"split_number,omitempty" validate:"omitempty,min=1"`
|
||||
SplitTotal int `json:"split_total,omitempty" validate:"omitempty,min=1"`
|
||||
SplitType *string `json:"split_type,omitempty" validate:"omitempty,oneof=AMOUNT ITEM"`
|
||||
SplitDescription *string `json:"split_description,omitempty" validate:"omitempty,max=255"`
|
||||
PaymentOrderItems []CreatePaymentOrderItemRequest `json:"payment_order_items,omitempty" validate:"omitempty,dive"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
@@ -167,18 +185,21 @@ type CreatePaymentRequest struct {
|
||||
|
||||
type CreatePaymentOrderItemRequest struct {
|
||||
OrderItemID uuid.UUID `json:"order_item_id" validate:"required"`
|
||||
Amount float64 `json:"amount" validate:"required,min=0"`
|
||||
Amount float64 `json:"amount" validate:"min=0"`
|
||||
}
|
||||
|
||||
type PaymentResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
OrderID uuid.UUID `json:"order_id"`
|
||||
PaymentMethodID uuid.UUID `json:"payment_method_id"`
|
||||
PaymentMethodName string `json:"payment_method_name"`
|
||||
PaymentMethodType string `json:"payment_method_type"`
|
||||
Amount float64 `json:"amount"`
|
||||
Status string `json:"status"`
|
||||
TransactionID *string `json:"transaction_id,omitempty"`
|
||||
SplitNumber int `json:"split_number"`
|
||||
SplitTotal int `json:"split_total"`
|
||||
SplitType *string `json:"split_type,omitempty"`
|
||||
SplitDescription *string `json:"split_description,omitempty"`
|
||||
RefundAmount float64 `json:"refund_amount"`
|
||||
RefundReason *string `json:"refund_reason,omitempty"`
|
||||
@@ -216,3 +237,33 @@ type RefundPaymentRequest struct {
|
||||
RefundAmount float64 `json:"refund_amount" validate:"required,min=0"`
|
||||
Reason string `json:"reason" validate:"omitempty,max=255"`
|
||||
}
|
||||
|
||||
type SplitBillRequest struct {
|
||||
OrderID uuid.UUID `json:"order_id" validate:"required"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
PaymentMethodID uuid.UUID `json:"payment_method_id" validate:"required"`
|
||||
CustomerID uuid.UUID `json:"customer_id"`
|
||||
Type string `json:"type" validate:"required,oneof=ITEM AMOUNT"`
|
||||
Items []SplitBillItemRequest `json:"items,omitempty" validate:"required_if=Type ITEM,dive"`
|
||||
Amount float64 `json:"amount,omitempty" validate:"required_if=Type AMOUNT,min=0"`
|
||||
}
|
||||
|
||||
type SplitBillItemRequest struct {
|
||||
OrderItemID uuid.UUID `json:"order_item_id" validate:"required"`
|
||||
Quantity int `json:"quantity" validate:"required,min=0"`
|
||||
}
|
||||
|
||||
type SplitBillResponse struct {
|
||||
PaymentID uuid.UUID `json:"payment_id"`
|
||||
OrderID uuid.UUID `json:"order_id"`
|
||||
CustomerID uuid.UUID `json:"customer_id"`
|
||||
Type string `json:"type"`
|
||||
Amount float64 `json:"amount"`
|
||||
Items []SplitBillItemResponse `json:"items,omitempty"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type SplitBillItemResponse struct {
|
||||
OrderItemID uuid.UUID `json:"order_item_id"`
|
||||
Amount float64 `json:"amount"`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type OrderIngredientTransactionContract interface {
|
||||
CreateOrderIngredientTransaction(ctx context.Context, req *CreateOrderIngredientTransactionRequest) (*OrderIngredientTransactionResponse, error)
|
||||
GetOrderIngredientTransactionByID(ctx context.Context, id uuid.UUID) (*OrderIngredientTransactionResponse, error)
|
||||
UpdateOrderIngredientTransaction(ctx context.Context, id uuid.UUID, req *UpdateOrderIngredientTransactionRequest) (*OrderIngredientTransactionResponse, error)
|
||||
DeleteOrderIngredientTransaction(ctx context.Context, id uuid.UUID) error
|
||||
ListOrderIngredientTransactions(ctx context.Context, req *ListOrderIngredientTransactionsRequest) ([]*OrderIngredientTransactionResponse, int64, error)
|
||||
GetOrderIngredientTransactionsByOrder(ctx context.Context, orderID uuid.UUID) ([]*OrderIngredientTransactionResponse, error)
|
||||
GetOrderIngredientTransactionsByOrderItem(ctx context.Context, orderItemID uuid.UUID) ([]*OrderIngredientTransactionResponse, error)
|
||||
GetOrderIngredientTransactionsByIngredient(ctx context.Context, ingredientID uuid.UUID) ([]*OrderIngredientTransactionResponse, error)
|
||||
GetOrderIngredientTransactionSummary(ctx context.Context, req *ListOrderIngredientTransactionsRequest) ([]*OrderIngredientTransactionSummary, error)
|
||||
BulkCreateOrderIngredientTransactions(ctx context.Context, transactions []*CreateOrderIngredientTransactionRequest) ([]*OrderIngredientTransactionResponse, error)
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateOrderIngredientTransactionRequest struct {
|
||||
OrderID uuid.UUID `json:"order_id" validate:"required"`
|
||||
OrderItemID *uuid.UUID `json:"order_item_id,omitempty"`
|
||||
ProductID uuid.UUID `json:"product_id" validate:"required"`
|
||||
ProductVariantID *uuid.UUID `json:"product_variant_id,omitempty"`
|
||||
IngredientID uuid.UUID `json:"ingredient_id" validate:"required"`
|
||||
GrossQty float64 `json:"gross_qty" validate:"required,gt=0"`
|
||||
NetQty float64 `json:"net_qty" validate:"required,gt=0"`
|
||||
WasteQty float64 `json:"waste_qty" validate:"min=0"`
|
||||
Unit string `json:"unit" validate:"required,max=50"`
|
||||
TransactionDate *time.Time `json:"transaction_date,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateOrderIngredientTransactionRequest struct {
|
||||
GrossQty *float64 `json:"gross_qty,omitempty" validate:"omitempty,gt=0"`
|
||||
NetQty *float64 `json:"net_qty,omitempty" validate:"omitempty,gt=0"`
|
||||
WasteQty *float64 `json:"waste_qty,omitempty" validate:"min=0"`
|
||||
Unit *string `json:"unit,omitempty" validate:"omitempty,max=50"`
|
||||
TransactionDate *time.Time `json:"transaction_date,omitempty"`
|
||||
}
|
||||
|
||||
type OrderIngredientTransactionResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
OutletID *uuid.UUID `json:"outlet_id"`
|
||||
OrderID uuid.UUID `json:"order_id"`
|
||||
OrderItemID *uuid.UUID `json:"order_item_id"`
|
||||
ProductID uuid.UUID `json:"product_id"`
|
||||
ProductVariantID *uuid.UUID `json:"product_variant_id"`
|
||||
IngredientID uuid.UUID `json:"ingredient_id"`
|
||||
GrossQty float64 `json:"gross_qty"`
|
||||
NetQty float64 `json:"net_qty"`
|
||||
WasteQty float64 `json:"waste_qty"`
|
||||
Unit string `json:"unit"`
|
||||
TransactionDate time.Time `json:"transaction_date"`
|
||||
CreatedBy uuid.UUID `json:"created_by"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// Relations - these would be populated by the service layer
|
||||
Organization interface{} `json:"organization,omitempty"`
|
||||
Outlet interface{} `json:"outlet,omitempty"`
|
||||
Order interface{} `json:"order,omitempty"`
|
||||
OrderItem interface{} `json:"order_item,omitempty"`
|
||||
Product interface{} `json:"product,omitempty"`
|
||||
ProductVariant interface{} `json:"product_variant,omitempty"`
|
||||
Ingredient interface{} `json:"ingredient,omitempty"`
|
||||
CreatedByUser interface{} `json:"created_by_user,omitempty"`
|
||||
}
|
||||
|
||||
type ListOrderIngredientTransactionsRequest struct {
|
||||
OrderID *uuid.UUID `json:"order_id,omitempty"`
|
||||
OrderItemID *uuid.UUID `json:"order_item_id,omitempty"`
|
||||
ProductID *uuid.UUID `json:"product_id,omitempty"`
|
||||
ProductVariantID *uuid.UUID `json:"product_variant_id,omitempty"`
|
||||
IngredientID *uuid.UUID `json:"ingredient_id,omitempty"`
|
||||
StartDate *time.Time `json:"start_date,omitempty"`
|
||||
EndDate *time.Time `json:"end_date,omitempty"`
|
||||
Page int `json:"page" validate:"min=1"`
|
||||
Limit int `json:"limit" validate:"min=1,max=100"`
|
||||
}
|
||||
|
||||
type OrderIngredientTransactionSummary struct {
|
||||
IngredientID uuid.UUID `json:"ingredient_id"`
|
||||
IngredientName string `json:"ingredient_name"`
|
||||
TotalGrossQty float64 `json:"total_gross_qty"`
|
||||
TotalNetQty float64 `json:"total_net_qty"`
|
||||
TotalWasteQty float64 `json:"total_waste_qty"`
|
||||
WastePercentage float64 `json:"waste_percentage"`
|
||||
Unit string `json:"unit"`
|
||||
}
|
||||
@@ -59,6 +59,7 @@ type ProductResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
CategoryID uuid.UUID `json:"category_id"`
|
||||
CategoryName string `json:"category_name"`
|
||||
SKU *string `json:"sku"`
|
||||
Name string `json:"name"`
|
||||
Description *string `json:"description"`
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Request structures
|
||||
type CreateProductRecipeRequest struct {
|
||||
OutletID *uuid.UUID `json:"outlet_id"`
|
||||
ProductID uuid.UUID `json:"product_id" validate:"required"`
|
||||
VariantID *uuid.UUID `json:"variant_id"`
|
||||
IngredientID uuid.UUID `json:"ingredient_id" validate:"required"`
|
||||
Quantity float64 `json:"quantity" validate:"required,gt=0"`
|
||||
WastePercentage float64 `json:"waste_percentage" validate:"min=0,max=100"`
|
||||
}
|
||||
|
||||
type UpdateProductRecipeRequest struct {
|
||||
OutletID *uuid.UUID `json:"outlet_id"`
|
||||
VariantID *uuid.UUID `json:"variant_id"`
|
||||
Quantity float64 `json:"quantity" validate:"required,gt=0"`
|
||||
WastePercentage float64 `json:"waste_percentage" validate:"min=0,max=100"`
|
||||
}
|
||||
|
||||
type GetProductRecipeByProductIDRequest struct {
|
||||
ProductID uuid.UUID `json:"-"`
|
||||
VariantID *uuid.UUID `json:"-"`
|
||||
}
|
||||
|
||||
type BulkCreateProductRecipeRequest struct {
|
||||
Recipes []CreateProductRecipeRequest `json:"recipes" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
// Response structures
|
||||
type ProductRecipeResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
OutletID *uuid.UUID `json:"outlet_id"`
|
||||
ProductID uuid.UUID `json:"product_id"`
|
||||
VariantID *uuid.UUID `json:"variant_id"`
|
||||
IngredientID uuid.UUID `json:"ingredient_id"`
|
||||
Quantity float64 `json:"quantity"`
|
||||
WastePercentage float64 `json:"waste_percentage"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Product *ProductResponse `json:"product,omitempty"`
|
||||
ProductVariant *ProductVariantResponse `json:"product_variant,omitempty"`
|
||||
Ingredient *ProductRecipeIngredientResponse `json:"ingredient,omitempty"`
|
||||
}
|
||||
|
||||
type ProductRecipeIngredientResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
OutletID *uuid.UUID `json:"outlet_id"`
|
||||
Name string `json:"name"`
|
||||
UnitID uuid.UUID `json:"unit_id"`
|
||||
Cost float64 `json:"cost"`
|
||||
Stock float64 `json:"stock"`
|
||||
IsSemiFinished bool `json:"is_semi_finished"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Unit *ProductRecipeUnitResponse `json:"unit,omitempty"`
|
||||
}
|
||||
|
||||
type ProductRecipeUnitResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Symbol string `json:"symbol"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreatePurchaseOrderRequest struct {
|
||||
VendorID uuid.UUID `json:"vendor_id" validate:"required"`
|
||||
PONumber string `json:"po_number" validate:"required,min=1,max=50"`
|
||||
TransactionDate string `json:"transaction_date" validate:"required"` // Format: YYYY-MM-DD
|
||||
DueDate string `json:"due_date" validate:"required"` // Format: YYYY-MM-DD
|
||||
Reference *string `json:"reference,omitempty" validate:"omitempty,max=100"`
|
||||
Status *string `json:"status,omitempty" validate:"omitempty,oneof=draft sent approved received cancelled"`
|
||||
Message *string `json:"message,omitempty" validate:"omitempty"`
|
||||
Items []CreatePurchaseOrderItemRequest `json:"items" validate:"required,min=1,dive"`
|
||||
AttachmentFileIDs []uuid.UUID `json:"attachment_file_ids,omitempty"`
|
||||
}
|
||||
|
||||
type CreatePurchaseOrderItemRequest struct {
|
||||
IngredientID uuid.UUID `json:"ingredient_id" validate:"required"`
|
||||
Description *string `json:"description,omitempty" validate:"omitempty"`
|
||||
Quantity float64 `json:"quantity" validate:"required,gt=0"`
|
||||
UnitID uuid.UUID `json:"unit_id" validate:"required"`
|
||||
Amount float64 `json:"amount" validate:"required,gte=0"`
|
||||
}
|
||||
|
||||
type UpdatePurchaseOrderRequest struct {
|
||||
VendorID *uuid.UUID `json:"vendor_id,omitempty" validate:"omitempty"`
|
||||
PONumber *string `json:"po_number,omitempty" validate:"omitempty,min=1,max=50"`
|
||||
TransactionDate *string `json:"transaction_date,omitempty" validate:"omitempty"` // Format: YYYY-MM-DD
|
||||
DueDate *string `json:"due_date,omitempty" validate:"omitempty"` // Format: YYYY-MM-DD
|
||||
Reference *string `json:"reference,omitempty" validate:"omitempty,max=100"`
|
||||
Status *string `json:"status,omitempty" validate:"omitempty,oneof=draft sent approved received cancelled"`
|
||||
Message *string `json:"message,omitempty" validate:"omitempty"`
|
||||
Items []UpdatePurchaseOrderItemRequest `json:"items,omitempty" validate:"omitempty,dive"`
|
||||
AttachmentFileIDs []uuid.UUID `json:"attachment_file_ids,omitempty"`
|
||||
}
|
||||
|
||||
type UpdatePurchaseOrderItemRequest struct {
|
||||
ID *uuid.UUID `json:"id,omitempty"` // For existing items
|
||||
IngredientID *uuid.UUID `json:"ingredient_id,omitempty" validate:"omitempty"`
|
||||
Description *string `json:"description,omitempty" validate:"omitempty"`
|
||||
Quantity *float64 `json:"quantity,omitempty" validate:"omitempty,gt=0"`
|
||||
UnitID *uuid.UUID `json:"unit_id,omitempty" validate:"omitempty"`
|
||||
Amount *float64 `json:"amount,omitempty" validate:"omitempty,gte=0"`
|
||||
}
|
||||
|
||||
type PurchaseOrderResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
VendorID uuid.UUID `json:"vendor_id"`
|
||||
PONumber string `json:"po_number"`
|
||||
TransactionDate time.Time `json:"transaction_date"`
|
||||
DueDate time.Time `json:"due_date"`
|
||||
Reference *string `json:"reference"`
|
||||
Status string `json:"status"`
|
||||
Message *string `json:"message"`
|
||||
TotalAmount float64 `json:"total_amount"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Vendor *VendorResponse `json:"vendor,omitempty"`
|
||||
Items []PurchaseOrderItemResponse `json:"items,omitempty"`
|
||||
Attachments []PurchaseOrderAttachmentResponse `json:"attachments,omitempty"`
|
||||
}
|
||||
|
||||
type PurchaseOrderItemResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
PurchaseOrderID uuid.UUID `json:"purchase_order_id"`
|
||||
IngredientID uuid.UUID `json:"ingredient_id"`
|
||||
Description *string `json:"description"`
|
||||
Quantity float64 `json:"quantity"`
|
||||
UnitID uuid.UUID `json:"unit_id"`
|
||||
Amount float64 `json:"amount"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Ingredient *IngredientResponse `json:"ingredient,omitempty"`
|
||||
Unit *UnitResponse `json:"unit,omitempty"`
|
||||
}
|
||||
|
||||
type PurchaseOrderAttachmentResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
PurchaseOrderID uuid.UUID `json:"purchase_order_id"`
|
||||
FileID uuid.UUID `json:"file_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
File *FileResponse `json:"file,omitempty"`
|
||||
}
|
||||
|
||||
type ListPurchaseOrdersRequest struct {
|
||||
Page int `json:"page" validate:"min=1"`
|
||||
Limit int `json:"limit" validate:"min=1,max=100"`
|
||||
Search string `json:"search,omitempty"`
|
||||
Status string `json:"status,omitempty" validate:"omitempty,oneof=draft sent approved received cancelled"`
|
||||
VendorID *uuid.UUID `json:"vendor_id,omitempty"`
|
||||
StartDate *time.Time `json:"start_date,omitempty"`
|
||||
EndDate *time.Time `json:"end_date,omitempty"`
|
||||
}
|
||||
|
||||
type ListPurchaseOrdersResponse struct {
|
||||
PurchaseOrders []PurchaseOrderResponse `json:"purchase_orders"`
|
||||
TotalCount int `json:"total_count"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
}
|
||||
|
||||
// Helper types for ingredient and unit responses
|
||||
type IngredientResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type UnitResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Request Contracts
|
||||
type CreateRewardRequest struct {
|
||||
Name string `json:"name" binding:"required,min=1,max=150"`
|
||||
RewardType string `json:"reward_type" binding:"required,oneof=VOUCHER PHYSICAL DIGITAL"`
|
||||
CostPoints int64 `json:"cost_points" binding:"required,min=1"`
|
||||
Stock *int `json:"stock,omitempty"`
|
||||
MaxPerCustomer int `json:"max_per_customer" binding:"min=1"`
|
||||
Tnc *TermsAndConditionsStruct `json:"tnc,omitempty"`
|
||||
Metadata *map[string]interface{} `json:"metadata,omitempty"`
|
||||
Images *[]string `json:"images,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateRewardRequest struct {
|
||||
ID uuid.UUID `json:"id" binding:"required"`
|
||||
Name string `json:"name" binding:"required,min=1,max=150"`
|
||||
RewardType string `json:"reward_type" binding:"required,oneof=VOUCHER PHYSICAL DIGITAL BALANCE"`
|
||||
CostPoints int64 `json:"cost_points" binding:"required,min=1"`
|
||||
Stock *int `json:"stock,omitempty"`
|
||||
MaxPerCustomer int `json:"max_per_customer" binding:"min=1"`
|
||||
Tnc *TermsAndConditionsStruct `json:"tnc,omitempty"`
|
||||
Metadata *map[string]interface{} `json:"metadata,omitempty"`
|
||||
Images *[]string `json:"images,omitempty"`
|
||||
}
|
||||
|
||||
type ListRewardsRequest struct {
|
||||
Page int `form:"page" binding:"min=1"`
|
||||
Limit int `form:"limit" binding:"min=1,max=100"`
|
||||
Search string `form:"search"`
|
||||
RewardType string `form:"reward_type"`
|
||||
MinPoints *int64 `form:"min_points"`
|
||||
MaxPoints *int64 `form:"max_points"`
|
||||
HasStock *bool `form:"has_stock"`
|
||||
}
|
||||
|
||||
type GetRewardRequest struct {
|
||||
ID uuid.UUID `uri:"id" binding:"required"`
|
||||
}
|
||||
|
||||
type DeleteRewardRequest struct {
|
||||
ID uuid.UUID `uri:"id" binding:"required"`
|
||||
}
|
||||
|
||||
// Response Contracts
|
||||
type RewardResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
RewardType string `json:"reward_type"`
|
||||
CostPoints int64 `json:"cost_points"`
|
||||
Stock *int `json:"stock,omitempty"`
|
||||
MaxPerCustomer int `json:"max_per_customer"`
|
||||
Tnc *TermsAndConditionsStruct `json:"tnc,omitempty"`
|
||||
Metadata *map[string]interface{} `json:"metadata,omitempty"`
|
||||
Images *[]string `json:"images,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListRewardsResponse struct {
|
||||
Rewards []RewardResponse `json:"rewards"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
}
|
||||
|
||||
// Helper structs
|
||||
type TermsAndConditionsStruct struct {
|
||||
Sections []TncSectionStruct `json:"sections"`
|
||||
ExpiryDays int `json:"expiry_days"`
|
||||
}
|
||||
|
||||
type TncSectionStruct struct {
|
||||
Title string `json:"title"`
|
||||
Rules []string `json:"rules"`
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package contract
|
||||
|
||||
// SpinGameRequest represents the request to play a spin game
|
||||
type SpinGameRequest struct {
|
||||
SpinID string `json:"spin_id" validate:"required,uuid"`
|
||||
}
|
||||
|
||||
// SpinGameResponse represents the response from playing a spin game
|
||||
type SpinGameResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data *SpinGameResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// SpinGameResponseData contains the game play result
|
||||
type SpinGameResponseData struct {
|
||||
GamePlay GamePlayResponse `json:"game_play"`
|
||||
PrizeWon *CustomerGamePrizeResponse `json:"prize_won,omitempty"`
|
||||
TokensRemaining int64 `json:"tokens_remaining"`
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
type CreateUserRequest struct {
|
||||
OrganizationID uuid.UUID `json:"organization_id" validate:"required"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
OutletID *uuid.UUID `json:"outlet_id,omitempty"`
|
||||
Name string `json:"name" validate:"required,min=1,max=255"`
|
||||
Email string `json:"email" validate:"required,email"`
|
||||
@@ -40,9 +40,11 @@ type LoginRequest struct {
|
||||
}
|
||||
|
||||
type LoginResponse struct {
|
||||
Token string `json:"token"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
User UserResponse `json:"user"`
|
||||
Token string `json:"token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
RefreshExpiresAt time.Time `json:"refresh_expires_at"`
|
||||
User UserResponse `json:"user"`
|
||||
}
|
||||
|
||||
type UserResponse struct {
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateVendorRequest struct {
|
||||
Name string `json:"name" validate:"required,min=1,max=255"`
|
||||
Email *string `json:"email,omitempty" validate:"omitempty,email"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty" validate:"omitempty"`
|
||||
Address *string `json:"address,omitempty" validate:"omitempty"`
|
||||
ContactPerson *string `json:"contact_person,omitempty" validate:"omitempty,max=255"`
|
||||
TaxNumber *string `json:"tax_number,omitempty" validate:"omitempty,max=50"`
|
||||
PaymentTerms *string `json:"payment_terms,omitempty" validate:"omitempty,max=100"`
|
||||
Notes *string `json:"notes,omitempty" validate:"omitempty"`
|
||||
IsActive *bool `json:"is_active,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateVendorRequest struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,min=1,max=255"`
|
||||
Email *string `json:"email,omitempty" validate:"omitempty,email"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty" validate:"omitempty"`
|
||||
Address *string `json:"address,omitempty" validate:"omitempty"`
|
||||
ContactPerson *string `json:"contact_person,omitempty" validate:"omitempty,max=255"`
|
||||
TaxNumber *string `json:"tax_number,omitempty" validate:"omitempty,max=50"`
|
||||
PaymentTerms *string `json:"payment_terms,omitempty" validate:"omitempty,max=100"`
|
||||
Notes *string `json:"notes,omitempty" validate:"omitempty"`
|
||||
IsActive *bool `json:"is_active,omitempty"`
|
||||
}
|
||||
|
||||
type VendorResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
Name string `json:"name"`
|
||||
Email *string `json:"email"`
|
||||
PhoneNumber *string `json:"phone_number"`
|
||||
Address *string `json:"address"`
|
||||
ContactPerson *string `json:"contact_person"`
|
||||
TaxNumber *string `json:"tax_number"`
|
||||
PaymentTerms *string `json:"payment_terms"`
|
||||
Notes *string `json:"notes"`
|
||||
IsActive bool `json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ListVendorsRequest struct {
|
||||
Page int `json:"page" validate:"min=1"`
|
||||
Limit int `json:"limit" validate:"min=1,max=100"`
|
||||
Search string `json:"search,omitempty"`
|
||||
IsActive *bool `json:"is_active,omitempty"`
|
||||
}
|
||||
|
||||
type ListVendorsResponse struct {
|
||||
Vendors []VendorResponse `json:"vendors"`
|
||||
TotalCount int `json:"total_count"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package db
|
||||
import (
|
||||
"apskel-pos-be/config"
|
||||
"fmt"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
"go.uber.org/zap"
|
||||
_ "gopkg.in/yaml.v3"
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type AccountType string
|
||||
|
||||
const (
|
||||
AccountTypeCash AccountType = "cash"
|
||||
AccountTypeWallet AccountType = "wallet"
|
||||
AccountTypeBank AccountType = "bank"
|
||||
AccountTypeCredit AccountType = "credit"
|
||||
AccountTypeDebit AccountType = "debit"
|
||||
AccountTypeAsset AccountType = "asset"
|
||||
AccountTypeLiability AccountType = "liability"
|
||||
AccountTypeEquity AccountType = "equity"
|
||||
AccountTypeRevenue AccountType = "revenue"
|
||||
AccountTypeExpense AccountType = "expense"
|
||||
)
|
||||
|
||||
type Account struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
|
||||
OutletID *uuid.UUID `gorm:"type:uuid;index" json:"outlet_id"`
|
||||
ChartOfAccountID uuid.UUID `gorm:"type:uuid;not null;index" json:"chart_of_account_id" validate:"required"`
|
||||
Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"`
|
||||
Number string `gorm:"not null;size:50" json:"number" validate:"required,min=1,max=50"`
|
||||
AccountType AccountType `gorm:"not null;size:20" json:"account_type" validate:"required,oneof=cash wallet bank credit debit asset liability equity revenue expense"`
|
||||
OpeningBalance float64 `gorm:"type:decimal(15,2);default:0.00" json:"opening_balance"`
|
||||
CurrentBalance float64 `gorm:"type:decimal(15,2);default:0.00" json:"current_balance"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
IsSystem bool `gorm:"default:false" json:"is_system"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
|
||||
Outlet *Outlet `gorm:"foreignKey:OutletID" json:"outlet,omitempty"`
|
||||
ChartOfAccount ChartOfAccount `gorm:"foreignKey:ChartOfAccountID" json:"chart_of_account,omitempty"`
|
||||
}
|
||||
|
||||
func (a *Account) BeforeCreate(tx *gorm.DB) error {
|
||||
if a.ID == uuid.Nil {
|
||||
a.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Account) TableName() string {
|
||||
return "accounts"
|
||||
}
|
||||
@@ -27,16 +27,35 @@ type SalesAnalytics struct {
|
||||
NetSales float64 `json:"net_sales"`
|
||||
}
|
||||
|
||||
// ProductAnalytics represents product analytics data
|
||||
type ProductAnalytics struct {
|
||||
ProductID uuid.UUID `json:"product_id"`
|
||||
ProductName string `json:"product_name"`
|
||||
CategoryID uuid.UUID `json:"category_id"`
|
||||
CategoryName string `json:"category_name"`
|
||||
QuantitySold int64 `json:"quantity_sold"`
|
||||
Revenue float64 `json:"revenue"`
|
||||
AveragePrice float64 `json:"average_price"`
|
||||
OrderCount int64 `json:"order_count"`
|
||||
ProductID uuid.UUID `json:"product_id"`
|
||||
ProductName string `json:"product_name"`
|
||||
ProductSku string `json:"product_sku"`
|
||||
CategoryID uuid.UUID `json:"category_id"`
|
||||
CategoryName string `json:"category_name"`
|
||||
CategoryOrder int `json:"category_order"`
|
||||
QuantitySold int64 `json:"quantity_sold"`
|
||||
Revenue float64 `json:"revenue"`
|
||||
AveragePrice float64 `json:"average_price"`
|
||||
OrderCount int64 `json:"order_count"`
|
||||
StandardHppPerUnit float64 `json:"standard_hpp_per_unit"`
|
||||
StandardHppTotal float64 `json:"standard_hpp_total"`
|
||||
FifoHppPerUnit float64 `json:"fifo_hpp_per_unit"`
|
||||
FifoHppTotal float64 `json:"fifo_hpp_total"`
|
||||
MovingAverageHppPerUnit float64 `json:"moving_average_hpp_per_unit"`
|
||||
MovingAverageHppTotal float64 `json:"moving_average_hpp_total"`
|
||||
}
|
||||
|
||||
type ProductAnalyticsPerCategory struct {
|
||||
CategoryID uuid.UUID `json:"category_id"`
|
||||
CategoryName string `json:"category_name"`
|
||||
TotalRevenue float64 `json:"total_revenue"`
|
||||
TotalQuantity int64 `json:"total_quantity"`
|
||||
ProductCount int64 `json:"product_count"`
|
||||
OrderCount int64 `json:"order_count"`
|
||||
TotalStandardHpp float64 `json:"total_standard_hpp"`
|
||||
TotalFifoHpp float64 `json:"total_fifo_hpp"`
|
||||
TotalMovingAverageHpp float64 `json:"total_moving_average_hpp"`
|
||||
}
|
||||
|
||||
// DashboardOverview represents dashboard overview data
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type CampaignType string
|
||||
|
||||
const (
|
||||
CampaignTypeReward CampaignType = "REWARD"
|
||||
CampaignTypePoints CampaignType = "POINTS"
|
||||
CampaignTypeTokens CampaignType = "TOKENS"
|
||||
CampaignTypeMixed CampaignType = "MIXED"
|
||||
)
|
||||
|
||||
type RuleType string
|
||||
|
||||
const (
|
||||
RuleTypeTier RuleType = "TIER"
|
||||
RuleTypeSpend RuleType = "SPEND"
|
||||
RuleTypeProduct RuleType = "PRODUCT"
|
||||
RuleTypeCategory RuleType = "CATEGORY"
|
||||
RuleTypeDay RuleType = "DAY"
|
||||
RuleTypeLocation RuleType = "LOCATION"
|
||||
)
|
||||
|
||||
type CampaignRewardType string
|
||||
|
||||
const (
|
||||
CampaignRewardTypePoints CampaignRewardType = "POINTS"
|
||||
CampaignRewardTypeTokens CampaignRewardType = "TOKENS"
|
||||
CampaignRewardTypeReward CampaignRewardType = "REWARD"
|
||||
)
|
||||
|
||||
type RewardSubtype string
|
||||
|
||||
const (
|
||||
RewardSubtypeMultiplier RewardSubtype = "MULTIPLIER"
|
||||
RewardSubtypeSpin RewardSubtype = "SPIN"
|
||||
RewardSubtypeBonus RewardSubtype = "BONUS"
|
||||
RewardSubtypePhysical RewardSubtype = "PHYSICAL"
|
||||
)
|
||||
|
||||
type Campaign struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
Name string `gorm:"type:varchar(150);not null" json:"name"`
|
||||
Description *string `gorm:"type:text" json:"description,omitempty"`
|
||||
Type CampaignType `gorm:"type:varchar(50);not null" json:"type"`
|
||||
StartDate time.Time `gorm:"type:timestamp;not null" json:"start_date"`
|
||||
EndDate time.Time `gorm:"type:timestamp;not null" json:"end_date"`
|
||||
IsActive bool `gorm:"type:boolean;default:true" json:"is_active"`
|
||||
ShowOnApp bool `gorm:"type:boolean;default:true" json:"show_on_app"`
|
||||
Position int `gorm:"type:int;default:0" json:"position"`
|
||||
Metadata *Metadata `gorm:"type:jsonb" json:"metadata,omitempty"`
|
||||
CreatedAt time.Time `gorm:"type:timestamp;default:now()" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"type:timestamp;default:now()" json:"updated_at"`
|
||||
|
||||
// Relations
|
||||
Rules []CampaignRule `gorm:"foreignKey:CampaignID;constraint:OnDelete:CASCADE" json:"rules,omitempty"`
|
||||
}
|
||||
|
||||
func (Campaign) TableName() string {
|
||||
return "campaigns"
|
||||
}
|
||||
|
||||
func (c *Campaign) BeforeCreate(tx *gorm.DB) error {
|
||||
if c.ID == uuid.Nil {
|
||||
c.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Campaign) BeforeUpdate(tx *gorm.DB) error {
|
||||
c.UpdatedAt = time.Now()
|
||||
return nil
|
||||
}
|
||||
|
||||
type CampaignRule struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
CampaignID uuid.UUID `gorm:"type:uuid;not null" json:"campaign_id"`
|
||||
RuleType RuleType `gorm:"type:varchar(50);not null" json:"rule_type"`
|
||||
ConditionValue *string `gorm:"type:varchar(255)" json:"condition_value,omitempty"`
|
||||
RewardType CampaignRewardType `gorm:"type:varchar(50);not null" json:"reward_type"`
|
||||
RewardValue *int64 `gorm:"type:bigint" json:"reward_value,omitempty"`
|
||||
RewardSubtype *RewardSubtype `gorm:"type:varchar(50)" json:"reward_subtype,omitempty"`
|
||||
RewardRefID *uuid.UUID `gorm:"type:uuid" json:"reward_ref_id,omitempty"`
|
||||
Metadata *Metadata `gorm:"type:jsonb" json:"metadata,omitempty"`
|
||||
CreatedAt time.Time `gorm:"type:timestamp;default:now()" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"type:timestamp;default:now()" json:"updated_at"`
|
||||
|
||||
// Relations
|
||||
Campaign Campaign `gorm:"foreignKey:CampaignID" json:"campaign,omitempty"`
|
||||
}
|
||||
|
||||
func (CampaignRule) TableName() string {
|
||||
return "campaign_rules"
|
||||
}
|
||||
|
||||
func (cr *CampaignRule) BeforeCreate(tx *gorm.DB) error {
|
||||
if cr.ID == uuid.Nil {
|
||||
cr.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cr *CampaignRule) BeforeUpdate(tx *gorm.DB) error {
|
||||
cr.UpdatedAt = time.Now()
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListCampaignsRequest struct {
|
||||
Page int `form:"page" binding:"min=1"`
|
||||
Limit int `form:"limit" binding:"min=1,max=100"`
|
||||
Search string `form:"search"`
|
||||
Type string `form:"type"`
|
||||
IsActive *bool `form:"is_active"`
|
||||
ShowOnApp *bool `form:"show_on_app"`
|
||||
StartDate *time.Time `form:"start_date"`
|
||||
EndDate *time.Time `form:"end_date"`
|
||||
}
|
||||
|
||||
type ListCampaignRulesRequest struct {
|
||||
Page int `form:"page" binding:"min=1"`
|
||||
Limit int `form:"limit" binding:"min=1,max=100"`
|
||||
CampaignID string `form:"campaign_id"`
|
||||
RuleType string `form:"rule_type"`
|
||||
RewardType string `form:"reward_type"`
|
||||
}
|
||||
@@ -35,6 +35,7 @@ type Category struct {
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
|
||||
Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
Order int `gorm:"default:0" json:"order"`
|
||||
BusinessType string `gorm:"size:50;default:'restaurant'" json:"business_type"`
|
||||
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ChartOfAccount struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
|
||||
OutletID uuid.UUID `gorm:"type:uuid;index" json:"outlet_id"`
|
||||
ChartOfAccountTypeID uuid.UUID `gorm:"type:uuid;not null;index" json:"chart_of_account_type_id" validate:"required"`
|
||||
ParentID *uuid.UUID `gorm:"type:uuid;index" json:"parent_id"`
|
||||
Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"`
|
||||
Code string `gorm:"not null;size:20" json:"code" validate:"required,min=1,max=20"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
IsSystem bool `gorm:"default:false" json:"is_system"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
|
||||
Outlet *Outlet `gorm:"foreignKey:OutletID" json:"outlet,omitempty"`
|
||||
ChartOfAccountType ChartOfAccountType `gorm:"foreignKey:ChartOfAccountTypeID" json:"chart_of_account_type,omitempty"`
|
||||
Parent *ChartOfAccount `gorm:"foreignKey:ParentID" json:"parent,omitempty"`
|
||||
Children []ChartOfAccount `gorm:"foreignKey:ParentID" json:"children,omitempty"`
|
||||
Accounts []Account `gorm:"foreignKey:ChartOfAccountID" json:"accounts,omitempty"`
|
||||
}
|
||||
|
||||
func (c *ChartOfAccount) BeforeCreate(tx *gorm.DB) error {
|
||||
if c.ID == uuid.Nil {
|
||||
c.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ChartOfAccount) TableName() string {
|
||||
return "chart_of_accounts"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ChartOfAccountType struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
Name string `gorm:"not null;size:100" json:"name" validate:"required,min=1,max=100"`
|
||||
Code string `gorm:"not null;size:10;unique" json:"code" validate:"required,min=1,max=10"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
ChartOfAccounts []ChartOfAccount `gorm:"foreignKey:ChartOfAccountTypeID" json:"chart_of_accounts,omitempty"`
|
||||
}
|
||||
|
||||
func (c *ChartOfAccountType) BeforeCreate(tx *gorm.DB) error {
|
||||
if c.ID == uuid.Nil {
|
||||
c.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ChartOfAccountType) TableName() string {
|
||||
return "chart_of_account_types"
|
||||
}
|
||||
@@ -8,17 +8,20 @@ import (
|
||||
)
|
||||
|
||||
type Customer struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
|
||||
Name string `gorm:"not null;size:255" json:"name" validate:"required"`
|
||||
Email *string `gorm:"size:255;uniqueIndex" json:"email,omitempty"`
|
||||
Phone *string `gorm:"size:20" json:"phone,omitempty"`
|
||||
Address *string `gorm:"size:500" json:"address,omitempty"`
|
||||
IsDefault bool `gorm:"default:false" json:"is_default"`
|
||||
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"`
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
|
||||
Name string `gorm:"not null;size:255" json:"name" validate:"required"`
|
||||
Email *string `gorm:"size:255;uniqueIndex" json:"email,omitempty"`
|
||||
Phone *string `gorm:"size:20" json:"phone,omitempty"`
|
||||
PhoneNumber *string `gorm:"size:20;uniqueIndex" json:"phone_number,omitempty"`
|
||||
Address *string `gorm:"size:500" json:"address,omitempty"`
|
||||
BirthDate *time.Time `gorm:"type:date" json:"birth_date,omitempty"`
|
||||
PasswordHash *string `gorm:"size:255" json:"-"`
|
||||
IsDefault bool `gorm:"default:false" json:"is_default"`
|
||||
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"`
|
||||
|
||||
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
|
||||
Orders []Order `gorm:"foreignKey:CustomerID" json:"orders,omitempty"`
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -18,6 +18,23 @@ func GetAllEntities() []interface{} {
|
||||
&Payment{},
|
||||
&Customer{},
|
||||
&Table{},
|
||||
&Vendor{},
|
||||
&PurchaseOrder{},
|
||||
&PurchaseOrderItem{},
|
||||
&PurchaseOrderAttachment{},
|
||||
&IngredientUnitConverter{},
|
||||
// Gamification entities
|
||||
&CustomerPoints{},
|
||||
&CustomerTokens{},
|
||||
&Tier{},
|
||||
&Game{},
|
||||
&GamePrize{},
|
||||
&GamePlay{},
|
||||
&OmsetTracker{},
|
||||
&Reward{},
|
||||
&Campaign{},
|
||||
&CampaignRule{},
|
||||
&OtpSession{},
|
||||
// Analytics entities are not database tables, they are query results
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
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"`
|
||||
Image *string `gorm:"type:varchar(500)" json:"image,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"
|
||||
}
|
||||
@@ -7,17 +7,18 @@ import (
|
||||
)
|
||||
|
||||
type Ingredient struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id"`
|
||||
OutletID *uuid.UUID `gorm:"type:uuid;index" json:"outlet_id"`
|
||||
Name string `gorm:"not null;size:255" json:"name"`
|
||||
UnitID uuid.UUID `gorm:"type:uuid;not null;index" json:"unit_id"`
|
||||
Cost float64 `gorm:"type:decimal(10,2);default:0.00" json:"cost"`
|
||||
Stock float64 `gorm:"type:decimal(10,2);default:0.00" json:"stock"`
|
||||
IsSemiFinished bool `gorm:"default:false" json:"is_semi_finished"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
Metadata map[string]any `gorm:"type:jsonb;default:'{}'" json:"metadata"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
Unit *Unit `gorm:"foreignKey:UnitID" json:"unit,omitempty"`
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id"`
|
||||
OutletID *uuid.UUID `gorm:"type:uuid;index" json:"outlet_id"`
|
||||
Name string `gorm:"not null;size:255" json:"name"`
|
||||
UnitID uuid.UUID `gorm:"type:uuid;not null;index" json:"unit_id"`
|
||||
Cost float64 `gorm:"type:decimal(10,2);default:0.00" json:"cost"`
|
||||
Stock float64 `gorm:"type:decimal(10,2);default:0.00" json:"stock"`
|
||||
IsSemiFinished bool `gorm:"default:false" json:"is_semi_finished"`
|
||||
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"`
|
||||
Unit *Unit `gorm:"foreignKey:UnitID;references:ID" json:"unit,omitempty"`
|
||||
Compositions []IngredientComposition `gorm:"foreignKey:ParentIngredientID;references:ID" json:"compositions,omitempty"`
|
||||
}
|
||||
|
||||
@@ -7,14 +7,14 @@ import (
|
||||
)
|
||||
|
||||
type IngredientComposition struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
OrganizationID uuid.UUID `json:"organization_id" db:"organization_id"`
|
||||
OutletID *uuid.UUID `json:"outlet_id" db:"outlet_id"`
|
||||
ParentIngredientID uuid.UUID `json:"parent_ingredient_id" db:"parent_ingredient_id"`
|
||||
ChildIngredientID uuid.UUID `json:"child_ingredient_id" db:"child_ingredient_id"`
|
||||
Quantity float64 `json:"quantity" db:"quantity"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
ParentIngredient *Ingredient `json:"parent_ingredient,omitempty"`
|
||||
ChildIngredient *Ingredient `json:"child_ingredient,omitempty"`
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id"`
|
||||
OutletID *uuid.UUID `gorm:"type:uuid;index" json:"outlet_id"`
|
||||
ParentIngredientID uuid.UUID `gorm:"type:uuid;not null;index" json:"parent_ingredient_id"`
|
||||
ChildIngredientID uuid.UUID `gorm:"type:uuid;not null;index" json:"child_ingredient_id"`
|
||||
Quantity float64 `gorm:"type:decimal(10,4);not null" json:"quantity"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
ParentIngredient *Ingredient `gorm:"foreignKey:ParentIngredientID;references:ID" json:"parent_ingredient,omitempty"`
|
||||
ChildIngredient *Ingredient `gorm:"foreignKey:ChildIngredientID;references:ID" json:"child_ingredient,omitempty"`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type IngredientUnitConverter struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null" json:"organization_id"`
|
||||
IngredientID uuid.UUID `gorm:"type:uuid;not null" json:"ingredient_id"`
|
||||
FromUnitID uuid.UUID `gorm:"type:uuid;not null" json:"from_unit_id"`
|
||||
ToUnitID uuid.UUID `gorm:"type:uuid;not null" json:"to_unit_id"`
|
||||
ConversionFactor float64 `gorm:"type:decimal(15,6);not null" json:"conversion_factor"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
CreatedBy uuid.UUID `gorm:"type:uuid;not null" json:"created_by"`
|
||||
UpdatedBy uuid.UUID `gorm:"type:uuid;not null" json:"updated_by"`
|
||||
|
||||
// Relationships
|
||||
Organization *Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
|
||||
Ingredient *Ingredient `gorm:"foreignKey:IngredientID" json:"ingredient,omitempty"`
|
||||
FromUnit *Unit `gorm:"foreignKey:FromUnitID" json:"from_unit,omitempty"`
|
||||
ToUnit *Unit `gorm:"foreignKey:ToUnitID" json:"to_unit,omitempty"`
|
||||
CreatedByUser *User `gorm:"foreignKey:CreatedBy" json:"created_by_user,omitempty"`
|
||||
UpdatedByUser *User `gorm:"foreignKey:UpdatedBy" json:"updated_by_user,omitempty"`
|
||||
}
|
||||
|
||||
func (IngredientUnitConverter) TableName() string {
|
||||
return "ingredient_unit_converters"
|
||||
}
|
||||
|
||||
// BeforeCreate hook to set default values
|
||||
func (iuc *IngredientUnitConverter) BeforeCreate() error {
|
||||
if iuc.ID == uuid.Nil {
|
||||
iuc.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ const (
|
||||
InventoryMovementTypeTransferOut InventoryMovementType = "transfer_out"
|
||||
InventoryMovementTypeDamage InventoryMovementType = "damage"
|
||||
InventoryMovementTypeExpiry InventoryMovementType = "expiry"
|
||||
InventoryMovementTypeIngredient InventoryMovementType = "ingredient"
|
||||
)
|
||||
|
||||
type InventoryMovementReferenceType string
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
+29
-27
@@ -28,6 +28,7 @@ const (
|
||||
|
||||
const (
|
||||
PaymentStatusPending PaymentStatus = "pending"
|
||||
PaymentStatusPartial PaymentStatus = "partial"
|
||||
PaymentStatusCompleted PaymentStatus = "completed"
|
||||
PaymentStatusFailed PaymentStatus = "failed"
|
||||
PaymentStatusRefunded PaymentStatus = "refunded"
|
||||
@@ -35,33 +36,34 @@ const (
|
||||
)
|
||||
|
||||
type Order struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
|
||||
OutletID uuid.UUID `gorm:"type:uuid;not null;index" json:"outlet_id" validate:"required"`
|
||||
UserID uuid.UUID `gorm:"type:uuid;not null;index" json:"user_id" validate:"required"`
|
||||
CustomerID *uuid.UUID `gorm:"type:uuid;index" json:"customer_id"`
|
||||
OrderNumber string `gorm:"uniqueIndex;not null;size:50" json:"order_number" validate:"required"`
|
||||
TableNumber *string `gorm:"size:20" json:"table_number"`
|
||||
OrderType OrderType `gorm:"not null;size:50" json:"order_type" validate:"required,oneof=dine_in takeout delivery"`
|
||||
Status OrderStatus `gorm:"default:'pending';size:50" json:"status"`
|
||||
Subtotal float64 `gorm:"type:decimal(10,2);not null" json:"subtotal" validate:"required,min=0"`
|
||||
TaxAmount float64 `gorm:"type:decimal(10,2);not null" json:"tax_amount" validate:"required,min=0"`
|
||||
DiscountAmount float64 `gorm:"type:decimal(10,2);default:0.00" json:"discount_amount" validate:"min=0"`
|
||||
TotalAmount float64 `gorm:"type:decimal(10,2);not null" json:"total_amount" validate:"required,min=0"`
|
||||
TotalCost float64 `gorm:"type:decimal(10,2);default:0.00" json:"total_cost"`
|
||||
PaymentStatus PaymentStatus `gorm:"default:'pending';size:50" json:"payment_status"`
|
||||
RefundAmount float64 `gorm:"type:decimal(10,2);default:0.00" json:"refund_amount"`
|
||||
IsVoid bool `gorm:"default:false" json:"is_void"`
|
||||
IsRefund bool `gorm:"default:false" json:"is_refund"`
|
||||
VoidReason *string `gorm:"size:255" json:"void_reason,omitempty"`
|
||||
VoidedAt *time.Time `gorm:"" json:"voided_at,omitempty"`
|
||||
VoidedBy *uuid.UUID `gorm:"type:uuid" json:"voided_by,omitempty"`
|
||||
RefundReason *string `gorm:"size:255" json:"refund_reason,omitempty"`
|
||||
RefundedAt *time.Time `gorm:"" json:"refunded_at,omitempty"`
|
||||
RefundedBy *uuid.UUID `gorm:"type:uuid" json:"refunded_by,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"`
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
|
||||
OutletID uuid.UUID `gorm:"type:uuid;not null;index" json:"outlet_id" validate:"required"`
|
||||
UserID uuid.UUID `gorm:"type:uuid;not null;index" json:"user_id" validate:"required"`
|
||||
CustomerID *uuid.UUID `gorm:"type:uuid;index" json:"customer_id"`
|
||||
OrderNumber string `gorm:"uniqueIndex;not null;size:50" json:"order_number" validate:"required"`
|
||||
TableNumber *string `gorm:"size:20" json:"table_number"`
|
||||
OrderType OrderType `gorm:"not null;size:50" json:"order_type" validate:"required,oneof=dine_in takeout delivery"`
|
||||
Status OrderStatus `gorm:"default:'pending';size:50" json:"status"`
|
||||
Subtotal float64 `gorm:"type:decimal(10,2);not null" json:"subtotal" validate:"required,min=0"`
|
||||
TaxAmount float64 `gorm:"type:decimal(10,2);not null" json:"tax_amount" validate:"required,min=0"`
|
||||
DiscountAmount float64 `gorm:"type:decimal(10,2);default:0.00" json:"discount_amount" validate:"min=0"`
|
||||
TotalAmount float64 `gorm:"type:decimal(10,2);not null" json:"total_amount" validate:"required,min=0"`
|
||||
TotalCost float64 `gorm:"type:decimal(10,2);default:0.00" json:"total_cost"`
|
||||
RemainingAmount float64 `gorm:"type:decimal(10,2);default:0.00" json:"remaining_amount"`
|
||||
PaymentStatus PaymentStatus `gorm:"default:'pending';size:50" json:"payment_status"`
|
||||
RefundAmount float64 `gorm:"type:decimal(10,2);default:0.00" json:"refund_amount"`
|
||||
IsVoid bool `gorm:"default:false" json:"is_void"`
|
||||
IsRefund bool `gorm:"default:false" json:"is_refund"`
|
||||
VoidReason *string `gorm:"size:255" json:"void_reason,omitempty"`
|
||||
VoidedAt *time.Time `gorm:"" json:"voided_at,omitempty"`
|
||||
VoidedBy *uuid.UUID `gorm:"type:uuid" json:"voided_by,omitempty"`
|
||||
RefundReason *string `gorm:"size:255" json:"refund_reason,omitempty"`
|
||||
RefundedAt *time.Time `gorm:"" json:"refunded_at,omitempty"`
|
||||
RefundedBy *uuid.UUID `gorm:"type:uuid" json:"refunded_by,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"`
|
||||
|
||||
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
|
||||
Outlet Outlet `gorm:"foreignKey:OutletID" json:"outlet,omitempty"`
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type OrderIngredientTransaction struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
|
||||
OutletID *uuid.UUID `gorm:"type:uuid;index" json:"outlet_id"`
|
||||
OrderID uuid.UUID `gorm:"type:uuid;not null;index" json:"order_id" validate:"required"`
|
||||
OrderItemID *uuid.UUID `gorm:"type:uuid;index" json:"order_item_id"`
|
||||
ProductID uuid.UUID `gorm:"type:uuid;not null;index" json:"product_id" validate:"required"`
|
||||
ProductVariantID *uuid.UUID `gorm:"type:uuid;index" json:"product_variant_id"`
|
||||
IngredientID uuid.UUID `gorm:"type:uuid;not null;index" json:"ingredient_id" validate:"required"`
|
||||
GrossQty float64 `gorm:"type:decimal(12,3);not null" json:"gross_qty" validate:"required,gt=0"`
|
||||
NetQty float64 `gorm:"type:decimal(12,3);not null" json:"net_qty" validate:"required,gt=0"`
|
||||
WasteQty float64 `gorm:"type:decimal(12,3);not null" json:"waste_qty" validate:"min=0"`
|
||||
Unit string `gorm:"size:50;not null" json:"unit" validate:"required,max=50"`
|
||||
TransactionDate time.Time `gorm:"not null;index" json:"transaction_date"`
|
||||
CreatedBy uuid.UUID `gorm:"type:uuid;not null;index" json:"created_by" validate:"required"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
// Relations
|
||||
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
|
||||
Outlet *Outlet `gorm:"foreignKey:OutletID" json:"outlet,omitempty"`
|
||||
Order Order `gorm:"foreignKey:OrderID" json:"order,omitempty"`
|
||||
OrderItem *OrderItem `gorm:"foreignKey:OrderItemID" json:"order_item,omitempty"`
|
||||
Product Product `gorm:"foreignKey:ProductID" json:"product,omitempty"`
|
||||
ProductVariant *ProductVariant `gorm:"foreignKey:ProductVariantID" json:"product_variant,omitempty"`
|
||||
Ingredient Ingredient `gorm:"foreignKey:IngredientID" json:"ingredient,omitempty"`
|
||||
CreatedByUser User `gorm:"foreignKey:CreatedBy" json:"created_by_user,omitempty"`
|
||||
}
|
||||
|
||||
func (oit *OrderIngredientTransaction) BeforeCreate(tx *gorm.DB) error {
|
||||
if oit.ID == uuid.Nil {
|
||||
oit.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (OrderIngredientTransaction) TableName() string {
|
||||
return "order_ingredients_transactions"
|
||||
}
|
||||
@@ -38,6 +38,7 @@ const (
|
||||
OrderItemStatusReady OrderItemStatus = "ready"
|
||||
OrderItemStatusServed OrderItemStatus = "served"
|
||||
OrderItemStatusCancelled OrderItemStatus = "cancelled"
|
||||
OrderItemStatusPaid OrderItemStatus = "paid"
|
||||
)
|
||||
|
||||
type OrderItem struct {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type OtpSession struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
Token string `gorm:"type:varchar(255);uniqueIndex;not null" json:"token"`
|
||||
Code string `gorm:"type:varchar(10);not null" json:"code"`
|
||||
PhoneNumber string `gorm:"type:varchar(20);not null;index" json:"phone_number"`
|
||||
Purpose string `gorm:"type:varchar(50);not null;index" json:"purpose"`
|
||||
ExpiresAt time.Time `gorm:"not null;index" json:"expires_at"`
|
||||
IsUsed bool `gorm:"default:false;index" json:"is_used"`
|
||||
AttemptsCount int `gorm:"default:0" json:"attempts_count"`
|
||||
MaxAttempts int `gorm:"default:3" json:"max_attempts"`
|
||||
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (o *OtpSession) BeforeCreate(tx *gorm.DB) error {
|
||||
if o.ID == uuid.Nil {
|
||||
o.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (OtpSession) TableName() string {
|
||||
return "otp_sessions"
|
||||
}
|
||||
|
||||
func (o *OtpSession) IsExpired() bool {
|
||||
return time.Now().After(o.ExpiresAt)
|
||||
}
|
||||
|
||||
func (o *OtpSession) IsMaxAttemptsReached() bool {
|
||||
return o.AttemptsCount >= o.MaxAttempts
|
||||
}
|
||||
|
||||
func (o *OtpSession) CanBeUsed() bool {
|
||||
return !o.IsUsed && !o.IsExpired() && !o.IsMaxAttemptsReached()
|
||||
}
|
||||
|
||||
func (o *OtpSession) IncrementAttempts() {
|
||||
o.AttemptsCount++
|
||||
}
|
||||
|
||||
func (o *OtpSession) MarkAsUsed() {
|
||||
o.IsUsed = true
|
||||
}
|
||||
@@ -50,6 +50,13 @@ const (
|
||||
PaymentTransactionStatusRefunded PaymentTransactionStatus = "refunded"
|
||||
)
|
||||
|
||||
type SplitType string
|
||||
|
||||
const (
|
||||
SplitTypeAmount SplitType = "AMOUNT"
|
||||
SplitTypeItem SplitType = "ITEM"
|
||||
)
|
||||
|
||||
type Payment struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrderID uuid.UUID `gorm:"type:uuid;not null;index" json:"order_id" validate:"required"`
|
||||
@@ -59,6 +66,7 @@ type Payment struct {
|
||||
TransactionID *string `gorm:"size:255" json:"transaction_id"`
|
||||
SplitNumber int `gorm:"default:1" json:"split_number"`
|
||||
SplitTotal int `gorm:"default:1" json:"split_total"`
|
||||
SplitType *SplitType `gorm:"size:20" json:"split_type,omitempty"`
|
||||
SplitDescription *string `gorm:"size:255" json:"split_description,omitempty"`
|
||||
RefundAmount float64 `gorm:"type:decimal(10,2);default:0.00" json:"refund_amount"`
|
||||
RefundReason *string `gorm:"size:255" json:"refund_reason,omitempty"`
|
||||
|
||||
@@ -11,6 +11,7 @@ type PaymentOrderItem struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
PaymentID uuid.UUID `gorm:"type:uuid;not null;index" json:"payment_id"`
|
||||
OrderItemID uuid.UUID `gorm:"type:uuid;not null;index" json:"order_item_id"`
|
||||
Quantity int `gorm:"not null;default:0" json:"quantity"` // Quantity paid for this specific payment
|
||||
Amount float64 `gorm:"type:decimal(10,2);not null" json:"amount"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
@@ -30,7 +30,7 @@ type Product struct {
|
||||
Category Category `gorm:"foreignKey:CategoryID" json:"category,omitempty"`
|
||||
Unit *Unit `gorm:"foreignKey:UnitID" json:"unit,omitempty"`
|
||||
ProductVariants []ProductVariant `gorm:"foreignKey:ProductID" json:"variants,omitempty"`
|
||||
ProductIngredients []ProductIngredient `gorm:"foreignKey:ProductID" json:"product_ingredients,omitempty"`
|
||||
ProductRecipes []ProductRecipe `gorm:"foreignKey:ProductID" json:"product_recipes,omitempty"`
|
||||
Inventory []Inventory `gorm:"foreignKey:ProductID" json:"inventory,omitempty"`
|
||||
OrderItems []OrderItem `gorm:"foreignKey:ProductID" json:"order_items,omitempty"`
|
||||
}
|
||||
|
||||
@@ -7,14 +7,15 @@ import (
|
||||
)
|
||||
|
||||
type ProductIngredient struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
OrganizationID uuid.UUID `json:"organization_id" db:"organization_id"`
|
||||
OutletID *uuid.UUID `json:"outlet_id" db:"outlet_id"`
|
||||
ProductID uuid.UUID `json:"product_id" db:"product_id"`
|
||||
IngredientID uuid.UUID `json:"ingredient_id" db:"ingredient_id"`
|
||||
Quantity float64 `json:"quantity" db:"quantity"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
OrganizationID uuid.UUID `json:"organization_id" db:"organization_id"`
|
||||
OutletID *uuid.UUID `json:"outlet_id" db:"outlet_id"`
|
||||
ProductID uuid.UUID `json:"product_id" db:"product_id"`
|
||||
IngredientID uuid.UUID `json:"ingredient_id" db:"ingredient_id"`
|
||||
Quantity float64 `json:"quantity" db:"quantity"`
|
||||
WastePercentage float64 `json:"waste_percentage" db:"waste_percentage"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
|
||||
// Relations
|
||||
Product *Product `json:"product,omitempty"`
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ProductRecipe struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id"`
|
||||
OutletID *uuid.UUID `gorm:"type:uuid;index" json:"outlet_id"`
|
||||
ProductID uuid.UUID `gorm:"type:uuid;not null;index" json:"product_id"`
|
||||
VariantID *uuid.UUID `gorm:"type:uuid;index" json:"variant_id"`
|
||||
IngredientID uuid.UUID `gorm:"type:uuid;not null;index" json:"ingredient_id"`
|
||||
Quantity float64 `gorm:"type:decimal(12,3);not null" json:"quantity"`
|
||||
WastePercentage float64 `gorm:"type:decimal(5,2);default:0" json:"waste_percentage"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
// Relations
|
||||
Product *Product `gorm:"foreignKey:ProductID" json:"product,omitempty"`
|
||||
ProductVariant *ProductVariant `gorm:"foreignKey:VariantID" json:"product_variant,omitempty"`
|
||||
Ingredient *Ingredient `gorm:"foreignKey:IngredientID" json:"ingredient,omitempty"`
|
||||
}
|
||||
|
||||
func (pr *ProductRecipe) BeforeCreate(tx *gorm.DB) error {
|
||||
if pr.ID == uuid.Nil {
|
||||
pr.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ProductRecipe) TableName() string {
|
||||
return "product_recipes"
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type PurchaseOrder struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null" json:"organization_id" validate:"required"`
|
||||
VendorID uuid.UUID `gorm:"type:uuid;not null" json:"vendor_id" validate:"required"`
|
||||
PONumber string `gorm:"not null;size:50" json:"po_number" validate:"required,min=1,max=50"`
|
||||
TransactionDate time.Time `gorm:"type:date;not null" json:"transaction_date" validate:"required"`
|
||||
DueDate time.Time `gorm:"type:date;not null" json:"due_date" validate:"required"`
|
||||
Reference *string `gorm:"size:100" json:"reference" validate:"omitempty,max=100"`
|
||||
Status string `gorm:"not null;size:20;default:'draft'" json:"status" validate:"required,oneof=draft sent approved received cancelled"`
|
||||
Message *string `gorm:"type:text" json:"message" validate:"omitempty"`
|
||||
TotalAmount float64 `gorm:"type:decimal(15,2);not null;default:0" json:"total_amount"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
Organization *Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
|
||||
Vendor *Vendor `gorm:"foreignKey:VendorID" json:"vendor,omitempty"`
|
||||
Items []PurchaseOrderItem `gorm:"foreignKey:PurchaseOrderID" json:"items,omitempty"`
|
||||
Attachments []PurchaseOrderAttachment `gorm:"foreignKey:PurchaseOrderID" json:"attachments,omitempty"`
|
||||
}
|
||||
|
||||
func (po *PurchaseOrder) BeforeCreate(tx *gorm.DB) error {
|
||||
if po.ID == uuid.Nil {
|
||||
id := uuid.New()
|
||||
po.ID = id
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (PurchaseOrder) TableName() string {
|
||||
return "purchase_orders"
|
||||
}
|
||||
|
||||
type PurchaseOrderItem struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
PurchaseOrderID uuid.UUID `gorm:"type:uuid;not null" json:"purchase_order_id" validate:"required"`
|
||||
IngredientID uuid.UUID `gorm:"type:uuid;not null" json:"ingredient_id" validate:"required"`
|
||||
Description *string `gorm:"type:text" json:"description" validate:"omitempty"`
|
||||
Quantity float64 `gorm:"type:decimal(10,3);not null" json:"quantity" validate:"required,gt=0"`
|
||||
UnitID uuid.UUID `gorm:"type:uuid;not null" json:"unit_id" validate:"required"`
|
||||
Amount float64 `gorm:"type:decimal(15,2);not null" json:"amount" validate:"required,gte=0"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
PurchaseOrder *PurchaseOrder `gorm:"foreignKey:PurchaseOrderID" json:"purchase_order,omitempty"`
|
||||
Ingredient *Ingredient `gorm:"foreignKey:IngredientID" json:"ingredient,omitempty"`
|
||||
Unit *Unit `gorm:"foreignKey:UnitID" json:"unit,omitempty"`
|
||||
}
|
||||
|
||||
func (poi *PurchaseOrderItem) BeforeCreate(tx *gorm.DB) error {
|
||||
if poi.ID == uuid.Nil {
|
||||
id := uuid.New()
|
||||
poi.ID = id
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (PurchaseOrderItem) TableName() string {
|
||||
return "purchase_order_items"
|
||||
}
|
||||
|
||||
type PurchaseOrderAttachment struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
PurchaseOrderID uuid.UUID `gorm:"type:uuid;not null" json:"purchase_order_id" validate:"required"`
|
||||
FileID uuid.UUID `gorm:"type:uuid;not null" json:"file_id" validate:"required"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
|
||||
PurchaseOrder *PurchaseOrder `gorm:"foreignKey:PurchaseOrderID" json:"purchase_order,omitempty"`
|
||||
File *File `gorm:"foreignKey:FileID" json:"file,omitempty"`
|
||||
}
|
||||
|
||||
func (poa *PurchaseOrderAttachment) BeforeCreate(tx *gorm.DB) error {
|
||||
if poa.ID == uuid.Nil {
|
||||
id := uuid.New()
|
||||
poa.ID = id
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (PurchaseOrderAttachment) TableName() string {
|
||||
return "purchase_order_attachments"
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type RewardType string
|
||||
|
||||
const (
|
||||
RewardTypeVoucher RewardType = "VOUCHER"
|
||||
RewardTypePhysical RewardType = "PHYSICAL"
|
||||
RewardTypeDigital RewardType = "DIGITAL"
|
||||
RewardTypeBalance RewardType = "BALANCE"
|
||||
)
|
||||
|
||||
// StringSlice is a custom type for []string that implements sql.Scanner and driver.Valuer
|
||||
type StringSlice []string
|
||||
|
||||
// Scan implements the sql.Scanner interface for StringSlice
|
||||
func (s *StringSlice) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
*s = StringSlice{}
|
||||
return nil
|
||||
}
|
||||
|
||||
var bytes []byte
|
||||
switch v := value.(type) {
|
||||
case []byte:
|
||||
bytes = v
|
||||
case string:
|
||||
bytes = []byte(v)
|
||||
default:
|
||||
return fmt.Errorf("cannot scan %T into StringSlice", value)
|
||||
}
|
||||
|
||||
return json.Unmarshal(bytes, s)
|
||||
}
|
||||
|
||||
// Value implements the driver.Valuer interface for StringSlice
|
||||
func (s StringSlice) Value() (driver.Value, error) {
|
||||
if s == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return json.Marshal(s)
|
||||
}
|
||||
|
||||
type TermsAndConditions struct {
|
||||
Sections []TncSection `json:"sections"`
|
||||
ExpiryDays int `json:"expiry_days"`
|
||||
}
|
||||
|
||||
// Scan implements the sql.Scanner interface for TermsAndConditions
|
||||
func (t *TermsAndConditions) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
*t = TermsAndConditions{}
|
||||
return nil
|
||||
}
|
||||
|
||||
var bytes []byte
|
||||
switch v := value.(type) {
|
||||
case []byte:
|
||||
bytes = v
|
||||
case string:
|
||||
bytes = []byte(v)
|
||||
default:
|
||||
return fmt.Errorf("cannot scan %T into TermsAndConditions", value)
|
||||
}
|
||||
|
||||
return json.Unmarshal(bytes, t)
|
||||
}
|
||||
|
||||
// Value implements the driver.Valuer interface for TermsAndConditions
|
||||
func (t TermsAndConditions) Value() (driver.Value, error) {
|
||||
return json.Marshal(t)
|
||||
}
|
||||
|
||||
type TncSection struct {
|
||||
Title string `json:"title"`
|
||||
Rules []string `json:"rules"`
|
||||
}
|
||||
|
||||
type Reward struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
Name string `gorm:"type:varchar(150);not null" json:"name"`
|
||||
RewardType RewardType `gorm:"type:varchar(50);not null" json:"reward_type"`
|
||||
CostPoints int64 `gorm:"type:bigint;not null" json:"cost_points"`
|
||||
Stock *int `gorm:"type:int" json:"stock,omitempty"`
|
||||
MaxPerCustomer int `gorm:"type:int;default:1" json:"max_per_customer"`
|
||||
Tnc *TermsAndConditions `gorm:"type:jsonb" json:"tnc,omitempty"`
|
||||
Metadata *map[string]interface{} `gorm:"type:jsonb" json:"metadata,omitempty"`
|
||||
Images *StringSlice `gorm:"type:jsonb" json:"images,omitempty"`
|
||||
CreatedAt time.Time `gorm:"type:timestamp;default:now()" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"type:timestamp;default:now()" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (Reward) TableName() string {
|
||||
return "rewards"
|
||||
}
|
||||
|
||||
func (r *Reward) BeforeCreate(tx *gorm.DB) error {
|
||||
if r.ID == uuid.Nil {
|
||||
r.ID = uuid.New()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reward) BeforeUpdate(tx *gorm.DB) error {
|
||||
r.UpdatedAt = time.Now()
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListRewardsRequest struct {
|
||||
Page int `form:"page" binding:"min=1"`
|
||||
Limit int `form:"limit" binding:"min=1,max=100"`
|
||||
Search string `form:"search"`
|
||||
RewardType string `form:"reward_type"`
|
||||
MinPoints *int64 `form:"min_points"`
|
||||
MaxPoints *int64 `form:"max_points"`
|
||||
HasStock *bool `form:"has_stock"`
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -13,6 +13,11 @@ type Unit struct {
|
||||
Name string `gorm:"not null;size:255" json:"name"`
|
||||
Abbreviation *string `gorm:"size:50" json:"abbreviation"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
DeletedAt *time.Time `gorm:"index" json:"deleted_at,omitempty"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (Unit) TableName() string {
|
||||
return "units"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Vendor struct {
|
||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null" json:"organization_id" validate:"required"`
|
||||
Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"`
|
||||
Email *string `gorm:"size:255" json:"email" validate:"omitempty,email"`
|
||||
PhoneNumber *string `gorm:"size:20" json:"phone_number" validate:"omitempty"`
|
||||
Address *string `gorm:"type:text" json:"address" validate:"omitempty"`
|
||||
ContactPerson *string `gorm:"size:255" json:"contact_person" validate:"omitempty,max=255"`
|
||||
TaxNumber *string `gorm:"size:50" json:"tax_number" validate:"omitempty,max=50"`
|
||||
PaymentTerms *string `gorm:"size:100" json:"payment_terms" validate:"omitempty,max=100"`
|
||||
Notes *string `gorm:"type:text" json:"notes" validate:"omitempty"`
|
||||
IsActive bool `gorm:"not null;default:true" json:"is_active"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
|
||||
Organization *Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
|
||||
}
|
||||
|
||||
func (v *Vendor) BeforeCreate(tx *gorm.DB) error {
|
||||
if v.ID == uuid.Nil {
|
||||
id := uuid.New()
|
||||
v.ID = id
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Vendor) TableName() string {
|
||||
return "vendors"
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/contract"
|
||||
"apskel-pos-be/internal/util"
|
||||
"apskel-pos-be/internal/validator"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type AccountHandler struct {
|
||||
service contract.AccountContract
|
||||
validator validator.AccountValidator
|
||||
}
|
||||
|
||||
func NewAccountHandler(service contract.AccountContract, validator validator.AccountValidator) *AccountHandler {
|
||||
return &AccountHandler{
|
||||
service: service,
|
||||
validator: validator,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *AccountHandler) CreateAccount(c *gin.Context) {
|
||||
var req contract.CreateAccountRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.CreateAccount(c, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "AccountHandler")
|
||||
}
|
||||
|
||||
func (h *AccountHandler) GetAccountByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.GetAccountByID(c, id)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "AccountHandler")
|
||||
}
|
||||
|
||||
func (h *AccountHandler) UpdateAccount(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.UpdateAccountRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.UpdateAccount(c, id, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "AccountHandler")
|
||||
}
|
||||
|
||||
func (h *AccountHandler) DeleteAccount(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.DeleteAccount(c, id)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(gin.H{"message": "Account deleted successfully"}), "AccountHandler")
|
||||
}
|
||||
|
||||
func (h *AccountHandler) ListAccounts(c *gin.Context) {
|
||||
var req contract.ListAccountsRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, total, err := h.service.ListAccounts(c, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(gin.H{
|
||||
"data": response,
|
||||
"total": total,
|
||||
"page": req.Page,
|
||||
"limit": req.Limit,
|
||||
}), "AccountHandler")
|
||||
}
|
||||
|
||||
func (h *AccountHandler) GetAccountsByOrganization(c *gin.Context) {
|
||||
organizationIDStr := c.Param("organization_id")
|
||||
organizationID, err := uuid.Parse(organizationIDStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid organization ID format"}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
var outletID *uuid.UUID
|
||||
if outletIDStr := c.Query("outlet_id"); outletIDStr != "" {
|
||||
if parsedOutletID, err := uuid.Parse(outletIDStr); err == nil {
|
||||
outletID = &parsedOutletID
|
||||
}
|
||||
}
|
||||
|
||||
response, err := h.service.GetAccountsByOrganization(c, organizationID, outletID)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "AccountHandler")
|
||||
}
|
||||
|
||||
func (h *AccountHandler) GetAccountsByChartOfAccount(c *gin.Context) {
|
||||
chartOfAccountIDStr := c.Param("chart_of_account_id")
|
||||
chartOfAccountID, err := uuid.Parse(chartOfAccountIDStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid chart of account ID format"}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.GetAccountsByChartOfAccount(c, chartOfAccountID)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "AccountHandler")
|
||||
}
|
||||
|
||||
func (h *AccountHandler) UpdateAccountBalance(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.UpdateAccountBalanceRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.UpdateAccountBalance(c, id, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(gin.H{"message": "Account balance updated successfully"}), "AccountHandler")
|
||||
}
|
||||
|
||||
func (h *AccountHandler) GetAccountBalance(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
balance, err := h.service.GetAccountBalance(c, id)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "AccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(gin.H{"balance": balance}), "AccountHandler")
|
||||
}
|
||||
@@ -97,6 +97,30 @@ func (h *AnalyticsHandler) GetProductAnalytics(c *gin.Context) {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetProductAnalytics")
|
||||
}
|
||||
|
||||
func (h *AnalyticsHandler) GetProductAnalyticsPerCategory(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
var req contract.ProductAnalyticsPerCategoryRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetProductAnalyticsPerCategory", err.Error())}), "AnalyticsHandler::GetProductAnalyticsPerCategory")
|
||||
return
|
||||
}
|
||||
|
||||
req.OrganizationID = contextInfo.OrganizationID
|
||||
req.OutletID = &contextInfo.OutletID
|
||||
modelReq := transformer.ProductAnalyticsPerCategoryContractToModel(&req)
|
||||
|
||||
response, err := h.analyticsService.GetProductAnalyticsPerCategory(ctx, modelReq)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "AnalyticsHandler::GetProductAnalyticsPerCategory", err.Error())}), "AnalyticsHandler::GetProductAnalyticsPerCategory")
|
||||
return
|
||||
}
|
||||
|
||||
contractResp := transformer.ProductAnalyticsPerCategoryModelToContract(response)
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetProductAnalyticsPerCategory")
|
||||
}
|
||||
|
||||
func (h *AnalyticsHandler) GetDashboardAnalytics(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
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"
|
||||
)
|
||||
|
||||
type CampaignHandler struct {
|
||||
campaignService service.CampaignService
|
||||
campaignValidator validator.CampaignValidator
|
||||
}
|
||||
|
||||
func NewCampaignHandler(campaignService service.CampaignService, campaignValidator validator.CampaignValidator) *CampaignHandler {
|
||||
return &CampaignHandler{
|
||||
campaignService: campaignService,
|
||||
campaignValidator: campaignValidator,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *CampaignHandler) CreateCampaign(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.CreateCampaignRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::CreateCampaign -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::CreateCampaign")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.campaignValidator.ValidateCreateCampaignRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("CampaignHandler::CreateCampaign -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::CreateCampaign")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.campaignService.CreateCampaign(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::CreateCampaign -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CampaignEntity, err.Error())}), "CampaignHandler::CreateCampaign")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CampaignHandler::CreateCampaign")
|
||||
}
|
||||
|
||||
func (h *CampaignHandler) GetCampaign(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
idStr := c.Param("id")
|
||||
if idStr == "" {
|
||||
logger.FromContext(c.Request.Context()).Error("CampaignHandler::GetCampaign -> missing ID parameter")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.CampaignEntity, "ID parameter is required")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::GetCampaign")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.campaignService.GetCampaign(ctx, idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::GetCampaign -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CampaignEntity, err.Error())}), "CampaignHandler::GetCampaign")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CampaignHandler::GetCampaign")
|
||||
}
|
||||
|
||||
func (h *CampaignHandler) ListCampaigns(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.ListCampaignsRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::ListCampaigns -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::ListCampaigns")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.campaignValidator.ValidateListCampaignsRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("CampaignHandler::ListCampaigns -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::ListCampaigns")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.campaignService.ListCampaigns(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::ListCampaigns -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CampaignEntity, err.Error())}), "CampaignHandler::ListCampaigns")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CampaignHandler::ListCampaigns")
|
||||
}
|
||||
|
||||
func (h *CampaignHandler) UpdateCampaign(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.UpdateCampaignRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::UpdateCampaign -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::UpdateCampaign")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.campaignValidator.ValidateUpdateCampaignRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("CampaignHandler::UpdateCampaign -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::UpdateCampaign")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.campaignService.UpdateCampaign(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::UpdateCampaign -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CampaignEntity, err.Error())}), "CampaignHandler::UpdateCampaign")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CampaignHandler::UpdateCampaign")
|
||||
}
|
||||
|
||||
func (h *CampaignHandler) DeleteCampaign(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
idStr := c.Param("id")
|
||||
if idStr == "" {
|
||||
logger.FromContext(c.Request.Context()).Error("CampaignHandler::DeleteCampaign -> missing ID parameter")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.CampaignEntity, "ID parameter is required")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::DeleteCampaign")
|
||||
return
|
||||
}
|
||||
|
||||
err := h.campaignService.DeleteCampaign(ctx, idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::DeleteCampaign -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CampaignEntity, err.Error())}), "CampaignHandler::DeleteCampaign")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse("Campaign deleted successfully"), "CampaignHandler::DeleteCampaign")
|
||||
}
|
||||
|
||||
func (h *CampaignHandler) GetActiveCampaigns(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
response, err := h.campaignService.GetActiveCampaigns(ctx)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::GetActiveCampaigns -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CampaignEntity, err.Error())}), "CampaignHandler::GetActiveCampaigns")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CampaignHandler::GetActiveCampaigns")
|
||||
}
|
||||
|
||||
func (h *CampaignHandler) GetCampaignsForApp(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
response, err := h.campaignService.GetCampaignsForApp(ctx)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::GetCampaignsForApp -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CampaignEntity, err.Error())}), "CampaignHandler::GetCampaignsForApp")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CampaignHandler::GetCampaignsForApp")
|
||||
}
|
||||
|
||||
// Campaign Rules Handlers
|
||||
|
||||
func (h *CampaignHandler) CreateCampaignRule(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.CreateCampaignRuleRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::CreateCampaignRule -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::CreateCampaignRule")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.campaignService.CreateCampaignRule(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::CreateCampaignRule -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CampaignRuleEntity, err.Error())}), "CampaignHandler::CreateCampaignRule")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CampaignHandler::CreateCampaignRule")
|
||||
}
|
||||
|
||||
func (h *CampaignHandler) GetCampaignRule(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
idStr := c.Param("id")
|
||||
if idStr == "" {
|
||||
logger.FromContext(c.Request.Context()).Error("CampaignHandler::GetCampaignRule -> missing ID parameter")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.CampaignRuleEntity, "ID parameter is required")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::GetCampaignRule")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.campaignService.GetCampaignRule(ctx, idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::GetCampaignRule -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CampaignRuleEntity, err.Error())}), "CampaignHandler::GetCampaignRule")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CampaignHandler::GetCampaignRule")
|
||||
}
|
||||
|
||||
func (h *CampaignHandler) ListCampaignRules(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.ListCampaignRulesRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::ListCampaignRules -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::ListCampaignRules")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.campaignService.ListCampaignRules(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::ListCampaignRules -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CampaignRuleEntity, err.Error())}), "CampaignHandler::ListCampaignRules")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CampaignHandler::ListCampaignRules")
|
||||
}
|
||||
|
||||
func (h *CampaignHandler) UpdateCampaignRule(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.UpdateCampaignRuleRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::UpdateCampaignRule -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::UpdateCampaignRule")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.campaignService.UpdateCampaignRule(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::UpdateCampaignRule -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CampaignRuleEntity, err.Error())}), "CampaignHandler::UpdateCampaignRule")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CampaignHandler::UpdateCampaignRule")
|
||||
}
|
||||
|
||||
func (h *CampaignHandler) DeleteCampaignRule(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
idStr := c.Param("id")
|
||||
if idStr == "" {
|
||||
logger.FromContext(c.Request.Context()).Error("CampaignHandler::DeleteCampaignRule -> missing ID parameter")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.CampaignRuleEntity, "ID parameter is required")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::DeleteCampaignRule")
|
||||
return
|
||||
}
|
||||
|
||||
err := h.campaignService.DeleteCampaignRule(ctx, idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::DeleteCampaignRule -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CampaignRuleEntity, err.Error())}), "CampaignHandler::DeleteCampaignRule")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse("Campaign rule deleted successfully"), "CampaignHandler::DeleteCampaignRule")
|
||||
}
|
||||
|
||||
func (h *CampaignHandler) GetCampaignRulesByCampaignID(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
campaignIDStr := c.Param("campaign_id")
|
||||
if campaignIDStr == "" {
|
||||
logger.FromContext(c.Request.Context()).Error("CampaignHandler::GetCampaignRulesByCampaignID -> missing campaign_id parameter")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.CampaignRuleEntity, "campaign_id parameter is required")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CampaignHandler::GetCampaignRulesByCampaignID")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.campaignService.GetCampaignRulesByCampaignID(ctx, campaignIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CampaignHandler::GetCampaignRulesByCampaignID -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.CampaignRuleEntity, err.Error())}), "CampaignHandler::GetCampaignRulesByCampaignID")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CampaignHandler::GetCampaignRulesByCampaignID")
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"apskel-pos-be/internal/appcontext"
|
||||
@@ -35,6 +36,7 @@ func (h *CategoryHandler) CreateCategory(c *gin.Context) {
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
var req contract.CreateCategoryRequest
|
||||
fmt.Printf("CategoryHandler::CreateCategory -> Request: %+v\n", req)
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CategoryHandler::CreateCategory -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
@@ -71,6 +73,7 @@ func (h *CategoryHandler) UpdateCategory(c *gin.Context) {
|
||||
}
|
||||
|
||||
var req contract.UpdateCategoryRequest
|
||||
fmt.Printf("CategoryHandler::UpdateCategory -> Request: %+v\n", req)
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("CategoryHandler::UpdateCategory -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
|
||||
@@ -138,10 +141,12 @@ func (h *CategoryHandler) GetCategory(c *gin.Context) {
|
||||
|
||||
func (h *CategoryHandler) ListCategories(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
req := &contract.ListCategoriesRequest{
|
||||
Page: 1,
|
||||
Limit: 10,
|
||||
Page: 1,
|
||||
Limit: 10,
|
||||
OrganizationID: &contextInfo.OrganizationID,
|
||||
}
|
||||
|
||||
// Parse query parameters
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/contract"
|
||||
"apskel-pos-be/internal/util"
|
||||
"apskel-pos-be/internal/validator"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ChartOfAccountHandler struct {
|
||||
service contract.ChartOfAccountContract
|
||||
validator validator.ChartOfAccountValidator
|
||||
}
|
||||
|
||||
func NewChartOfAccountHandler(service contract.ChartOfAccountContract, validator validator.ChartOfAccountValidator) *ChartOfAccountHandler {
|
||||
return &ChartOfAccountHandler{
|
||||
service: service,
|
||||
validator: validator,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ChartOfAccountHandler) CreateChartOfAccount(c *gin.Context) {
|
||||
var req contract.CreateChartOfAccountRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.CreateChartOfAccount(c, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "ChartOfAccountHandler")
|
||||
}
|
||||
|
||||
func (h *ChartOfAccountHandler) GetChartOfAccountByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.GetChartOfAccountByID(c, id)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "ChartOfAccountHandler")
|
||||
}
|
||||
|
||||
func (h *ChartOfAccountHandler) UpdateChartOfAccount(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.UpdateChartOfAccountRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.UpdateChartOfAccount(c, id, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "ChartOfAccountHandler")
|
||||
}
|
||||
|
||||
func (h *ChartOfAccountHandler) DeleteChartOfAccount(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.DeleteChartOfAccount(c, id)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(gin.H{"message": "Chart of account deleted successfully"}), "ChartOfAccountHandler")
|
||||
}
|
||||
|
||||
func (h *ChartOfAccountHandler) ListChartOfAccounts(c *gin.Context) {
|
||||
var req contract.ListChartOfAccountsRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, total, err := h.service.ListChartOfAccounts(c, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(gin.H{
|
||||
"data": response,
|
||||
"total": total,
|
||||
"page": req.Page,
|
||||
"limit": req.Limit,
|
||||
}), "ChartOfAccountHandler")
|
||||
}
|
||||
|
||||
func (h *ChartOfAccountHandler) GetChartOfAccountsByOrganization(c *gin.Context) {
|
||||
organizationIDStr := c.Param("organization_id")
|
||||
organizationID, err := uuid.Parse(organizationIDStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid organization ID format"}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
var outletID *uuid.UUID
|
||||
if outletIDStr := c.Query("outlet_id"); outletIDStr != "" {
|
||||
if parsedOutletID, err := uuid.Parse(outletIDStr); err == nil {
|
||||
outletID = &parsedOutletID
|
||||
}
|
||||
}
|
||||
|
||||
response, err := h.service.GetChartOfAccountsByOrganization(c, organizationID, outletID)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "ChartOfAccountHandler")
|
||||
}
|
||||
|
||||
func (h *ChartOfAccountHandler) GetChartOfAccountsByType(c *gin.Context) {
|
||||
organizationIDStr := c.Param("organization_id")
|
||||
organizationID, err := uuid.Parse(organizationIDStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid organization ID format"}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
typeIDStr := c.Param("type_id")
|
||||
typeID, err := uuid.Parse(typeIDStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid type ID format"}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
var outletID *uuid.UUID
|
||||
if outletIDStr := c.Query("outlet_id"); outletIDStr != "" {
|
||||
if parsedOutletID, err := uuid.Parse(outletIDStr); err == nil {
|
||||
outletID = &parsedOutletID
|
||||
}
|
||||
}
|
||||
|
||||
response, err := h.service.GetChartOfAccountsByType(c, organizationID, typeID, outletID)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "ChartOfAccountHandler")
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"apskel-pos-be/internal/contract"
|
||||
"apskel-pos-be/internal/util"
|
||||
"apskel-pos-be/internal/validator"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ChartOfAccountTypeHandler struct {
|
||||
service contract.ChartOfAccountTypeContract
|
||||
validator validator.ChartOfAccountTypeValidator
|
||||
}
|
||||
|
||||
func NewChartOfAccountTypeHandler(service contract.ChartOfAccountTypeContract, validator validator.ChartOfAccountTypeValidator) *ChartOfAccountTypeHandler {
|
||||
return &ChartOfAccountTypeHandler{
|
||||
service: service,
|
||||
validator: validator,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ChartOfAccountTypeHandler) CreateChartOfAccountType(c *gin.Context) {
|
||||
var req contract.CreateChartOfAccountTypeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountTypeHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.CreateChartOfAccountType(c, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountTypeHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "ChartOfAccountTypeHandler")
|
||||
}
|
||||
|
||||
func (h *ChartOfAccountTypeHandler) GetChartOfAccountTypeByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "ChartOfAccountTypeHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.GetChartOfAccountTypeByID(c, id)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountTypeHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "ChartOfAccountTypeHandler")
|
||||
}
|
||||
|
||||
func (h *ChartOfAccountTypeHandler) UpdateChartOfAccountType(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "ChartOfAccountTypeHandler")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.UpdateChartOfAccountTypeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountTypeHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.UpdateChartOfAccountType(c, id, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountTypeHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "ChartOfAccountTypeHandler")
|
||||
}
|
||||
|
||||
func (h *ChartOfAccountTypeHandler) DeleteChartOfAccountType(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "ChartOfAccountTypeHandler")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.DeleteChartOfAccountType(c, id)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountTypeHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(gin.H{"message": "Chart of account type deleted successfully"}), "ChartOfAccountTypeHandler")
|
||||
}
|
||||
|
||||
func (h *ChartOfAccountTypeHandler) ListChartOfAccountTypes(c *gin.Context) {
|
||||
// Parse query parameters
|
||||
filters := make(map[string]interface{})
|
||||
|
||||
if isActive := c.Query("is_active"); isActive != "" {
|
||||
if isActiveBool, err := strconv.ParseBool(isActive); err == nil {
|
||||
filters["is_active"] = isActiveBool
|
||||
}
|
||||
}
|
||||
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
|
||||
|
||||
response, total, err := h.service.ListChartOfAccountTypes(c, filters, page, limit)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "ChartOfAccountTypeHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(gin.H{
|
||||
"data": response,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"limit": limit,
|
||||
}), "ChartOfAccountTypeHandler")
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
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"
|
||||
)
|
||||
|
||||
type CustomerAuthHandler struct {
|
||||
customerAuthService service.CustomerAuthService
|
||||
customerAuthValidator validator.CustomerAuthValidator
|
||||
}
|
||||
|
||||
func NewCustomerAuthHandler(customerAuthService service.CustomerAuthService, customerAuthValidator validator.CustomerAuthValidator) *CustomerAuthHandler {
|
||||
return &CustomerAuthHandler{
|
||||
customerAuthService: customerAuthService,
|
||||
customerAuthValidator: customerAuthValidator,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *CustomerAuthHandler) CheckPhone(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.CheckPhoneRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerAuthHandler::CheckPhone -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerAuthHandler::CheckPhone")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.customerAuthValidator.ValidateCheckPhoneRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("CustomerAuthHandler::CheckPhone -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerAuthHandler::CheckPhone")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.customerAuthService.CheckPhoneNumber(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerAuthHandler::CheckPhone -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())}), "CustomerAuthHandler::CheckPhone")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CustomerAuthHandler::CheckPhone")
|
||||
}
|
||||
|
||||
func (h *CustomerAuthHandler) RegisterStart(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.RegisterStartRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerAuthHandler::RegisterStart -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerAuthHandler::RegisterStart")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.customerAuthValidator.ValidateRegisterStartRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("CustomerAuthHandler::RegisterStart -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerAuthHandler::RegisterStart")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.customerAuthService.StartRegistration(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerAuthHandler::RegisterStart -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())}), "CustomerAuthHandler::RegisterStart")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CustomerAuthHandler::RegisterStart")
|
||||
}
|
||||
|
||||
func (h *CustomerAuthHandler) RegisterVerifyOtp(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.RegisterVerifyOtpRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerAuthHandler::RegisterVerifyOtp -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerAuthHandler::RegisterVerifyOtp")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.customerAuthValidator.ValidateRegisterVerifyOtpRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("CustomerAuthHandler::RegisterVerifyOtp -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerAuthHandler::RegisterVerifyOtp")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.customerAuthService.VerifyOtp(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerAuthHandler::RegisterVerifyOtp -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())}), "CustomerAuthHandler::RegisterVerifyOtp")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CustomerAuthHandler::RegisterVerifyOtp")
|
||||
}
|
||||
|
||||
func (h *CustomerAuthHandler) RegisterSetPassword(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.RegisterSetPasswordRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerAuthHandler::RegisterSetPassword -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerAuthHandler::RegisterSetPassword")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.customerAuthValidator.ValidateRegisterSetPasswordRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("CustomerAuthHandler::RegisterSetPassword -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerAuthHandler::RegisterSetPassword")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.customerAuthService.SetPassword(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerAuthHandler::RegisterSetPassword -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())}), "CustomerAuthHandler::RegisterSetPassword")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CustomerAuthHandler::RegisterSetPassword")
|
||||
}
|
||||
|
||||
func (h *CustomerAuthHandler) Login(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.CustomerLoginRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerAuthHandler::Login -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerAuthHandler::Login")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.customerAuthValidator.ValidateCustomerLoginRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(validationError).Error("CustomerAuthHandler::Login -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerAuthHandler::Login")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.customerAuthService.Login(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerAuthHandler::Login -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())}), "CustomerAuthHandler::Login")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CustomerAuthHandler::Login")
|
||||
}
|
||||
|
||||
func (h *CustomerAuthHandler) ResendOtp(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.ResendOtpRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("CustomerAuthHandler::ResendOtp -> binding request failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())}), "CustomerAuthHandler::ResendOtp")
|
||||
return
|
||||
}
|
||||
|
||||
// Validate request
|
||||
if err, entity := h.customerAuthValidator.ValidateResendOtpRequest(&req); err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("CustomerAuthHandler::ResendOtp -> validation failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.MissingFieldErrorCode, entity, err.Error())}), "CustomerAuthHandler::ResendOtp")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.customerAuthService.ResendOtp(ctx, &req)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("CustomerAuthHandler::ResendOtp -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())}), "CustomerAuthHandler::ResendOtp")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CustomerAuthHandler::ResendOtp")
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
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"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type CustomerPointsHandler struct {
|
||||
customerPointsService service.CustomerPointsService
|
||||
}
|
||||
|
||||
func NewCustomerPointsHandler(customerPointsService service.CustomerPointsService) *CustomerPointsHandler {
|
||||
return &CustomerPointsHandler{
|
||||
customerPointsService: customerPointsService,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *CustomerPointsHandler) GetCustomerPoints(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
// Get customer ID from context (set by middleware)
|
||||
customerID, exists := c.Get("customer_id")
|
||||
if !exists {
|
||||
logger.FromContext(ctx).Error("Customer ID not found in context")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.ValidationErrorCode, constants.AuthHandlerEntity, "Customer ID not found"),
|
||||
}), "CustomerPointsHandler::GetCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
customerIDStr, ok := customerID.(string)
|
||||
if !ok {
|
||||
logger.FromContext(ctx).Error("Invalid customer ID type in context")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.ValidationErrorCode, constants.AuthHandlerEntity, "Invalid customer ID"),
|
||||
}), "CustomerPointsHandler::GetCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.customerPointsService.GetCustomerPoints(ctx, customerIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("CustomerPointsHandler::GetCustomerPoints -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "CustomerPointsHandler::GetCustomerPoints")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CustomerPointsHandler::GetCustomerPoints")
|
||||
}
|
||||
|
||||
func (h *CustomerPointsHandler) GetCustomerTokens(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
// Get customer ID from context (set by middleware)
|
||||
customerID, exists := c.Get("customer_id")
|
||||
if !exists {
|
||||
logger.FromContext(ctx).Error("Customer ID not found in context")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.ValidationErrorCode, constants.AuthHandlerEntity, "Customer ID not found"),
|
||||
}), "CustomerPointsHandler::GetCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
customerIDStr, ok := customerID.(string)
|
||||
if !ok {
|
||||
logger.FromContext(ctx).Error("Invalid customer ID type in context")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.ValidationErrorCode, constants.AuthHandlerEntity, "Invalid customer ID"),
|
||||
}), "CustomerPointsHandler::GetCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.customerPointsService.GetCustomerTokens(ctx, customerIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("CustomerPointsHandler::GetCustomerTokens -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "CustomerPointsHandler::GetCustomerTokens")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CustomerPointsHandler::GetCustomerTokens")
|
||||
}
|
||||
|
||||
func (h *CustomerPointsHandler) GetCustomerWallet(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
// Get customer ID from context (set by middleware)
|
||||
customerID, exists := c.Get("customer_id")
|
||||
if !exists {
|
||||
logger.FromContext(ctx).Error("Customer ID not found in context")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.ValidationErrorCode, constants.AuthHandlerEntity, "Customer ID not found"),
|
||||
}), "CustomerPointsHandler::GetCustomerWallet")
|
||||
return
|
||||
}
|
||||
|
||||
customerIDStr, ok := customerID.(string)
|
||||
if !ok {
|
||||
logger.FromContext(ctx).Error("Invalid customer ID type in context")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.ValidationErrorCode, constants.AuthHandlerEntity, "Invalid customer ID"),
|
||||
}), "CustomerPointsHandler::GetCustomerWallet")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.customerPointsService.GetCustomerWallet(ctx, customerIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("CustomerPointsHandler::GetCustomerWallet -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "CustomerPointsHandler::GetCustomerWallet")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CustomerPointsHandler::GetCustomerWallet")
|
||||
}
|
||||
|
||||
func (h *CustomerPointsHandler) GetCustomerGames(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
response, err := h.customerPointsService.GetCustomerGames(ctx)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("CustomerPointsHandler::GetCustomerGames -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "CustomerPointsHandler::GetCustomerGames")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CustomerPointsHandler::GetCustomerGames")
|
||||
}
|
||||
|
||||
func (h *CustomerPointsHandler) GetFerrisWheelGame(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
response, err := h.customerPointsService.GetFerrisWheelGame(ctx)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("CustomerPointsHandler::GetFerrisWheelGame -> service call failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "CustomerPointsHandler::GetFerrisWheelGame")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "CustomerPointsHandler::GetFerrisWheelGame")
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
@@ -18,9 +18,7 @@ type IngredientHandler struct {
|
||||
}
|
||||
|
||||
func NewIngredientHandler(ingredientService IngredientService) *IngredientHandler {
|
||||
return &IngredientHandler{
|
||||
ingredientService: ingredientService,
|
||||
}
|
||||
return &IngredientHandler{ingredientService: ingredientService}
|
||||
}
|
||||
|
||||
func (h *IngredientHandler) Create(c *gin.Context) {
|
||||
@@ -29,53 +27,53 @@ func (h *IngredientHandler) Create(c *gin.Context) {
|
||||
|
||||
var request models.CreateIngredientRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("IngredientHandler::Create -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientHandler::Create")
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::Create -> request binding failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "IngredientHandler::Create")
|
||||
return
|
||||
}
|
||||
|
||||
request.OrganizationID = contextInfo.OrganizationID
|
||||
|
||||
ingredientResponse, err := h.ingredientService.CreateIngredient(ctx, &request)
|
||||
resp, err := h.ingredientService.CreateIngredient(ctx, &request)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::Create -> Failed to create ingredient from service")
|
||||
validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientHandler::Create")
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::Create -> failed")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "IngredientHandler::Create")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(ingredientResponse), "IngredientHandler::Create")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::Create")
|
||||
}
|
||||
|
||||
func (h *IngredientHandler) GetByID(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::GetByID -> Invalid ingredient ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientHandler::GetByID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID"),
|
||||
}), "IngredientHandler::GetByID")
|
||||
return
|
||||
}
|
||||
|
||||
ingredientResponse, err := h.ingredientService.GetIngredientByID(ctx, id)
|
||||
resp, err := h.ingredientService.GetIngredientByID(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::GetByID -> Failed to get ingredient from service")
|
||||
validationResponseError := contract.NewResponseError(constants.NotFoundErrorCode, constants.RequestEntity, "Ingredient not found")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientHandler::GetByID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.NotFoundErrorCode, constants.RequestEntity, "Ingredient not found"),
|
||||
}), "IngredientHandler::GetByID")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(ingredientResponse), "IngredientHandler::GetByID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::GetByID")
|
||||
}
|
||||
|
||||
func (h *IngredientHandler) GetAll(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
// Get query parameters
|
||||
pageStr := c.DefaultQuery("page", "1")
|
||||
limitStr := c.DefaultQuery("limit", "10")
|
||||
search := c.Query("search")
|
||||
@@ -83,95 +81,177 @@ func (h *IngredientHandler) GetAll(c *gin.Context) {
|
||||
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::GetAll -> Invalid page parameter")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid page parameter")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientHandler::GetAll")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid page parameter"),
|
||||
}), "IngredientHandler::GetAll")
|
||||
return
|
||||
}
|
||||
|
||||
limit, err := strconv.Atoi(limitStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::GetAll -> Invalid limit parameter")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid limit parameter")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientHandler::GetAll")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid limit parameter"),
|
||||
}), "IngredientHandler::GetAll")
|
||||
return
|
||||
}
|
||||
|
||||
var outletID *uuid.UUID
|
||||
if outletIDStr != "" {
|
||||
parsedOutletID, err := uuid.Parse(outletIDStr)
|
||||
parsed, err := uuid.Parse(outletIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::GetAll -> Invalid outlet ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid outlet ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientHandler::GetAll")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid outlet ID"),
|
||||
}), "IngredientHandler::GetAll")
|
||||
return
|
||||
}
|
||||
outletID = &parsedOutletID
|
||||
outletID = &parsed
|
||||
}
|
||||
|
||||
ingredientResponse, err := h.ingredientService.ListIngredients(ctx, contextInfo.OrganizationID, outletID, page, limit, search)
|
||||
resp, err := h.ingredientService.ListIngredients(ctx, contextInfo.OrganizationID, outletID, page, limit, search)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::GetAll -> Failed to get ingredients from service")
|
||||
validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, "Failed to get ingredients")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientHandler::GetAll")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, "Failed to get ingredients"),
|
||||
}), "IngredientHandler::GetAll")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(ingredientResponse), "IngredientHandler::GetAll")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::GetAll")
|
||||
}
|
||||
|
||||
func (h *IngredientHandler) Update(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::Update -> Invalid ingredient ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientHandler::Update")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID"),
|
||||
}), "IngredientHandler::Update")
|
||||
return
|
||||
}
|
||||
|
||||
var request models.UpdateIngredientRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::Update -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientHandler::Update")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body"),
|
||||
}), "IngredientHandler::Update")
|
||||
return
|
||||
}
|
||||
|
||||
ingredientResponse, err := h.ingredientService.UpdateIngredient(ctx, id, &request)
|
||||
resp, err := h.ingredientService.UpdateIngredient(ctx, id, &request)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::Update -> Failed to update ingredient from service")
|
||||
validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientHandler::Update")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "IngredientHandler::Update")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(ingredientResponse), "IngredientHandler::Update")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::Update")
|
||||
}
|
||||
|
||||
func (h *IngredientHandler) Delete(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::Delete -> Invalid ingredient ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientHandler::Delete")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID"),
|
||||
}), "IngredientHandler::Delete")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.ingredientService.DeleteIngredient(ctx, id)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientHandler::Delete -> Failed to delete ingredient from service")
|
||||
validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientHandler::Delete")
|
||||
if err := h.ingredientService.DeleteIngredient(ctx, id); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "IngredientHandler::Delete")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(map[string]interface{}{
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(map[string]string{
|
||||
"message": "Ingredient deleted successfully",
|
||||
}), "IngredientHandler::Delete")
|
||||
}
|
||||
|
||||
// AddCompositions adds multiple composition items to a semi-finished ingredient.
|
||||
func (h *IngredientHandler) AddCompositions(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "invalid ingredient id"),
|
||||
}), "IngredientHandler::AddCompositions")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.AddIngredientCompositionsRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "IngredientHandler::AddCompositions")
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := h.ingredientService.AddCompositions(ctx, id, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "IngredientHandler::AddCompositions")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::AddCompositions")
|
||||
}
|
||||
|
||||
// UpdateComposition updates quantity/outlet of a single composition entry.
|
||||
func (h *IngredientHandler) UpdateComposition(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
id, err := uuid.Parse(c.Param("composition_id"))
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "invalid composition id"),
|
||||
}), "IngredientHandler::UpdateComposition")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.UpdateIngredientCompositionRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "IngredientHandler::UpdateComposition")
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := h.ingredientService.UpdateComposition(ctx, id, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "IngredientHandler::UpdateComposition")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::UpdateComposition")
|
||||
}
|
||||
|
||||
// DeleteComposition removes a single composition entry.
|
||||
func (h *IngredientHandler) DeleteComposition(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
id, err := uuid.Parse(c.Param("composition_id"))
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "invalid composition id"),
|
||||
}), "IngredientHandler::DeleteComposition")
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := h.ingredientService.DeleteComposition(ctx, id)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()),
|
||||
}), "IngredientHandler::DeleteComposition")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::DeleteComposition")
|
||||
}
|
||||
|
||||
@@ -13,4 +13,7 @@ type IngredientService interface {
|
||||
DeleteIngredient(ctx context.Context, id uuid.UUID) error
|
||||
GetIngredientByID(ctx context.Context, id uuid.UUID) (*models.IngredientResponse, error)
|
||||
ListIngredients(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, page, limit int, search string) (*models.PaginatedResponse[models.IngredientResponse], error)
|
||||
UpdateComposition(ctx context.Context, id uuid.UUID, req *models.UpdateIngredientCompositionRequest) (*models.IngredientCompositionResponse, error)
|
||||
DeleteComposition(ctx context.Context, id uuid.UUID) (*models.IngredientResponse, error)
|
||||
AddCompositions(ctx context.Context, parentID uuid.UUID, req *models.AddIngredientCompositionsRequest) (*models.AddIngredientCompositionsResponse, error)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/appcontext"
|
||||
"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"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type IngredientUnitConverterHandler struct {
|
||||
converterService service.IngredientUnitConverterService
|
||||
converterValidator validator.IngredientUnitConverterValidator
|
||||
}
|
||||
|
||||
func NewIngredientUnitConverterHandler(
|
||||
converterService service.IngredientUnitConverterService,
|
||||
converterValidator validator.IngredientUnitConverterValidator,
|
||||
) *IngredientUnitConverterHandler {
|
||||
return &IngredientUnitConverterHandler{
|
||||
converterService: converterService,
|
||||
converterValidator: converterValidator,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *IngredientUnitConverterHandler) CreateIngredientUnitConverter(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
var req contract.CreateIngredientUnitConverterRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("IngredientUnitConverterHandler::CreateIngredientUnitConverter -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::CreateIngredientUnitConverter")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.converterValidator.ValidateCreateIngredientUnitConverterRequest(&req)
|
||||
if validationError != nil {
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::CreateIngredientUnitConverter")
|
||||
return
|
||||
}
|
||||
|
||||
converterResponse := h.converterService.CreateIngredientUnitConverter(ctx, contextInfo, &req)
|
||||
if converterResponse.HasErrors() {
|
||||
errorResp := converterResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::CreateIngredientUnitConverter -> Failed to create ingredient unit converter from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::CreateIngredientUnitConverter")
|
||||
}
|
||||
|
||||
func (h *IngredientUnitConverterHandler) UpdateIngredientUnitConverter(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
converterIDStr := c.Param("id")
|
||||
converterID, err := uuid.Parse(converterIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientUnitConverterHandler::UpdateIngredientUnitConverter -> Invalid converter ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid converter ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::UpdateIngredientUnitConverter")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.UpdateIngredientUnitConverterRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientUnitConverterHandler::UpdateIngredientUnitConverter -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::UpdateIngredientUnitConverter")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.converterValidator.ValidateUpdateIngredientUnitConverterRequest(&req)
|
||||
if validationError != nil {
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::UpdateIngredientUnitConverter")
|
||||
return
|
||||
}
|
||||
|
||||
converterResponse := h.converterService.UpdateIngredientUnitConverter(ctx, contextInfo, converterID, &req)
|
||||
if converterResponse.HasErrors() {
|
||||
errorResp := converterResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::UpdateIngredientUnitConverter -> Failed to update ingredient unit converter from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::UpdateIngredientUnitConverter")
|
||||
}
|
||||
|
||||
func (h *IngredientUnitConverterHandler) DeleteIngredientUnitConverter(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
converterIDStr := c.Param("id")
|
||||
converterID, err := uuid.Parse(converterIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientUnitConverterHandler::DeleteIngredientUnitConverter -> Invalid converter ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid converter ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::DeleteIngredientUnitConverter")
|
||||
return
|
||||
}
|
||||
|
||||
converterResponse := h.converterService.DeleteIngredientUnitConverter(ctx, contextInfo, converterID)
|
||||
if converterResponse.HasErrors() {
|
||||
errorResp := converterResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::DeleteIngredientUnitConverter -> Failed to delete ingredient unit converter from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::DeleteIngredientUnitConverter")
|
||||
}
|
||||
|
||||
func (h *IngredientUnitConverterHandler) GetIngredientUnitConverter(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
converterIDStr := c.Param("id")
|
||||
converterID, err := uuid.Parse(converterIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientUnitConverterHandler::GetIngredientUnitConverter -> Invalid converter ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid converter ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::GetIngredientUnitConverter")
|
||||
return
|
||||
}
|
||||
|
||||
converterResponse := h.converterService.GetIngredientUnitConverter(ctx, contextInfo, converterID)
|
||||
if converterResponse.HasErrors() {
|
||||
errorResp := converterResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::GetIngredientUnitConverter -> Failed to get ingredient unit converter from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::GetIngredientUnitConverter")
|
||||
}
|
||||
|
||||
func (h *IngredientUnitConverterHandler) ListIngredientUnitConverters(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
req := &contract.ListIngredientUnitConvertersRequest{
|
||||
Page: 1,
|
||||
Limit: 10,
|
||||
}
|
||||
|
||||
// Parse query parameters
|
||||
if pageStr := c.Query("page"); pageStr != "" {
|
||||
if page, err := strconv.Atoi(pageStr); err == nil {
|
||||
req.Page = page
|
||||
}
|
||||
}
|
||||
|
||||
if limitStr := c.Query("limit"); limitStr != "" {
|
||||
if limit, err := strconv.Atoi(limitStr); err == nil {
|
||||
req.Limit = limit
|
||||
}
|
||||
}
|
||||
|
||||
if search := c.Query("search"); search != "" {
|
||||
req.Search = search
|
||||
}
|
||||
|
||||
if ingredientIDStr := c.Query("ingredient_id"); ingredientIDStr != "" {
|
||||
if ingredientID, err := uuid.Parse(ingredientIDStr); err == nil {
|
||||
req.IngredientID = &ingredientID
|
||||
}
|
||||
}
|
||||
|
||||
if fromUnitIDStr := c.Query("from_unit_id"); fromUnitIDStr != "" {
|
||||
if fromUnitID, err := uuid.Parse(fromUnitIDStr); err == nil {
|
||||
req.FromUnitID = &fromUnitID
|
||||
}
|
||||
}
|
||||
|
||||
if toUnitIDStr := c.Query("to_unit_id"); toUnitIDStr != "" {
|
||||
if toUnitID, err := uuid.Parse(toUnitIDStr); err == nil {
|
||||
req.ToUnitID = &toUnitID
|
||||
}
|
||||
}
|
||||
|
||||
if isActiveStr := c.Query("is_active"); isActiveStr != "" {
|
||||
if isActive, err := strconv.ParseBool(isActiveStr); err == nil {
|
||||
req.IsActive = &isActive
|
||||
}
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.converterValidator.ValidateListIngredientUnitConvertersRequest(req)
|
||||
if validationError != nil {
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::ListIngredientUnitConverters")
|
||||
return
|
||||
}
|
||||
|
||||
converterResponse := h.converterService.ListIngredientUnitConverters(ctx, contextInfo, req)
|
||||
if converterResponse.HasErrors() {
|
||||
errorResp := converterResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::ListIngredientUnitConverters -> Failed to list ingredient unit converters from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::ListIngredientUnitConverters")
|
||||
}
|
||||
|
||||
func (h *IngredientUnitConverterHandler) GetConvertersForIngredient(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
ingredientIDStr := c.Param("ingredient_id")
|
||||
ingredientID, err := uuid.Parse(ingredientIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientUnitConverterHandler::GetConvertersForIngredient -> Invalid ingredient ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::GetConvertersForIngredient")
|
||||
return
|
||||
}
|
||||
|
||||
converterResponse := h.converterService.GetConvertersForIngredient(ctx, contextInfo, ingredientID)
|
||||
if converterResponse.HasErrors() {
|
||||
errorResp := converterResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::GetConvertersForIngredient -> Failed to get converters for ingredient from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::GetConvertersForIngredient")
|
||||
}
|
||||
|
||||
func (h *IngredientUnitConverterHandler) ConvertUnit(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
var req contract.ConvertUnitRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("IngredientUnitConverterHandler::ConvertUnit -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::ConvertUnit")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.converterValidator.ValidateConvertUnitRequest(&req)
|
||||
if validationError != nil {
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::ConvertUnit")
|
||||
return
|
||||
}
|
||||
|
||||
converterResponse := h.converterService.ConvertUnit(ctx, contextInfo, &req)
|
||||
if converterResponse.HasErrors() {
|
||||
errorResp := converterResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::ConvertUnit -> Failed to convert unit from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::ConvertUnit")
|
||||
}
|
||||
|
||||
func (h *IngredientUnitConverterHandler) GetUnitsByIngredientID(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
ingredientIDStr := c.Param("ingredient_id")
|
||||
ingredientID, err := uuid.Parse(ingredientIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("IngredientUnitConverterHandler::GetUnitsByIngredientID -> Invalid ingredient ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::GetUnitsByIngredientID")
|
||||
return
|
||||
}
|
||||
|
||||
unitsResponse := h.converterService.GetUnitsByIngredientID(ctx, contextInfo, ingredientID)
|
||||
if unitsResponse.HasErrors() {
|
||||
errorResp := unitsResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::GetUnitsByIngredientID -> Failed to get units for ingredient from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, unitsResponse, "IngredientUnitConverterHandler::GetUnitsByIngredientID")
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@ package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"apskel-pos-be/internal/appcontext"
|
||||
"apskel-pos-be/internal/constants"
|
||||
"apskel-pos-be/internal/contract"
|
||||
"apskel-pos-be/internal/logger"
|
||||
"apskel-pos-be/internal/models"
|
||||
"apskel-pos-be/internal/service"
|
||||
"apskel-pos-be/internal/util"
|
||||
"apskel-pos-be/internal/validator"
|
||||
@@ -138,13 +140,14 @@ func (h *InventoryHandler) GetInventory(c *gin.Context) {
|
||||
|
||||
func (h *InventoryHandler) ListInventory(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
req := &contract.ListInventoryRequest{
|
||||
Page: 1,
|
||||
Limit: 10,
|
||||
Page: 1,
|
||||
Limit: 10,
|
||||
OutletID: &contextInfo.OutletID,
|
||||
}
|
||||
|
||||
// Parse query parameters
|
||||
if pageStr := c.Query("page"); pageStr != "" {
|
||||
if page, err := strconv.Atoi(pageStr); err == nil {
|
||||
req.Page = page
|
||||
@@ -235,6 +238,34 @@ func (h *InventoryHandler) AdjustInventory(c *gin.Context) {
|
||||
util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::AdjustInventory")
|
||||
}
|
||||
|
||||
func (h *InventoryHandler) RestockInventory(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var req contract.RestockInventoryRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("InventoryHandler::RestockInventory -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::RestockInventory")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Add validation for restock request
|
||||
// validationError, validationErrorCode := h.inventoryValidator.ValidateRestockInventoryRequest(&req)
|
||||
// if validationError != nil {
|
||||
// validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
// util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::RestockInventory")
|
||||
// return
|
||||
// }
|
||||
|
||||
inventoryResponse := h.inventoryService.RestockInventory(ctx, &req)
|
||||
if inventoryResponse.HasErrors() {
|
||||
errorResp := inventoryResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::RestockInventory -> Failed to restock inventory from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::RestockInventory")
|
||||
}
|
||||
|
||||
func (h *InventoryHandler) GetLowStockItems(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
|
||||
@@ -276,3 +307,131 @@ func (h *InventoryHandler) GetZeroStockItems(c *gin.Context) {
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::GetZeroStockItems")
|
||||
}
|
||||
|
||||
func (h *InventoryHandler) GetInventoryReportSummary(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
outletIDStr := c.Param("outlet_id")
|
||||
outletID, err := uuid.Parse(outletIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("InventoryHandler::GetInventoryReportSummary -> Invalid outlet ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid outlet ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::GetInventoryReportSummary")
|
||||
return
|
||||
}
|
||||
|
||||
// Parse date range parameters for summary
|
||||
var dateFrom, dateTo *time.Time
|
||||
if dateFromStr := c.Query("date_from"); dateFromStr != "" {
|
||||
if parsedDateFrom, err := time.Parse("2006-01-02", dateFromStr); err == nil {
|
||||
dateFrom = &parsedDateFrom
|
||||
}
|
||||
}
|
||||
if dateToStr := c.Query("date_to"); dateToStr != "" {
|
||||
if parsedDateTo, err := time.Parse("2006-01-02", dateToStr); err == nil {
|
||||
dateTo = &parsedDateTo
|
||||
}
|
||||
}
|
||||
|
||||
summary, err := h.inventoryService.GetInventoryReportSummary(ctx, outletID, contextInfo.OrganizationID, dateFrom, dateTo)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("InventoryHandler::GetInventoryReportSummary -> Failed to get inventory report summary from service")
|
||||
responseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{responseError}), "InventoryHandler::GetInventoryReportSummary")
|
||||
return
|
||||
}
|
||||
|
||||
response := contract.BuildSuccessResponse(summary)
|
||||
util.HandleResponse(c.Writer, c.Request, response, "InventoryHandler::GetInventoryReportSummary")
|
||||
}
|
||||
|
||||
func (h *InventoryHandler) GetInventoryReportDetails(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
filter := &models.InventoryReportFilter{}
|
||||
|
||||
if outletIDStr := c.Param("outlet_id"); outletIDStr != "" {
|
||||
outletID, err := uuid.Parse(outletIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("InventoryHandler::GetInventoryReportDetails -> Invalid outlet ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid outlet ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::GetInventoryReportDetails")
|
||||
return
|
||||
}
|
||||
filter.OutletID = &outletID
|
||||
} else {
|
||||
logger.FromContext(ctx).Error("InventoryHandler::GetInventoryReportDetails -> Missing outlet_id parameter")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "outlet_id is required")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::GetInventoryReportDetails")
|
||||
return
|
||||
}
|
||||
|
||||
if categoryIDStr := c.Query("category_id"); categoryIDStr != "" {
|
||||
categoryID, err := uuid.Parse(categoryIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("InventoryHandler::GetInventoryReportDetails -> Invalid category ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid category ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::GetInventoryReportDetails")
|
||||
return
|
||||
}
|
||||
filter.CategoryID = &categoryID
|
||||
}
|
||||
|
||||
// Parse show_low_stock (optional)
|
||||
if showLowStockStr := c.Query("show_low_stock"); showLowStockStr != "" {
|
||||
if showLowStock, err := strconv.ParseBool(showLowStockStr); err == nil {
|
||||
filter.ShowLowStock = &showLowStock
|
||||
}
|
||||
}
|
||||
|
||||
// Parse show_zero_stock (optional)
|
||||
if showZeroStockStr := c.Query("show_zero_stock"); showZeroStockStr != "" {
|
||||
if showZeroStock, err := strconv.ParseBool(showZeroStockStr); err == nil {
|
||||
filter.ShowZeroStock = &showZeroStock
|
||||
}
|
||||
}
|
||||
|
||||
// Parse search (optional)
|
||||
if search := c.Query("search"); search != "" {
|
||||
filter.Search = &search
|
||||
}
|
||||
|
||||
// Parse limit (optional)
|
||||
if limitStr := c.Query("limit"); limitStr != "" {
|
||||
if limit, err := strconv.Atoi(limitStr); err == nil && limit > 0 {
|
||||
filter.Limit = &limit
|
||||
}
|
||||
}
|
||||
|
||||
// Parse offset (optional)
|
||||
if offsetStr := c.Query("offset"); offsetStr != "" {
|
||||
if offset, err := strconv.Atoi(offsetStr); err == nil && offset >= 0 {
|
||||
filter.Offset = &offset
|
||||
}
|
||||
}
|
||||
|
||||
dateFromStr := c.Query("date_from")
|
||||
dateToStr := c.Query("date_to")
|
||||
|
||||
if fromTime, toTime, err := util.ParseDateRangeToJakartaTime(dateFromStr, dateToStr); err == nil {
|
||||
if fromTime != nil {
|
||||
filter.DateFrom = fromTime
|
||||
}
|
||||
if toTime != nil {
|
||||
filter.DateTo = toTime
|
||||
}
|
||||
}
|
||||
|
||||
report, err := h.inventoryService.GetInventoryReportDetails(ctx, filter, contextInfo.OrganizationID)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("InventoryHandler::GetInventoryReportDetails -> Failed to get inventory report details from service")
|
||||
responseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{responseError}), "InventoryHandler::GetInventoryReportDetails")
|
||||
return
|
||||
}
|
||||
|
||||
response := contract.BuildSuccessResponse(report)
|
||||
util.HandleResponse(c.Writer, c.Request, response, "InventoryHandler::GetInventoryReportDetails")
|
||||
}
|
||||
|
||||
@@ -122,6 +122,9 @@ func (h *OrderHandler) AddToOrder(c *gin.Context) {
|
||||
|
||||
func (h *OrderHandler) ListOrders(c *gin.Context) {
|
||||
var query contract.ListOrdersQuery
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_query_parameters", "OrderHandler::ListOrders", err.Error())}), "OrderHandler::ListOrders")
|
||||
return
|
||||
@@ -133,6 +136,7 @@ func (h *OrderHandler) ListOrders(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
modelReq.OrganizationID = &contextInfo.OrganizationID
|
||||
response, err := h.orderService.ListOrders(c.Request.Context(), modelReq)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "OrderHandler::ListOrders", err.Error())}), "OrderHandler::ListOrders")
|
||||
@@ -265,7 +269,6 @@ func (h *OrderHandler) SetOrderCustomer(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
// Parse order ID from URL parameter
|
||||
orderIDStr := c.Param("id")
|
||||
orderID, err := uuid.Parse(orderIDStr)
|
||||
if err != nil {
|
||||
@@ -273,24 +276,47 @@ func (h *OrderHandler) SetOrderCustomer(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
var req contract.SetOrderCustomerRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "OrderHandler::SetOrderCustomer", err.Error())}), "OrderHandler::SetOrderCustomer")
|
||||
return
|
||||
}
|
||||
|
||||
// Transform contract to model
|
||||
modelReq := transformer.SetOrderCustomerContractToModel(&req)
|
||||
|
||||
// Call service
|
||||
response, err := h.orderService.SetOrderCustomer(ctx, orderID, modelReq, contextInfo.OrganizationID)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "OrderHandler::SetOrderCustomer", err.Error())}), "OrderHandler::SetOrderCustomer")
|
||||
return
|
||||
}
|
||||
|
||||
// Transform model to contract
|
||||
contractResp := transformer.SetOrderCustomerModelToContract(response)
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "OrderHandler::SetOrderCustomer")
|
||||
}
|
||||
|
||||
func (h *OrderHandler) SplitBill(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
var req contract.SplitBillRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "OrderHandler::SplitBill", err.Error())}), "OrderHandler::SplitBill")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.validator.Validate(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("validation_failed", "OrderHandler::SplitBill", err.Error())}), "OrderHandler::SplitBill")
|
||||
return
|
||||
}
|
||||
|
||||
req.OrganizationID = contextInfo.OrganizationID
|
||||
modelReq := transformer.SplitBillContractToModel(&req)
|
||||
response, err := h.orderService.SplitBill(c.Request.Context(), modelReq)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "OrderHandler::SplitBill", err.Error())}), "OrderHandler::SplitBill")
|
||||
return
|
||||
}
|
||||
|
||||
contractResp := transformer.SplitBillModelToContract(response)
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "OrderHandler::SplitBill")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/contract"
|
||||
"apskel-pos-be/internal/util"
|
||||
"apskel-pos-be/internal/validator"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type OrderIngredientTransactionHandler struct {
|
||||
service OrderIngredientTransactionService
|
||||
validator validator.OrderIngredientTransactionValidator
|
||||
}
|
||||
|
||||
func NewOrderIngredientTransactionHandler(service OrderIngredientTransactionService, validator validator.OrderIngredientTransactionValidator) *OrderIngredientTransactionHandler {
|
||||
return &OrderIngredientTransactionHandler{
|
||||
service: service,
|
||||
validator: validator,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *OrderIngredientTransactionHandler) CreateOrderIngredientTransaction(c *gin.Context) {
|
||||
var req contract.CreateOrderIngredientTransactionRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.CreateOrderIngredientTransaction(c, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "OrderIngredientTransactionHandler")
|
||||
}
|
||||
|
||||
func (h *OrderIngredientTransactionHandler) GetOrderIngredientTransactionByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.GetOrderIngredientTransactionByID(c, id)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "OrderIngredientTransactionHandler")
|
||||
}
|
||||
|
||||
func (h *OrderIngredientTransactionHandler) UpdateOrderIngredientTransaction(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.UpdateOrderIngredientTransactionRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.UpdateOrderIngredientTransaction(c, id, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "OrderIngredientTransactionHandler")
|
||||
}
|
||||
|
||||
func (h *OrderIngredientTransactionHandler) DeleteOrderIngredientTransaction(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ID format"}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.DeleteOrderIngredientTransaction(c, id)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(gin.H{"message": "Order ingredient transaction deleted successfully"}), "OrderIngredientTransactionHandler")
|
||||
}
|
||||
|
||||
func (h *OrderIngredientTransactionHandler) ListOrderIngredientTransactions(c *gin.Context) {
|
||||
var req contract.ListOrderIngredientTransactionsRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, total, err := h.service.ListOrderIngredientTransactions(c, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(gin.H{
|
||||
"data": response,
|
||||
"total": total,
|
||||
"page": req.Page,
|
||||
"limit": req.Limit,
|
||||
}), "OrderIngredientTransactionHandler")
|
||||
}
|
||||
|
||||
func (h *OrderIngredientTransactionHandler) GetOrderIngredientTransactionsByOrder(c *gin.Context) {
|
||||
orderIDStr := c.Param("order_id")
|
||||
orderID, err := uuid.Parse(orderIDStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid order ID format"}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.GetOrderIngredientTransactionsByOrder(c, orderID)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "OrderIngredientTransactionHandler")
|
||||
}
|
||||
|
||||
func (h *OrderIngredientTransactionHandler) GetOrderIngredientTransactionsByOrderItem(c *gin.Context) {
|
||||
orderItemIDStr := c.Param("order_item_id")
|
||||
orderItemID, err := uuid.Parse(orderItemIDStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid order item ID format"}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.GetOrderIngredientTransactionsByOrderItem(c, orderItemID)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "OrderIngredientTransactionHandler")
|
||||
}
|
||||
|
||||
func (h *OrderIngredientTransactionHandler) GetOrderIngredientTransactionsByIngredient(c *gin.Context) {
|
||||
ingredientIDStr := c.Param("ingredient_id")
|
||||
ingredientID, err := uuid.Parse(ingredientIDStr)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: "Invalid ingredient ID format"}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.GetOrderIngredientTransactionsByIngredient(c, ingredientID)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "OrderIngredientTransactionHandler")
|
||||
}
|
||||
|
||||
func (h *OrderIngredientTransactionHandler) GetOrderIngredientTransactionSummary(c *gin.Context) {
|
||||
var req contract.ListOrderIngredientTransactionsRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.GetOrderIngredientTransactionSummary(c, &req)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "OrderIngredientTransactionHandler")
|
||||
}
|
||||
|
||||
func (h *OrderIngredientTransactionHandler) BulkCreateOrderIngredientTransactions(c *gin.Context) {
|
||||
var req struct {
|
||||
Transactions []*contract.CreateOrderIngredientTransactionRequest `json:"transactions" validate:"required,min=1"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.service.BulkCreateOrderIngredientTransactions(c, req.Transactions)
|
||||
if err != nil {
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{{Cause: err.Error()}}), "OrderIngredientTransactionHandler")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "OrderIngredientTransactionHandler")
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/contract"
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type OrderIngredientTransactionService interface {
|
||||
CreateOrderIngredientTransaction(ctx context.Context, req *contract.CreateOrderIngredientTransactionRequest) (*contract.OrderIngredientTransactionResponse, error)
|
||||
GetOrderIngredientTransactionByID(ctx context.Context, id uuid.UUID) (*contract.OrderIngredientTransactionResponse, error)
|
||||
UpdateOrderIngredientTransaction(ctx context.Context, id uuid.UUID, req *contract.UpdateOrderIngredientTransactionRequest) (*contract.OrderIngredientTransactionResponse, error)
|
||||
DeleteOrderIngredientTransaction(ctx context.Context, id uuid.UUID) error
|
||||
ListOrderIngredientTransactions(ctx context.Context, req *contract.ListOrderIngredientTransactionsRequest) ([]*contract.OrderIngredientTransactionResponse, int64, error)
|
||||
GetOrderIngredientTransactionsByOrder(ctx context.Context, orderID uuid.UUID) ([]*contract.OrderIngredientTransactionResponse, error)
|
||||
GetOrderIngredientTransactionsByOrderItem(ctx context.Context, orderItemID uuid.UUID) ([]*contract.OrderIngredientTransactionResponse, error)
|
||||
GetOrderIngredientTransactionsByIngredient(ctx context.Context, ingredientID uuid.UUID) ([]*contract.OrderIngredientTransactionResponse, error)
|
||||
GetOrderIngredientTransactionSummary(ctx context.Context, req *contract.ListOrderIngredientTransactionsRequest) ([]*contract.OrderIngredientTransactionSummary, error)
|
||||
BulkCreateOrderIngredientTransactions(ctx context.Context, transactions []*contract.CreateOrderIngredientTransactionRequest) ([]*contract.OrderIngredientTransactionResponse, error)
|
||||
}
|
||||
@@ -36,7 +36,6 @@ func (h *OutletHandler) ListOutlets(c *gin.Context) {
|
||||
OrganizationID: contextInfo.OrganizationID,
|
||||
}
|
||||
|
||||
// Parse query parameters
|
||||
if pageStr := c.Query("page"); pageStr != "" {
|
||||
if page, err := strconv.Atoi(pageStr); err == nil {
|
||||
req.Page = page
|
||||
@@ -103,6 +102,37 @@ func (h *OutletHandler) GetOutlet(c *gin.Context) {
|
||||
util.HandleResponse(c.Writer, c.Request, outletResponse, "OutletHandler::GetOutlet")
|
||||
}
|
||||
|
||||
func (h *OutletHandler) CreateOutlet(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
var req contract.CreateOutletRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("OutletHandler::CreateOutlet -> Failed to bind JSON")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid request body")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OutletHandler::CreateOutlet")
|
||||
return
|
||||
}
|
||||
|
||||
req.OrganizationID = contextInfo.OrganizationID
|
||||
|
||||
validationError, validationErrorCode := h.outletValidator.ValidateCreateOutletRequest(&req)
|
||||
if validationError != nil {
|
||||
logger.FromContext(ctx).WithError(validationError).Error("OutletHandler::CreateOutlet -> request validation failed")
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OutletHandler::CreateOutlet")
|
||||
return
|
||||
}
|
||||
|
||||
outletResponse := h.outletService.CreateOutlet(ctx, &req)
|
||||
if outletResponse.HasErrors() {
|
||||
errorResp := outletResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("OutletHandler::CreateOutlet -> Failed to create outlet from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, outletResponse, "OutletHandler::CreateOutlet")
|
||||
}
|
||||
|
||||
func (h *OutletHandler) UpdateOutlet(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
@@ -51,7 +51,7 @@ func (h *PaymentMethodHandler) CreatePaymentMethod(c *gin.Context) {
|
||||
|
||||
req.OrganizationID = contextInfo.OrganizationID
|
||||
req.OutletID = contextInfo.OutletID
|
||||
|
||||
|
||||
paymentMethodResponse := h.paymentMethodService.CreatePaymentMethod(ctx, contextInfo, &req)
|
||||
if paymentMethodResponse.HasErrors() {
|
||||
errorResp := paymentMethodResponse.GetErrors()[0]
|
||||
@@ -84,13 +84,13 @@ func (h *PaymentMethodHandler) GetPaymentMethod(c *gin.Context) {
|
||||
|
||||
func (h *PaymentMethodHandler) ListPaymentMethods(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
req := &contract.ListPaymentMethodsRequest{
|
||||
Page: 1,
|
||||
Limit: 10,
|
||||
}
|
||||
|
||||
// Parse query parameters
|
||||
if pageStr := c.Query("page"); pageStr != "" {
|
||||
if page, err := strconv.Atoi(pageStr); err == nil {
|
||||
req.Page = page
|
||||
@@ -111,11 +111,7 @@ func (h *PaymentMethodHandler) ListPaymentMethods(c *gin.Context) {
|
||||
req.Type = &paymentMethodType
|
||||
}
|
||||
|
||||
if organizationIDStr := c.Query("organization_id"); organizationIDStr != "" {
|
||||
if organizationID, err := uuid.Parse(organizationIDStr); err == nil {
|
||||
req.OrganizationID = &organizationID
|
||||
}
|
||||
}
|
||||
req.OrganizationID = &contextInfo.OrganizationID
|
||||
|
||||
if isActiveStr := c.Query("is_active"); isActiveStr != "" {
|
||||
if isActive, err := strconv.ParseBool(isActiveStr); err == nil {
|
||||
|
||||
@@ -138,13 +138,14 @@ func (h *ProductHandler) GetProduct(c *gin.Context) {
|
||||
|
||||
func (h *ProductHandler) ListProducts(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
req := &contract.ListProductsRequest{
|
||||
Page: 1,
|
||||
Limit: 10,
|
||||
Page: 1,
|
||||
Limit: 10,
|
||||
OrganizationID: &contextInfo.OrganizationID,
|
||||
}
|
||||
|
||||
// Parse query parameters
|
||||
if pageStr := c.Query("page"); pageStr != "" {
|
||||
if page, err := strconv.Atoi(pageStr); err == nil {
|
||||
req.Page = page
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/appcontext"
|
||||
"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"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ProductRecipeHandler struct {
|
||||
productRecipeService service.ProductRecipeService
|
||||
}
|
||||
|
||||
func NewProductRecipeHandler(productRecipeService service.ProductRecipeService) *ProductRecipeHandler {
|
||||
return &ProductRecipeHandler{
|
||||
productRecipeService: productRecipeService,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ProductRecipeHandler) Create(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
var request contract.CreateProductRecipeRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Create -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Create")
|
||||
return
|
||||
}
|
||||
|
||||
recipeResponse, err := h.productRecipeService.Create(ctx, contextInfo.OrganizationID, &request)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Create -> Failed to create product recipe")
|
||||
validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Create")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(recipeResponse), "ProductRecipeHandler::Create")
|
||||
}
|
||||
|
||||
func (h *ProductRecipeHandler) GetByID(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByID -> Invalid recipe ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid recipe ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByID")
|
||||
return
|
||||
}
|
||||
|
||||
recipeResponse, err := h.productRecipeService.GetByID(ctx, id, contextInfo.OrganizationID)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByID -> Failed to get product recipe")
|
||||
validationResponseError := contract.NewResponseError(constants.NotFoundErrorCode, constants.RequestEntity, "Product recipe not found")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByID")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(recipeResponse), "ProductRecipeHandler::GetByID")
|
||||
}
|
||||
|
||||
func (h *ProductRecipeHandler) GetByProductID(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
// Parse product ID from URL parameter
|
||||
productIDStr := c.Param("product_id")
|
||||
productID, err := uuid.Parse(productIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByProductID -> Invalid product ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid product ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByProductID")
|
||||
return
|
||||
}
|
||||
|
||||
// Parse optional variant ID from query parameter
|
||||
var variantID *uuid.UUID
|
||||
if variantIDStr := c.Query("variant_id"); variantIDStr != "" {
|
||||
parsed, err := uuid.Parse(variantIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByProductID -> Invalid variant ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid variant ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByProductID")
|
||||
return
|
||||
}
|
||||
variantID = &parsed
|
||||
}
|
||||
|
||||
// Create request object
|
||||
request := &contract.GetProductRecipeByProductIDRequest{
|
||||
ProductID: productID,
|
||||
VariantID: variantID,
|
||||
}
|
||||
|
||||
// Call service
|
||||
recipes, err := h.productRecipeService.GetByProductID(ctx, request, contextInfo.OrganizationID)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByProductID -> Failed to get product recipes")
|
||||
validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByProductID")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(recipes), "ProductRecipeHandler::GetByProductID")
|
||||
}
|
||||
|
||||
func (h *ProductRecipeHandler) GetByIngredientID(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
ingredientIDStr := c.Param("ingredient_id")
|
||||
ingredientID, err := uuid.Parse(ingredientIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByIngredientID -> Invalid ingredient ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByIngredientID")
|
||||
return
|
||||
}
|
||||
|
||||
recipes, err := h.productRecipeService.GetByIngredientID(ctx, ingredientID, contextInfo.OrganizationID)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByIngredientID -> Failed to get product recipes")
|
||||
validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByIngredientID")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(recipes), "ProductRecipeHandler::GetByIngredientID")
|
||||
}
|
||||
|
||||
func (h *ProductRecipeHandler) Update(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Update -> Invalid recipe ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid recipe ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Update")
|
||||
return
|
||||
}
|
||||
|
||||
var request contract.UpdateProductRecipeRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Update -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Update")
|
||||
return
|
||||
}
|
||||
|
||||
recipeResponse, err := h.productRecipeService.Update(ctx, id, contextInfo.OrganizationID, &request)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Update -> Failed to update product recipe")
|
||||
validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Update")
|
||||
return
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(recipeResponse), "ProductRecipeHandler::Update")
|
||||
}
|
||||
|
||||
func (h *ProductRecipeHandler) Delete(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
idStr := c.Param("id")
|
||||
id, err := uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Delete -> Invalid recipe ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid recipe ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Delete")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.productRecipeService.Delete(ctx, id, contextInfo.OrganizationID)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Delete -> Failed to delete product recipe")
|
||||
validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Delete")
|
||||
return
|
||||
}
|
||||
|
||||
response := map[string]interface{}{
|
||||
"message": "Product recipe deleted successfully",
|
||||
}
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "ProductRecipeHandler::Delete")
|
||||
}
|
||||
|
||||
func (h *ProductRecipeHandler) BulkCreate(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
var request contract.BulkCreateProductRecipeRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::BulkCreate -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::BulkCreate")
|
||||
return
|
||||
}
|
||||
|
||||
recipes, err := h.productRecipeService.BulkCreate(ctx, contextInfo.OrganizationID, &request)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::BulkCreate -> Failed to bulk create product recipes")
|
||||
validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::BulkCreate")
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, contract.BuildSuccessResponse(recipes))
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"apskel-pos-be/internal/appcontext"
|
||||
"apskel-pos-be/internal/util"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"apskel-pos-be/internal/constants"
|
||||
"apskel-pos-be/internal/contract"
|
||||
"apskel-pos-be/internal/logger"
|
||||
"apskel-pos-be/internal/service"
|
||||
"apskel-pos-be/internal/validator"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type PurchaseOrderHandler struct {
|
||||
purchaseOrderService service.PurchaseOrderService
|
||||
purchaseOrderValidator validator.PurchaseOrderValidator
|
||||
}
|
||||
|
||||
func NewPurchaseOrderHandler(
|
||||
purchaseOrderService service.PurchaseOrderService,
|
||||
purchaseOrderValidator validator.PurchaseOrderValidator,
|
||||
) *PurchaseOrderHandler {
|
||||
return &PurchaseOrderHandler{
|
||||
purchaseOrderService: purchaseOrderService,
|
||||
purchaseOrderValidator: purchaseOrderValidator,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *PurchaseOrderHandler) CreatePurchaseOrder(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
var req contract.CreatePurchaseOrderRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(c.Request.Context()).WithError(err).Error("PurchaseOrderHandler::CreatePurchaseOrder -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PurchaseOrderHandler::CreatePurchaseOrder")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.purchaseOrderValidator.ValidateCreatePurchaseOrderRequest(&req)
|
||||
if validationError != nil {
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PurchaseOrderHandler::CreatePurchaseOrder")
|
||||
return
|
||||
}
|
||||
|
||||
poResponse := h.purchaseOrderService.CreatePurchaseOrder(ctx, contextInfo, &req)
|
||||
if poResponse.HasErrors() {
|
||||
errorResp := poResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("PurchaseOrderHandler::CreatePurchaseOrder -> Failed to create purchase order from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, poResponse, "PurchaseOrderHandler::CreatePurchaseOrder")
|
||||
}
|
||||
|
||||
func (h *PurchaseOrderHandler) UpdatePurchaseOrder(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
poIDStr := c.Param("id")
|
||||
poID, err := uuid.Parse(poIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("PurchaseOrderHandler::UpdatePurchaseOrder -> Invalid purchase order ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid purchase order ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PurchaseOrderHandler::UpdatePurchaseOrder")
|
||||
return
|
||||
}
|
||||
|
||||
var req contract.UpdatePurchaseOrderRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("PurchaseOrderHandler::UpdatePurchaseOrder -> request binding failed")
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PurchaseOrderHandler::UpdatePurchaseOrder")
|
||||
return
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.purchaseOrderValidator.ValidateUpdatePurchaseOrderRequest(&req)
|
||||
if validationError != nil {
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PurchaseOrderHandler::UpdatePurchaseOrder")
|
||||
return
|
||||
}
|
||||
|
||||
poResponse := h.purchaseOrderService.UpdatePurchaseOrder(ctx, contextInfo, poID, &req)
|
||||
if poResponse.HasErrors() {
|
||||
errorResp := poResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("PurchaseOrderHandler::UpdatePurchaseOrder -> Failed to update purchase order from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, poResponse, "PurchaseOrderHandler::UpdatePurchaseOrder")
|
||||
}
|
||||
|
||||
func (h *PurchaseOrderHandler) DeletePurchaseOrder(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
poIDStr := c.Param("id")
|
||||
poID, err := uuid.Parse(poIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("PurchaseOrderHandler::DeletePurchaseOrder -> Invalid purchase order ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid purchase order ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PurchaseOrderHandler::DeletePurchaseOrder")
|
||||
return
|
||||
}
|
||||
|
||||
poResponse := h.purchaseOrderService.DeletePurchaseOrder(ctx, contextInfo, poID)
|
||||
if poResponse.HasErrors() {
|
||||
errorResp := poResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("PurchaseOrderHandler::DeletePurchaseOrder -> Failed to delete purchase order from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, poResponse, "PurchaseOrderHandler::DeletePurchaseOrder")
|
||||
}
|
||||
|
||||
func (h *PurchaseOrderHandler) GetPurchaseOrder(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
poIDStr := c.Param("id")
|
||||
poID, err := uuid.Parse(poIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("PurchaseOrderHandler::GetPurchaseOrder -> Invalid purchase order ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid purchase order ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PurchaseOrderHandler::GetPurchaseOrder")
|
||||
return
|
||||
}
|
||||
|
||||
poResponse := h.purchaseOrderService.GetPurchaseOrderByID(ctx, contextInfo, poID)
|
||||
if poResponse.HasErrors() {
|
||||
errorResp := poResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("PurchaseOrderHandler::GetPurchaseOrder -> Failed to get purchase order from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, poResponse, "PurchaseOrderHandler::GetPurchaseOrder")
|
||||
}
|
||||
|
||||
func (h *PurchaseOrderHandler) ListPurchaseOrders(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
req := &contract.ListPurchaseOrdersRequest{
|
||||
Page: 1,
|
||||
Limit: 10,
|
||||
}
|
||||
|
||||
// Parse query parameters
|
||||
if pageStr := c.Query("page"); pageStr != "" {
|
||||
if page, err := strconv.Atoi(pageStr); err == nil {
|
||||
req.Page = page
|
||||
}
|
||||
}
|
||||
|
||||
if limitStr := c.Query("limit"); limitStr != "" {
|
||||
if limit, err := strconv.Atoi(limitStr); err == nil {
|
||||
req.Limit = limit
|
||||
}
|
||||
}
|
||||
|
||||
if search := c.Query("search"); search != "" {
|
||||
req.Search = search
|
||||
}
|
||||
|
||||
if status := c.Query("status"); status != "" {
|
||||
req.Status = status
|
||||
}
|
||||
|
||||
if vendorIDStr := c.Query("vendor_id"); vendorIDStr != "" {
|
||||
if vendorID, err := uuid.Parse(vendorIDStr); err == nil {
|
||||
req.VendorID = &vendorID
|
||||
}
|
||||
}
|
||||
|
||||
if startDateStr := c.Query("start_date"); startDateStr != "" {
|
||||
if startDate, err := time.Parse("2006-01-02", startDateStr); err == nil {
|
||||
req.StartDate = &startDate
|
||||
}
|
||||
}
|
||||
|
||||
if endDateStr := c.Query("end_date"); endDateStr != "" {
|
||||
if endDate, err := time.Parse("2006-01-02", endDateStr); err == nil {
|
||||
req.EndDate = &endDate
|
||||
}
|
||||
}
|
||||
|
||||
validationError, validationErrorCode := h.purchaseOrderValidator.ValidateListPurchaseOrdersRequest(req)
|
||||
if validationError != nil {
|
||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PurchaseOrderHandler::ListPurchaseOrders")
|
||||
return
|
||||
}
|
||||
|
||||
poResponse := h.purchaseOrderService.ListPurchaseOrders(ctx, contextInfo, req)
|
||||
if poResponse.HasErrors() {
|
||||
errorResp := poResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("PurchaseOrderHandler::ListPurchaseOrders -> Failed to list purchase orders from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, poResponse, "PurchaseOrderHandler::ListPurchaseOrders")
|
||||
}
|
||||
|
||||
func (h *PurchaseOrderHandler) GetPurchaseOrdersByStatus(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
status := c.Param("status")
|
||||
if status == "" {
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Status parameter is required")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PurchaseOrderHandler::GetPurchaseOrdersByStatus")
|
||||
return
|
||||
}
|
||||
|
||||
poResponse := h.purchaseOrderService.GetPurchaseOrdersByStatus(ctx, contextInfo, status)
|
||||
if poResponse.HasErrors() {
|
||||
errorResp := poResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("PurchaseOrderHandler::GetPurchaseOrdersByStatus -> Failed to get purchase orders by status from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, poResponse, "PurchaseOrderHandler::GetPurchaseOrdersByStatus")
|
||||
}
|
||||
|
||||
func (h *PurchaseOrderHandler) GetOverduePurchaseOrders(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
poResponse := h.purchaseOrderService.GetOverduePurchaseOrders(ctx, contextInfo)
|
||||
if poResponse.HasErrors() {
|
||||
errorResp := poResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("PurchaseOrderHandler::GetOverduePurchaseOrders -> Failed to get overdue purchase orders from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, poResponse, "PurchaseOrderHandler::GetOverduePurchaseOrders")
|
||||
}
|
||||
|
||||
func (h *PurchaseOrderHandler) UpdatePurchaseOrderStatus(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
poIDStr := c.Param("id")
|
||||
poID, err := uuid.Parse(poIDStr)
|
||||
if err != nil {
|
||||
logger.FromContext(ctx).WithError(err).Error("PurchaseOrderHandler::UpdatePurchaseOrderStatus -> Invalid purchase order ID")
|
||||
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid purchase order ID")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PurchaseOrderHandler::UpdatePurchaseOrderStatus")
|
||||
return
|
||||
}
|
||||
|
||||
status := c.Param("status")
|
||||
if status == "" {
|
||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Status parameter is required")
|
||||
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PurchaseOrderHandler::UpdatePurchaseOrderStatus")
|
||||
return
|
||||
}
|
||||
|
||||
poResponse := h.purchaseOrderService.UpdatePurchaseOrderStatus(ctx, contextInfo, poID, status)
|
||||
if poResponse.HasErrors() {
|
||||
errorResp := poResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("PurchaseOrderHandler::UpdatePurchaseOrderStatus -> Failed to update purchase order status from service")
|
||||
}
|
||||
|
||||
util.HandleResponse(c.Writer, c.Request, poResponse, "PurchaseOrderHandler::UpdatePurchaseOrderStatus")
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user