From 4cc563f6f11f6957030c7b84a1bdc6350d42f6b7 Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 9 May 2026 00:12:00 +0700 Subject: [PATCH] Add self-order/orders/:sessionId --- internal/app/app.go | 1 + internal/contract/self_order_contract.go | 36 +++++++++++ internal/handler/self_order_handler.go | 82 ++++++++++++++++++++++++ internal/repository/order_repository.go | 19 ++++++ internal/router/router.go | 1 + 5 files changed, 139 insertions(+) diff --git a/internal/app/app.go b/internal/app/app.go index e466e6e..65dbb71 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -55,6 +55,7 @@ func (a *App) Initialize(cfg *config.Config) error { repos.outletRepo, repos.userRepo, repos.sessionRepo, + repos.orderRepo, ) a.router = router.NewRouter( diff --git a/internal/contract/self_order_contract.go b/internal/contract/self_order_contract.go index 4918f92..4e0d227 100644 --- a/internal/contract/self_order_contract.go +++ b/internal/contract/self_order_contract.go @@ -1,6 +1,8 @@ package contract import ( + "time" + "github.com/google/uuid" ) @@ -74,3 +76,37 @@ type SelfOrderCategoryItem struct { type SelfOrderListCategoriesResponse struct { Categories []SelfOrderCategoryItem `json:"categories"` } + +type SelfOrderListOrdersResponse struct { + Orders []SelfOrderOrderItem `json:"orders"` +} + +type SelfOrderOrderItem struct { + ID uuid.UUID `json:"id"` + OrderNumber string `json:"order_number"` + TableNumber *string `json:"table_number,omitempty"` + OrderType string `json:"order_type"` + Status string `json:"status"` + Subtotal float64 `json:"subtotal"` + TaxAmount float64 `json:"tax_amount"` + DiscountAmount float64 `json:"discount_amount"` + TotalAmount float64 `json:"total_amount"` + RemainingAmount float64 `json:"remaining_amount"` + PaymentStatus string `json:"payment_status"` + IsVoid bool `json:"is_void"` + IsRefund bool `json:"is_refund"` + Items []SelfOrderOrderLineItem `json:"items,omitempty"` + CreatedAt time.Time `json:"created_at"` +} + +type SelfOrderOrderLineItem struct { + ProductID uuid.UUID `json:"product_id"` + ProductName string `json:"product_name"` + ProductVariantID *uuid.UUID `json:"product_variant_id,omitempty"` + ProductVariantNam *string `json:"product_variant_name,omitempty"` + Quantity int `json:"quantity"` + UnitPrice float64 `json:"unit_price"` + TotalPrice float64 `json:"total_price"` + Notes *string `json:"notes,omitempty"` + Status string `json:"status"` +} diff --git a/internal/handler/self_order_handler.go b/internal/handler/self_order_handler.go index c632a7c..605a137 100644 --- a/internal/handler/self_order_handler.go +++ b/internal/handler/self_order_handler.go @@ -27,6 +27,7 @@ type SelfOrderHandler struct { outletRepo processor.OutletRepository userRepo processor.UserRepository sessionRepo repository.SessionRepository + orderRepo repository.OrderRepository } func NewSelfOrderHandler( @@ -37,6 +38,7 @@ func NewSelfOrderHandler( outletRepo processor.OutletRepository, userRepo processor.UserRepository, sessionRepo repository.SessionRepository, + orderRepo repository.OrderRepository, ) *SelfOrderHandler { return &SelfOrderHandler{ orderService: orderService, @@ -46,6 +48,7 @@ func NewSelfOrderHandler( outletRepo: outletRepo, userRepo: userRepo, sessionRepo: sessionRepo, + orderRepo: orderRepo, } } @@ -352,6 +355,85 @@ func (h *SelfOrderHandler) CreateOrder(c *gin.Context) { util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "SelfOrderHandler::CreateOrder") } +func (h *SelfOrderHandler) GetOrdersBySession(c *gin.Context) { + ctx := c.Request.Context() + sessionID := c.Param("sessionId") + + if sessionID == "" { + util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ + contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "session_id is required"), + }), "SelfOrderHandler::GetOrdersBySession") + return + } + + session, err := h.sessionRepo.GetByID(ctx, sessionID) + if err != nil { + logger.FromContext(ctx).WithError(err).Error("SelfOrderHandler::GetOrdersBySession -> failed to get session") + util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ + contract.NewResponseError(constants.NotFoundErrorCode, constants.RequestEntity, "session not found"), + }), "SelfOrderHandler::GetOrdersBySession") + return + } + if session == nil { + util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ + contract.NewResponseError(constants.NotFoundErrorCode, constants.RequestEntity, "session not found"), + }), "SelfOrderHandler::GetOrdersBySession") + return + } + + orders, err := h.orderRepo.ListBySessionID(ctx, sessionID) + if err != nil { + logger.FromContext(ctx).WithError(err).Error("SelfOrderHandler::GetOrdersBySession -> failed to list orders") + util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ + contract.NewResponseError(constants.InternalServerErrorCode, constants.OrderServiceEntity, "failed to list orders"), + }), "SelfOrderHandler::GetOrdersBySession") + return + } + + resp := &contract.SelfOrderListOrdersResponse{ + Orders: make([]contract.SelfOrderOrderItem, 0, len(orders)), + } + for _, o := range orders { + item := contract.SelfOrderOrderItem{ + ID: o.ID, + OrderNumber: o.OrderNumber, + TableNumber: o.TableNumber, + OrderType: string(o.OrderType), + Status: string(o.Status), + Subtotal: o.Subtotal, + TaxAmount: o.TaxAmount, + DiscountAmount: o.DiscountAmount, + TotalAmount: o.TotalAmount, + RemainingAmount: o.RemainingAmount, + PaymentStatus: string(o.PaymentStatus), + IsVoid: o.IsVoid, + IsRefund: o.IsRefund, + CreatedAt: o.CreatedAt, + } + for _, oi := range o.OrderItems { + lineItem := contract.SelfOrderOrderLineItem{ + ProductID: oi.ProductID, + Quantity: oi.Quantity, + UnitPrice: oi.UnitPrice, + TotalPrice: oi.TotalPrice, + Notes: oi.Notes, + Status: string(oi.Status), + ProductVariantID: oi.ProductVariantID, + } + if oi.Product.ID != uuid.Nil { + lineItem.ProductName = oi.Product.Name + } + if oi.ProductVariant != nil { + lineItem.ProductVariantNam = &oi.ProductVariant.Name + } + item.Items = append(item.Items, lineItem) + } + resp.Orders = append(resp.Orders, item) + } + + util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "SelfOrderHandler::GetOrdersBySession") +} + func (h *SelfOrderHandler) validateCreateOrderRequest(req *contract.SelfOrderCreateOrderRequest) error { if req.SessionID == "" { return fmt.Errorf("session_id is required") diff --git a/internal/repository/order_repository.go b/internal/repository/order_repository.go index e7e4b36..1ba460b 100644 --- a/internal/repository/order_repository.go +++ b/internal/repository/order_repository.go @@ -18,6 +18,7 @@ type OrderRepository interface { Update(ctx context.Context, order *entities.Order) error Delete(ctx context.Context, id uuid.UUID) error List(ctx context.Context, filters map[string]interface{}, limit, offset int) ([]*entities.Order, int64, error) + ListBySessionID(ctx context.Context, sessionID string) ([]*entities.Order, error) GetByOrderNumber(ctx context.Context, orderNumber string) (*entities.Order, error) ExistsByOrderNumber(ctx context.Context, orderNumber string) (bool, error) VoidOrder(ctx context.Context, id uuid.UUID, reason string, voidedBy uuid.UUID) error @@ -130,6 +131,24 @@ func (r *OrderRepositoryImpl) List(ctx context.Context, filters map[string]inter return orders, total, err } +func (r *OrderRepositoryImpl) ListBySessionID(ctx context.Context, sessionID string) ([]*entities.Order, error) { + var orders []*entities.Order + err := r.db.WithContext(ctx).Model(&entities.Order{}). + Preload("Organization"). + Preload("Outlet"). + Preload("User"). + Preload("OrderItems"). + Preload("OrderItems.Product"). + Preload("OrderItems.ProductVariant"). + Preload("Payments"). + Preload("Payments.PaymentMethod"). + Preload("Payments.PaymentOrderItems"). + Where("metadata->>'session_id' = ?", sessionID). + Order("created_at ASC"). + Find(&orders).Error + return orders, err +} + func (r *OrderRepositoryImpl) GetByOrderNumber(ctx context.Context, orderNumber string) (*entities.Order, error) { var order entities.Order err := r.db.WithContext(ctx).First(&order, "order_number = ?", orderNumber).Error diff --git a/internal/router/router.go b/internal/router/router.go index 3edf861..ea62af9 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -153,6 +153,7 @@ func (r *Router) addAppRoutes(rg *gin.Engine) { selfOrder.GET("/categories", r.selfOrderHandler.ListCategories) selfOrder.GET("/menu", r.selfOrderHandler.GetMenu) selfOrder.POST("/orders", r.selfOrderHandler.CreateOrder) + selfOrder.GET("/orders/:sessionId", r.selfOrderHandler.GetOrdersBySession) } organizations := v1.Group("/organizations")