Self Order - Feature

This commit is contained in:
ryan 2026-05-05 20:14:54 +07:00
parent b993da898f
commit d2296e5b13
4 changed files with 259 additions and 192 deletions

View File

@ -42,8 +42,16 @@ func (a *App) Initialize(cfg *config.Config) error {
processors := a.initProcessors(cfg, repos)
services := a.initServices(processors, repos, cfg)
validators := a.initValidators()
middleware := a.initMiddleware(services, cfg, repos)
middleware := a.initMiddleware(services, cfg)
healthHandler := handler.NewHealthHandler()
selfOrderHandler := handler.NewSelfOrderHandler(
services.orderService,
services.categoryService,
services.productService,
repos.tableRepo,
repos.outletRepo,
repos.userRepo,
)
a.router = router.NewRouter(
cfg,
@ -105,14 +113,7 @@ func (a *App) Initialize(cfg *config.Config) error {
services.customerPointsService,
services.spinGameService,
middleware.customerAuthMiddleware,
handler.NewSelfOrderHandler(
services.orderService,
services.productService,
repos.customerRepo,
repos.userRepo,
repos.outletRepo,
),
middleware.selfOrderMiddleware,
selfOrderHandler,
)
return nil
@ -449,14 +450,12 @@ func (a *App) initServices(processors *processors, repos *repositories, cfg *con
type middlewares struct {
authMiddleware *middleware.AuthMiddleware
customerAuthMiddleware *middleware.CustomerAuthMiddleware
selfOrderMiddleware *middleware.SelfOrderMiddleware
}
func (a *App) initMiddleware(services *services, cfg *config.Config, repos *repositories) *middlewares {
func (a *App) initMiddleware(services *services, cfg *config.Config) *middlewares {
return &middlewares{
authMiddleware: middleware.NewAuthMiddleware(services.authService),
customerAuthMiddleware: middleware.NewCustomerAuthMiddleware(cfg.GetCustomerJWTSecret()),
selfOrderMiddleware: middleware.NewSelfOrderMiddleware(repos.tableRepo),
}
}

View File

@ -1,51 +1,54 @@
package contract
import (
"time"
"github.com/google/uuid"
)
type CreateSelfOrderRequest struct {
CustomerName string `json:"customer_name" validate:"required,min=1,max=255"`
PhoneNumber *string `json:"phone_number,omitempty" validate:"omitempty"`
OrderItems []SelfOrderItemRequest `json:"order_items" validate:"required,min=1,dive"`
Notes *string `json:"notes,omitempty" validate:"omitempty,max=1000"`
}
type SelfOrderItemRequest struct {
ProductID uuid.UUID `json:"product_id" validate:"required"`
ProductVariantID *uuid.UUID `json:"product_variant_id,omitempty"`
Quantity int `json:"quantity" validate:"required,min=1"`
Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"`
}
type SelfOrderResponse struct {
OrderID uuid.UUID `json:"order_id"`
OrderNumber string `json:"order_number"`
TableID uuid.UUID `json:"table_id"`
TableName string `json:"table_name"`
OutletID uuid.UUID `json:"outlet_id"`
OutletName string `json:"outlet_name"`
CustomerName string `json:"customer_name"`
OrderItems []OrderItemResponse `json:"order_items"`
Subtotal float64 `json:"subtotal"`
TaxAmount float64 `json:"tax_amount"`
TotalAmount float64 `json:"total_amount"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
type SelfOrderMenuRequest struct {
TableID uuid.UUID `json:"table_id" validate:"required"`
CustomerName string `json:"customer_name" validate:"required"`
Phone *string `json:"phone,omitempty"`
}
type SelfOrderMenuResponse struct {
OutletID uuid.UUID `json:"outlet_id"`
OutletName string `json:"outlet_name"`
TableID uuid.UUID `json:"table_id"`
TableName string `json:"table_name"`
Organization OrganizationMenuInfo `json:"organization"`
Products ListProductsResponse `json:"products"`
Categories []SelfOrderMenuCategory `json:"categories"`
}
type OrganizationMenuInfo struct {
type SelfOrderMenuCategory struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Description *string `json:"description,omitempty"`
Order int `json:"order"`
Products []SelfOrderMenuItem `json:"products"`
}
type SelfOrderMenuItem struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Description *string `json:"description,omitempty"`
Price float64 `json:"price"`
ImageURL *string `json:"image_url,omitempty"`
Variants []SelfOrderMenuVariant `json:"variants,omitempty"`
}
type SelfOrderMenuVariant struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
PriceModifier float64 `json:"price_modifier"`
}
type SelfOrderCreateOrderRequest struct {
TableID uuid.UUID `json:"table_id" validate:"required"`
CustomerName string `json:"customer_name" validate:"required"`
Phone *string `json:"phone,omitempty"`
OrderItems []SelfOrderCreateOrderItem `json:"order_items" validate:"required,min=1,dive"`
}
type SelfOrderCreateOrderItem struct {
ProductID uuid.UUID `json:"product_id" validate:"required"`
ProductVariantID *uuid.UUID `json:"product_variant_id,omitempty"`
Quantity int `json:"quantity" validate:"required,min=1"`
Notes *string `json:"notes,omitempty"`
}

View File

@ -3,11 +3,16 @@ package handler
import (
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/entities"
"apskel-pos-be/internal/logger"
"apskel-pos-be/internal/models"
"apskel-pos-be/internal/processor"
"apskel-pos-be/internal/repository"
"apskel-pos-be/internal/service"
"apskel-pos-be/internal/transformer"
"apskel-pos-be/internal/util"
"context"
"fmt"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
@ -15,102 +20,179 @@ import (
type SelfOrderHandler struct {
orderService service.OrderService
categoryService service.CategoryService
productService service.ProductService
customerRepo *repository.CustomerRepository
userRepo *repository.UserRepositoryImpl
outletRepo *repository.OutletRepositoryImpl
tableRepo repository.TableRepositoryInterface
outletRepo processor.OutletRepository
userRepo processor.UserRepository
}
func NewSelfOrderHandler(
orderService service.OrderService,
categoryService service.CategoryService,
productService service.ProductService,
customerRepo *repository.CustomerRepository,
userRepo *repository.UserRepositoryImpl,
outletRepo *repository.OutletRepositoryImpl,
tableRepo repository.TableRepositoryInterface,
outletRepo processor.OutletRepository,
userRepo processor.UserRepository,
) *SelfOrderHandler {
return &SelfOrderHandler{
orderService: orderService,
categoryService: categoryService,
productService: productService,
customerRepo: customerRepo,
userRepo: userRepo,
tableRepo: tableRepo,
outletRepo: outletRepo,
userRepo: userRepo,
}
}
func (h *SelfOrderHandler) GetMenu(c *gin.Context) {
ctx := c.Request.Context()
organizationIDStr, _ := c.Get("self_order_organization_id")
outletIDStr, _ := c.Get("self_order_outlet_id")
tableIDStr, _ := c.Get("self_order_table_id")
tableName, _ := c.Get("self_order_table_name")
organizationID, err := uuid.Parse(organizationIDStr.(string))
if err != nil {
var req contract.SelfOrderMenuRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(ctx).WithError(err).Error("SelfOrderHandler::GetMenu -> request binding failed")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.InternalServerErrorCode, constants.SelfOrderEntity, "invalid organization ID"),
contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()),
}), "SelfOrderHandler::GetMenu")
return
}
outletID, err := uuid.Parse(outletIDStr.(string))
if err != nil {
if req.TableID == uuid.Nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.InternalServerErrorCode, constants.SelfOrderEntity, "invalid outlet ID"),
contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "table_id is required"),
}), "SelfOrderHandler::GetMenu")
return
}
tableID, _ := uuid.Parse(tableIDStr.(string))
if req.CustomerName == "" {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "customer_name is required"),
}), "SelfOrderHandler::GetMenu")
return
}
table, err := h.tableRepo.GetByID(ctx, req.TableID)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("SelfOrderHandler::GetMenu -> table not found")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.NotFoundErrorCode, constants.TableEntity, "table not found"),
}), "SelfOrderHandler::GetMenu")
return
}
if !table.IsActive {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.ValidationErrorCode, constants.TableEntity, "table is not active"),
}), "SelfOrderHandler::GetMenu")
return
}
outlet, err := h.outletRepo.GetByID(ctx, table.OutletID)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("SelfOrderHandler::GetMenu -> outlet not found")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.NotFoundErrorCode, constants.OrderServiceEntity, "outlet not found"),
}), "SelfOrderHandler::GetMenu")
return
}
isActive := true
req := &contract.ListProductsRequest{
OrganizationID: &organizationID,
IsActive: &isActive,
catResp := h.categoryService.ListCategories(ctx, &contract.ListCategoriesRequest{
OrganizationID: &table.OrganizationID,
Page: 1,
Limit: 100,
})
if catResp.HasErrors() {
logger.FromContext(ctx).WithError(catResp.GetErrors()[0]).Error("SelfOrderHandler::GetMenu -> failed to list categories")
util.HandleResponse(c.Writer, c.Request, catResp, "SelfOrderHandler::GetMenu")
return
}
productsResponse := h.productService.ListProducts(ctx, req)
outlet, outletErr := h.outletRepo.GetByID(ctx, outletID)
outletName := ""
if outletErr == nil && outlet != nil {
outletName = outlet.Name
prodResp := h.productService.ListProducts(ctx, &contract.ListProductsRequest{
OrganizationID: &table.OrganizationID,
IsActive: &isActive,
Page: 1,
Limit: 1000,
})
if prodResp.HasErrors() {
logger.FromContext(ctx).WithError(prodResp.GetErrors()[0]).Error("SelfOrderHandler::GetMenu -> failed to list products")
util.HandleResponse(c.Writer, c.Request, prodResp, "SelfOrderHandler::GetMenu")
return
}
menuResponse := &contract.SelfOrderMenuResponse{
OutletID: outletID,
OutletName: outletName,
TableID: tableID,
TableName: tableName.(string),
Organization: contract.OrganizationMenuInfo{
ID: organizationID,
},
catList, ok := catResp.Data.(*contract.ListCategoriesResponse)
if !ok {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.InternalServerErrorCode, constants.CategoryServiceEntity, "unexpected categories response type"),
}), "SelfOrderHandler::GetMenu")
return
}
if productsResponse != nil {
if data, ok := productsResponse.Data.(*contract.ListProductsResponse); ok {
menuResponse.Products = *data
}
prodList, ok := prodResp.Data.(*contract.ListProductsResponse)
if !ok {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.InternalServerErrorCode, constants.ProductServiceEntity, "unexpected products response type"),
}), "SelfOrderHandler::GetMenu")
return
}
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(menuResponse), "SelfOrderHandler::GetMenu")
menu := h.buildMenuResponse(outlet, table, catList.Categories, prodList.Products)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(menu), "SelfOrderHandler::GetMenu")
}
func (h *SelfOrderHandler) buildMenuResponse(
outlet *entities.Outlet,
table *entities.Table,
categories []contract.CategoryResponse,
products []contract.ProductResponse,
) *contract.SelfOrderMenuResponse {
productMap := make(map[uuid.UUID][]contract.ProductResponse)
for _, p := range products {
productMap[p.CategoryID] = append(productMap[p.CategoryID], p)
}
menuCategories := make([]contract.SelfOrderMenuCategory, 0, len(categories))
for _, cat := range categories {
menuItems := make([]contract.SelfOrderMenuItem, 0)
if prods, ok := productMap[cat.ID]; ok {
for _, p := range prods {
item := contract.SelfOrderMenuItem{
ID: p.ID,
Name: p.Name,
Description: p.Description,
Price: p.Price,
ImageURL: p.ImageURL,
}
for _, v := range p.Variants {
item.Variants = append(item.Variants, contract.SelfOrderMenuVariant{
ID: v.ID,
Name: v.Name,
PriceModifier: v.PriceModifier,
})
}
menuItems = append(menuItems, item)
}
}
menuCategories = append(menuCategories, contract.SelfOrderMenuCategory{
ID: cat.ID,
Name: cat.Name,
Description: cat.Description,
Order: cat.Order,
Products: menuItems,
})
}
return &contract.SelfOrderMenuResponse{
OutletName: outlet.Name,
TableName: table.TableName,
Categories: menuCategories,
}
}
func (h *SelfOrderHandler) CreateOrder(c *gin.Context) {
ctx := c.Request.Context()
organizationIDStr, _ := c.Get("self_order_organization_id")
outletIDStr, _ := c.Get("self_order_outlet_id")
tableIDStr, _ := c.Get("self_order_table_id")
tableName, _ := c.Get("self_order_table_name")
organizationID, _ := uuid.Parse(organizationIDStr.(string))
outletID, _ := uuid.Parse(outletIDStr.(string))
tableID, _ := uuid.Parse(tableIDStr.(string))
var req contract.CreateSelfOrderRequest
var req contract.SelfOrderCreateOrderRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(ctx).WithError(err).Error("SelfOrderHandler::CreateOrder -> request binding failed")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
@ -119,121 +201,108 @@ func (h *SelfOrderHandler) CreateOrder(c *gin.Context) {
return
}
if req.CustomerName == "" {
if err := h.validateCreateOrderRequest(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.ValidationErrorCode, constants.SelfOrderEntity, "customer_name is required"),
contract.NewResponseError(constants.ValidationErrorCode, constants.RequestEntity, err.Error()),
}), "SelfOrderHandler::CreateOrder")
return
}
if len(req.OrderItems) == 0 {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.ValidationErrorCode, constants.SelfOrderEntity, "at least one order item is required"),
}), "SelfOrderHandler::CreateOrder")
return
}
adminUser, err := h.userRepo.GetAdminByOrganizationID(ctx, organizationID)
table, err := h.tableRepo.GetByID(ctx, req.TableID)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("SelfOrderHandler::CreateOrder -> failed to get admin user")
logger.FromContext(ctx).WithError(err).Error("SelfOrderHandler::CreateOrder -> table not found")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.InternalServerErrorCode, constants.SelfOrderEntity, "failed to resolve system user"),
contract.NewResponseError(constants.NotFoundErrorCode, constants.TableEntity, "table not found"),
}), "SelfOrderHandler::CreateOrder")
return
}
var customerID *uuid.UUID
if req.PhoneNumber != nil && *req.PhoneNumber != "" {
customer, err := h.customerRepo.GetByPhoneNumber(ctx, *req.PhoneNumber)
if !table.IsActive || !table.IsAvailable() {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.ValidationErrorCode, constants.TableEntity, "table is not available for ordering"),
}), "SelfOrderHandler::CreateOrder")
return
}
userID, err := h.resolveOrgUser(ctx, table.OrganizationID)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("SelfOrderHandler::CreateOrder -> failed to lookup customer by phone")
}
if customer != nil {
customerID = &customer.ID
}
logger.FromContext(ctx).WithError(err).Error("SelfOrderHandler::CreateOrder -> failed to resolve org user")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.InternalServerErrorCode, constants.OrderServiceEntity, "failed to create self-order"),
}), "SelfOrderHandler::CreateOrder")
return
}
metadata := map[string]interface{}{
"source": string(constants.OrderSourceSelfOrder),
"customer_phone": "",
}
if req.PhoneNumber != nil {
metadata["customer_phone"] = *req.PhoneNumber
}
orderItems := make([]models.CreateOrderItemRequest, len(req.OrderItems))
for i, item := range req.OrderItems {
orderItems[i] = models.CreateOrderItemRequest{
orderItems := make([]models.CreateOrderItemRequest, 0, len(req.OrderItems))
for _, item := range req.OrderItems {
orderItems = append(orderItems, models.CreateOrderItemRequest{
ProductID: item.ProductID,
ProductVariantID: item.ProductVariantID,
Quantity: item.Quantity,
Notes: item.Notes,
}
})
}
tableNameStr := tableName.(string)
metadata := make(map[string]interface{})
metadata["self_order"] = true
metadata["customer_name"] = req.CustomerName
if req.Phone != nil {
metadata["customer_phone"] = *req.Phone
}
tableID := req.TableID
modelReq := &models.CreateOrderRequest{
OutletID: outletID,
UserID: adminUser.ID,
CustomerID: customerID,
OutletID: table.OutletID,
UserID: userID,
TableID: &tableID,
TableNumber: &tableNameStr,
TableNumber: &table.TableName,
OrderType: constants.OrderTypeDineIn,
OrderItems: orderItems,
Notes: req.Notes,
CustomerName: &req.CustomerName,
Metadata: metadata,
}
response, err := h.orderService.CreateOrder(ctx, modelReq, organizationID)
response, err := h.orderService.CreateOrder(ctx, modelReq, table.OrganizationID)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("SelfOrderHandler::CreateOrder -> failed to create order")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
contract.NewResponseError(constants.InternalServerErrorCode, constants.SelfOrderEntity, err.Error()),
contract.NewResponseError(constants.InternalServerErrorCode, constants.OrderServiceEntity, err.Error()),
}), "SelfOrderHandler::CreateOrder")
return
}
outlet, _ := h.outletRepo.GetByID(ctx, outletID)
outletName := ""
if outlet != nil {
outletName = outlet.Name
}
orderItemsResp := make([]contract.OrderItemResponse, len(response.OrderItems))
for i, item := range response.OrderItems {
orderItemsResp[i] = contract.OrderItemResponse{
ID: item.ID,
OrderID: item.OrderID,
ProductID: item.ProductID,
ProductName: item.ProductName,
ProductVariantID: item.ProductVariantID,
ProductVariantName: item.ProductVariantName,
Quantity: item.Quantity,
UnitPrice: item.UnitPrice,
TotalPrice: item.TotalPrice,
Notes: item.Notes,
Status: string(item.Status),
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
}
}
selfOrderResp := &contract.SelfOrderResponse{
OrderID: response.ID,
OrderNumber: response.OrderNumber,
TableID: tableID,
TableName: tableNameStr,
OutletID: outletID,
OutletName: outletName,
CustomerName: req.CustomerName,
OrderItems: orderItemsResp,
Subtotal: response.Subtotal,
TaxAmount: response.TaxAmount,
TotalAmount: response.TotalAmount,
Status: string(response.Status),
CreatedAt: response.CreatedAt,
}
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(selfOrderResp), "SelfOrderHandler::CreateOrder")
contractResp := transformer.OrderModelToContract(response)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "SelfOrderHandler::CreateOrder")
}
func (h *SelfOrderHandler) validateCreateOrderRequest(req *contract.SelfOrderCreateOrderRequest) error {
if req.TableID == uuid.Nil {
return fmt.Errorf("table_id is required")
}
if req.CustomerName == "" {
return fmt.Errorf("customer_name is required")
}
if len(req.OrderItems) == 0 {
return fmt.Errorf("at least one order item is required")
}
for i, item := range req.OrderItems {
if item.ProductID == uuid.Nil {
return fmt.Errorf("product_id is required for item %d", i+1)
}
if item.Quantity <= 0 {
return fmt.Errorf("quantity must be greater than zero for item %d", i+1)
}
}
return nil
}
func (h *SelfOrderHandler) resolveOrgUser(ctx context.Context, organizationID uuid.UUID) (uuid.UUID, error) {
users, err := h.userRepo.GetByOrganizationID(ctx, organizationID)
if err != nil {
return uuid.Nil, fmt.Errorf("failed to get users for organization: %w", err)
}
if len(users) == 0 {
return uuid.Nil, fmt.Errorf("no users found for organization")
}
return users[0].ID, nil
}

View File

@ -49,10 +49,9 @@ type Router struct {
selfOrderHandler *handler.SelfOrderHandler
authMiddleware *middleware.AuthMiddleware
customerAuthMiddleware *middleware.CustomerAuthMiddleware
selfOrderMiddleware *middleware.SelfOrderMiddleware
}
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, 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, selfOrderHandler *handler.SelfOrderHandler, selfOrderMiddleware *middleware.SelfOrderMiddleware) *Router {
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, 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, selfOrderHandler *handler.SelfOrderHandler) *Router {
return &Router{
config: cfg,
@ -90,9 +89,8 @@ func NewRouter(cfg *config.Config, healthHandler *handler.HealthHandler, authSer
spinGameHandler: handler.NewSpinGameHandler(spinGameService),
authMiddleware: authMiddleware,
customerAuthMiddleware: customerAuthMiddleware,
selfOrderHandler: selfOrderHandler,
selfOrderMiddleware: selfOrderMiddleware,
productVariantHandler: handler.NewProductVariantHandler(productVariantService, productVariantValidator),
selfOrderHandler: selfOrderHandler,
}
}
@ -149,11 +147,9 @@ func (r *Router) addAppRoutes(rg *gin.Engine) {
customer.POST("/spin", r.spinGameHandler.PlaySpinGame)
}
// Self-order routes (public, token-based table identification)
selfOrder := v1.Group("/self-order")
selfOrder.Use(r.selfOrderMiddleware.ResolveToken())
{
selfOrder.GET("/menu", r.selfOrderHandler.GetMenu)
selfOrder.POST("/menu", r.selfOrderHandler.GetMenu)
selfOrder.POST("/order", r.selfOrderHandler.CreateOrder)
}