EnakGame phases 1-8 of docs/tasks-enakgame.md (EG-101 to EG-803), built on the existing EnakPoint/EnakCoin wallet (docs/rfc-enakgame.md). Foundation (phase 1) - Migrations 000103-000106: games extended with organization, slug, status, entry cost and result rules, old games archived (not deleted); budgets, versioned reward configs, sessions and session rewards; the ledger types GAME_SPEND_REFUND, GAME_REWARD and REWARD_REDEEM_REFUND; audit_logs. - AuditLogger writes in the caller's transaction only. - enakgame.limit.user_daily and global_daily organization settings. Games and sessions (phases 2-4) - Admin /marketing/enakgame: games, reward config versions (immutable but for status, one ACTIVE per game), budgets with non-overlapping global periods and a daily job opening the next month. - Customer /customer/enakgame: start (Idempotency-Key, entry cost and config frozen on the session), complete (result validation, reward engine, max_reward cap, daily limits via game_reward_counters, one GAME_REWARD per budget), automatic refunds for system errors and deactivated games, and a session job. - Reward engine: FIXED, SCORE_BASED, OUTCOME_BASED, PROBABILITY (crypto/rand), rounded down. Vouchers and budgets (phases 5-6) - Migration 000108 and 000107: vouchers, codes, redemptions, cost attribution; Economy Guard counters. - STATIC and CODE_POOL redemption in one transaction with the REDEEM PIN action; realized cost traced through the lots to the budget that paid the reward. - Budget metrics: realized cost, forecast, exposure and status. Migrations 000109-000110 add the wallet_lots indexes they need, built CONCURRENTLY. Events (phase 7) - Migration 000111: game events, each with its own EVENT budget. Event extras stack per PRD §16 defaults, with event and per-customer limits. External vouchers (phase 8) - VoucherProvider contract, two-step PENDING redemption and a recovery job, tested with a fake provider. No provider adapter is registered yet, so EXTERNAL vouchers stay out of the catalog. Not yet decided before release: reward rounding, event stacking, budget exhaustion policy and thresholds (RFC §19.2). Migrations 000103-000111 have not been run on any shared database. Also fixes a leftover PAYMENT filter in a wallet test and a data race in a test PIN fake. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
760 lines
44 KiB
Go
760 lines
44 KiB
Go
package router
|
|
|
|
import (
|
|
"apskel-pos-be/config"
|
|
"apskel-pos-be/internal/handler"
|
|
"apskel-pos-be/internal/middleware"
|
|
"apskel-pos-be/internal/service"
|
|
"apskel-pos-be/internal/transformer"
|
|
"apskel-pos-be/internal/validator"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
type Router struct {
|
|
config *config.Config
|
|
healthHandler *handler.HealthHandler
|
|
authHandler *handler.AuthHandler
|
|
userHandler *handler.UserHandler
|
|
organizationHandler *handler.OrganizationHandler
|
|
outletHandler *handler.OutletHandler
|
|
outletSettingHandler *handler.OutletSettingHandlerImpl
|
|
categoryHandler *handler.CategoryHandler
|
|
productHandler *handler.ProductHandler
|
|
productVariantHandler *handler.ProductVariantHandler
|
|
inventoryHandler *handler.InventoryHandler
|
|
orderHandler *handler.OrderHandler
|
|
fileHandler *handler.FileHandler
|
|
customerHandler *handler.CustomerHandler
|
|
paymentMethodHandler *handler.PaymentMethodHandler
|
|
analyticsHandler *handler.AnalyticsHandler
|
|
reportHandler *handler.ReportHandler
|
|
tableHandler *handler.TableHandler
|
|
unitHandler *handler.UnitHandler
|
|
ingredientHandler *handler.IngredientHandler
|
|
productRecipeHandler *handler.ProductRecipeHandler
|
|
vendorHandler *handler.VendorHandler
|
|
purchaseOrderHandler *handler.PurchaseOrderHandler
|
|
purchaseCategoryHandler *handler.PurchaseCategoryHandler
|
|
unitConverterHandler *handler.IngredientUnitConverterHandler
|
|
chartOfAccountTypeHandler *handler.ChartOfAccountTypeHandler
|
|
chartOfAccountHandler *handler.ChartOfAccountHandler
|
|
accountHandler *handler.AccountHandler
|
|
orderIngredientTransactionHandler *handler.OrderIngredientTransactionHandler
|
|
gamificationHandler *handler.GamificationHandler
|
|
rewardHandler *handler.RewardHandler
|
|
campaignHandler *handler.CampaignHandler
|
|
customerAuthHandler *handler.CustomerAuthHandler
|
|
customerPointsHandler *handler.CustomerPointsHandler
|
|
spinGameHandler *handler.SpinGameHandler
|
|
userDeviceHandler *handler.UserDeviceHandler
|
|
notificationHandler *handler.NotificationHandler
|
|
selfOrderHandler *handler.SelfOrderHandler
|
|
productOutletPriceHandler *handler.ProductOutletPriceHandler
|
|
expenseHandler *handler.ExpenseHandler
|
|
cashAdvanceHandler *handler.CashAdvanceHandler
|
|
walletAdminHandler *handler.WalletAdminHandler
|
|
loyaltySettingsHandler *handler.LoyaltySettingsHandler
|
|
customerPinHandler *handler.CustomerPinHandler
|
|
customerWalletHandler *handler.CustomerWalletHandler
|
|
customerDeviceHandler *handler.CustomerDeviceHandler
|
|
customerOutletHandler *handler.CustomerOutletHandler
|
|
customerOrderHandler *handler.CustomerOrderHandler
|
|
enakGameAdminHandler *handler.EnakGameAdminHandler
|
|
enakGameCustomerHandler *handler.EnakGameCustomerHandler
|
|
authMiddleware *middleware.AuthMiddleware
|
|
customerAuthMiddleware *middleware.CustomerAuthMiddleware
|
|
redisClient *redis.Client
|
|
}
|
|
|
|
func NewRouter(cfg *config.Config, healthHandler *handler.HealthHandler, authService service.AuthService, authMiddleware *middleware.AuthMiddleware, userService *service.UserServiceImpl, userValidator *validator.UserValidatorImpl, organizationService service.OrganizationService, organizationValidator validator.OrganizationValidator, outletService service.OutletService, outletValidator validator.OutletValidator, outletSettingService service.OutletSettingService, categoryService service.CategoryService, categoryValidator validator.CategoryValidator, productService service.ProductService, productValidator validator.ProductValidator, productVariantService service.ProductVariantService, productVariantValidator validator.ProductVariantValidator, inventoryService service.InventoryService, inventoryValidator validator.InventoryValidator, orderService service.OrderService, orderValidator validator.OrderValidator, fileService service.FileService, fileValidator validator.FileValidator, customerService service.CustomerService, customerValidator validator.CustomerValidator, paymentMethodService service.PaymentMethodService, paymentMethodValidator validator.PaymentMethodValidator, analyticsService *service.AnalyticsServiceImpl, reportService service.ReportService, tableService *service.TableServiceImpl, tableValidator *validator.TableValidator, unitService handler.UnitService, ingredientService handler.IngredientService, productRecipeService service.ProductRecipeService, vendorService service.VendorService, vendorValidator validator.VendorValidator, purchaseOrderService service.PurchaseOrderService, purchaseOrderValidator validator.PurchaseOrderValidator, purchaseCategoryService service.PurchaseCategoryService, purchaseCategoryValidator validator.PurchaseCategoryValidator, unitConverterService service.IngredientUnitConverterService, unitConverterValidator validator.IngredientUnitConverterValidator, chartOfAccountTypeService service.ChartOfAccountTypeService, chartOfAccountTypeValidator validator.ChartOfAccountTypeValidator, chartOfAccountService service.ChartOfAccountService, chartOfAccountValidator validator.ChartOfAccountValidator, accountService service.AccountService, accountValidator validator.AccountValidator, orderIngredientTransactionService service.OrderIngredientTransactionService, orderIngredientTransactionValidator validator.OrderIngredientTransactionValidator, gamificationService service.GamificationService, gamificationValidator validator.GamificationValidator, rewardService service.RewardService, rewardValidator validator.RewardValidator, campaignService service.CampaignService, campaignValidator validator.CampaignValidator, customerAuthService service.CustomerAuthService, customerAuthValidator validator.CustomerAuthValidator, customerPointsService service.CustomerPointsService, spinGameService service.SpinGameService, customerAuthMiddleware *middleware.CustomerAuthMiddleware, userDeviceService service.UserDeviceService, userDeviceValidator validator.UserDeviceValidator, notificationService service.NotificationService, notificationValidator validator.NotificationValidator, productOutletPriceService service.ProductOutletPriceService, productOutletPriceValidator validator.ProductOutletPriceValidator, selfOrderHandler *handler.SelfOrderHandler, expenseService *service.ExpenseServiceImpl, expenseValidator *validator.ExpenseValidatorImpl, cashAdvanceService service.CashAdvanceService, cashAdvanceValidator validator.CashAdvanceValidator, walletAdminService service.WalletAdminService, walletValidator validator.WalletValidator, loyaltySettingsService service.LoyaltySettingsService, customerPinService service.CustomerPinService, customerWalletService service.CustomerWalletService, customerDeviceService service.CustomerDeviceService, customerOutletService service.CustomerOutletService, customerOrderService service.CustomerOrderService, enakGameAdminService service.EnakGameAdminService, enakGameCustomerService service.EnakGameCustomerService, redisClient *redis.Client) *Router {
|
|
|
|
return &Router{
|
|
config: cfg,
|
|
healthHandler: healthHandler,
|
|
authHandler: handler.NewAuthHandler(authService),
|
|
userHandler: handler.NewUserHandler(userService, userValidator),
|
|
organizationHandler: handler.NewOrganizationHandler(organizationService, organizationValidator),
|
|
outletHandler: handler.NewOutletHandler(outletService, outletValidator),
|
|
outletSettingHandler: handler.NewOutletSettingHandlerImpl(outletSettingService),
|
|
categoryHandler: handler.NewCategoryHandler(categoryService, categoryValidator),
|
|
productHandler: handler.NewProductHandler(productService, productValidator),
|
|
inventoryHandler: handler.NewInventoryHandler(inventoryService, inventoryValidator),
|
|
orderHandler: handler.NewOrderHandler(orderService, orderValidator, transformer.NewTransformer()),
|
|
fileHandler: handler.NewFileHandler(fileService, fileValidator, transformer.NewTransformer()),
|
|
customerHandler: handler.NewCustomerHandler(customerService, customerValidator),
|
|
paymentMethodHandler: handler.NewPaymentMethodHandler(paymentMethodService, paymentMethodValidator),
|
|
analyticsHandler: handler.NewAnalyticsHandler(analyticsService, transformer.NewTransformer()),
|
|
reportHandler: handler.NewReportHandler(reportService, userService),
|
|
tableHandler: handler.NewTableHandler(tableService, tableValidator, cfg.Server.SelfOrderUrl),
|
|
unitHandler: handler.NewUnitHandler(unitService),
|
|
ingredientHandler: handler.NewIngredientHandler(ingredientService),
|
|
productRecipeHandler: handler.NewProductRecipeHandler(productRecipeService),
|
|
vendorHandler: handler.NewVendorHandler(vendorService, vendorValidator),
|
|
purchaseOrderHandler: handler.NewPurchaseOrderHandler(purchaseOrderService, purchaseOrderValidator),
|
|
purchaseCategoryHandler: handler.NewPurchaseCategoryHandler(purchaseCategoryService, purchaseCategoryValidator),
|
|
unitConverterHandler: handler.NewIngredientUnitConverterHandler(unitConverterService, unitConverterValidator),
|
|
chartOfAccountTypeHandler: handler.NewChartOfAccountTypeHandler(chartOfAccountTypeService, chartOfAccountTypeValidator),
|
|
chartOfAccountHandler: handler.NewChartOfAccountHandler(chartOfAccountService, chartOfAccountValidator),
|
|
accountHandler: handler.NewAccountHandler(accountService, accountValidator),
|
|
orderIngredientTransactionHandler: handler.NewOrderIngredientTransactionHandler(&orderIngredientTransactionService, orderIngredientTransactionValidator),
|
|
gamificationHandler: handler.NewGamificationHandler(gamificationService, gamificationValidator),
|
|
rewardHandler: handler.NewRewardHandler(rewardService, rewardValidator),
|
|
campaignHandler: handler.NewCampaignHandler(campaignService, campaignValidator),
|
|
customerAuthHandler: handler.NewCustomerAuthHandler(customerAuthService, customerAuthValidator),
|
|
customerPointsHandler: handler.NewCustomerPointsHandler(customerPointsService),
|
|
spinGameHandler: handler.NewSpinGameHandler(spinGameService),
|
|
authMiddleware: authMiddleware,
|
|
customerAuthMiddleware: customerAuthMiddleware,
|
|
productVariantHandler: handler.NewProductVariantHandler(productVariantService, productVariantValidator),
|
|
userDeviceHandler: handler.NewUserDeviceHandler(userDeviceService, userDeviceValidator),
|
|
notificationHandler: handler.NewNotificationHandler(notificationService, notificationValidator),
|
|
selfOrderHandler: selfOrderHandler,
|
|
productOutletPriceHandler: handler.NewProductOutletPriceHandler(productOutletPriceService, productOutletPriceValidator),
|
|
expenseHandler: handler.NewExpenseHandler(expenseService, expenseValidator),
|
|
cashAdvanceHandler: handler.NewCashAdvanceHandler(cashAdvanceService, cashAdvanceValidator),
|
|
walletAdminHandler: handler.NewWalletAdminHandler(walletAdminService, walletValidator),
|
|
loyaltySettingsHandler: handler.NewLoyaltySettingsHandler(loyaltySettingsService),
|
|
customerPinHandler: handler.NewCustomerPinHandler(customerPinService),
|
|
customerWalletHandler: handler.NewCustomerWalletHandler(customerWalletService),
|
|
customerDeviceHandler: handler.NewCustomerDeviceHandler(customerDeviceService),
|
|
customerOutletHandler: handler.NewCustomerOutletHandler(customerOutletService),
|
|
customerOrderHandler: handler.NewCustomerOrderHandler(customerOrderService),
|
|
enakGameAdminHandler: handler.NewEnakGameAdminHandler(enakGameAdminService),
|
|
enakGameCustomerHandler: handler.NewEnakGameCustomerHandler(enakGameCustomerService),
|
|
redisClient: redisClient,
|
|
}
|
|
}
|
|
|
|
func (r *Router) Init() *gin.Engine {
|
|
gin.SetMode(gin.ReleaseMode)
|
|
engine := gin.New()
|
|
engine.Use(
|
|
middleware.JsonAPI(),
|
|
middleware.CORS(),
|
|
middleware.CorrelationID(),
|
|
middleware.Recover(),
|
|
middleware.HTTPStatLogger(),
|
|
middleware.PopulateContext(),
|
|
)
|
|
|
|
r.addAppRoutes(engine)
|
|
return engine
|
|
}
|
|
|
|
func (r *Router) addAppRoutes(rg *gin.Engine) {
|
|
rg.GET("/health", r.healthHandler.HealthCheck)
|
|
|
|
v1 := rg.Group("/api/v1")
|
|
{
|
|
auth := v1.Group("/auth")
|
|
{
|
|
auth.POST("/login", r.authHandler.Login)
|
|
auth.POST("/logout", r.authHandler.Logout)
|
|
auth.POST("/refresh", r.authHandler.RefreshToken)
|
|
auth.GET("/validate", r.authHandler.ValidateToken)
|
|
auth.GET("/profile", r.authHandler.GetProfile)
|
|
}
|
|
|
|
// Customer authentication routes
|
|
customerAuth := v1.Group("/customer-auth")
|
|
{
|
|
customerAuth.POST("/check-phone", r.customerAuthHandler.CheckPhone)
|
|
customerAuth.POST("/register/start", r.customerAuthHandler.RegisterStart)
|
|
customerAuth.POST("/register/verify-otp", r.customerAuthHandler.RegisterVerifyOtp)
|
|
customerAuth.POST("/register/set-password", r.customerAuthHandler.RegisterSetPassword)
|
|
customerAuth.POST("/login", r.customerAuthHandler.Login)
|
|
customerAuth.POST("/resend-otp", r.customerAuthHandler.ResendOtp)
|
|
}
|
|
|
|
// Customer authenticated routes
|
|
customer := v1.Group("/customer")
|
|
customer.Use(r.customerAuthMiddleware.ValidateCustomerToken())
|
|
{
|
|
customer.GET("/points", r.customerPointsHandler.GetCustomerPoints)
|
|
customer.GET("/wallet", r.customerPointsHandler.GetCustomerWallet)
|
|
customer.GET("/wallet/transactions", r.customerPointsHandler.GetCustomerWalletTransactions)
|
|
customer.GET("/wallet/expiring", r.customerPointsHandler.GetCustomerWalletExpiring)
|
|
customer.GET("/wallet/exchange/preview", r.customerWalletHandler.PreviewExchange)
|
|
customer.POST("/wallet/exchange", r.customerWalletHandler.Exchange)
|
|
customer.GET("/wallet/transfer/recipient", r.customerWalletHandler.TransferRecipient)
|
|
customer.POST("/wallet/transfer", r.customerWalletHandler.Transfer)
|
|
customer.PUT("/devices", r.customerDeviceHandler.Register)
|
|
customer.DELETE("/devices/:device_id", r.customerDeviceHandler.Unregister)
|
|
customer.GET("/outlets", r.customerOutletHandler.List)
|
|
customer.GET("/orders", r.customerOrderHandler.List)
|
|
customer.GET("/orders/:id", r.customerOrderHandler.Detail)
|
|
// PIN that approves moving EnakPoint and EnakCoin (docs/prd-point-coin.md F11)
|
|
customer.GET("/pin/status", r.customerPinHandler.Status)
|
|
customer.POST("/pin/otp", r.customerPinHandler.RequestOtp)
|
|
customer.POST("/pin", r.customerPinHandler.CreatePin)
|
|
customer.PUT("/pin", r.customerPinHandler.ChangePin)
|
|
customer.POST("/pin/reset", r.customerPinHandler.ResetPin)
|
|
customer.GET("/games", r.customerPointsHandler.GetCustomerGames)
|
|
customer.GET("/ferris-wheel", r.customerPointsHandler.GetFerrisWheelGame)
|
|
customer.POST("/spin", r.spinGameHandler.PlaySpinGame)
|
|
|
|
// EnakGame (docs/rfc-enakgame.md §11). /enakgame because /customer/games is
|
|
// the old spin.
|
|
enakGame := customer.Group("/enakgame")
|
|
{
|
|
enakGame.GET("/games", r.enakGameCustomerHandler.ListGames)
|
|
enakGame.POST("/sessions", r.enakGameCustomerHandler.StartSession)
|
|
enakGame.GET("/sessions", r.enakGameCustomerHandler.ListSessions)
|
|
enakGame.GET("/sessions/:id", r.enakGameCustomerHandler.GetSession)
|
|
enakGame.POST("/sessions/:id/complete", r.enakGameCustomerHandler.CompleteSession)
|
|
enakGame.GET("/vouchers", r.enakGameCustomerHandler.ListVouchers)
|
|
enakGame.POST("/vouchers/:id/redeem", r.enakGameCustomerHandler.RedeemVoucher)
|
|
enakGame.GET("/redemptions", r.enakGameCustomerHandler.ListRedemptions)
|
|
}
|
|
}
|
|
|
|
selfOrder := v1.Group("/self-order")
|
|
{
|
|
selfOrder.GET("/table/:token", r.selfOrderHandler.ValidateToken)
|
|
selfOrder.GET("/categories", r.selfOrderHandler.ListCategories)
|
|
selfOrder.GET("/menu", r.selfOrderHandler.GetMenu)
|
|
selfOrder.POST("/orders", r.selfOrderHandler.CreateOrder)
|
|
selfOrder.GET("/orders/:session_id", r.selfOrderHandler.GetOrdersBySession)
|
|
}
|
|
|
|
organizations := v1.Group("/organizations")
|
|
{
|
|
organizations.POST("", r.organizationHandler.CreateOrganization)
|
|
}
|
|
|
|
protected := v1.Group("")
|
|
protected.Use(r.authMiddleware.RequireAuth())
|
|
{
|
|
users := protected.Group("/users")
|
|
{
|
|
adminUsers := users.Group("")
|
|
adminUsers.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
adminUsers.POST("", r.userHandler.CreateUser)
|
|
adminUsers.GET("", r.userHandler.ListUsers)
|
|
adminUsers.GET("/:id", r.userHandler.GetUser)
|
|
adminUsers.PUT("/:id", r.userHandler.UpdateUser)
|
|
adminUsers.DELETE("/:id", r.userHandler.DeleteUser)
|
|
adminUsers.PUT("/:id/activate", r.userHandler.ActivateUser)
|
|
adminUsers.PUT("/:id/deactivate", r.userHandler.DeactivateUser)
|
|
adminUsers.POST("/select-outlet", r.userHandler.UpdateUserOutlet)
|
|
}
|
|
|
|
users.PUT("/:id/password", r.userHandler.ChangePassword)
|
|
}
|
|
|
|
protectedOrganizations := protected.Group("/organizations")
|
|
{
|
|
adminOrgRoutes := protectedOrganizations.Group("")
|
|
adminOrgRoutes.Use(r.authMiddleware.RequireSuperAdmin())
|
|
{
|
|
adminOrgRoutes.GET("", r.organizationHandler.ListOrganizations)
|
|
adminOrgRoutes.GET("/:id", r.organizationHandler.GetOrganization)
|
|
adminOrgRoutes.PUT("/:id", r.organizationHandler.UpdateOrganization)
|
|
adminOrgRoutes.DELETE("/:id", r.organizationHandler.DeleteOrganization)
|
|
}
|
|
}
|
|
|
|
categories := protected.Group("/categories")
|
|
categories.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
categories.POST("", r.categoryHandler.CreateCategory)
|
|
categories.GET("", r.categoryHandler.ListCategories)
|
|
categories.GET("/:id", r.categoryHandler.GetCategory)
|
|
categories.PUT("/:id", r.categoryHandler.UpdateCategory)
|
|
categories.DELETE("/:id", r.categoryHandler.DeleteCategory)
|
|
}
|
|
|
|
units := protected.Group("/units")
|
|
units.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
units.POST("", r.unitHandler.Create)
|
|
units.GET("", r.unitHandler.GetAll)
|
|
units.GET("/:id", r.unitHandler.GetByID)
|
|
units.PUT("/:id", r.unitHandler.Update)
|
|
units.DELETE("/:id", r.unitHandler.Delete)
|
|
}
|
|
|
|
products := protected.Group("/products")
|
|
products.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
products.POST("", r.productHandler.CreateProduct)
|
|
products.GET("", r.productHandler.ListProducts)
|
|
products.GET("/all", r.productHandler.ListProductAll)
|
|
products.GET("/:id", r.productHandler.GetProduct)
|
|
products.PUT("/:id", r.productHandler.UpdateProduct)
|
|
products.DELETE("/:id", r.productHandler.DeleteProduct)
|
|
}
|
|
|
|
productOutletPrices := protected.Group("/product-outlet-prices")
|
|
productOutletPrices.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
productOutletPrices.POST("", r.productOutletPriceHandler.Upsert)
|
|
productOutletPrices.POST("/bulk", r.productOutletPriceHandler.BulkUpsert)
|
|
productOutletPrices.GET("/product/:product_id", r.productOutletPriceHandler.GetByProduct)
|
|
productOutletPrices.GET("/outlet/:outlet_id", r.productOutletPriceHandler.GetByOutlet)
|
|
productOutletPrices.GET("/product/:product_id/outlet/:outlet_id", r.productOutletPriceHandler.GetByProductAndOutlet)
|
|
productOutletPrices.DELETE("/:id", r.productOutletPriceHandler.Delete)
|
|
}
|
|
|
|
productVariants := protected.Group("/product-variants")
|
|
{
|
|
productVariants.POST("", r.productVariantHandler.CreateProductVariant)
|
|
productVariants.PUT("/:id", r.productVariantHandler.UpdateProductVariant)
|
|
productVariants.DELETE("/:id", r.productVariantHandler.DeleteProductVariant)
|
|
productVariants.GET("/:id", r.productVariantHandler.GetProductVariant)
|
|
}
|
|
|
|
inventory := protected.Group("/inventory")
|
|
inventory.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
inventory.POST("", r.inventoryHandler.CreateInventory)
|
|
inventory.GET("", r.inventoryHandler.ListInventory)
|
|
inventory.GET("/:id", r.inventoryHandler.GetInventory)
|
|
inventory.PUT("/:id", r.inventoryHandler.UpdateInventory)
|
|
inventory.DELETE("/:id", r.inventoryHandler.DeleteInventory)
|
|
inventory.POST("/adjust", r.inventoryHandler.AdjustInventory)
|
|
inventory.POST("/restock", r.inventoryHandler.RestockInventory)
|
|
inventory.GET("/low-stock/:outlet_id", r.inventoryHandler.GetLowStockItems)
|
|
inventory.GET("/zero-stock/:outlet_id", r.inventoryHandler.GetZeroStockItems)
|
|
inventory.GET("/report/summary/:outlet_id", r.inventoryHandler.GetInventoryReportSummary)
|
|
inventory.GET("/report/details/:outlet_id", r.inventoryHandler.GetInventoryReportDetails)
|
|
}
|
|
|
|
orders := protected.Group("/orders")
|
|
orders.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
orders.GET("", r.orderHandler.ListOrders)
|
|
orders.GET("/:id", r.orderHandler.GetOrderByID)
|
|
orders.POST("", r.orderHandler.CreateOrder)
|
|
orders.POST("/:id/add-items", middleware.IdempotencyMiddleware(r.redisClient), r.orderHandler.AddToOrder)
|
|
orders.PUT("/:id", r.orderHandler.UpdateOrder)
|
|
orders.PUT("/:id/customer", r.orderHandler.SetOrderCustomer)
|
|
orders.POST("/void", middleware.IdempotencyMiddleware(r.redisClient), r.orderHandler.VoidOrder)
|
|
orders.POST("/:id/refund", middleware.IdempotencyMiddleware(r.redisClient), r.orderHandler.RefundOrder)
|
|
orders.POST("/split-bill", r.orderHandler.SplitBill)
|
|
}
|
|
|
|
payments := protected.Group("/payments")
|
|
payments.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
payments.POST("", middleware.IdempotencyMiddleware(r.redisClient), r.orderHandler.CreatePayment)
|
|
payments.POST("/:id/refund", middleware.IdempotencyMiddleware(r.redisClient), r.orderHandler.RefundPayment)
|
|
}
|
|
|
|
paymentMethods := protected.Group("/payment-methods")
|
|
paymentMethods.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
paymentMethods.POST("", r.paymentMethodHandler.CreatePaymentMethod)
|
|
paymentMethods.GET("", r.paymentMethodHandler.ListPaymentMethods)
|
|
paymentMethods.GET("/:id", r.paymentMethodHandler.GetPaymentMethod)
|
|
paymentMethods.PUT("/:id", r.paymentMethodHandler.UpdatePaymentMethod)
|
|
paymentMethods.DELETE("/:id", r.paymentMethodHandler.DeletePaymentMethod)
|
|
paymentMethods.GET("/organization/:organization_id/active", r.paymentMethodHandler.GetActivePaymentMethodsByOrganization)
|
|
}
|
|
|
|
files := protected.Group("/files")
|
|
files.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
files.GET("/organization", r.fileHandler.GetFilesByOrganization)
|
|
files.GET("/user", r.fileHandler.GetFilesByUser)
|
|
files.GET("/:id", r.fileHandler.GetFileByID)
|
|
files.POST("/upload", r.fileHandler.UploadFile)
|
|
files.PUT("/:id", r.fileHandler.UpdateFile)
|
|
}
|
|
|
|
customers := protected.Group("/customers")
|
|
customers.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
customers.POST("", r.customerHandler.CreateCustomer)
|
|
customers.GET("", r.customerHandler.ListCustomers)
|
|
customers.GET("/:id", r.customerHandler.GetCustomer)
|
|
customers.PUT("/:id", r.customerHandler.UpdateCustomer)
|
|
customers.DELETE("/:id", r.customerHandler.DeleteCustomer)
|
|
customers.POST("/set-default", r.customerHandler.SetDefaultCustomer)
|
|
customers.GET("/default", r.customerHandler.GetDefaultCustomer)
|
|
}
|
|
|
|
analytics := protected.Group("/analytics")
|
|
analytics.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
analytics.GET("/payment-methods", r.analyticsHandler.GetPaymentMethodAnalytics)
|
|
analytics.GET("/sales", r.analyticsHandler.GetSalesAnalytics)
|
|
analytics.GET("/purchasing", r.analyticsHandler.GetPurchasingAnalytics)
|
|
analytics.GET("/products", r.analyticsHandler.GetProductAnalytics)
|
|
analytics.GET("/categories", r.analyticsHandler.GetProductAnalyticsPerCategory)
|
|
analytics.GET("/profit-sharing", r.analyticsHandler.GetProductAnalyticsPerParentCategory)
|
|
analytics.GET("/profit-sharing/:parent_category_id", r.analyticsHandler.GetParentCategoryAnalyticsDetail)
|
|
analytics.GET("/dashboard", r.analyticsHandler.GetDashboardAnalytics)
|
|
analytics.GET("/profit-loss", r.analyticsHandler.GetProfitLossAnalytics)
|
|
analytics.GET("/exclusive-summary/period", r.analyticsHandler.GetExclusiveSummaryPeriod)
|
|
analytics.GET("/exclusive-summary/monthly", r.analyticsHandler.GetExclusiveSummaryMonthly)
|
|
analytics.GET("/exclusive-summary/mtd", r.analyticsHandler.GetExclusiveSummaryMTD)
|
|
}
|
|
|
|
tables := protected.Group("/tables")
|
|
tables.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
tables.POST("", r.tableHandler.Create)
|
|
tables.GET("", r.tableHandler.List)
|
|
tables.GET("/:id", r.tableHandler.GetByID)
|
|
tables.PUT("/:id", r.tableHandler.Update)
|
|
tables.DELETE("/:id", r.tableHandler.Delete)
|
|
tables.POST("/:id/occupy", r.tableHandler.OccupyTable)
|
|
tables.POST("/:id/release", r.tableHandler.ReleaseTable)
|
|
tables.GET("/:id/qr", r.tableHandler.GenerateQRCode)
|
|
}
|
|
|
|
ingredients := protected.Group("/ingredients")
|
|
ingredients.Use(r.authMiddleware.RequireAdminOrManagerOrPurchasing())
|
|
{
|
|
ingredients.POST("", r.ingredientHandler.Create)
|
|
ingredients.GET("", r.ingredientHandler.GetAll)
|
|
ingredients.GET("/:id", r.ingredientHandler.GetByID)
|
|
ingredients.PUT("/:id", r.ingredientHandler.Update)
|
|
ingredients.DELETE("/:id", r.ingredientHandler.Delete)
|
|
ingredients.POST("/:id/compositions", r.ingredientHandler.AddCompositions)
|
|
ingredients.PUT("/compositions/:composition_id", r.ingredientHandler.UpdateComposition)
|
|
ingredients.DELETE("/compositions/:composition_id", r.ingredientHandler.DeleteComposition)
|
|
}
|
|
|
|
vendors := protected.Group("/vendors")
|
|
vendors.Use(r.authMiddleware.RequireAdminOrManagerOrPurchasing())
|
|
{
|
|
vendors.POST("", r.vendorHandler.CreateVendor)
|
|
vendors.GET("", r.vendorHandler.ListVendors)
|
|
vendors.GET("/active", r.vendorHandler.GetActiveVendors)
|
|
vendors.GET("/:id", r.vendorHandler.GetVendor)
|
|
vendors.PUT("/:id", r.vendorHandler.UpdateVendor)
|
|
vendors.DELETE("/:id", r.vendorHandler.DeleteVendor)
|
|
}
|
|
|
|
purchaseOrders := protected.Group("/purchase-orders")
|
|
purchaseOrders.Use(r.authMiddleware.RequireAdminOrManagerOrPurchasing())
|
|
{
|
|
purchaseOrders.POST("", r.purchaseOrderHandler.CreatePurchaseOrder)
|
|
purchaseOrders.GET("", r.purchaseOrderHandler.ListPurchaseOrders)
|
|
purchaseOrders.GET("/status/:status", r.purchaseOrderHandler.GetPurchaseOrdersByStatus)
|
|
purchaseOrders.GET("/overdue", r.purchaseOrderHandler.GetOverduePurchaseOrders)
|
|
purchaseOrders.GET("/teams", r.purchaseOrderHandler.ListPurchaseTeams)
|
|
purchaseOrders.GET("/:id", r.purchaseOrderHandler.GetPurchaseOrder)
|
|
purchaseOrders.PUT("/:id", r.purchaseOrderHandler.UpdatePurchaseOrder)
|
|
purchaseOrders.PUT("/:id/status/:status", r.purchaseOrderHandler.UpdatePurchaseOrderStatus)
|
|
purchaseOrders.DELETE("/:id", r.purchaseOrderHandler.DeletePurchaseOrder)
|
|
}
|
|
|
|
purchaseCategories := protected.Group("/purchase-categories")
|
|
purchaseCategories.Use(r.authMiddleware.RequireAdminOrManagerOrPurchasing())
|
|
{
|
|
purchaseCategories.POST("", r.purchaseCategoryHandler.CreatePurchaseCategory)
|
|
purchaseCategories.GET("", r.purchaseCategoryHandler.ListPurchaseCategories)
|
|
purchaseCategories.GET("/:id", r.purchaseCategoryHandler.GetPurchaseCategory)
|
|
purchaseCategories.PUT("/:id", r.purchaseCategoryHandler.UpdatePurchaseCategory)
|
|
purchaseCategories.DELETE("/:id", r.purchaseCategoryHandler.DeletePurchaseCategory)
|
|
}
|
|
|
|
unitConverters := protected.Group("/unit-converters")
|
|
unitConverters.Use(r.authMiddleware.RequireAdminOrManagerOrPurchasing())
|
|
{
|
|
unitConverters.POST("", r.unitConverterHandler.CreateIngredientUnitConverter)
|
|
unitConverters.GET("", r.unitConverterHandler.ListIngredientUnitConverters)
|
|
unitConverters.GET("/ingredient/:ingredient_id", r.unitConverterHandler.GetConvertersForIngredient)
|
|
unitConverters.GET("/ingredient/:ingredient_id/units", r.unitConverterHandler.GetUnitsByIngredientID)
|
|
unitConverters.POST("/convert", r.unitConverterHandler.ConvertUnit)
|
|
unitConverters.GET("/:id", r.unitConverterHandler.GetIngredientUnitConverter)
|
|
unitConverters.PUT("/:id", r.unitConverterHandler.UpdateIngredientUnitConverter)
|
|
unitConverters.DELETE("/:id", r.unitConverterHandler.DeleteIngredientUnitConverter)
|
|
}
|
|
|
|
productRecipes := protected.Group("/product-recipes")
|
|
productRecipes.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
productRecipes.POST("", r.productRecipeHandler.Create)
|
|
productRecipes.POST("/bulk", r.productRecipeHandler.BulkCreate)
|
|
productRecipes.GET("/:id", r.productRecipeHandler.GetByID)
|
|
productRecipes.PUT("/:id", r.productRecipeHandler.Update)
|
|
productRecipes.DELETE("/:id", r.productRecipeHandler.Delete)
|
|
productRecipes.GET("/product/:product_id", r.productRecipeHandler.GetByProductID)
|
|
productRecipes.GET("/ingredient/:ingredient_id", r.productRecipeHandler.GetByIngredientID)
|
|
}
|
|
|
|
// Accounting routes
|
|
chartOfAccountTypes := protected.Group("/chart-of-account-types")
|
|
chartOfAccountTypes.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
chartOfAccountTypes.POST("", r.chartOfAccountTypeHandler.CreateChartOfAccountType)
|
|
chartOfAccountTypes.GET("", r.chartOfAccountTypeHandler.ListChartOfAccountTypes)
|
|
chartOfAccountTypes.GET("/:id", r.chartOfAccountTypeHandler.GetChartOfAccountTypeByID)
|
|
chartOfAccountTypes.PUT("/:id", r.chartOfAccountTypeHandler.UpdateChartOfAccountType)
|
|
chartOfAccountTypes.DELETE("/:id", r.chartOfAccountTypeHandler.DeleteChartOfAccountType)
|
|
}
|
|
|
|
chartOfAccounts := protected.Group("/chart-of-accounts")
|
|
chartOfAccounts.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
chartOfAccounts.POST("", r.chartOfAccountHandler.CreateChartOfAccount)
|
|
chartOfAccounts.GET("", r.chartOfAccountHandler.ListChartOfAccounts)
|
|
chartOfAccounts.GET("/:id", r.chartOfAccountHandler.GetChartOfAccountByID)
|
|
chartOfAccounts.PUT("/:id", r.chartOfAccountHandler.UpdateChartOfAccount)
|
|
chartOfAccounts.DELETE("/:id", r.chartOfAccountHandler.DeleteChartOfAccount)
|
|
chartOfAccounts.GET("/organization/:organization_id", r.chartOfAccountHandler.GetChartOfAccountsByOrganization)
|
|
chartOfAccounts.GET("/organization/:organization_id/type/:type_id", r.chartOfAccountHandler.GetChartOfAccountsByType)
|
|
}
|
|
|
|
accounts := protected.Group("/accounts")
|
|
accounts.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
accounts.POST("", r.accountHandler.CreateAccount)
|
|
accounts.GET("", r.accountHandler.ListAccounts)
|
|
accounts.GET("/:id", r.accountHandler.GetAccountByID)
|
|
accounts.PUT("/:id", r.accountHandler.UpdateAccount)
|
|
accounts.DELETE("/:id", r.accountHandler.DeleteAccount)
|
|
accounts.GET("/organization/:organization_id", r.accountHandler.GetAccountsByOrganization)
|
|
accounts.GET("/chart-of-account/:chart_of_account_id", r.accountHandler.GetAccountsByChartOfAccount)
|
|
accounts.PUT("/:id/balance", r.accountHandler.UpdateAccountBalance)
|
|
accounts.GET("/:id/balance", r.accountHandler.GetAccountBalance)
|
|
}
|
|
|
|
expenses := protected.Group("/expenses")
|
|
expenses.Use(r.authMiddleware.RequireAdminOrManagerOrPurchasing())
|
|
{
|
|
expenses.POST("", r.expenseHandler.CreateExpense)
|
|
expenses.GET("", r.expenseHandler.ListExpenses)
|
|
expenses.GET("/analytics", r.expenseHandler.GetExpenseAnalytics)
|
|
expenses.GET("/:id", r.expenseHandler.GetExpense)
|
|
expenses.PUT("/:id", r.expenseHandler.UpdateExpense)
|
|
expenses.DELETE("/:id", r.expenseHandler.DeleteExpense)
|
|
}
|
|
|
|
cashAdvances := protected.Group("/cash-advances")
|
|
cashAdvances.Use(r.authMiddleware.RequireAdminOrManagerOrPurchasing())
|
|
{
|
|
cashAdvances.POST("", r.cashAdvanceHandler.CreateCashAdvance)
|
|
cashAdvances.GET("", r.cashAdvanceHandler.ListCashAdvances)
|
|
// Registered ahead of /:id so the picker path is not read as an id.
|
|
cashAdvances.GET("/teams", r.cashAdvanceHandler.ListCashAdvanceTeams)
|
|
cashAdvances.GET("/:id", r.cashAdvanceHandler.GetCashAdvance)
|
|
cashAdvances.PUT("/:id", r.cashAdvanceHandler.UpdateCashAdvance)
|
|
cashAdvances.PUT("/:id/status/:status", r.cashAdvanceHandler.UpdateCashAdvanceStatus)
|
|
cashAdvances.DELETE("/:id", r.cashAdvanceHandler.DeleteCashAdvance)
|
|
}
|
|
|
|
orderIngredientTransactions := protected.Group("/order-ingredient-transactions")
|
|
orderIngredientTransactions.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
orderIngredientTransactions.POST("", r.orderIngredientTransactionHandler.CreateOrderIngredientTransaction)
|
|
orderIngredientTransactions.GET("", r.orderIngredientTransactionHandler.ListOrderIngredientTransactions)
|
|
orderIngredientTransactions.GET("/:id", r.orderIngredientTransactionHandler.GetOrderIngredientTransactionByID)
|
|
orderIngredientTransactions.PUT("/:id", r.orderIngredientTransactionHandler.UpdateOrderIngredientTransaction)
|
|
orderIngredientTransactions.DELETE("/:id", r.orderIngredientTransactionHandler.DeleteOrderIngredientTransaction)
|
|
orderIngredientTransactions.GET("/order/:order_id", r.orderIngredientTransactionHandler.GetOrderIngredientTransactionsByOrder)
|
|
orderIngredientTransactions.GET("/order-item/:order_item_id", r.orderIngredientTransactionHandler.GetOrderIngredientTransactionsByOrderItem)
|
|
orderIngredientTransactions.GET("/ingredient/:ingredient_id", r.orderIngredientTransactionHandler.GetOrderIngredientTransactionsByIngredient)
|
|
orderIngredientTransactions.GET("/summary", r.orderIngredientTransactionHandler.GetOrderIngredientTransactionSummary)
|
|
orderIngredientTransactions.POST("/bulk", r.orderIngredientTransactionHandler.BulkCreateOrderIngredientTransactions)
|
|
}
|
|
|
|
gamification := protected.Group("/marketing")
|
|
gamification.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
// Tiers
|
|
tiers := gamification.Group("/tiers")
|
|
{
|
|
tiers.POST("", r.gamificationHandler.CreateTier)
|
|
tiers.GET("", r.gamificationHandler.ListTiers)
|
|
tiers.GET("/:id", r.gamificationHandler.GetTier)
|
|
tiers.PUT("/:id", r.gamificationHandler.UpdateTier)
|
|
tiers.DELETE("/:id", r.gamificationHandler.DeleteTier)
|
|
tiers.GET("/by-points/:points", r.gamificationHandler.GetTierByPoints)
|
|
}
|
|
|
|
// Games
|
|
games := gamification.Group("/games")
|
|
{
|
|
games.POST("", r.gamificationHandler.CreateGame)
|
|
games.GET("", r.gamificationHandler.ListGames)
|
|
games.GET("/active", r.gamificationHandler.GetActiveGames)
|
|
games.GET("/:id", r.gamificationHandler.GetGame)
|
|
games.PUT("/:id", r.gamificationHandler.UpdateGame)
|
|
games.DELETE("/:id", r.gamificationHandler.DeleteGame)
|
|
}
|
|
|
|
// Game Prizes
|
|
gamePrizes := gamification.Group("/game-prizes")
|
|
{
|
|
gamePrizes.POST("", r.gamificationHandler.CreateGamePrize)
|
|
gamePrizes.GET("", r.gamificationHandler.ListGamePrizes)
|
|
gamePrizes.GET("/:id", r.gamificationHandler.GetGamePrize)
|
|
gamePrizes.PUT("/:id", r.gamificationHandler.UpdateGamePrize)
|
|
gamePrizes.DELETE("/:id", r.gamificationHandler.DeleteGamePrize)
|
|
gamePrizes.GET("/game/:game_id", r.gamificationHandler.GetGamePrizesByGameID)
|
|
gamePrizes.GET("/game/:game_id/available", r.gamificationHandler.GetAvailablePrizes)
|
|
}
|
|
|
|
//// Game Plays
|
|
//gamePlays := gamification.Group("/game-plays")
|
|
//{
|
|
// gamePlays.POST("", r.gamificationHandler.CreateGamePlay)
|
|
// gamePlays.GET("", r.gamificationHandler.ListGamePlays)
|
|
// gamePlays.GET("/:id", r.gamificationHandler.GetGamePlay)
|
|
// gamePlays.POST("/play", r.gamificationHandler.PlayGame)
|
|
//}
|
|
|
|
// Omset Tracker
|
|
//omsetTracker := gamification.Group("/omset-tracker")
|
|
//{
|
|
// omsetTracker.POST("", r.gamificationHandler.CreateOmsetTracker)
|
|
// omsetTracker.GET("", r.gamificationHandler.ListOmsetTrackers)
|
|
// omsetTracker.GET("/:id", r.gamificationHandler.GetOmsetTracker)
|
|
// omsetTracker.PUT("/:id", r.gamificationHandler.UpdateOmsetTracker)
|
|
// omsetTracker.DELETE("/:id", r.gamificationHandler.DeleteOmsetTracker)
|
|
//}
|
|
|
|
// Rewards
|
|
rewards := gamification.Group("/rewards")
|
|
{
|
|
rewards.POST("", r.rewardHandler.CreateReward)
|
|
rewards.GET("", r.rewardHandler.ListRewards)
|
|
rewards.GET("/:id", r.rewardHandler.GetReward)
|
|
rewards.PUT("/:id", r.rewardHandler.UpdateReward)
|
|
rewards.DELETE("/:id", r.rewardHandler.DeleteReward)
|
|
rewards.PUT("/:id/stock/:stock", r.rewardHandler.UpdateRewardStock)
|
|
rewards.GET("/type/:type", r.rewardHandler.GetRewardsByType)
|
|
}
|
|
|
|
// Campaigns
|
|
campaigns := gamification.Group("/campaigns")
|
|
{
|
|
campaigns.POST("", r.campaignHandler.CreateCampaign)
|
|
campaigns.GET("", r.campaignHandler.ListCampaigns)
|
|
campaigns.GET("/active", r.campaignHandler.GetActiveCampaigns)
|
|
campaigns.GET("/app", r.campaignHandler.GetCampaignsForApp)
|
|
campaigns.GET("/:id", r.campaignHandler.GetCampaign)
|
|
campaigns.PUT("/:id", r.campaignHandler.UpdateCampaign)
|
|
campaigns.DELETE("/:id", r.campaignHandler.DeleteCampaign)
|
|
}
|
|
|
|
// Campaign Rules
|
|
// EnakPoint & EnakCoin settings of the organization (docs/prd-point-coin.md F2)
|
|
gamification.GET("/loyalty-settings", r.loyaltySettingsHandler.GetOrganizationSettings)
|
|
gamification.PUT("/loyalty-settings", r.authMiddleware.RequireLoyaltyManager(), r.loyaltySettingsHandler.UpdateOrganizationSettings)
|
|
gamification.GET("/loyalty-settings/history", r.loyaltySettingsHandler.ListHistory)
|
|
|
|
// EnakPoint & EnakCoin wallet of one customer (docs/prd-point-coin.md F7)
|
|
marketingCustomers := gamification.Group("/customers")
|
|
{
|
|
marketingCustomers.GET("/:id/wallet", r.walletAdminHandler.GetCustomerWallet)
|
|
marketingCustomers.POST("/:id/wallet/adjust", r.authMiddleware.RequireLoyaltyManager(), r.walletAdminHandler.AdjustCustomerWallet)
|
|
marketingCustomers.DELETE("/:id/pin", r.authMiddleware.RequireLoyaltyManager(), r.customerPinHandler.RemovePin)
|
|
marketingCustomers.GET("/:id/security-events", r.customerPinHandler.ListSecurityEvents)
|
|
}
|
|
// Trace one ledger row lot by lot back to where its balance came from (F7, §8.1)
|
|
gamification.GET("/wallet-transactions/:id/trace", r.walletAdminHandler.TraceTransaction)
|
|
|
|
// EnakGame (docs/rfc-enakgame.md §11). Reward configurations and budgets
|
|
// change what rewards cost, so writing them takes a loyalty manager.
|
|
enakGame := gamification.Group("/enakgame")
|
|
{
|
|
enakGame.POST("/games", r.enakGameAdminHandler.CreateGame)
|
|
enakGame.GET("/games", r.enakGameAdminHandler.ListGames)
|
|
enakGame.GET("/games/:id", r.enakGameAdminHandler.GetGame)
|
|
enakGame.PUT("/games/:id", r.enakGameAdminHandler.UpdateGame)
|
|
enakGame.PUT("/games/:id/status", r.enakGameAdminHandler.SetGameStatus)
|
|
enakGame.GET("/games/:id/reward-configs", r.enakGameAdminHandler.ListRewardConfigs)
|
|
enakGame.POST("/games/:id/reward-configs", r.authMiddleware.RequireLoyaltyManager(), r.enakGameAdminHandler.CreateRewardConfig)
|
|
enakGame.POST("/reward-configs/:id/activate", r.authMiddleware.RequireLoyaltyManager(), r.enakGameAdminHandler.ActivateRewardConfig)
|
|
|
|
enakGame.GET("/budgets", r.enakGameAdminHandler.ListBudgets)
|
|
enakGame.GET("/budgets/:id", r.enakGameAdminHandler.GetBudget)
|
|
enakGame.GET("/budgets/:id/metrics", r.enakGameAdminHandler.BudgetMetrics)
|
|
enakGame.POST("/budgets", r.authMiddleware.RequireLoyaltyManager(), r.enakGameAdminHandler.CreateBudget)
|
|
enakGame.PUT("/budgets/:id", r.authMiddleware.RequireLoyaltyManager(), r.enakGameAdminHandler.UpdateBudget)
|
|
enakGame.DELETE("/budgets/:id", r.authMiddleware.RequireLoyaltyManager(), r.enakGameAdminHandler.DeleteBudget)
|
|
|
|
// Events change what rewards cost, like budgets.
|
|
enakGame.GET("/events", r.enakGameAdminHandler.ListEvents)
|
|
enakGame.GET("/events/:id", r.enakGameAdminHandler.GetEvent)
|
|
enakGame.POST("/events", r.authMiddleware.RequireLoyaltyManager(), r.enakGameAdminHandler.CreateEvent)
|
|
enakGame.PUT("/events/:id", r.authMiddleware.RequireLoyaltyManager(), r.enakGameAdminHandler.UpdateEvent)
|
|
enakGame.PUT("/events/:id/status", r.authMiddleware.RequireLoyaltyManager(), r.enakGameAdminHandler.SetEventStatus)
|
|
|
|
enakGame.GET("/vouchers", r.enakGameAdminHandler.ListVouchers)
|
|
enakGame.GET("/vouchers/:id", r.enakGameAdminHandler.GetVoucher)
|
|
enakGame.GET("/vouchers/:id/codes", r.enakGameAdminHandler.ListVoucherCodes)
|
|
enakGame.POST("/vouchers", r.authMiddleware.RequireLoyaltyManager(), r.enakGameAdminHandler.CreateVoucher)
|
|
enakGame.PUT("/vouchers/:id", r.authMiddleware.RequireLoyaltyManager(), r.enakGameAdminHandler.UpdateVoucher)
|
|
enakGame.PUT("/vouchers/:id/status", r.authMiddleware.RequireLoyaltyManager(), r.enakGameAdminHandler.SetVoucherStatus)
|
|
enakGame.POST("/vouchers/:id/codes", r.authMiddleware.RequireLoyaltyManager(), r.enakGameAdminHandler.ImportVoucherCodes)
|
|
}
|
|
|
|
campaignRules := gamification.Group("/campaign-rules")
|
|
{
|
|
campaignRules.POST("", r.campaignHandler.CreateCampaignRule)
|
|
campaignRules.GET("", r.campaignHandler.ListCampaignRules)
|
|
campaignRules.GET("/:id", r.campaignHandler.GetCampaignRule)
|
|
campaignRules.PUT("/:id", r.campaignHandler.UpdateCampaignRule)
|
|
campaignRules.DELETE("/:id", r.campaignHandler.DeleteCampaignRule)
|
|
campaignRules.GET("/campaign/:campaign_id", r.campaignHandler.GetCampaignRulesByCampaignID)
|
|
}
|
|
}
|
|
|
|
outlets := protected.Group("/outlets")
|
|
outlets.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
outlets.POST("", r.outletHandler.CreateOutlet)
|
|
outlets.GET("/list", r.outletHandler.ListOutlets)
|
|
outlets.GET("/detail/:id", r.outletHandler.GetOutlet)
|
|
outlets.PUT("/detail/:id", r.outletHandler.UpdateOutlet)
|
|
outlets.GET("/printer-setting/:outlet_id", r.outletSettingHandler.GetPrinterSettings)
|
|
outlets.PUT("/printer-setting/:outlet_id", r.outletSettingHandler.UpdatePrinterSettings)
|
|
// EnakPoint & EnakCoin settings of the outlet (docs/prd-point-coin.md F1)
|
|
outlets.GET("/:outlet_id/loyalty-settings", r.loyaltySettingsHandler.GetOutletSettings)
|
|
outlets.PUT("/:outlet_id/loyalty-settings", r.authMiddleware.RequireLoyaltyManager(), r.loyaltySettingsHandler.UpdateOutletSettings)
|
|
outlets.GET("/:outlet_id/tables/available", r.tableHandler.GetAvailableTables)
|
|
outlets.GET("/:outlet_id/tables/occupied", r.tableHandler.GetOccupiedTables)
|
|
// Reports
|
|
outlets.GET("/:outlet_id/reports/daily-transaction.pdf", r.reportHandler.GetDailyTransactionReportPDF)
|
|
outlets.GET("/:outlet_id/reports/profit-loss.pdf", r.reportHandler.GetProfitLossReportPDF)
|
|
}
|
|
|
|
// User device routes - accessible by authenticated users for their own devices
|
|
userDevices := protected.Group("/user-devices")
|
|
{
|
|
userDevices.POST("/register", r.userDeviceHandler.RegisterDevice)
|
|
userDevices.GET("/me", r.userDeviceHandler.GetMyDevices)
|
|
userDevices.GET("/:id", r.userDeviceHandler.GetDevice)
|
|
userDevices.PUT("/:id", r.userDeviceHandler.UpdateDevice)
|
|
userDevices.DELETE("/:id", r.userDeviceHandler.DeleteDevice)
|
|
}
|
|
|
|
// Admin-only user device routes
|
|
adminUserDevices := protected.Group("/user-devices")
|
|
adminUserDevices.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
adminUserDevices.GET("", r.userDeviceHandler.ListDevices)
|
|
adminUserDevices.GET("/user/:user_id", r.userDeviceHandler.GetDevicesByUser)
|
|
}
|
|
|
|
// Notification routes - authenticated users manage their own notifications
|
|
notifications := protected.Group("/notifications")
|
|
{
|
|
notifications.GET("", r.notificationHandler.List)
|
|
notifications.GET("/:id", r.notificationHandler.GetByID)
|
|
notifications.PUT("/:id/read", r.notificationHandler.MarkAsRead)
|
|
notifications.PUT("/read-all", r.notificationHandler.MarkAllAsRead)
|
|
notifications.DELETE("/:id", r.notificationHandler.Delete)
|
|
}
|
|
|
|
// Admin notification routes - send and broadcast
|
|
adminNotifications := protected.Group("/notifications")
|
|
adminNotifications.Use(r.authMiddleware.RequireAdminOrManager())
|
|
{
|
|
adminNotifications.POST("/send", r.notificationHandler.Send)
|
|
adminNotifications.POST("/broadcast", r.notificationHandler.Broadcast)
|
|
}
|
|
}
|
|
}
|
|
}
|