From 195371f5c61fc354f0a86e5e0c7d8025d2001077 Mon Sep 17 00:00:00 2001 From: ferdiansyah783 Date: Fri, 26 Jul 2024 11:37:22 +0700 Subject: [PATCH] feat: history-order-list --- go.sum | 2 - internal/entity/order.go | 53 +++++++++++++++++++++++++++ internal/handlers/http/order/order.go | 53 ++++++++++++++++++++++++++- internal/handlers/request/order.go | 12 ++++++ internal/handlers/response/order.go | 19 ++++++++++ internal/repository/orders/order.go | 41 +++++++++++++++++++++ internal/repository/repository.go | 1 + internal/services/order/order.go | 36 ++++++++++++++++++ internal/services/service.go | 7 ++-- 9 files changed, 218 insertions(+), 6 deletions(-) diff --git a/go.sum b/go.sum index f7afa6b..1e41251 100644 --- a/go.sum +++ b/go.sum @@ -84,8 +84,6 @@ github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uq github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/getbrevo/brevo-go v1.0.0 h1:E/pRCsQeExvZeTCJU5vy+xHWcLaL5axWQ9QkxjlFke4= github.com/getbrevo/brevo-go v1.0.0/go.mod h1:2TBMEnaDqq/oiAXUYtn6eykiEdHcEoS7tc63+YoFibw= -github.com/getbrevo/brevo-go v1.1.1 h1:6/SXEQ7ZfUjetPnJ4EncfLSUgXjQv4qUj1EQgLXnDto= -github.com/getbrevo/brevo-go v1.1.1/go.mod h1:ExhytIoPxt/cOBl6ZEMeEZNLUKrWEYA5U3hM/8WP2bg= github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= diff --git a/internal/entity/order.go b/internal/entity/order.go index 57a1b21..8f617b5 100644 --- a/internal/entity/order.go +++ b/internal/entity/order.go @@ -81,3 +81,56 @@ type CallbackRequest struct { TransactionStatus string `json:"transaction_status"` TransactionID string `json:"transaction_id"` } + +type HistoryOrder struct { + ID int64 `gorm:"primaryKey;autoIncrement;column:id"` + Employee string `gorm:"type:varchar;column:employee"` + Site string `gorm:"type:varchar;column:site"` + Timestamp time.Time `gorm:"autoCreateTime;column:timestamp"` + BookingTime time.Time `gorm:"autoCreateTime;column:booking_time"` + Tickets []string `gorm:"-"` + RawTickets string `gorm:"type:text;column:tickets"` + PaymentType string `gorm:"type:varchar;column:payment_type"` + Status string `gorm:"type:varchar;column:status"` + Amount float64 `gorm:"type:numeric;column:amount"` +} + +type HistoryOrderDB struct { + HistoryOrder +} + +type HistoryOrderSearch struct { + Limit int + Offset int +} + +type HistoryOrderList []*HistoryOrderDB + +func (b *HistoryOrder) ToHistoryOrderDB() *HistoryOrderDB { + return &HistoryOrderDB{ + HistoryOrder: *b, + } +} + +func (e *HistoryOrderDB) ToHistoryOrder() *HistoryOrder { + return &HistoryOrder{ + ID: e.ID, + Employee: e.Employee, + Site: e.Site, + Timestamp: e.Timestamp, + BookingTime: e.BookingTime, + Tickets: e.Tickets, + RawTickets: e.RawTickets, + PaymentType: e.PaymentType, + Status: e.Status, + Amount: e.Amount, + } +} + +func (b *HistoryOrderList) ToHistoryOrderList() []*HistoryOrder { + var HistoryOrders []*HistoryOrder + for _, historyOrder := range *b { + HistoryOrders = append(HistoryOrders, historyOrder.ToHistoryOrder()) + } + return HistoryOrders +} diff --git a/internal/handlers/http/order/order.go b/internal/handlers/http/order/order.go index fcd1ee0..77e1630 100644 --- a/internal/handlers/http/order/order.go +++ b/internal/handlers/http/order/order.go @@ -6,9 +6,11 @@ import ( "furtuna-be/internal/handlers/request" "furtuna-be/internal/handlers/response" "furtuna-be/internal/services" + "net/http" + "time" + "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" - "net/http" ) type Handler struct { @@ -20,6 +22,7 @@ func (h *Handler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) { route.POST("/inquiry", jwt, h.Inquiry) route.POST("/execute", jwt, h.Execute) + route.GET("/history", jwt, h.GetAllHistoryOrders) } func NewHandler(service services.Order) *Handler { @@ -151,3 +154,51 @@ func MapOrderToExecuteOrderResponse(orderResponse *entity.ExecuteOrderResponse) RedirectURL: orderResponse.RedirectURL, } } + +func (h *Handler) toHistoryOrderResponse(resp *entity.HistoryOrder) response.HistoryOrder { + return response.HistoryOrder{ + ID: resp.ID, + Employee: resp.Employee, + Site: resp.Site, + Timestamp: resp.Timestamp.Format(time.RFC3339), + BookingTime: resp.BookingTime.Format(time.RFC3339), + Tickets: resp.Tickets, + PaymentType: resp.PaymentType, + Status: resp.Status, + Amount: resp.Amount, + } +} + +func (h *Handler) GetAllHistoryOrders(c *gin.Context) { + var req request.HistoryOrderParam + if err := c.ShouldBindQuery(&req); err != nil { + response.ErrorWrapper(c, errors.ErrorBadRequest) + return + } + + orders, total, err := h.service.GetAllHistoryOrders(c.Request.Context(), req.ToEntity()) + if err != nil { + response.ErrorWrapper(c, err) + return + } + + c.JSON(http.StatusOK, response.BaseResponse{ + Success: true, + Status: http.StatusOK, + Data: h.toHistoryOrderList(orders, int64(total), req), + }) +} + +func (h *Handler) toHistoryOrderList(resp []*entity.HistoryOrder, total int64, req request.HistoryOrderParam) response.HistoryOrderList { + var orders []response.HistoryOrder + for _, b := range resp { + orders = append(orders, h.toHistoryOrderResponse(b)) + } + + return response.HistoryOrderList{ + Orders: orders, + Total: total, + Limit: req.Limit, + Offset: req.Offset, + } +} diff --git a/internal/handlers/request/order.go b/internal/handlers/request/order.go index ed653a7..c0eb134 100644 --- a/internal/handlers/request/order.go +++ b/internal/handlers/request/order.go @@ -11,6 +11,18 @@ type Order struct { OrderItems []OrderItem `json:"order_items" validate:"required"` } +type HistoryOrderParam struct { + Limit int `form:"limit" json:"limit" example:"10"` + Offset int `form:"offset" json:"offset" example:"0"` +} + +func (o *HistoryOrderParam) ToEntity() entity.HistoryOrderSearch { + return entity.HistoryOrderSearch{ + Limit: o.Limit, + Offset: o.Offset, + } +} + type OrderItem struct { ProductID int64 `json:"product_id" validate:"required"` Quantity int64 `json:"quantity" validate:"required"` diff --git a/internal/handlers/response/order.go b/internal/handlers/response/order.go index 419a867..940bd7d 100644 --- a/internal/handlers/response/order.go +++ b/internal/handlers/response/order.go @@ -21,6 +21,18 @@ type Order struct { UpdatedAt string `json:"updated_at"` } +type HistoryOrder struct { + ID int64 `json:"id"` + Employee string `json:"employee"` + Site string `json:"site"` + Timestamp string `json:"timestamp"` + BookingTime string `json:"booking_time"` + Tickets []string `json:"tickets"` + PaymentType string `json:"payment_type"` + Status string `json:"status"` + Amount float64 `json:"amount"` +} + type OrderItem struct { OrderItemID int64 `json:"order_item_id" ` ItemID int64 `json:"item_id" ` @@ -39,6 +51,13 @@ type OrderList struct { Offset int `json:"offset"` } +type HistoryOrderList struct { + Orders []HistoryOrder `json:"history_orders"` + Total int64 `json:"total"` + Limit int `json:"limit"` + Offset int `json:"offset"` +} + type OrderMonthlyRevenue struct { TotalRevenue float64 `json:"total_revenue"` TotalTransaction int64 `json:"total_transaction"` diff --git a/internal/repository/orders/order.go b/internal/repository/orders/order.go index 24757bb..a77eb19 100644 --- a/internal/repository/orders/order.go +++ b/internal/repository/orders/order.go @@ -4,6 +4,8 @@ import ( "context" "furtuna-be/internal/common/logger" "furtuna-be/internal/entity" + "strings" + "go.uber.org/zap" "gorm.io/gorm" ) @@ -80,3 +82,42 @@ func (r *OrderRepository) Update(ctx context.Context, order *entity.Order) (*ent } return order, nil } + +func (b *OrderRepository) GetAllHystoryOrders(ctx context.Context, req entity.HistoryOrderSearch) (entity.HistoryOrderList, int, error) { + var orders []*entity.HistoryOrderDB + var total int64 + + query := b.db.Table("orders"). + Select("orders.id as id, users.name as employee, sites.name as site, orders.created_at as timestamp, orders.created_at as booking_time, STRING_AGG(ticket_summary.name || ' x' || ticket_summary.total_qty, ', ') AS tickets, orders.payment_type as payment_type, orders.status as status, orders.amount as amount"). + Joins("left join (SELECT items.order_id, products.name, SUM(items.qty) AS total_qty FROM order_items items LEFT JOIN products ON items.item_id = products.id GROUP BY items.order_id, products.name) AS ticket_summary ON orders.id = ticket_summary.order_id"). + Joins("left join users on orders.created_by = users.id"). + Joins("left join partners on orders.partner_id = partners.id"). + Joins("left join sites on partners.id = sites.partner_id"). + Group("orders.id, users.name, sites.name, orders.created_at, orders.payment_type, orders.status") + + if err := query.Count(&total).Error; err != nil { + logger.ContextLogger(ctx).Error("error when count history orders", zap.Error(err)) + return nil, 0, err + } + + if req.Offset > 0 { + query = query.Offset(req.Offset) + } + + if req.Limit > 0 { + query = query.Limit(req.Limit) + } + + if err := query.Scan(&orders).Error; err != nil { + logger.ContextLogger(ctx).Error("error when get all history orders", zap.Error(err)) + return nil, 0, err + } + + for i, order := range orders { + if order.RawTickets != "" { + orders[i].Tickets = strings.Split(order.RawTickets, ", ") + } + } + + return orders, int(total), nil +} diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 309aeef..18ce638 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -130,6 +130,7 @@ type Order interface { FindByID(ctx context.Context, id int64) (*entity.Order, error) Update(ctx context.Context, order *entity.Order) (*entity.Order, error) SetOrderStatus(ctx context.Context, db *gorm.DB, orderID int64, status string) error + GetAllHystoryOrders(ctx context.Context, req entity.HistoryOrderSearch) (entity.HistoryOrderList, int, error) } type OSSRepository interface { diff --git a/internal/services/order/order.go b/internal/services/order/order.go index 2b075e2..94b5bbc 100644 --- a/internal/services/order/order.go +++ b/internal/services/order/order.go @@ -296,3 +296,39 @@ func (s *OrderService) updateWalletBalance(ctx context.Context, tx *gorm.DB, par _, err = s.wallet.Update(ctx, tx, wallet) return err } + +func (s *OrderService) GetAllHistoryOrders(ctx context.Context, req entity.HistoryOrderSearch) ([]*entity.HistoryOrder, int, error) { + historyOrders, total, err := s.repo.GetAllHystoryOrders(ctx, req) + if err != nil { + logger.ContextLogger(ctx).Error("error when get all history orders", zap.Error(err)) + return nil, 0, err + } + + data := historyOrders.ToHistoryOrderList() + + // resultsMap := make(map[int64]*entity.MergedHistoryOrder) + + // for _, d := range data { + // if _, exists := resultsMap[d.ID]; !exists { + // resultsMap[d.ID] = &entity.MergedHistoryOrder{ + // ID: d.ID, + // Employee: d.Employee, + // Site: d.Site, + // Timestamp: d.Timestamp.Format(time.RFC3339), + // BookingTime: d.BookingTime.Format(time.RFC3339), + // Tickets: []string{}, + // PaymentType: d.PaymentType, + // Status: d.Status, + // Amount: d.Amount, + // } + // } + // resultsMap[d.ID].Tickets = append(resultsMap[d.ID].Tickets, fmt.Sprintf("%s x%d", d.Ticket, d.Quantity)) + // } + + // var results []*entity.MergedHistoryOrder + // for _, v := range resultsMap { + // results = append(results, v) + // } + + return data, total, nil +} diff --git a/internal/services/service.go b/internal/services/service.go index 679d847..b65ba48 100644 --- a/internal/services/service.go +++ b/internal/services/service.go @@ -8,9 +8,10 @@ import ( "furtuna-be/internal/services/oss" "furtuna-be/internal/services/partner" "furtuna-be/internal/services/product" - "furtuna-be/internal/services/sites" + site "furtuna-be/internal/services/sites" "furtuna-be/internal/services/studio" "furtuna-be/internal/services/users" + "gorm.io/gorm" "furtuna-be/config" @@ -41,8 +42,7 @@ func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl) BranchSvc: branch.NewBranchService(repo.Branch), StudioSvc: studio.NewStudioService(repo.Studio), ProductSvc: product.NewProductService(repo.Product), - OrderSvc: order.NewOrderService(repo.Order, repo.Product, - repo.Crypto, repo.Midtrans, repo.Payment, repo.Trx, repo.Wallet), + OrderSvc: order.NewOrderService(repo.Order, repo.Product, repo.Crypto, repo.Midtrans, repo.Payment, repo.Trx, repo.Wallet), OSSSvc: oss.NewOSSService(repo.OSS), PartnerSvc: partner.NewPartnerService( repo.Partner, users.NewUserService(repo.User, repo.Branch), repo.Trx, repo.Wallet), @@ -101,6 +101,7 @@ type Order interface { CreateOrder(ctx context.Context, req *entity.OrderRequest) (*entity.OrderResponse, error) Execute(ctx context.Context, req *entity.OrderExecuteRequest) (*entity.ExecuteOrderResponse, error) ProcessCallback(ctx context.Context, req *entity.CallbackRequest) error + GetAllHistoryOrders(ctx context.Context, req entity.HistoryOrderSearch) ([]*entity.HistoryOrder, int, error) } type OSSService interface {