Files
apskel-pos-backend/internal/router/router.go
T

706 lines
40 KiB
Go
Raw Normal View History

2025-07-18 20:10:29 +07:00
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"
2025-07-18 20:10:29 +07:00
)
type Router struct {
2025-09-12 15:37:19 +07:00
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
2026-06-08 12:29:59 +07:00
purchaseCategoryHandler *handler.PurchaseCategoryHandler
2025-09-12 15:37:19 +07:00
unitConverterHandler *handler.IngredientUnitConverterHandler
chartOfAccountTypeHandler *handler.ChartOfAccountTypeHandler
chartOfAccountHandler *handler.ChartOfAccountHandler
accountHandler *handler.AccountHandler
orderIngredientTransactionHandler *handler.OrderIngredientTransactionHandler
2025-09-17 19:30:17 +07:00
gamificationHandler *handler.GamificationHandler
2025-09-17 23:55:11 +07:00
rewardHandler *handler.RewardHandler
campaignHandler *handler.CampaignHandler
2025-09-18 01:32:01 +07:00
customerAuthHandler *handler.CustomerAuthHandler
2025-09-18 02:01:50 +07:00
customerPointsHandler *handler.CustomerPointsHandler
2025-09-18 13:39:37 +07:00
spinGameHandler *handler.SpinGameHandler
2026-05-10 10:42:09 +07:00
userDeviceHandler *handler.UserDeviceHandler
2026-05-10 10:57:38 +07:00
notificationHandler *handler.NotificationHandler
2026-05-05 21:07:03 +07:00
selfOrderHandler *handler.SelfOrderHandler
2026-05-13 21:58:54 +07:00
productOutletPriceHandler *handler.ProductOutletPriceHandler
2026-05-25 14:59:40 +07:00
expenseHandler *handler.ExpenseHandler
2026-08-13 14:38:28 +07:00
cashAdvanceHandler *handler.CashAdvanceHandler
walletAdminHandler *handler.WalletAdminHandler
loyaltySettingsHandler *handler.LoyaltySettingsHandler
customerPinHandler *handler.CustomerPinHandler
customerWalletHandler *handler.CustomerWalletHandler
customerDeviceHandler *handler.CustomerDeviceHandler
2026-09-30 19:21:13 +07:00
customerOutletHandler *handler.CustomerOutletHandler
customerOrderHandler *handler.CustomerOrderHandler
2026-10-04 21:54:13 +07:00
authMiddleware *middleware.AuthMiddleware
2025-09-18 02:01:50 +07:00
customerAuthMiddleware *middleware.CustomerAuthMiddleware
redisClient *redis.Client
2025-07-18 20:10:29 +07:00
}
2026-10-07 13:48:29 +07:00
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, redisClient *redis.Client) *Router {
2025-07-18 20:10:29 +07:00
return &Router{
2025-09-12 15:37:19 +07:00
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),
2026-05-10 14:13:20 +07:00
tableHandler: handler.NewTableHandler(tableService, tableValidator, cfg.Server.SelfOrderUrl),
2025-09-12 15:37:19 +07:00
unitHandler: handler.NewUnitHandler(unitService),
ingredientHandler: handler.NewIngredientHandler(ingredientService),
productRecipeHandler: handler.NewProductRecipeHandler(productRecipeService),
vendorHandler: handler.NewVendorHandler(vendorService, vendorValidator),
purchaseOrderHandler: handler.NewPurchaseOrderHandler(purchaseOrderService, purchaseOrderValidator),
2026-06-08 12:29:59 +07:00
purchaseCategoryHandler: handler.NewPurchaseCategoryHandler(purchaseCategoryService, purchaseCategoryValidator),
2025-09-12 15:37:19 +07:00
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),
2025-09-17 19:30:17 +07:00
gamificationHandler: handler.NewGamificationHandler(gamificationService, gamificationValidator),
2025-09-17 23:55:11 +07:00
rewardHandler: handler.NewRewardHandler(rewardService, rewardValidator),
campaignHandler: handler.NewCampaignHandler(campaignService, campaignValidator),
2025-09-18 01:32:01 +07:00
customerAuthHandler: handler.NewCustomerAuthHandler(customerAuthService, customerAuthValidator),
2025-09-18 02:01:50 +07:00
customerPointsHandler: handler.NewCustomerPointsHandler(customerPointsService),
2025-09-18 13:39:37 +07:00
spinGameHandler: handler.NewSpinGameHandler(spinGameService),
2025-09-12 15:37:19 +07:00
authMiddleware: authMiddleware,
2025-09-18 02:01:50 +07:00
customerAuthMiddleware: customerAuthMiddleware,
2026-04-16 14:30:09 +07:00
productVariantHandler: handler.NewProductVariantHandler(productVariantService, productVariantValidator),
2026-05-10 10:42:09 +07:00
userDeviceHandler: handler.NewUserDeviceHandler(userDeviceService, userDeviceValidator),
2026-05-10 10:57:38 +07:00
notificationHandler: handler.NewNotificationHandler(notificationService, notificationValidator),
2026-05-05 21:07:03 +07:00
selfOrderHandler: selfOrderHandler,
2026-05-13 21:58:54 +07:00
productOutletPriceHandler: handler.NewProductOutletPriceHandler(productOutletPriceService, productOutletPriceValidator),
2026-05-25 14:59:40 +07:00
expenseHandler: handler.NewExpenseHandler(expenseService, expenseValidator),
2026-08-13 14:38:28 +07:00
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),
2026-09-30 19:21:13 +07:00
customerOutletHandler: handler.NewCustomerOutletHandler(customerOutletService),
customerOrderHandler: handler.NewCustomerOrderHandler(customerOrderService),
redisClient: redisClient,
2025-07-18 20:10:29 +07:00
}
}
func (r *Router) Init() *gin.Engine {
gin.SetMode(gin.ReleaseMode)
engine := gin.New()
engine.Use(
middleware.JsonAPI(),
2025-09-01 16:14:15 +07:00
middleware.CORS(),
2025-07-18 20:10:29 +07:00
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)
}
2025-09-18 01:32:01 +07:00
// 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)
}
2025-09-18 02:01:50 +07:00
// 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)
2026-09-30 19:21:13 +07:00
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)
2025-09-18 12:01:20 +07:00
customer.GET("/games", r.customerPointsHandler.GetCustomerGames)
customer.GET("/ferris-wheel", r.customerPointsHandler.GetFerrisWheelGame)
2025-09-18 13:39:37 +07:00
customer.POST("/spin", r.spinGameHandler.PlaySpinGame)
2025-09-18 02:01:50 +07:00
}
2026-05-05 21:07:03 +07:00
selfOrder := v1.Group("/self-order")
{
2026-05-08 18:41:14 +07:00
selfOrder.GET("/table/:token", r.selfOrderHandler.ValidateToken)
2026-05-06 11:56:11 +07:00
selfOrder.GET("/categories", r.selfOrderHandler.ListCategories)
2026-05-08 23:18:52 +07:00
selfOrder.GET("/menu", r.selfOrderHandler.GetMenu)
2026-05-08 18:41:14 +07:00
selfOrder.POST("/orders", r.selfOrderHandler.CreateOrder)
2026-05-10 19:56:34 +07:00
selfOrder.GET("/orders/:session_id", r.selfOrderHandler.GetOrdersBySession)
2026-05-05 21:07:03 +07:00
}
2025-07-18 20:10:29 +07:00
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)
2025-08-03 23:55:51 +07:00
adminUsers.POST("/select-outlet", r.userHandler.UpdateUserOutlet)
2025-07-18 20:10:29 +07:00
}
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)
}
2025-08-03 23:55:51 +07:00
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)
}
2025-07-18 20:10:29 +07:00
products := protected.Group("/products")
products.Use(r.authMiddleware.RequireAdminOrManager())
{
products.POST("", r.productHandler.CreateProduct)
products.GET("", r.productHandler.ListProducts)
2026-05-14 00:15:28 +07:00
products.GET("/all", r.productHandler.ListProductAll)
2025-07-18 20:10:29 +07:00
products.GET("/:id", r.productHandler.GetProduct)
products.PUT("/:id", r.productHandler.UpdateProduct)
products.DELETE("/:id", r.productHandler.DeleteProduct)
}
2026-05-13 21:58:54 +07:00
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)
}
2026-04-16 14:30:09 +07:00
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)
}
2025-07-18 20:10:29 +07:00
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)
2025-08-14 01:35:19 +07:00
inventory.POST("/restock", r.inventoryHandler.RestockInventory)
2025-07-18 20:10:29 +07:00
inventory.GET("/low-stock/:outlet_id", r.inventoryHandler.GetLowStockItems)
inventory.GET("/zero-stock/:outlet_id", r.inventoryHandler.GetZeroStockItems)
2025-08-13 23:36:31 +07:00
inventory.GET("/report/summary/:outlet_id", r.inventoryHandler.GetInventoryReportSummary)
2025-08-14 00:38:26 +07:00
inventory.GET("/report/details/:outlet_id", r.inventoryHandler.GetInventoryReportDetails)
2025-07-18 20:10:29 +07:00
}
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)
2025-07-18 20:10:29 +07:00
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)
2025-08-07 22:45:02 +07:00
orders.POST("/split-bill", r.orderHandler.SplitBill)
2025-07-18 20:10:29 +07:00
}
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)
2025-07-18 20:10:29 +07:00
}
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)
2026-05-19 14:45:26 +07:00
analytics.GET("/purchasing", r.analyticsHandler.GetPurchasingAnalytics)
2025-07-18 20:10:29 +07:00
analytics.GET("/products", r.analyticsHandler.GetProductAnalytics)
2025-08-14 00:45:14 +07:00
analytics.GET("/categories", r.analyticsHandler.GetProductAnalyticsPerCategory)
2026-10-04 21:54:13 +07:00
analytics.GET("/profit-sharing", r.analyticsHandler.GetProductAnalyticsPerParentCategory)
analytics.GET("/profit-sharing/:parent_category_id", r.analyticsHandler.GetParentCategoryAnalyticsDetail)
2025-07-18 20:10:29 +07:00
analytics.GET("/dashboard", r.analyticsHandler.GetDashboardAnalytics)
analytics.GET("/profit-loss", r.analyticsHandler.GetProfitLossAnalytics)
2026-06-17 18:17:08 +07:00
analytics.GET("/exclusive-summary/period", r.analyticsHandler.GetExclusiveSummaryPeriod)
analytics.GET("/exclusive-summary/monthly", r.analyticsHandler.GetExclusiveSummaryMonthly)
2026-06-18 14:19:45 +07:00
analytics.GET("/exclusive-summary/mtd", r.analyticsHandler.GetExclusiveSummaryMTD)
2025-07-18 20:10:29 +07:00
}
2025-07-30 23:18:20 +07:00
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)
2026-05-09 01:01:25 +07:00
tables.GET("/:id/qr", r.tableHandler.GenerateQRCode)
2025-07-30 23:18:20 +07:00
}
2025-08-03 23:55:51 +07:00
ingredients := protected.Group("/ingredients")
2026-06-19 13:58:36 +07:00
ingredients.Use(r.authMiddleware.RequireAdminOrManagerOrPurchasing())
2025-08-03 23:55:51 +07:00
{
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)
2026-04-27 21:17:12 +07:00
ingredients.POST("/:id/compositions", r.ingredientHandler.AddCompositions)
ingredients.PUT("/compositions/:composition_id", r.ingredientHandler.UpdateComposition)
ingredients.DELETE("/compositions/:composition_id", r.ingredientHandler.DeleteComposition)
2025-08-03 23:55:51 +07:00
}
2025-09-12 01:12:11 +07:00
vendors := protected.Group("/vendors")
2026-06-19 13:58:36 +07:00
vendors.Use(r.authMiddleware.RequireAdminOrManagerOrPurchasing())
2025-09-12 01:12:11 +07:00
{
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")
2026-06-19 13:58:36 +07:00
purchaseOrders.Use(r.authMiddleware.RequireAdminOrManagerOrPurchasing())
2025-09-12 01:12:11 +07:00
{
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)
2025-09-12 01:12:11 +07:00
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)
}
2026-06-08 12:29:59 +07:00
purchaseCategories := protected.Group("/purchase-categories")
2026-06-19 13:58:36 +07:00
purchaseCategories.Use(r.authMiddleware.RequireAdminOrManagerOrPurchasing())
2026-06-08 12:29:59 +07:00
{
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)
}
2025-09-12 01:12:11 +07:00
unitConverters := protected.Group("/unit-converters")
2026-06-19 13:58:36 +07:00
unitConverters.Use(r.authMiddleware.RequireAdminOrManagerOrPurchasing())
2025-09-12 01:12:11 +07:00
{
unitConverters.POST("", r.unitConverterHandler.CreateIngredientUnitConverter)
unitConverters.GET("", r.unitConverterHandler.ListIngredientUnitConverters)
unitConverters.GET("/ingredient/:ingredient_id", r.unitConverterHandler.GetConvertersForIngredient)
2025-09-12 15:37:19 +07:00
unitConverters.GET("/ingredient/:ingredient_id/units", r.unitConverterHandler.GetUnitsByIngredientID)
2025-09-12 01:12:11 +07:00
unitConverters.POST("/convert", r.unitConverterHandler.ConvertUnit)
unitConverters.GET("/:id", r.unitConverterHandler.GetIngredientUnitConverter)
unitConverters.PUT("/:id", r.unitConverterHandler.UpdateIngredientUnitConverter)
unitConverters.DELETE("/:id", r.unitConverterHandler.DeleteIngredientUnitConverter)
}
2025-08-10 21:46:44 +07:00
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)
}
2025-09-12 01:12:11 +07:00
// 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)
}
2026-05-25 14:59:40 +07:00
expenses := protected.Group("/expenses")
2026-06-19 13:58:36 +07:00
expenses.Use(r.authMiddleware.RequireAdminOrManagerOrPurchasing())
2026-05-25 14:59:40 +07:00
{
expenses.POST("", r.expenseHandler.CreateExpense)
expenses.GET("", r.expenseHandler.ListExpenses)
2026-06-03 14:56:27 +07:00
expenses.GET("/analytics", r.expenseHandler.GetExpenseAnalytics)
2026-05-25 14:59:40 +07:00
expenses.GET("/:id", r.expenseHandler.GetExpense)
expenses.PUT("/:id", r.expenseHandler.UpdateExpense)
expenses.DELETE("/:id", r.expenseHandler.DeleteExpense)
}
2026-08-13 14:38:28 +07:00
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)
}
2025-09-12 15:37:19 +07:00
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)
}
2025-09-17 19:30:17 +07:00
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)
//}
2025-09-17 23:55:11 +07:00
// 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)
}
2025-09-18 13:39:37 +07:00
// 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)
2025-09-18 13:39:37 +07:00
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)
}
2025-09-17 19:30:17 +07:00
}
2025-07-30 23:18:20 +07:00
outlets := protected.Group("/outlets")
outlets.Use(r.authMiddleware.RequireAdminOrManager())
{
2026-04-16 19:23:36 +07:00
outlets.POST("", r.outletHandler.CreateOutlet)
2025-07-30 23:18:20 +07:00
outlets.GET("/list", r.outletHandler.ListOutlets)
2025-08-03 00:34:25 +07:00
outlets.GET("/detail/:id", r.outletHandler.GetOutlet)
outlets.PUT("/detail/:id", r.outletHandler.UpdateOutlet)
2025-07-30 23:18:20 +07:00
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)
2025-07-30 23:18:20 +07:00
outlets.GET("/:outlet_id/tables/available", r.tableHandler.GetAvailableTables)
outlets.GET("/:outlet_id/tables/occupied", r.tableHandler.GetOccupiedTables)
2025-08-10 20:41:34 +07:00
// Reports
outlets.GET("/:outlet_id/reports/daily-transaction.pdf", r.reportHandler.GetDailyTransactionReportPDF)
2026-06-19 13:31:33 +07:00
outlets.GET("/:outlet_id/reports/profit-loss.pdf", r.reportHandler.GetProfitLossReportPDF)
2025-07-30 23:18:20 +07:00
}
2026-05-10 10:42:09 +07:00
// 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)
}
2026-05-10 10:57:38 +07:00
// 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)
}
2025-07-18 20:10:29 +07:00
}
}
}