Add refund order
This commit is contained in:
parent
58d3b32c40
commit
ebb33186b8
27
internal/entity/casheer_session.go
Normal file
27
internal/entity/casheer_session.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type CashierSession struct {
|
||||||
|
ID int64
|
||||||
|
CashierID int64
|
||||||
|
OpenedAt time.Time
|
||||||
|
ClosedAt *time.Time
|
||||||
|
OpeningAmount float64
|
||||||
|
ClosingAmount *float64
|
||||||
|
ExpectedAmount *float64
|
||||||
|
Status string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaymentSummary struct {
|
||||||
|
PaymentType string
|
||||||
|
PaymentProvider string
|
||||||
|
TotalAmount float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type CashierSessionReport struct {
|
||||||
|
SessionID int64
|
||||||
|
ExpectedAmount float64
|
||||||
|
ClosingAmount float64
|
||||||
|
Payments []PaymentSummary
|
||||||
|
}
|
||||||
9
internal/entity/category.go
Normal file
9
internal/entity/category.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
type Category struct {
|
||||||
|
ID int64
|
||||||
|
PartnerID int64
|
||||||
|
Name string
|
||||||
|
CreatedAt int64
|
||||||
|
UpdatedAt int64
|
||||||
|
}
|
||||||
@ -26,6 +26,7 @@ type Order struct {
|
|||||||
User User `gorm:"foreignKey:CreatedBy;constraint:OnDelete:CASCADE;"`
|
User User `gorm:"foreignKey:CreatedBy;constraint:OnDelete:CASCADE;"`
|
||||||
Source string `gorm:"type:varchar;column:source"`
|
Source string `gorm:"type:varchar;column:source"`
|
||||||
OrderType string `gorm:"type:varchar;column:order_type"`
|
OrderType string `gorm:"type:varchar;column:order_type"`
|
||||||
|
CashierSessionID int64 `gorm:"type:varchar;column:cashier_session_id"`
|
||||||
TableNumber string
|
TableNumber string
|
||||||
InProgressOrderID int64
|
InProgressOrderID int64
|
||||||
}
|
}
|
||||||
@ -113,6 +114,7 @@ type OrderRequest struct {
|
|||||||
PaymentProvider string
|
PaymentProvider string
|
||||||
OrderType string
|
OrderType string
|
||||||
ID int64
|
ID int64
|
||||||
|
CashierSessionID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type OrderItemRequest struct {
|
type OrderItemRequest struct {
|
||||||
|
|||||||
@ -26,6 +26,7 @@ type OrderInquiry struct {
|
|||||||
PaymentProvider string `json:"payment_provider"`
|
PaymentProvider string `json:"payment_provider"`
|
||||||
TableNumber string `json:"table_number"`
|
TableNumber string `json:"table_number"`
|
||||||
OrderType string `json:"order_type"`
|
OrderType string `json:"order_type"`
|
||||||
|
CashierSessionID int64 `json:"cashier_session_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OrderCalculation struct {
|
type OrderCalculation struct {
|
||||||
@ -54,6 +55,7 @@ func NewOrderInquiry(
|
|||||||
paymentProvider string,
|
paymentProvider string,
|
||||||
tableNumber string,
|
tableNumber string,
|
||||||
orderType string,
|
orderType string,
|
||||||
|
cashierSessionID int64,
|
||||||
) *OrderInquiry {
|
) *OrderInquiry {
|
||||||
return &OrderInquiry{
|
return &OrderInquiry{
|
||||||
ID: constants.GenerateUUID(),
|
ID: constants.GenerateUUID(),
|
||||||
@ -75,6 +77,7 @@ func NewOrderInquiry(
|
|||||||
PaymentProvider: paymentProvider,
|
PaymentProvider: paymentProvider,
|
||||||
TableNumber: tableNumber,
|
TableNumber: tableNumber,
|
||||||
OrderType: orderType,
|
OrderType: orderType,
|
||||||
|
CashierSessionID: cashierSessionID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,6 +114,7 @@ func (i *OrderInquiry) ToOrder(paymentMethod, paymentProvider string) *Order {
|
|||||||
OrderType: i.OrderType,
|
OrderType: i.OrderType,
|
||||||
CustomerName: i.CustomerName,
|
CustomerName: i.CustomerName,
|
||||||
TableNumber: i.TableNumber,
|
TableNumber: i.TableNumber,
|
||||||
|
CashierSessionID: i.CashierSessionID,
|
||||||
}
|
}
|
||||||
|
|
||||||
for idx, item := range i.OrderItems {
|
for idx, item := range i.OrderItems {
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package entity
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"enaklo-pos-be/internal/constants/product"
|
"enaklo-pos-be/internal/constants/product"
|
||||||
|
"enaklo-pos-be/internal/repository/models"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,6 +20,8 @@ type Product struct {
|
|||||||
CreatedBy int64 `gorm:"type:int;column:created_by"`
|
CreatedBy int64 `gorm:"type:int;column:created_by"`
|
||||||
UpdatedBy int64 `gorm:"type:int;column:updated_by"`
|
UpdatedBy int64 `gorm:"type:int;column:updated_by"`
|
||||||
Image string `gorm:"type:varchar;column:image"`
|
Image string `gorm:"type:varchar;column:image"`
|
||||||
|
CategoryID *int64 `gorm:"column:category_id"`
|
||||||
|
Category *models.CategoryDB `gorm:"foreignKey:CategoryID;references:ID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Product) TableName() string {
|
func (Product) TableName() string {
|
||||||
@ -34,6 +37,7 @@ type ProductSearch struct {
|
|||||||
Available product.ProductStock
|
Available product.ProductStock
|
||||||
Limit int
|
Limit int
|
||||||
Offset int
|
Offset int
|
||||||
|
CategoryID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProductPOS struct {
|
type ProductPOS struct {
|
||||||
@ -72,6 +76,8 @@ func (e *ProductDB) ToProduct() *Product {
|
|||||||
CreatedBy: e.CreatedBy,
|
CreatedBy: e.CreatedBy,
|
||||||
UpdatedBy: e.UpdatedBy,
|
UpdatedBy: e.UpdatedBy,
|
||||||
Image: e.Image,
|
Image: e.Image,
|
||||||
|
Category: e.Category,
|
||||||
|
CategoryID: e.CategoryID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
123
internal/handlers/http/cashier.go
Normal file
123
internal/handlers/http/cashier.go
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"enaklo-pos-be/internal/common/errors"
|
||||||
|
"enaklo-pos-be/internal/handlers/request"
|
||||||
|
"enaklo-pos-be/internal/handlers/response"
|
||||||
|
"enaklo-pos-be/internal/services/v2/cashier_session"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CashierSessionHandler struct {
|
||||||
|
service cashier_session.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCashierSession(service cashier_session.Service) *CashierSessionHandler {
|
||||||
|
return &CashierSessionHandler{service: service}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *CashierSessionHandler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
|
||||||
|
route := group.Group("/cashier-sessions")
|
||||||
|
route.Use(jwt)
|
||||||
|
|
||||||
|
route.POST("/open", h.OpenSession)
|
||||||
|
route.POST("/close/:id", h.CloseSession)
|
||||||
|
route.GET("/open", h.GetOpenSession)
|
||||||
|
route.GET("/report/:id", h.GetSessionReport)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *CashierSessionHandler) OpenSession(c *gin.Context) {
|
||||||
|
ctx := request.GetMyContext(c)
|
||||||
|
|
||||||
|
var req request.OpenCashierSessionRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
session, err := h.service.OpenSession(ctx, req.ToEntity(ctx.RequestedBy()))
|
||||||
|
if err != nil {
|
||||||
|
response.ErrorWrapper(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, response.BaseResponse{
|
||||||
|
Success: true,
|
||||||
|
Status: http.StatusOK,
|
||||||
|
Data: response.MapToCashierSessionResponse(session),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *CashierSessionHandler) CloseSession(c *gin.Context) {
|
||||||
|
ctx := request.GetMyContext(c)
|
||||||
|
idStr := c.Param("id")
|
||||||
|
sessionID, err := strconv.ParseInt(idStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var body struct {
|
||||||
|
ClosingAmount float64 `json:"closing_amount"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.ShouldBindJSON(&body); err != nil {
|
||||||
|
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
report, err := h.service.CloseSession(ctx, sessionID, body.ClosingAmount)
|
||||||
|
if err != nil {
|
||||||
|
response.ErrorWrapper(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, response.BaseResponse{
|
||||||
|
Success: true,
|
||||||
|
Status: http.StatusOK,
|
||||||
|
Data: response.MapToCashierSessionReport(report),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *CashierSessionHandler) GetOpenSession(c *gin.Context) {
|
||||||
|
ctx := request.GetMyContext(c)
|
||||||
|
|
||||||
|
cashierID := ctx.RequestedBy()
|
||||||
|
|
||||||
|
session, err := h.service.GetOpenSession(ctx, cashierID)
|
||||||
|
if err != nil {
|
||||||
|
response.ErrorWrapper(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, response.BaseResponse{
|
||||||
|
Success: true,
|
||||||
|
Status: http.StatusOK,
|
||||||
|
Data: response.MapToCashierSessionResponse(session),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *CashierSessionHandler) GetSessionReport(c *gin.Context) {
|
||||||
|
ctx := request.GetMyContext(c)
|
||||||
|
idStr := c.Param("id")
|
||||||
|
|
||||||
|
sessionID, err := strconv.ParseInt(idStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
report, err := h.service.GetSessionReport(ctx, sessionID)
|
||||||
|
if err != nil {
|
||||||
|
response.ErrorWrapper(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, response.BaseResponse{
|
||||||
|
Success: true,
|
||||||
|
Status: http.StatusOK,
|
||||||
|
Data: response.MapToCashierSessionReport(report),
|
||||||
|
})
|
||||||
|
}
|
||||||
139
internal/handlers/http/categories.go
Normal file
139
internal/handlers/http/categories.go
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"enaklo-pos-be/internal/common/errors"
|
||||||
|
"enaklo-pos-be/internal/handlers/request"
|
||||||
|
"enaklo-pos-be/internal/handlers/response"
|
||||||
|
category "enaklo-pos-be/internal/services/v2/categories"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CategoryHandler struct {
|
||||||
|
service category.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCategoryHandler(service category.Service) *CategoryHandler {
|
||||||
|
return &CategoryHandler{service: service}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *CategoryHandler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
|
||||||
|
route := group.Group("/categories")
|
||||||
|
route.Use(jwt)
|
||||||
|
|
||||||
|
route.POST("/create", h.Create)
|
||||||
|
route.GET("/list", h.GetByPartner)
|
||||||
|
route.GET("/:id", h.GetByID)
|
||||||
|
route.PUT("/:id", h.Update)
|
||||||
|
route.DELETE("/:id", h.Delete)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *CategoryHandler) Create(c *gin.Context) {
|
||||||
|
ctx := request.GetMyContext(c)
|
||||||
|
|
||||||
|
var req request.CategoryRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
category, err := h.service.Create(ctx, req.ToEntity(ctx.RequestedBy()))
|
||||||
|
if err != nil {
|
||||||
|
response.ErrorWrapper(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, response.BaseResponse{
|
||||||
|
Success: true,
|
||||||
|
Status: http.StatusOK,
|
||||||
|
Data: response.MapToCategoryResponse(category),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *CategoryHandler) GetByPartner(c *gin.Context) {
|
||||||
|
ctx := request.GetMyContext(c)
|
||||||
|
|
||||||
|
categories, err := h.service.GetByPartnerID(ctx, ctx.RequestedBy())
|
||||||
|
if err != nil {
|
||||||
|
response.ErrorWrapper(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, response.BaseResponse{
|
||||||
|
Success: true,
|
||||||
|
Status: http.StatusOK,
|
||||||
|
Data: response.MapToCategoryListResponse(categories),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *CategoryHandler) GetByID(c *gin.Context) {
|
||||||
|
ctx := request.GetMyContext(c)
|
||||||
|
|
||||||
|
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
category, err := h.service.GetByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
response.ErrorWrapper(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, response.BaseResponse{
|
||||||
|
Success: true,
|
||||||
|
Status: http.StatusOK,
|
||||||
|
Data: response.MapToCategoryResponse(category),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *CategoryHandler) Update(c *gin.Context) {
|
||||||
|
ctx := request.GetMyContext(c)
|
||||||
|
|
||||||
|
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var req request.CategoryRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
category := req.ToEntity(ctx.RequestedBy())
|
||||||
|
category.ID = id
|
||||||
|
|
||||||
|
if err := h.service.Update(ctx, category); err != nil {
|
||||||
|
response.ErrorWrapper(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, response.BaseResponse{
|
||||||
|
Success: true,
|
||||||
|
Status: http.StatusOK,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *CategoryHandler) Delete(c *gin.Context) {
|
||||||
|
ctx := request.GetMyContext(c)
|
||||||
|
|
||||||
|
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.service.Delete(ctx, id); err != nil {
|
||||||
|
response.ErrorWrapper(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, response.BaseResponse{
|
||||||
|
Success: true,
|
||||||
|
Status: http.StatusOK,
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -1,268 +0,0 @@
|
|||||||
package customerorder
|
|
||||||
|
|
||||||
import (
|
|
||||||
"enaklo-pos-be/internal/common/errors"
|
|
||||||
"enaklo-pos-be/internal/entity"
|
|
||||||
"enaklo-pos-be/internal/handlers/request"
|
|
||||||
"enaklo-pos-be/internal/handlers/response"
|
|
||||||
"enaklo-pos-be/internal/services"
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/go-playground/validator/v10"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Handler struct {
|
|
||||||
service services.Order
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
|
|
||||||
route := group.Group("/order")
|
|
||||||
|
|
||||||
route.POST("/inquiry", h.Inquiry)
|
|
||||||
route.POST("/execute", jwt, h.Execute)
|
|
||||||
route.GET("/history", jwt, h.History)
|
|
||||||
route.GET("/detail", jwt, h.Detail)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHandler(service services.Order) *Handler {
|
|
||||||
return &Handler{
|
|
||||||
service: service,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) Inquiry(c *gin.Context) {
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
var req request.CustomerOrder
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := request.ValidateAndHandleError(req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.NewErrorMessage(errors.ErrorBadRequest, err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
order, err := h.service.CreateOrder(ctx, req.ToEntity(ctx.RequestedBy()))
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: MapOrderToCreateOrderResponse(order, req),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) Execute(c *gin.Context) {
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
var req request.Execute
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
validate := validator.New()
|
|
||||||
if err := validate.Struct(req); err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
order, err := h.service.Execute(ctx, req.ToOrderExecuteRequest(ctx.RequestedBy()))
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: MapOrderToExecuteOrderResponse(order),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func MapOrderToCreateOrderResponse(orderResponse *entity.OrderResponse, req request.CustomerOrder) response.CreateOrderResponse {
|
|
||||||
order := orderResponse.Order
|
|
||||||
orderItems := make([]response.CreateOrderItemResponse, len(order.OrderItems))
|
|
||||||
for i, item := range order.OrderItems {
|
|
||||||
orderItems[i] = response.CreateOrderItemResponse{
|
|
||||||
ID: item.ID,
|
|
||||||
ItemID: item.ItemID,
|
|
||||||
Quantity: item.Quantity,
|
|
||||||
Price: item.Price,
|
|
||||||
Name: item.Product.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.CreateOrderResponse{
|
|
||||||
ID: order.ID,
|
|
||||||
PartnerID: order.PartnerID,
|
|
||||||
Status: order.Status,
|
|
||||||
Amount: order.Amount,
|
|
||||||
PaymentType: order.PaymentType,
|
|
||||||
CreatedAt: order.CreatedAt,
|
|
||||||
OrderItems: orderItems,
|
|
||||||
Tax: order.Tax,
|
|
||||||
Total: order.Total,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MapOrderToExecuteOrderResponse(orderResponse *entity.ExecuteOrderResponse) response.ExecuteOrderResponse {
|
|
||||||
order := orderResponse.Order
|
|
||||||
orderItems := make([]response.CreateOrderItemResponse, len(order.OrderItems))
|
|
||||||
for i, item := range order.OrderItems {
|
|
||||||
orderItems[i] = response.CreateOrderItemResponse{
|
|
||||||
ID: item.ID,
|
|
||||||
ItemID: item.ItemID,
|
|
||||||
Quantity: item.Quantity,
|
|
||||||
Price: item.Price,
|
|
||||||
Name: item.Product.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.ExecuteOrderResponse{
|
|
||||||
ID: order.ID,
|
|
||||||
PartnerID: order.PartnerID,
|
|
||||||
Status: order.Status,
|
|
||||||
Amount: order.Amount,
|
|
||||||
PaymentType: order.PaymentType,
|
|
||||||
CreatedAt: order.CreatedAt,
|
|
||||||
OrderItems: orderItems,
|
|
||||||
PaymentToken: orderResponse.PaymentToken,
|
|
||||||
RedirectURL: orderResponse.RedirectURL,
|
|
||||||
QRcode: orderResponse.QRCode,
|
|
||||||
VirtualAccount: orderResponse.VirtualAccount,
|
|
||||||
BankName: orderResponse.BankName,
|
|
||||||
BankCode: orderResponse.BankCode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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.GetPaymentStatus(),
|
|
||||||
Amount: resp.Amount,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) toHistoryOrderList(resp []*entity.HistoryOrder, total int64, req request.OrderParamCustomer) 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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) History(c *gin.Context) {
|
|
||||||
var req request.OrderParamCustomer
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
orders, total, err := h.service.GetAllHistoryOrders(ctx, req.ToOrderEntity(ctx))
|
|
||||||
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) Detail(c *gin.Context) {
|
|
||||||
var req request.OrderParamCustomer
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
order, err := h.service.GetByID(ctx, req.ID, req.ReferenceID)
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: h.toOrderDetail(order),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) toOrderDetail(order *entity.Order) *response.OrderDetail {
|
|
||||||
if order == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
payment := map[string]string{}
|
|
||||||
paymentLink := ""
|
|
||||||
paymentToken := ""
|
|
||||||
|
|
||||||
if order.Payment.RequestMetadata != nil && order.Status != "EXPIRED" {
|
|
||||||
json.Unmarshal(order.Payment.RequestMetadata, &payment)
|
|
||||||
paymentLink = payment["payment_redirect_url"]
|
|
||||||
paymentToken = payment["payment_token"]
|
|
||||||
}
|
|
||||||
|
|
||||||
qrCode := ""
|
|
||||||
|
|
||||||
var siteName string
|
|
||||||
|
|
||||||
if order.Site != nil {
|
|
||||||
siteName = order.Site.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
orderDetail := &response.OrderDetail{
|
|
||||||
ID: order.ID,
|
|
||||||
QRCode: qrCode,
|
|
||||||
FullName: order.User.Name,
|
|
||||||
Email: order.User.Email,
|
|
||||||
PhoneNumber: order.User.PhoneNumber,
|
|
||||||
TotalAmount: order.Total,
|
|
||||||
CreatedAt: order.CreatedAt,
|
|
||||||
Status: order.Status,
|
|
||||||
PaymentLink: paymentLink,
|
|
||||||
PaymentToken: paymentToken,
|
|
||||||
SiteName: siteName,
|
|
||||||
Fee: order.Tax,
|
|
||||||
}
|
|
||||||
|
|
||||||
orderDetail.OrderItems = make([]response.OrderDetailItem, len(order.OrderItems))
|
|
||||||
for i, item := range order.OrderItems {
|
|
||||||
orderDetail.OrderItems[i] = response.OrderDetailItem{
|
|
||||||
Name: item.Product.Name,
|
|
||||||
ItemType: item.ItemType,
|
|
||||||
Description: "",
|
|
||||||
Quantity: int(item.Quantity),
|
|
||||||
UnitPrice: item.Price,
|
|
||||||
TotalPrice: float64(item.Quantity) * item.Price,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return orderDetail
|
|
||||||
}
|
|
||||||
@ -1,229 +0,0 @@
|
|||||||
package discovery
|
|
||||||
|
|
||||||
import (
|
|
||||||
"enaklo-pos-be/internal/common/errors"
|
|
||||||
"enaklo-pos-be/internal/entity"
|
|
||||||
"enaklo-pos-be/internal/handlers/request"
|
|
||||||
"enaklo-pos-be/internal/handlers/response"
|
|
||||||
"enaklo-pos-be/internal/services"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Handler struct {
|
|
||||||
service services.DiscoverService
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
|
|
||||||
route := group.Group("/discovery")
|
|
||||||
|
|
||||||
route.GET("/home", h.DisoveryHome)
|
|
||||||
route.GET("/search", h.DisoverySearch)
|
|
||||||
route.GET("/site/detail", h.DiscoveryGetByID)
|
|
||||||
route.GET("/site/products", h.DiscoveryProducts)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHandler(service services.DiscoverService) *Handler {
|
|
||||||
return &Handler{
|
|
||||||
service: service,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) DisoveryHome(c *gin.Context) {
|
|
||||||
var req request.DiscoveryHomeParam
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := h.service.Home(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: ConvertEntityToResponse(res),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) DisoverySearch(c *gin.Context) {
|
|
||||||
var req request.DiscoveryHomeParam
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res, total, err := h.service.Search(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: ConvertEntityToSearchResponse(res, total, req),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) DiscoveryGetByID(c *gin.Context) {
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
var req request.DiscoverySearchByID
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := h.service.GetByID(ctx, req.ID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: ConvertEntityToGetByIDResp(res),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) DiscoveryProducts(c *gin.Context) {
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
var req request.DiscoverySearchByID
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := h.service.GetProductsByID(ctx, req.ID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: ConvertToProductResp(res),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func ConvertEntityToResponse(entityResp *entity.DiscoverySearchResp) *response.ExploreResponse {
|
|
||||||
// Convert ExploreRegions
|
|
||||||
exploreRegions := make([]response.Region, len(entityResp.ExploreRegions))
|
|
||||||
for i, region := range entityResp.ExploreRegions {
|
|
||||||
exploreRegions[i] = response.Region{
|
|
||||||
Name: region.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert ExploreDestinations
|
|
||||||
exploreDestinations := make([]response.Destination, len(entityResp.ExploreDestinations))
|
|
||||||
for i, destination := range entityResp.ExploreDestinations {
|
|
||||||
exploreDestinations[i] = response.Destination{
|
|
||||||
Name: destination.Name,
|
|
||||||
ImageURL: destination.ImageURL,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mustVisit := make([]response.MustVisit, len(entityResp.MustVisit))
|
|
||||||
for i, mv := range entityResp.MustVisit {
|
|
||||||
mustVisit[i] = response.MustVisit{
|
|
||||||
Name: mv.Name,
|
|
||||||
Region: mv.Region,
|
|
||||||
Rating: mv.Rating,
|
|
||||||
ReviewCount: mv.ReviewCount,
|
|
||||||
Price: mv.Price,
|
|
||||||
ImageURL: mv.ImageURL,
|
|
||||||
SiteID: mv.SiteID,
|
|
||||||
Regency: mv.Regency,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &response.ExploreResponse{
|
|
||||||
ExploreRegions: exploreRegions,
|
|
||||||
ExploreDestinations: exploreDestinations,
|
|
||||||
MustVisit: mustVisit,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ConvertEntityToSearchResponse(entityResp *entity.DiscoverySearchResp, total int64, req request.DiscoveryHomeParam) *response.SearchResponse {
|
|
||||||
data := make([]response.SiteSeach, len(entityResp.MustVisit))
|
|
||||||
for i, mv := range entityResp.MustVisit {
|
|
||||||
data[i] = response.SiteSeach{
|
|
||||||
Name: mv.Name,
|
|
||||||
Region: mv.Region,
|
|
||||||
Rating: mv.Rating,
|
|
||||||
ReviewCount: mv.ReviewCount,
|
|
||||||
Price: mv.Price,
|
|
||||||
ImageURL: mv.ImageURL,
|
|
||||||
SiteID: mv.SiteID,
|
|
||||||
Regency: mv.Regency,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &response.SearchResponse{
|
|
||||||
Data: data,
|
|
||||||
Total: int(total),
|
|
||||||
Limit: req.Limit,
|
|
||||||
Offset: req.Offset,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ConvertEntityToGetByIDResp(resp *entity.Site) *response.SearchSiteByIDResponse {
|
|
||||||
if resp == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &response.SearchSiteByIDResponse{
|
|
||||||
ID: resp.ID,
|
|
||||||
Name: resp.Name,
|
|
||||||
Image: resp.Image,
|
|
||||||
Address: resp.Address,
|
|
||||||
LocationLink: resp.LocationLink,
|
|
||||||
Description: resp.Description,
|
|
||||||
Highlight: resp.Highlight,
|
|
||||||
ContactPerson: resp.ContactPerson,
|
|
||||||
TnC: resp.TnC,
|
|
||||||
AdditionalInfo: resp.AdditionalInfo,
|
|
||||||
PartnerID: resp.PartnerID,
|
|
||||||
Regency: resp.Regency,
|
|
||||||
Region: resp.Region,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ConvertToProductResp(resp []*entity.Product) *response.SearchProductSiteResponse {
|
|
||||||
if resp == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var productResp []response.SearchProductSiteByIDResponse
|
|
||||||
|
|
||||||
partnerID := int64(0)
|
|
||||||
for _, res := range resp {
|
|
||||||
productResp = append(productResp, response.SearchProductSiteByIDResponse{
|
|
||||||
ID: res.ID,
|
|
||||||
Name: res.Name,
|
|
||||||
Price: res.Price,
|
|
||||||
Description: res.Description,
|
|
||||||
Type: res.Type,
|
|
||||||
})
|
|
||||||
|
|
||||||
partnerID = res.PartnerID
|
|
||||||
}
|
|
||||||
|
|
||||||
return &response.SearchProductSiteResponse{
|
|
||||||
Product: productResp,
|
|
||||||
PartnerID: partnerID,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,205 +0,0 @@
|
|||||||
package event
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
|
|
||||||
"enaklo-pos-be/internal/common/errors"
|
|
||||||
"enaklo-pos-be/internal/entity"
|
|
||||||
"enaklo-pos-be/internal/handlers/request"
|
|
||||||
"enaklo-pos-be/internal/handlers/response"
|
|
||||||
"enaklo-pos-be/internal/services"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Handler struct {
|
|
||||||
service services.Event
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
|
|
||||||
route := group.Group("/event")
|
|
||||||
|
|
||||||
route.POST("/", jwt, h.Create)
|
|
||||||
route.GET("/list", jwt, h.GetAll)
|
|
||||||
route.PUT("/:id", jwt, h.Update)
|
|
||||||
route.GET("/:id", jwt, h.GetByID)
|
|
||||||
route.DELETE("/:id", jwt, h.Delete)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHandler(service services.Event) *Handler {
|
|
||||||
return &Handler{
|
|
||||||
service: service,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) Create(c *gin.Context) {
|
|
||||||
var req request.Event
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := req.Validate(); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorInvalidRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := h.service.Create(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.toEventResponse(res),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) Update(c *gin.Context) {
|
|
||||||
id := c.Param("id")
|
|
||||||
|
|
||||||
eventID, err := strconv.ParseInt(id, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var req request.Event
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := req.Validate(); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
updatedEvent, err := h.service.Update(c.Request.Context(), eventID, req.ToEntity())
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: h.toEventResponse(updatedEvent),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) GetAll(c *gin.Context) {
|
|
||||||
var req request.EventParam
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
events, total, err := h.service.GetAll(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.toEventResponseList(events, int64(total), req),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) Delete(c *gin.Context) {
|
|
||||||
id := c.Param("id")
|
|
||||||
|
|
||||||
// Parse the ID into a uint
|
|
||||||
eventID, err := strconv.ParseInt(id, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = h.service.Delete(c.Request.Context(), eventID)
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusInternalServerError, response.BaseResponse{
|
|
||||||
Success: false,
|
|
||||||
Status: http.StatusInternalServerError,
|
|
||||||
Message: err.Error(),
|
|
||||||
Data: nil,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: nil,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) GetByID(c *gin.Context) {
|
|
||||||
id := c.Param("id")
|
|
||||||
|
|
||||||
// Parse the ID into a uint
|
|
||||||
eventID, err := strconv.ParseInt(id, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := h.service.GetByID(c.Request.Context(), eventID)
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusInternalServerError, response.BaseResponse{
|
|
||||||
Success: false,
|
|
||||||
Status: http.StatusInternalServerError,
|
|
||||||
Message: err.Error(),
|
|
||||||
Data: nil,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: h.toEventResponse(res),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) toEventResponse(resp *entity.Event) response.Event {
|
|
||||||
return response.Event{
|
|
||||||
ID: resp.ID,
|
|
||||||
Name: resp.Name,
|
|
||||||
Description: resp.Description,
|
|
||||||
StartDate: resp.StartDate.Format("2006-01-02"),
|
|
||||||
EndDate: resp.EndDate.Format("2006-01-02"),
|
|
||||||
StartTime: resp.StartDate.Format("15:04:05"),
|
|
||||||
EndTime: resp.EndDate.Format("15:04:05"),
|
|
||||||
Location: resp.Location,
|
|
||||||
Level: resp.Level,
|
|
||||||
Included: resp.Included,
|
|
||||||
Price: resp.Price,
|
|
||||||
Paid: resp.Paid,
|
|
||||||
LocationID: resp.LocationID,
|
|
||||||
CreatedAt: resp.CreatedAt.Format(time.RFC3339),
|
|
||||||
UpdatedAt: resp.CreatedAt.Format(time.RFC3339),
|
|
||||||
Status: string(resp.Status),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) toEventResponseList(resp []*entity.Event, total int64, req request.EventParam) response.EventList {
|
|
||||||
var events []response.Event
|
|
||||||
for _, evt := range resp {
|
|
||||||
events = append(events, h.toEventResponse(evt))
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.EventList{
|
|
||||||
Events: events,
|
|
||||||
Total: total,
|
|
||||||
Limit: req.Limit,
|
|
||||||
Offset: req.Offset,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -56,7 +56,7 @@ func (h *MenuHandler) GetProducts(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
searchParam := req.ToEntity()
|
searchParam := req.ToEntity(partnerID)
|
||||||
searchParam.PartnerID = partnerID
|
searchParam.PartnerID = partnerID
|
||||||
|
|
||||||
products, total, err := h.service.GetProductsByPartnerID(ctx, searchParam)
|
products, total, err := h.service.GetProductsByPartnerID(ctx, searchParam)
|
||||||
|
|||||||
@ -29,6 +29,7 @@ func (h *Handler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
|
|||||||
|
|
||||||
route.POST("/inquiry", jwt, h.Inquiry)
|
route.POST("/inquiry", jwt, h.Inquiry)
|
||||||
route.POST("/execute", jwt, h.Execute)
|
route.POST("/execute", jwt, h.Execute)
|
||||||
|
route.POST("/refund", jwt, h.Refund)
|
||||||
route.GET("/history", jwt, h.GetOrderHistory)
|
route.GET("/history", jwt, h.GetOrderHistory)
|
||||||
route.GET("/payment-analysis", jwt, h.GetPaymentMethodAnalysis)
|
route.GET("/payment-analysis", jwt, h.GetPaymentMethodAnalysis)
|
||||||
route.GET("/revenue-overview", jwt, h.GetRevenueOverview)
|
route.GET("/revenue-overview", jwt, h.GetRevenueOverview)
|
||||||
@ -47,6 +48,7 @@ type InquiryRequest struct {
|
|||||||
OrderType string `json:"order_type"`
|
OrderType string `json:"order_type"`
|
||||||
PaymentProvider string `json:"payment_provider"`
|
PaymentProvider string `json:"payment_provider"`
|
||||||
TableNumber string `json:"table_number"`
|
TableNumber string `json:"table_number"`
|
||||||
|
CashierSessionID int64 `json:"cashier_session_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *InquiryRequest) GetPaymentProvider() string {
|
func (o *InquiryRequest) GetPaymentProvider() string {
|
||||||
@ -70,6 +72,11 @@ type ExecuteRequest struct {
|
|||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RefundRequest struct {
|
||||||
|
OrderID int64 `json:"order_id" validate:"required"`
|
||||||
|
Reason string `json:"reason" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handler) Inquiry(c *gin.Context) {
|
func (h *Handler) Inquiry(c *gin.Context) {
|
||||||
ctx := request.GetMyContext(c)
|
ctx := request.GetMyContext(c)
|
||||||
userID := ctx.RequestedBy()
|
userID := ctx.RequestedBy()
|
||||||
@ -109,6 +116,7 @@ func (h *Handler) Inquiry(c *gin.Context) {
|
|||||||
OrderType: req.OrderType,
|
OrderType: req.OrderType,
|
||||||
PaymentProvider: req.GetPaymentProvider(),
|
PaymentProvider: req.GetPaymentProvider(),
|
||||||
TableNumber: req.TableNumber,
|
TableNumber: req.TableNumber,
|
||||||
|
CashierSessionID: req.CashierSessionID,
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := h.service.CreateOrderInquiry(ctx, orderReq)
|
result, err := h.service.CreateOrderInquiry(ctx, orderReq)
|
||||||
@ -152,6 +160,33 @@ func (h *Handler) Execute(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handler) Refund(c *gin.Context) {
|
||||||
|
ctx := request.GetMyContext(c)
|
||||||
|
|
||||||
|
var req RefundRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
validate := validator.New()
|
||||||
|
if err := validate.Struct(req); err != nil {
|
||||||
|
response.ErrorWrapper(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := h.service.RefundRequest(ctx, *ctx.GetPartnerID(), req.OrderID, req.Reason)
|
||||||
|
if err != nil {
|
||||||
|
response.ErrorWrapper(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, response.BaseResponse{
|
||||||
|
Success: true,
|
||||||
|
Status: http.StatusOK,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handler) GetOrderHistory(c *gin.Context) {
|
func (h *Handler) GetOrderHistory(c *gin.Context) {
|
||||||
ctx := request.GetMyContext(c)
|
ctx := request.GetMyContext(c)
|
||||||
partnerID := ctx.GetPartnerID()
|
partnerID := ctx.GetPartnerID()
|
||||||
|
|||||||
@ -1,461 +0,0 @@
|
|||||||
package order
|
|
||||||
|
|
||||||
import (
|
|
||||||
"enaklo-pos-be/internal/common/errors"
|
|
||||||
"enaklo-pos-be/internal/entity"
|
|
||||||
"enaklo-pos-be/internal/handlers/request"
|
|
||||||
"enaklo-pos-be/internal/handlers/response"
|
|
||||||
"enaklo-pos-be/internal/services"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/go-playground/validator/v10"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Handler struct {
|
|
||||||
service services.Order
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
|
|
||||||
route := group.Group("/order")
|
|
||||||
|
|
||||||
route.POST("/inquiry", jwt, h.Inquiry)
|
|
||||||
route.GET("/print-detail", jwt, h.PrintDetail)
|
|
||||||
route.POST("/execute", jwt, h.Execute)
|
|
||||||
route.GET("/history", jwt, h.GetAllHistoryOrders)
|
|
||||||
route.GET("/ticket-sold", jwt, h.CountSoldOfTicket)
|
|
||||||
route.POST("/checkin/inquiry", jwt, h.CheckInInquiry)
|
|
||||||
route.POST("/checkin/execute", jwt, h.CheckInExecute)
|
|
||||||
route.GET("/sum-amount", jwt, h.SumAmount)
|
|
||||||
route.GET("/daily-sales", jwt, h.GetDailySalesTicket)
|
|
||||||
route.GET("/payment-distribution", jwt, h.GetPaymentDistributionChart)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHandler(service services.Order) *Handler {
|
|
||||||
return &Handler{
|
|
||||||
service: service,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) Inquiry(c *gin.Context) {
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
var req request.Order
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
validate := validator.New()
|
|
||||||
if err := validate.Struct(req); err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
orderRequest := req.ToEntity(*ctx.GetPartnerID(), ctx.RequestedBy())
|
|
||||||
|
|
||||||
order, err := h.service.CreateOrder(ctx, orderRequest)
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: MapOrderToCreateOrderResponse(order),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) PrintDetail(c *gin.Context) {
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
var req request.OrderPrintDetail
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
order, err := h.service.GetPrintDetail(ctx, req.ID)
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: MapOrderToPrintDetailResponse(order, ctx.GetName()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) Execute(c *gin.Context) {
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
var req request.Execute
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ctx.IsCasheer() {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
req.PartnerID = *ctx.GetPartnerID()
|
|
||||||
|
|
||||||
validate := validator.New()
|
|
||||||
if err := validate.Struct(req); err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
order, err := h.service.Execute(ctx, req.ToOrderExecuteRequest(ctx.RequestedBy()))
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: MapOrderToExecuteOrderResponse(order),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) CheckInInquiry(c *gin.Context) {
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
var req request.Checkin
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ctx.IsCasheer() || req.QRCode == "" {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
partnerID := ctx.GetPartnerID()
|
|
||||||
|
|
||||||
resp, err := h.service.CheckInInquiry(ctx, req.QRCode, partnerID)
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: response.CheckingInquiryResponse{
|
|
||||||
Token: resp.Token,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) CheckInExecute(c *gin.Context) {
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
var req request.CheckinExecute
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ctx.IsCasheer() || req.Token == "" {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
partnerID := ctx.GetPartnerID()
|
|
||||||
|
|
||||||
resp, err := h.service.CheckInExecute(ctx, req.Token, partnerID)
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: MapOrderToExecuteCheckinResponse(resp.Order),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func MapOrderToCreateOrderResponse(orderResponse *entity.OrderResponse) response.CreateOrderResponse {
|
|
||||||
order := orderResponse.Order
|
|
||||||
orderItems := make([]response.CreateOrderItemResponse, len(order.OrderItems))
|
|
||||||
for i, item := range order.OrderItems {
|
|
||||||
orderItems[i] = response.CreateOrderItemResponse{
|
|
||||||
ID: item.ID,
|
|
||||||
ItemID: item.ItemID,
|
|
||||||
Quantity: item.Quantity,
|
|
||||||
Price: item.Price,
|
|
||||||
Name: item.Product.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.CreateOrderResponse{
|
|
||||||
ID: order.ID,
|
|
||||||
PartnerID: order.PartnerID,
|
|
||||||
Status: order.Status,
|
|
||||||
Amount: order.Amount,
|
|
||||||
Total: order.Total,
|
|
||||||
Tax: order.Tax,
|
|
||||||
PaymentType: order.PaymentType,
|
|
||||||
CreatedAt: order.CreatedAt,
|
|
||||||
OrderItems: orderItems,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MapOrderToExecuteOrderResponse(orderResponse *entity.ExecuteOrderResponse) response.ExecuteOrderResponse {
|
|
||||||
order := orderResponse.Order
|
|
||||||
orderItems := make([]response.CreateOrderItemResponse, len(order.OrderItems))
|
|
||||||
for i, item := range order.OrderItems {
|
|
||||||
orderItems[i] = response.CreateOrderItemResponse{
|
|
||||||
ID: item.ID,
|
|
||||||
ItemID: item.ItemID,
|
|
||||||
Quantity: item.Quantity,
|
|
||||||
Price: item.Price,
|
|
||||||
Name: item.Product.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.ExecuteOrderResponse{
|
|
||||||
ID: order.ID,
|
|
||||||
PartnerID: order.PartnerID,
|
|
||||||
Status: order.Status,
|
|
||||||
Amount: order.Amount,
|
|
||||||
PaymentType: order.PaymentType,
|
|
||||||
CreatedAt: order.CreatedAt,
|
|
||||||
OrderItems: orderItems,
|
|
||||||
PaymentToken: orderResponse.PaymentToken,
|
|
||||||
RedirectURL: orderResponse.RedirectURL,
|
|
||||||
QRcode: orderResponse.QRCode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MapOrderToExecuteCheckinResponse(order *entity.Order) response.ExecuteCheckinResponse {
|
|
||||||
orderItems := make([]response.CreateOrderItemResponse, len(order.OrderItems))
|
|
||||||
for i, item := range order.OrderItems {
|
|
||||||
orderItems[i] = response.CreateOrderItemResponse{
|
|
||||||
ID: item.ID,
|
|
||||||
ItemID: item.ItemID,
|
|
||||||
Quantity: item.Quantity,
|
|
||||||
Price: item.Price,
|
|
||||||
Name: item.Product.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.ExecuteCheckinResponse{
|
|
||||||
ID: order.ID,
|
|
||||||
PartnerID: order.PartnerID,
|
|
||||||
Status: order.Status,
|
|
||||||
Amount: order.Amount,
|
|
||||||
PaymentType: order.PaymentType,
|
|
||||||
CreatedAt: order.CreatedAt,
|
|
||||||
OrderItems: orderItems,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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("2006-01-02 15:04:05"),
|
|
||||||
BookingTime: resp.BookingTime.Format("2006-01-02 15:04:05"),
|
|
||||||
Tickets: resp.Tickets,
|
|
||||||
PaymentType: resp.PaymentType,
|
|
||||||
Status: resp.Status,
|
|
||||||
Amount: resp.Amount,
|
|
||||||
VisitDate: resp.VisitDate.Format("2006-01-02"),
|
|
||||||
TicketStatus: resp.TicketStatus,
|
|
||||||
Source: resp.Source,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) SumAmount(c *gin.Context) {
|
|
||||||
var req request.OrderParam
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
order, err := h.service.SumAmount(ctx, req.ToOrderEntity(ctx))
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: response.OrderAmount{
|
|
||||||
Amount: order.Amount,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) GetAllHistoryOrders(c *gin.Context) {
|
|
||||||
var req request.OrderParam
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
orders, total, err := h.service.GetAllHistoryOrders(ctx, req.ToOrderEntity(ctx))
|
|
||||||
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) CountSoldOfTicket(c *gin.Context) {
|
|
||||||
var req request.OrderParam
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
res, err := h.service.CountSoldOfTicket(ctx, req.ToOrderEntity(ctx))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: response.TicketSold{
|
|
||||||
Count: res.Count,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) GetDailySalesTicket(c *gin.Context) {
|
|
||||||
var req request.OrderParam
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
resp, err := h.service.GetDailySales(ctx, req.ToOrderEntity(ctx))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: h.toDailySales(resp),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) GetPaymentDistributionChart(c *gin.Context) {
|
|
||||||
var req request.OrderParam
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
resp, err := h.service.GetPaymentDistribution(ctx, req.ToOrderEntity(ctx))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: h.toPaymentDistributionChart(resp),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) toHistoryOrderList(resp []*entity.HistoryOrder, total int64, req request.OrderParam) 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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) toDailySales(resp []entity.ProductDailySales) []response.ProductDailySales {
|
|
||||||
var dailySales []response.ProductDailySales
|
|
||||||
for _, b := range resp {
|
|
||||||
dailySales = append(dailySales, response.ProductDailySales{
|
|
||||||
Day: b.Day,
|
|
||||||
SiteID: b.SiteID,
|
|
||||||
Total: b.Total,
|
|
||||||
SiteName: b.SiteName,
|
|
||||||
PaymentType: b.PaymentType,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return dailySales
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) toPaymentDistributionChart(resp []entity.PaymentTypeDistribution) []response.PaymentDistribution {
|
|
||||||
var dailySales []response.PaymentDistribution
|
|
||||||
for _, b := range resp {
|
|
||||||
dailySales = append(dailySales, response.PaymentDistribution{
|
|
||||||
PaymentType: b.PaymentType,
|
|
||||||
Count: b.Count,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return dailySales
|
|
||||||
}
|
|
||||||
|
|
||||||
func MapOrderToPrintDetailResponse(order *entity.OrderPrintDetail, casherName string) response.PrintDetailResponse {
|
|
||||||
orderItems := make([]response.CreateOrderItemResponse, len(order.OrderItems))
|
|
||||||
for i, item := range order.OrderItems {
|
|
||||||
orderItems[i] = response.CreateOrderItemResponse{
|
|
||||||
ID: item.ID,
|
|
||||||
ItemID: item.ItemID,
|
|
||||||
Quantity: item.Quantity,
|
|
||||||
Price: item.Price,
|
|
||||||
Name: item.Product.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.PrintDetailResponse{
|
|
||||||
ID: order.ID,
|
|
||||||
OrderID: order.OrderID,
|
|
||||||
Total: order.Total,
|
|
||||||
Fee: order.Fee,
|
|
||||||
PaymentType: order.GetPaymanetType(),
|
|
||||||
Source: order.Source,
|
|
||||||
VisitDateAt: order.VisitDate.Format("2006-01-02"),
|
|
||||||
VisitTime: time.Now().Format("15:04:05"),
|
|
||||||
OrderItems: orderItems,
|
|
||||||
CasheerName: casherName,
|
|
||||||
PartnerName: order.SiteName,
|
|
||||||
Logo: order.Logo,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -55,7 +55,6 @@ func (h *Handler) Create(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
req.PartnerID = *ctx.GetPartnerID()
|
req.PartnerID = *ctx.GetPartnerID()
|
||||||
req.SiteID = *ctx.GetSiteID()
|
|
||||||
|
|
||||||
res, err := h.service.Create(ctx, req.ToEntity())
|
res, err := h.service.Create(ctx, req.ToEntity())
|
||||||
|
|
||||||
@ -140,7 +139,9 @@ func (h *Handler) GetAll(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
products, total, err := h.service.GetAll(c.Request.Context(), req.ToEntity())
|
ctx := request.GetMyContext(c)
|
||||||
|
|
||||||
|
products, total, err := h.service.GetAll(ctx, req.ToEntity(*ctx.GetPartnerID()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.ErrorWrapper(c, err)
|
response.ErrorWrapper(c, err)
|
||||||
return
|
return
|
||||||
@ -266,6 +267,13 @@ func (h *Handler) GetByID(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) toProductResponse(resp *entity.Product) response.Product {
|
func (h *Handler) toProductResponse(resp *entity.Product) response.Product {
|
||||||
|
category := response.Category{}
|
||||||
|
|
||||||
|
if resp.Category != nil {
|
||||||
|
category.ID = resp.Category.ID
|
||||||
|
category.Name = resp.Category.Name
|
||||||
|
}
|
||||||
|
|
||||||
return response.Product{
|
return response.Product{
|
||||||
ID: resp.ID,
|
ID: resp.ID,
|
||||||
Name: resp.Name,
|
Name: resp.Name,
|
||||||
@ -274,6 +282,7 @@ func (h *Handler) toProductResponse(resp *entity.Product) response.Product {
|
|||||||
Status: resp.Status,
|
Status: resp.Status,
|
||||||
Description: resp.Description,
|
Description: resp.Description,
|
||||||
Image: resp.Image,
|
Image: resp.Image,
|
||||||
|
Category: category,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,232 +0,0 @@
|
|||||||
package studio
|
|
||||||
|
|
||||||
import (
|
|
||||||
"enaklo-pos-be/internal/common/errors"
|
|
||||||
"enaklo-pos-be/internal/entity"
|
|
||||||
"enaklo-pos-be/internal/handlers/request"
|
|
||||||
"enaklo-pos-be/internal/handlers/response"
|
|
||||||
"enaklo-pos-be/internal/services"
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/go-playground/validator/v10"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StudioHandler struct {
|
|
||||||
service services.Studio
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *StudioHandler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
|
|
||||||
route := group.Group("/studio")
|
|
||||||
|
|
||||||
route.POST("/", jwt, h.Create)
|
|
||||||
route.PUT("/:id", jwt, h.Update)
|
|
||||||
route.GET("/:id", jwt, h.GetByID)
|
|
||||||
route.GET("/search", jwt, h.Search)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewStudioHandler(service services.Studio) *StudioHandler {
|
|
||||||
return &StudioHandler{
|
|
||||||
service: service,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create handles the creation of a new studio.
|
|
||||||
// @Summary Create a new studio
|
|
||||||
// @Description Create a new studio based on the provided details.
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param Authorization header string true "JWT token"
|
|
||||||
// @Param req body request.Studio true "New studio details"
|
|
||||||
// @Success 200 {object} response.BaseResponse{data=response.Studio} "Studio created successfully"
|
|
||||||
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
|
|
||||||
// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized"
|
|
||||||
// @Router /api/v1/studio [post]
|
|
||||||
// @Tags Studio APIs
|
|
||||||
func (h *StudioHandler) Create(c *gin.Context) {
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
var req request.Studio
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
validate := validator.New()
|
|
||||||
if err := validate.Struct(req); err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := h.service.Create(ctx, req.ToEntity())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: h.toStudioResponse(res),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update handles the update of an existing studio.
|
|
||||||
// @Summary Update an existing studio
|
|
||||||
// @Description Update the details of an existing studio based on the provided ID.
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param Authorization header string true "JWT token"
|
|
||||||
// @Param id path int64 true "Studio ID to update"
|
|
||||||
// @Param req body request.Studio true "Updated studio details"
|
|
||||||
// @Success 200 {object} response.BaseResponse{data=response.Studio} "Studio updated successfully"
|
|
||||||
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
|
|
||||||
// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized"
|
|
||||||
// @Router /api/v1/studio/{id} [put]
|
|
||||||
// @Tags Studio APIs
|
|
||||||
func (h *StudioHandler) Update(c *gin.Context) {
|
|
||||||
ctx := request.GetMyContext(c)
|
|
||||||
|
|
||||||
id := c.Param("id")
|
|
||||||
|
|
||||||
studioID, err := strconv.ParseInt(id, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var req request.Studio
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
validate := validator.New()
|
|
||||||
if err := validate.Struct(req); err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
updatedStudio, err := h.service.Update(ctx, studioID, req.ToEntity())
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: h.toStudioResponse(updatedStudio),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search retrieves a list of studios based on search criteria.
|
|
||||||
// @Summary Search for studios
|
|
||||||
// @Description Search for studios based on query parameters.
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param Authorization header string true "JWT token"
|
|
||||||
// @Param Name query string false "Studio name for search"
|
|
||||||
// @Param Status query string false "Studio status for search"
|
|
||||||
// @Param Limit query int false "Number of items to retrieve (default 10)"
|
|
||||||
// @Param Offset query int false "Offset for pagination (default 0)"
|
|
||||||
// @Success 200 {object} response.BaseResponse{data=response.StudioList} "List of studios"
|
|
||||||
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
|
|
||||||
// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized"
|
|
||||||
// @Router /api/v1/studio/search [get]
|
|
||||||
// @Tags Studio APIs
|
|
||||||
func (h *StudioHandler) Search(c *gin.Context) {
|
|
||||||
var req request.StudioParam
|
|
||||||
if err := c.ShouldBindQuery(&req); err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
studios, total, err := h.service.Search(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.toStudioResponseList(studios, int64(total), req),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByID retrieves details of a specific studio by ID.
|
|
||||||
// @Summary Get details of a studio by ID
|
|
||||||
// @Description Get details of a studio based on the provided ID.
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param Authorization header string true "JWT token"
|
|
||||||
// @Param id path int64 true "Studio ID to retrieve"
|
|
||||||
// @Success 200 {object} response.BaseResponse{data=response.Studio} "Studio details"
|
|
||||||
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
|
|
||||||
// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized"
|
|
||||||
// @Router /api/v1/studio/{id} [get]
|
|
||||||
// @Tags Studio APIs
|
|
||||||
func (h *StudioHandler) GetByID(c *gin.Context) {
|
|
||||||
id := c.Param("id")
|
|
||||||
|
|
||||||
studioID, err := strconv.ParseInt(id, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := h.service.GetByID(c.Request.Context(), studioID)
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusInternalServerError, response.BaseResponse{
|
|
||||||
Success: false,
|
|
||||||
Status: http.StatusInternalServerError,
|
|
||||||
Message: err.Error(),
|
|
||||||
Data: nil,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response.BaseResponse{
|
|
||||||
Success: true,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
Data: h.toStudioResponse(res),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *StudioHandler) toStudioResponse(resp *entity.Studio) response.Studio {
|
|
||||||
metadata := make(map[string]interface{})
|
|
||||||
if err := json.Unmarshal(resp.Metadata, &metadata); err != nil {
|
|
||||||
//TODO taufanvps
|
|
||||||
// Handle the error if the metadata cannot be unmarshaled.
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.Studio{
|
|
||||||
ID: &resp.ID,
|
|
||||||
BranchId: &resp.BranchId,
|
|
||||||
Name: resp.Name,
|
|
||||||
Status: string(resp.Status),
|
|
||||||
Price: resp.Price,
|
|
||||||
Metadata: metadata,
|
|
||||||
CreatedAt: resp.CreatedAt.Format(time.RFC3339),
|
|
||||||
UpdatedAt: resp.CreatedAt.Format(time.RFC3339),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *StudioHandler) toStudioResponseList(resp []*entity.Studio, total int64, req request.StudioParam) response.StudioList {
|
|
||||||
var studios []response.Studio
|
|
||||||
for _, b := range resp {
|
|
||||||
studios = append(studios, h.toStudioResponse(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.StudioList{
|
|
||||||
Studios: studios,
|
|
||||||
Total: total,
|
|
||||||
Limit: req.Limit,
|
|
||||||
Offset: req.Offset,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
18
internal/handlers/request/cashier.go
Normal file
18
internal/handlers/request/cashier.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import "enaklo-pos-be/internal/entity"
|
||||||
|
|
||||||
|
type OpenCashierSessionRequest struct {
|
||||||
|
OpeningAmount float64 `json:"opening_amount" validate:"required,gt=0"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CloseCashierSessionRequest struct {
|
||||||
|
ClosingAmount float64 `json:"closing_amount" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OpenCashierSessionRequest) ToEntity(cashierID int64) *entity.CashierSession {
|
||||||
|
return &entity.CashierSession{
|
||||||
|
CashierID: cashierID,
|
||||||
|
OpeningAmount: o.OpeningAmount,
|
||||||
|
}
|
||||||
|
}
|
||||||
14
internal/handlers/request/category.go
Normal file
14
internal/handlers/request/category.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import "enaklo-pos-be/internal/entity"
|
||||||
|
|
||||||
|
type CategoryRequest struct {
|
||||||
|
Name string `json:"name" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CategoryRequest) ToEntity(partnerID int64) *entity.Category {
|
||||||
|
return &entity.Category{
|
||||||
|
PartnerID: partnerID,
|
||||||
|
Name: r.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,17 +13,19 @@ type ProductParam struct {
|
|||||||
Available product.ProductStock `form:"available" json:"available" example:"1" example:"AVAILABLE/UNAVAILABLE"`
|
Available product.ProductStock `form:"available" json:"available" example:"1" example:"AVAILABLE/UNAVAILABLE"`
|
||||||
Limit int `form:"limit" json:"limit" example:"10"`
|
Limit int `form:"limit" json:"limit" example:"10"`
|
||||||
Offset int `form:"offset" json:"offset" example:"0"`
|
Offset int `form:"offset" json:"offset" example:"0"`
|
||||||
|
CategoryID int64 `form:"category_id" json:"category_id" example:"1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProductParam) ToEntity() entity.ProductSearch {
|
func (p *ProductParam) ToEntity(partnerID int64) entity.ProductSearch {
|
||||||
return entity.ProductSearch{
|
return entity.ProductSearch{
|
||||||
Search: p.Search,
|
Search: p.Search,
|
||||||
Name: p.Name,
|
Name: p.Name,
|
||||||
Type: p.Type,
|
Type: p.Type,
|
||||||
BranchID: p.BranchID,
|
PartnerID: partnerID,
|
||||||
Available: p.Available,
|
Available: p.Available,
|
||||||
Limit: p.Limit,
|
Limit: p.Limit,
|
||||||
Offset: p.Offset,
|
Offset: p.Offset,
|
||||||
|
CategoryID: p.CategoryID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,6 +42,7 @@ type Product struct {
|
|||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Stock int64 `json:"stock"`
|
Stock int64 `json:"stock"`
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
|
CategoryID int64 `json:"category_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Product) ToEntity() *entity.Product {
|
func (e *Product) ToEntity() *entity.Product {
|
||||||
@ -51,5 +54,6 @@ func (e *Product) ToEntity() *entity.Product {
|
|||||||
Description: e.Description,
|
Description: e.Description,
|
||||||
PartnerID: e.PartnerID,
|
PartnerID: e.PartnerID,
|
||||||
Image: e.Image,
|
Image: e.Image,
|
||||||
|
CategoryID: &e.CategoryID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
62
internal/handlers/response/cashier.go
Normal file
62
internal/handlers/response/cashier.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"enaklo-pos-be/internal/entity"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CashierSessionResponse struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
CashierID int64 `json:"cashier_id"`
|
||||||
|
OpenedAt time.Time `json:"opened_at"`
|
||||||
|
ClosedAt *time.Time `json:"closed_at,omitempty"`
|
||||||
|
OpeningAmount float64 `json:"opening_amount"`
|
||||||
|
ClosingAmount *float64 `json:"closing_amount,omitempty"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaymentSummaryResponse struct {
|
||||||
|
PaymentType string `json:"payment_type"`
|
||||||
|
PaymentProvider string `json:"payment_provider"`
|
||||||
|
TotalAmount float64 `json:"total_amount"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CashierSessionReportResponse struct {
|
||||||
|
SessionID int64 `json:"session_id"`
|
||||||
|
ExpectedAmount float64 `json:"expected_amount"`
|
||||||
|
ClosingAmount float64 `json:"closing_amount"`
|
||||||
|
Payments []PaymentSummaryResponse `json:"payments"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func MapToCashierSessionResponse(e *entity.CashierSession) *CashierSessionResponse {
|
||||||
|
if e == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &CashierSessionResponse{
|
||||||
|
ID: e.ID,
|
||||||
|
CashierID: e.CashierID,
|
||||||
|
OpenedAt: e.OpenedAt,
|
||||||
|
ClosedAt: e.ClosedAt,
|
||||||
|
OpeningAmount: e.OpeningAmount,
|
||||||
|
ClosingAmount: e.ClosingAmount,
|
||||||
|
Status: e.Status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MapToCashierSessionReport(e *entity.CashierSessionReport) *CashierSessionReportResponse {
|
||||||
|
payments := make([]PaymentSummaryResponse, len(e.Payments))
|
||||||
|
for i, p := range e.Payments {
|
||||||
|
payments[i] = PaymentSummaryResponse{
|
||||||
|
PaymentType: p.PaymentType,
|
||||||
|
PaymentProvider: p.PaymentProvider,
|
||||||
|
TotalAmount: p.TotalAmount,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &CashierSessionReportResponse{
|
||||||
|
SessionID: e.SessionID,
|
||||||
|
ExpectedAmount: e.ExpectedAmount,
|
||||||
|
ClosingAmount: e.ClosingAmount,
|
||||||
|
Payments: payments,
|
||||||
|
}
|
||||||
|
}
|
||||||
29
internal/handlers/response/category.go
Normal file
29
internal/handlers/response/category.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import "enaklo-pos-be/internal/entity"
|
||||||
|
|
||||||
|
type CategoryResponse struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
PartnerID int64 `json:"partner_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func MapToCategoryResponse(cat *entity.Category) *CategoryResponse {
|
||||||
|
if cat == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &CategoryResponse{
|
||||||
|
ID: cat.ID,
|
||||||
|
Name: cat.Name,
|
||||||
|
PartnerID: cat.PartnerID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MapToCategoryListResponse(cats []*entity.Category) []*CategoryResponse {
|
||||||
|
result := make([]*CategoryResponse, len(cats))
|
||||||
|
for i, c := range cats {
|
||||||
|
result[i] = MapToCategoryResponse(c)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
@ -8,6 +8,12 @@ type Product struct {
|
|||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
|
Category Category `json:"category"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Category struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProductList struct {
|
type ProductList struct {
|
||||||
|
|||||||
137
internal/repository/casheer_seasion.go
Normal file
137
internal/repository/casheer_seasion.go
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"enaklo-pos-be/internal/common/mycontext"
|
||||||
|
"enaklo-pos-be/internal/entity"
|
||||||
|
"enaklo-pos-be/internal/repository/models"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CashierSessionRepository interface {
|
||||||
|
CreateSession(ctx mycontext.Context, session *entity.CashierSession) (*entity.CashierSession, error)
|
||||||
|
CloseSession(ctx mycontext.Context, sessionID int64, closingAmount, expectedAmount float64) error
|
||||||
|
GetOpenSessionByCashierID(ctx mycontext.Context, cashierID int64) (*entity.CashierSession, error)
|
||||||
|
GetSessionByID(ctx mycontext.Context, sessionID int64) (*entity.CashierSession, error)
|
||||||
|
GetPaymentSummaryBySessionID(ctx mycontext.Context, sessionID int64) ([]entity.PaymentSummary, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type cashierSessionRepository struct {
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCashierSessionRepository(db *gorm.DB) CashierSessionRepository {
|
||||||
|
return &cashierSessionRepository{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *cashierSessionRepository) CreateSession(ctx mycontext.Context, session *entity.CashierSession) (*entity.CashierSession, error) {
|
||||||
|
dbModel := models.CashierSessionDB{
|
||||||
|
CashierID: session.CashierID,
|
||||||
|
OpenedAt: time.Now(),
|
||||||
|
OpeningAmount: session.OpeningAmount,
|
||||||
|
Status: "open",
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.db.Create(&dbModel).Error; err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to create cashier session")
|
||||||
|
}
|
||||||
|
|
||||||
|
session.ID = dbModel.ID
|
||||||
|
session.Status = dbModel.Status
|
||||||
|
session.OpenedAt = dbModel.OpenedAt
|
||||||
|
|
||||||
|
return session, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *cashierSessionRepository) CloseSession(ctx mycontext.Context, sessionID int64, closingAmount, expectedAmount float64) error {
|
||||||
|
result := r.db.Model(&models.CashierSessionDB{}).
|
||||||
|
Where("id = ?", sessionID).
|
||||||
|
Updates(map[string]interface{}{
|
||||||
|
"closed_at": time.Now(),
|
||||||
|
"closing_amount": closingAmount,
|
||||||
|
"expected_amount": expectedAmount,
|
||||||
|
"status": "closed",
|
||||||
|
})
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return errors.Wrap(result.Error, "failed to close session")
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.RowsAffected == 0 {
|
||||||
|
return errors.New("no session updated")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *cashierSessionRepository) GetOpenSessionByCashierID(ctx mycontext.Context, cashierID int64) (*entity.CashierSession, error) {
|
||||||
|
var dbModel models.CashierSessionDB
|
||||||
|
if err := r.db.Where("cashier_id = ? AND status = 'open'", cashierID).
|
||||||
|
Order("opened_at DESC").First(&dbModel).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, errors.Wrap(err, "failed to get open session")
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.toEntity(&dbModel), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *cashierSessionRepository) GetSessionByID(ctx mycontext.Context, sessionID int64) (*entity.CashierSession, error) {
|
||||||
|
var dbModel models.CashierSessionDB
|
||||||
|
if err := r.db.First(&dbModel, sessionID).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, errors.Wrap(err, "failed to get session by ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.toEntity(&dbModel), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *cashierSessionRepository) toEntity(db *models.CashierSessionDB) *entity.CashierSession {
|
||||||
|
return &entity.CashierSession{
|
||||||
|
ID: db.ID,
|
||||||
|
CashierID: db.CashierID,
|
||||||
|
OpenedAt: db.OpenedAt,
|
||||||
|
ClosedAt: db.ClosedAt,
|
||||||
|
OpeningAmount: db.OpeningAmount,
|
||||||
|
ClosingAmount: db.ClosingAmount,
|
||||||
|
ExpectedAmount: db.ExpectedAmount,
|
||||||
|
Status: db.Status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *cashierSessionRepository) GetPaymentSummaryBySessionID(ctx mycontext.Context, sessionID int64) ([]entity.PaymentSummary, error) {
|
||||||
|
type result struct {
|
||||||
|
PaymentType string
|
||||||
|
PaymentProvider string
|
||||||
|
TotalAmount float64
|
||||||
|
}
|
||||||
|
|
||||||
|
var rows []result
|
||||||
|
|
||||||
|
err := r.db.WithContext(ctx).
|
||||||
|
Table("orders").
|
||||||
|
Select("payment_type, payment_provider, SUM(total) AS total_amount").
|
||||||
|
Where("cashier_session_id = ?", sessionID).
|
||||||
|
Group("payment_type, payment_provider").
|
||||||
|
Scan(&rows).Error
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to summarize payments from orders")
|
||||||
|
}
|
||||||
|
|
||||||
|
summary := make([]entity.PaymentSummary, len(rows))
|
||||||
|
for i, row := range rows {
|
||||||
|
summary[i] = entity.PaymentSummary{
|
||||||
|
PaymentType: row.PaymentType,
|
||||||
|
PaymentProvider: row.PaymentProvider,
|
||||||
|
TotalAmount: row.TotalAmount,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return summary, nil
|
||||||
|
}
|
||||||
94
internal/repository/categories_repo.go
Normal file
94
internal/repository/categories_repo.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"enaklo-pos-be/internal/common/mycontext"
|
||||||
|
"enaklo-pos-be/internal/entity"
|
||||||
|
"enaklo-pos-be/internal/repository/models"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CategoryRepository interface {
|
||||||
|
Create(ctx mycontext.Context, category *entity.Category) (*entity.Category, error)
|
||||||
|
GetByPartnerID(ctx mycontext.Context, partnerID int64) ([]*entity.Category, error)
|
||||||
|
GetByID(ctx mycontext.Context, id int64) (*entity.Category, error)
|
||||||
|
Update(ctx mycontext.Context, category *entity.Category) error
|
||||||
|
Delete(ctx mycontext.Context, id int64) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type categoryRepository struct {
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCategoryRepository(db *gorm.DB) CategoryRepository {
|
||||||
|
return &categoryRepository{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *categoryRepository) Create(ctx mycontext.Context, category *entity.Category) (*entity.Category, error) {
|
||||||
|
dbModel := &models.CategoryDB{
|
||||||
|
PartnerID: category.PartnerID,
|
||||||
|
Name: category.Name,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
UpdatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
if err := r.db.WithContext(ctx).Create(dbModel).Error; err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to create category")
|
||||||
|
}
|
||||||
|
category.ID = dbModel.ID
|
||||||
|
return category, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *categoryRepository) GetByPartnerID(ctx mycontext.Context, partnerID int64) ([]*entity.Category, error) {
|
||||||
|
var dbModels []models.CategoryDB
|
||||||
|
if err := r.db.WithContext(ctx).
|
||||||
|
Where("partner_id = ? AND deleted_at IS NULL", partnerID).
|
||||||
|
Find(&dbModels).Error; err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to fetch categories by partner ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []*entity.Category
|
||||||
|
for _, db := range dbModels {
|
||||||
|
result = append(result, r.toEntity(&db))
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *categoryRepository) GetByID(ctx mycontext.Context, id int64) (*entity.Category, error) {
|
||||||
|
var db models.CategoryDB
|
||||||
|
if err := r.db.WithContext(ctx).
|
||||||
|
Where("id = ? AND deleted_at IS NULL", id).
|
||||||
|
First(&db).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, errors.Wrap(err, "failed to get category by ID")
|
||||||
|
}
|
||||||
|
return r.toEntity(&db), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *categoryRepository) Update(ctx mycontext.Context, category *entity.Category) error {
|
||||||
|
return r.db.WithContext(ctx).Model(&models.CategoryDB{}).
|
||||||
|
Where("id = ?", category.ID).
|
||||||
|
Updates(map[string]interface{}{
|
||||||
|
"name": category.Name,
|
||||||
|
"updated_at": time.Now(),
|
||||||
|
}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *categoryRepository) Delete(ctx mycontext.Context, id int64) error {
|
||||||
|
return r.db.WithContext(ctx).
|
||||||
|
Model(&models.CategoryDB{}).
|
||||||
|
Where("id = ?", id).
|
||||||
|
Update("deleted_at", time.Now()).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *categoryRepository) toEntity(db *models.CategoryDB) *entity.Category {
|
||||||
|
return &entity.Category{
|
||||||
|
ID: db.ID,
|
||||||
|
PartnerID: db.PartnerID,
|
||||||
|
Name: db.Name,
|
||||||
|
CreatedAt: db.CreatedAt.Unix(),
|
||||||
|
UpdatedAt: db.UpdatedAt.Unix(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,86 +0,0 @@
|
|||||||
package event
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
|
|
||||||
"enaklo-pos-be/internal/common/logger"
|
|
||||||
"enaklo-pos-be/internal/entity"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EventRepoImpl struct {
|
|
||||||
DB *gorm.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEventRepo(db *gorm.DB) *EventRepoImpl {
|
|
||||||
return &EventRepoImpl{DB: db}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EventRepoImpl) CreateEvent(ctx context.Context, event *entity.EventDB) (*entity.EventDB, error) {
|
|
||||||
err := e.DB.Create(event).Error
|
|
||||||
if err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when create event", zap.Error(err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return event, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EventRepoImpl) UpdateEvent(ctx context.Context, event *entity.EventDB) (*entity.EventDB, error) {
|
|
||||||
if err := e.DB.Save(event).Error; err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when update event", zap.Error(err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return event, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EventRepoImpl) GetEventByID(ctx context.Context, id int64) (*entity.EventDB, error) {
|
|
||||||
event := new(entity.EventDB)
|
|
||||||
if err := e.DB.First(event, id).Error; err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when get event by id", zap.Error(err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return event, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EventRepoImpl) GetAllEvents(ctx context.Context, nameFilter string, limit, offset int) (entity.EventList, int, error) {
|
|
||||||
var events []*entity.EventDB
|
|
||||||
var total int64
|
|
||||||
|
|
||||||
query := e.DB
|
|
||||||
query = query.Where("deleted_at is null")
|
|
||||||
|
|
||||||
if nameFilter != "" {
|
|
||||||
query = query.Where("name LIKE ?", "%"+nameFilter+"%")
|
|
||||||
}
|
|
||||||
|
|
||||||
if limit > 0 {
|
|
||||||
query = query.Limit(limit)
|
|
||||||
}
|
|
||||||
if offset > 0 {
|
|
||||||
query = query.Offset(offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := query.Find(&events).Error; err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when get all events", zap.Error(err))
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := e.DB.Model(&entity.EventDB{}).Where(query).Count(&total).Error; err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when count event", zap.Error(err))
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return events, int(total), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EventRepoImpl) DeleteEvent(ctx context.Context, id int64) error {
|
|
||||||
event := new(entity.EventDB)
|
|
||||||
event.ID = id
|
|
||||||
if err := e.DB.Delete(event).Error; err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when get all events", zap.Error(err))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
20
internal/repository/models/casheer_seasion.go
Normal file
20
internal/repository/models/casheer_seasion.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type CashierSessionDB struct {
|
||||||
|
ID int64 `gorm:"primaryKey"`
|
||||||
|
CashierID int64 `gorm:"not null"`
|
||||||
|
OpenedAt time.Time `gorm:"not null"`
|
||||||
|
ClosedAt *time.Time
|
||||||
|
OpeningAmount float64 `gorm:"not null"`
|
||||||
|
ClosingAmount *float64
|
||||||
|
ExpectedAmount *float64
|
||||||
|
Notes *string
|
||||||
|
Status string `gorm:"not null"`
|
||||||
|
CreatedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (CashierSessionDB) TableName() string {
|
||||||
|
return "cashier_sessions"
|
||||||
|
}
|
||||||
16
internal/repository/models/categories.go
Normal file
16
internal/repository/models/categories.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type CategoryDB struct {
|
||||||
|
ID int64 `gorm:"primaryKey;autoIncrement"`
|
||||||
|
PartnerID int64 `gorm:"not null"`
|
||||||
|
Name string `gorm:"type:varchar(255);not null"`
|
||||||
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
|
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||||
|
DeletedAt *time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (CategoryDB) TableName() string {
|
||||||
|
return "categories"
|
||||||
|
}
|
||||||
@ -23,6 +23,8 @@ type OrderDB struct {
|
|||||||
TableNumber string `gorm:"column:table_number"`
|
TableNumber string `gorm:"column:table_number"`
|
||||||
PaymentProvider string `gorm:"column:payment_provider"`
|
PaymentProvider string `gorm:"column:payment_provider"`
|
||||||
CustomerName string `gorm:"column:customer_name"`
|
CustomerName string `gorm:"column:customer_name"`
|
||||||
|
CashierSessionID int64 `gorm:"column:cashier_session_id"`
|
||||||
|
Description string `gorm:"column:description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (OrderDB) TableName() string {
|
func (OrderDB) TableName() string {
|
||||||
@ -68,6 +70,7 @@ type OrderInquiryDB struct {
|
|||||||
PaymentProvider string `gorm:"column:payment_provider"`
|
PaymentProvider string `gorm:"column:payment_provider"`
|
||||||
TableNumber string `gorm:"column:table_number"`
|
TableNumber string `gorm:"column:table_number"`
|
||||||
OrderType string `gorm:"column:order_type"`
|
OrderType string `gorm:"column:order_type"`
|
||||||
|
CashierSessionID int64 `gorm:"column:cashier_session_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (OrderInquiryDB) TableName() string {
|
func (OrderInquiryDB) TableName() string {
|
||||||
|
|||||||
@ -40,6 +40,7 @@ type OrderRepository interface {
|
|||||||
FindByIDAndPartnerID(ctx mycontext.Context, id int64, partnerID int64) (*entity.Order, error)
|
FindByIDAndPartnerID(ctx mycontext.Context, id int64, partnerID int64) (*entity.Order, error)
|
||||||
GetOrderHistoryByUserID(ctx mycontext.Context, userID int64, req entity.SearchRequest) ([]*entity.Order, int64, error)
|
GetOrderHistoryByUserID(ctx mycontext.Context, userID int64, req entity.SearchRequest) ([]*entity.Order, int64, error)
|
||||||
FindByIDAndCustomerID(ctx mycontext.Context, id int64, customerID int64) (*entity.Order, error)
|
FindByIDAndCustomerID(ctx mycontext.Context, id int64, customerID int64) (*entity.Order, error)
|
||||||
|
UpdateOrder(ctx mycontext.Context, id int64, status string, description string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type orderRepository struct {
|
type orderRepository struct {
|
||||||
@ -232,6 +233,28 @@ func (r *orderRepository) UpdateInquiryStatus(ctx mycontext.Context, id string,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *orderRepository) UpdateOrder(ctx mycontext.Context, id int64, status string, description string) error {
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
result := r.db.Model(&models.OrderDB{}).
|
||||||
|
Where("id = ?", id).
|
||||||
|
Updates(map[string]interface{}{
|
||||||
|
"status": status,
|
||||||
|
"updated_at": now,
|
||||||
|
"description": description,
|
||||||
|
})
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return errors.Wrap(result.Error, "failed to update order status")
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.RowsAffected == 0 {
|
||||||
|
logger.ContextLogger(ctx).Warn("no order updated")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *orderRepository) toOrderDBModel(order *entity.Order) models.OrderDB {
|
func (r *orderRepository) toOrderDBModel(order *entity.Order) models.OrderDB {
|
||||||
return models.OrderDB{
|
return models.OrderDB{
|
||||||
ID: order.ID,
|
ID: order.ID,
|
||||||
@ -251,6 +274,7 @@ func (r *orderRepository) toOrderDBModel(order *entity.Order) models.OrderDB {
|
|||||||
TableNumber: order.TableNumber,
|
TableNumber: order.TableNumber,
|
||||||
PaymentProvider: order.PaymentProvider,
|
PaymentProvider: order.PaymentProvider,
|
||||||
CustomerName: order.CustomerName,
|
CustomerName: order.CustomerName,
|
||||||
|
CashierSessionID: order.CashierSessionID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,6 +370,7 @@ func (r *orderRepository) toOrderInquiryDBModel(inquiry *entity.OrderInquiry) mo
|
|||||||
PaymentProvider: inquiry.PaymentProvider,
|
PaymentProvider: inquiry.PaymentProvider,
|
||||||
OrderType: inquiry.OrderType,
|
OrderType: inquiry.OrderType,
|
||||||
TableNumber: inquiry.TableNumber,
|
TableNumber: inquiry.TableNumber,
|
||||||
|
CashierSessionID: inquiry.CashierSessionID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,6 +392,7 @@ func (r *orderRepository) toDomainOrderInquiryModel(dbModel *models.OrderInquiry
|
|||||||
CustomerName: dbModel.CustomerName,
|
CustomerName: dbModel.CustomerName,
|
||||||
PaymentProvider: dbModel.PaymentProvider,
|
PaymentProvider: dbModel.PaymentProvider,
|
||||||
TableNumber: dbModel.TableNumber,
|
TableNumber: dbModel.TableNumber,
|
||||||
|
CashierSessionID: dbModel.CashierSessionID,
|
||||||
}
|
}
|
||||||
|
|
||||||
if dbModel.CustomerID != nil {
|
if dbModel.CustomerID != nil {
|
||||||
@ -718,7 +744,7 @@ func (r *orderRepository) GetRevenueOverview(
|
|||||||
ctx mycontext.Context,
|
ctx mycontext.Context,
|
||||||
req entity.RevenueOverviewRequest,
|
req entity.RevenueOverviewRequest,
|
||||||
) ([]entity.RevenueOverviewItem, error) {
|
) ([]entity.RevenueOverviewItem, error) {
|
||||||
var overview []entity.RevenueOverviewItem
|
overview := []entity.RevenueOverviewItem{}
|
||||||
|
|
||||||
baseQuery := r.db.Model(&models.OrderDB{}).
|
baseQuery := r.db.Model(&models.OrderDB{}).
|
||||||
Where("partner_id = ?", req.PartnerID).
|
Where("partner_id = ?", req.PartnerID).
|
||||||
|
|||||||
@ -38,7 +38,7 @@ func (b *ProductRepository) UpdateProduct(ctx context.Context, product *entity.P
|
|||||||
|
|
||||||
func (b *ProductRepository) GetProductByID(ctx context.Context, id int64) (*entity.ProductDB, error) {
|
func (b *ProductRepository) GetProductByID(ctx context.Context, id int64) (*entity.ProductDB, error) {
|
||||||
product := new(entity.ProductDB)
|
product := new(entity.ProductDB)
|
||||||
if err := b.db.First(product, id).Error; err != nil {
|
if err := b.db.Preload("Category").First(product, id).Error; err != nil {
|
||||||
logger.ContextLogger(ctx).Error("error when get by id product", zap.Error(err))
|
logger.ContextLogger(ctx).Error("error when get by id product", zap.Error(err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -84,8 +84,12 @@ func (b *ProductRepository) GetAllProducts(ctx context.Context, req entity.Produ
|
|||||||
query = query.Where("type = ? ", req.Type)
|
query = query.Where("type = ? ", req.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.BranchID > 0 {
|
if req.CategoryID > 0 {
|
||||||
query = query.Where("branch_id = ? ", req.BranchID)
|
query = query.Where("category_id = ? ", req.CategoryID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.PartnerID > 0 {
|
||||||
|
query = query.Where("partner_id = ? ", req.PartnerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Limit > 0 {
|
if req.Limit > 0 {
|
||||||
@ -96,7 +100,7 @@ func (b *ProductRepository) GetAllProducts(ctx context.Context, req entity.Produ
|
|||||||
query = query.Offset(req.Offset)
|
query = query.Offset(req.Offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := query.Find(&products).Error; err != nil {
|
if err := query.Preload("Category").Find(&products).Order("id ASC").Error; err != nil {
|
||||||
logger.ContextLogger(ctx).Error("error when get all products", zap.Error(err))
|
logger.ContextLogger(ctx).Error("error when get all products", zap.Error(err))
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import (
|
|||||||
pg "enaklo-pos-be/internal/repository/payment_gateway"
|
pg "enaklo-pos-be/internal/repository/payment_gateway"
|
||||||
"enaklo-pos-be/internal/repository/products"
|
"enaklo-pos-be/internal/repository/products"
|
||||||
"enaklo-pos-be/internal/repository/sites"
|
"enaklo-pos-be/internal/repository/sites"
|
||||||
"enaklo-pos-be/internal/repository/studios"
|
|
||||||
transactions "enaklo-pos-be/internal/repository/transaction"
|
transactions "enaklo-pos-be/internal/repository/transaction"
|
||||||
"enaklo-pos-be/internal/repository/trx"
|
"enaklo-pos-be/internal/repository/trx"
|
||||||
"enaklo-pos-be/internal/repository/users"
|
"enaklo-pos-be/internal/repository/users"
|
||||||
@ -28,15 +27,12 @@ import (
|
|||||||
"enaklo-pos-be/internal/entity"
|
"enaklo-pos-be/internal/entity"
|
||||||
"enaklo-pos-be/internal/repository/auth"
|
"enaklo-pos-be/internal/repository/auth"
|
||||||
"enaklo-pos-be/internal/repository/crypto"
|
"enaklo-pos-be/internal/repository/crypto"
|
||||||
event "enaklo-pos-be/internal/repository/events"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type RepoManagerImpl struct {
|
type RepoManagerImpl struct {
|
||||||
Crypto Crypto
|
Crypto Crypto
|
||||||
Auth Auth
|
Auth Auth
|
||||||
Event Event
|
|
||||||
User User
|
User User
|
||||||
Studio Studio
|
|
||||||
Product Product
|
Product Product
|
||||||
Order Order
|
Order Order
|
||||||
OSS OSSRepository
|
OSS OSSRepository
|
||||||
@ -60,15 +56,15 @@ type RepoManagerImpl struct {
|
|||||||
MemberRepository MemberRepository
|
MemberRepository MemberRepository
|
||||||
PartnerSetting PartnerSettingsRepository
|
PartnerSetting PartnerSettingsRepository
|
||||||
UndianRepository UndianRepo
|
UndianRepository UndianRepo
|
||||||
|
CashierSeasionRepo CashierSessionRepository
|
||||||
|
CategoryRepository CategoryRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRepoManagerImpl(db *gorm.DB, cfg *config.Config) *RepoManagerImpl {
|
func NewRepoManagerImpl(db *gorm.DB, cfg *config.Config) *RepoManagerImpl {
|
||||||
return &RepoManagerImpl{
|
return &RepoManagerImpl{
|
||||||
Crypto: crypto.NewCrypto(cfg.Auth()),
|
Crypto: crypto.NewCrypto(cfg.Auth()),
|
||||||
Auth: auth.NewAuthRepository(db),
|
Auth: auth.NewAuthRepository(db),
|
||||||
Event: event.NewEventRepo(db),
|
|
||||||
User: users.NewUserRepository(db),
|
User: users.NewUserRepository(db),
|
||||||
Studio: studios.NewStudioRepository(db),
|
|
||||||
Product: products.NewProductRepository(db),
|
Product: products.NewProductRepository(db),
|
||||||
Order: orders.NewOrderRepository(db),
|
Order: orders.NewOrderRepository(db),
|
||||||
OSS: oss.NewOssRepositoryImpl(cfg.OSSConfig),
|
OSS: oss.NewOssRepositoryImpl(cfg.OSSConfig),
|
||||||
@ -92,6 +88,8 @@ func NewRepoManagerImpl(db *gorm.DB, cfg *config.Config) *RepoManagerImpl {
|
|||||||
InProgressOrderRepo: NewInProgressOrderRepository(db),
|
InProgressOrderRepo: NewInProgressOrderRepository(db),
|
||||||
PartnerSetting: NewPartnerSettingsRepository(db),
|
PartnerSetting: NewPartnerSettingsRepository(db),
|
||||||
UndianRepository: NewUndianRepository(db),
|
UndianRepository: NewUndianRepository(db),
|
||||||
|
CashierSeasionRepo: NewCashierSessionRepository(db),
|
||||||
|
CategoryRepository: NewCategoryRepository(db),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,14 +99,6 @@ type Auth interface {
|
|||||||
UpdatePassword(ctx context.Context, trx *gorm.DB, newHashedPassword string, userID int64, resetPassword bool) error
|
UpdatePassword(ctx context.Context, trx *gorm.DB, newHashedPassword string, userID int64, resetPassword bool) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Event interface {
|
|
||||||
CreateEvent(ctx context.Context, event *entity.EventDB) (*entity.EventDB, error)
|
|
||||||
UpdateEvent(ctx context.Context, event *entity.EventDB) (*entity.EventDB, error)
|
|
||||||
GetEventByID(ctx context.Context, id int64) (*entity.EventDB, error)
|
|
||||||
GetAllEvents(ctx context.Context, nameFilter string, limit, offset int) (entity.EventList, int, error)
|
|
||||||
DeleteEvent(ctx context.Context, id int64) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type Crypto interface {
|
type Crypto interface {
|
||||||
CompareHashAndPassword(hash string, password string) bool
|
CompareHashAndPassword(hash string, password string) bool
|
||||||
ValidateWT(tokenString string) (*jwt.Token, error)
|
ValidateWT(tokenString string) (*jwt.Token, error)
|
||||||
|
|||||||
@ -1,89 +0,0 @@
|
|||||||
package studios
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"enaklo-pos-be/internal/common/logger"
|
|
||||||
"enaklo-pos-be/internal/entity"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StudioRepository struct {
|
|
||||||
db *gorm.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewStudioRepository(db *gorm.DB) *StudioRepository {
|
|
||||||
return &StudioRepository{
|
|
||||||
db: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StudioRepository) CreateStudio(ctx context.Context, studio *entity.StudioDB) (*entity.StudioDB, error) {
|
|
||||||
err := s.db.Omit("ID").Create(studio).Error
|
|
||||||
if err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when creating studio", zap.Error(err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return studio, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StudioRepository) UpdateStudio(ctx context.Context, studio *entity.StudioDB) (*entity.StudioDB, error) {
|
|
||||||
if err := s.db.Save(studio).Error; err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when updating studio", zap.Error(err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return studio, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StudioRepository) GetStudioByID(ctx context.Context, id int64) (*entity.StudioDB, error) {
|
|
||||||
studio := new(entity.StudioDB)
|
|
||||||
if err := s.db.First(studio, id).Error; err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when getting studio by ID", zap.Error(err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return studio, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StudioRepository) SearchStudios(ctx context.Context, req entity.StudioSearch) (entity.StudioList, int, error) {
|
|
||||||
var studios []*entity.StudioDB
|
|
||||||
var total int64
|
|
||||||
|
|
||||||
query := s.db
|
|
||||||
|
|
||||||
if req.Id > 0 {
|
|
||||||
query = query.Where("id = ?", req.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Name != "" {
|
|
||||||
query = query.Where("name ILIKE ?", "%"+req.Name+"%")
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Status != "" {
|
|
||||||
query = query.Where("status = ?", req.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.BranchId > 0 {
|
|
||||||
query = query.Where("branch_id = ?", req.BranchId)
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Limit > 0 {
|
|
||||||
query = query.Limit(req.Limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Offset > 0 {
|
|
||||||
query = query.Offset(req.Offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := query.Find(&studios).Error; err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when getting all studios", zap.Error(err))
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.db.Model(&entity.StudioDB{}).Where(query).Count(&total).Error; err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when counting studios", zap.Error(err))
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return studios, int(total), nil
|
|
||||||
}
|
|
||||||
@ -3,7 +3,6 @@ package routes
|
|||||||
import (
|
import (
|
||||||
"enaklo-pos-be/internal/handlers/http"
|
"enaklo-pos-be/internal/handlers/http"
|
||||||
"enaklo-pos-be/internal/handlers/http/customerauth"
|
"enaklo-pos-be/internal/handlers/http/customerauth"
|
||||||
"enaklo-pos-be/internal/handlers/http/discovery"
|
|
||||||
"enaklo-pos-be/internal/middlewares"
|
"enaklo-pos-be/internal/middlewares"
|
||||||
|
|
||||||
"enaklo-pos-be/internal/app"
|
"enaklo-pos-be/internal/app"
|
||||||
@ -19,7 +18,6 @@ func RegisterCustomerRoutes(app *app.Server, serviceManager *services.ServiceMan
|
|||||||
optionlMiddleWare := middlewares.OptionalCustomerAuthorizationMiddleware(repoManager.Crypto)
|
optionlMiddleWare := middlewares.OptionalCustomerAuthorizationMiddleware(repoManager.Crypto)
|
||||||
|
|
||||||
serverRoutes := []HTTPHandlerRoutes{
|
serverRoutes := []HTTPHandlerRoutes{
|
||||||
discovery.NewHandler(serviceManager.DiscoverService),
|
|
||||||
customerauth.NewAuthHandler(serviceManager.AuthV2Svc, serviceManager.MemberRegistrationSvc),
|
customerauth.NewAuthHandler(serviceManager.AuthV2Svc, serviceManager.MemberRegistrationSvc),
|
||||||
http.NewMenuHandler(serviceManager.ProductV2Svc, serviceManager.InProgressSvc),
|
http.NewMenuHandler(serviceManager.ProductV2Svc, serviceManager.InProgressSvc),
|
||||||
http.NewCustomerOrderHandler(serviceManager.OrderV2Svc),
|
http.NewCustomerOrderHandler(serviceManager.OrderV2Svc),
|
||||||
|
|||||||
@ -8,14 +8,12 @@ import (
|
|||||||
"enaklo-pos-be/internal/handlers/http/partner"
|
"enaklo-pos-be/internal/handlers/http/partner"
|
||||||
"enaklo-pos-be/internal/handlers/http/product"
|
"enaklo-pos-be/internal/handlers/http/product"
|
||||||
site "enaklo-pos-be/internal/handlers/http/sites"
|
site "enaklo-pos-be/internal/handlers/http/sites"
|
||||||
"enaklo-pos-be/internal/handlers/http/studio"
|
|
||||||
"enaklo-pos-be/internal/handlers/http/transaction"
|
"enaklo-pos-be/internal/handlers/http/transaction"
|
||||||
"enaklo-pos-be/internal/handlers/http/user"
|
"enaklo-pos-be/internal/handlers/http/user"
|
||||||
swaggerFiles "github.com/swaggo/files"
|
swaggerFiles "github.com/swaggo/files"
|
||||||
ginSwagger "github.com/swaggo/gin-swagger"
|
ginSwagger "github.com/swaggo/gin-swagger"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"enaklo-pos-be/internal/handlers/http/event"
|
|
||||||
"enaklo-pos-be/internal/middlewares"
|
"enaklo-pos-be/internal/middlewares"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -46,9 +44,7 @@ func RegisterPrivateRoutes(app *app.Server, serviceManager *services.ServiceMana
|
|||||||
authMiddleware := middlewares.AuthorizationMiddleware(repoManager.Crypto)
|
authMiddleware := middlewares.AuthorizationMiddleware(repoManager.Crypto)
|
||||||
serverRoutes := []HTTPHandlerRoutes{
|
serverRoutes := []HTTPHandlerRoutes{
|
||||||
auth.NewAuthHandler(serviceManager.AuthSvc),
|
auth.NewAuthHandler(serviceManager.AuthSvc),
|
||||||
event.NewHandler(serviceManager.EventSvc),
|
|
||||||
user.NewHandler(serviceManager.UserSvc),
|
user.NewHandler(serviceManager.UserSvc),
|
||||||
studio.NewStudioHandler(serviceManager.StudioSvc),
|
|
||||||
product.NewHandler(serviceManager.ProductSvc),
|
product.NewHandler(serviceManager.ProductSvc),
|
||||||
oss.NewOssHandler(serviceManager.OSSSvc),
|
oss.NewOssHandler(serviceManager.OSSSvc),
|
||||||
partner.NewHandler(serviceManager.PartnerSvc),
|
partner.NewHandler(serviceManager.PartnerSvc),
|
||||||
@ -74,6 +70,8 @@ func RegisterPrivateRoutesV2(app *app.Server, serviceManager *services.ServiceMa
|
|||||||
http2.NewMemberRegistrationHandler(serviceManager.MemberRegistrationSvc),
|
http2.NewMemberRegistrationHandler(serviceManager.MemberRegistrationSvc),
|
||||||
http2.NewCustomerHandler(serviceManager.CustomerV2Svc),
|
http2.NewCustomerHandler(serviceManager.CustomerV2Svc),
|
||||||
http2.NewInProgressOrderHandler(serviceManager.InProgressSvc),
|
http2.NewInProgressOrderHandler(serviceManager.InProgressSvc),
|
||||||
|
http2.NewCashierSession(serviceManager.CashierSvc),
|
||||||
|
http2.NewCategoryHandler(serviceManager.CategorySvc),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, handler := range serverRoutes {
|
for _, handler := range serverRoutes {
|
||||||
|
|||||||
@ -1,168 +0,0 @@
|
|||||||
package discovery
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"enaklo-pos-be/config"
|
|
||||||
"errors"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
|
|
||||||
"enaklo-pos-be/internal/entity"
|
|
||||||
"enaklo-pos-be/internal/repository"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultLatitude = -6.2088
|
|
||||||
defaultLongitude = 106.8456
|
|
||||||
radius = 10000
|
|
||||||
)
|
|
||||||
|
|
||||||
type DiscoveryService struct {
|
|
||||||
repo repository.SiteRepository
|
|
||||||
cfg config.Discovery
|
|
||||||
product repository.Product
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDiscoveryService(repo repository.SiteRepository, cfg config.Discovery, product repository.Product) *DiscoveryService {
|
|
||||||
return &DiscoveryService{
|
|
||||||
repo: repo,
|
|
||||||
cfg: cfg,
|
|
||||||
product: product,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DiscoveryService) Home(ctx context.Context, search *entity.DiscoverySearch) (*entity.DiscoverySearchResp, error) {
|
|
||||||
if search.Lat == 0 || search.Long == 0 {
|
|
||||||
search.Lat = defaultLatitude
|
|
||||||
search.Long = defaultLongitude
|
|
||||||
}
|
|
||||||
|
|
||||||
siteProducts, err := s.repo.GetNearestSites(ctx, search.Lat, search.Long, radius)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
exploreDestinations := []entity.ExploreDestination{}
|
|
||||||
for _, exploreDestination := range s.cfg.ExploreDestinations {
|
|
||||||
exploreDestinations = append(exploreDestinations, entity.ExploreDestination{
|
|
||||||
Name: exploreDestination.Name,
|
|
||||||
ImageURL: exploreDestination.ImageURL,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
exploreRegions := []entity.ExploreRegion{}
|
|
||||||
for _, exploreRegion := range s.cfg.ExploreRegions {
|
|
||||||
exploreRegions = append(exploreRegions, entity.ExploreRegion{
|
|
||||||
Name: exploreRegion.Name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
mustVisits := []entity.MustVisit{}
|
|
||||||
|
|
||||||
for _, siteProduct := range siteProducts {
|
|
||||||
if siteProduct.Status == "Active" {
|
|
||||||
mustVisits = append(mustVisits, entity.MustVisit{
|
|
||||||
Name: siteProduct.SiteName,
|
|
||||||
Price: siteProduct.ProductPrice,
|
|
||||||
Region: siteProduct.Region,
|
|
||||||
SiteID: siteProduct.SiteID,
|
|
||||||
ImageURL: siteProduct.Image,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
response := &entity.DiscoverySearchResp{
|
|
||||||
ExploreRegions: exploreRegions,
|
|
||||||
ExploreDestinations: exploreDestinations,
|
|
||||||
MustVisit: mustVisits,
|
|
||||||
}
|
|
||||||
|
|
||||||
return response, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DiscoveryService) Search(ctx context.Context, search *entity.DiscoverySearch) (*entity.DiscoverySearchResp, int64, error) {
|
|
||||||
if search.Lat == 0 || search.Long == 0 {
|
|
||||||
search.Lat = defaultLatitude
|
|
||||||
search.Long = defaultLongitude
|
|
||||||
search.Radius = radius
|
|
||||||
}
|
|
||||||
|
|
||||||
search.Status = "Active"
|
|
||||||
siteProducts, total, err := s.repo.SearchSites(ctx, search)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
exploreDestinations := []entity.ExploreDestination{}
|
|
||||||
for _, exploreDestination := range s.cfg.ExploreDestinations {
|
|
||||||
exploreDestinations = append(exploreDestinations, entity.ExploreDestination{
|
|
||||||
Name: exploreDestination.Name,
|
|
||||||
ImageURL: exploreDestination.ImageURL,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
exploreRegions := []entity.ExploreRegion{}
|
|
||||||
for _, exploreRegion := range s.cfg.ExploreRegions {
|
|
||||||
exploreRegions = append(exploreRegions, entity.ExploreRegion{
|
|
||||||
Name: exploreRegion.Name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
mustVisits := []entity.MustVisit{}
|
|
||||||
|
|
||||||
for _, siteProduct := range siteProducts {
|
|
||||||
mustVisits = append(mustVisits, entity.MustVisit{
|
|
||||||
Name: siteProduct.SiteName,
|
|
||||||
Price: siteProduct.ProductPrice,
|
|
||||||
Region: siteProduct.Region,
|
|
||||||
SiteID: siteProduct.SiteID,
|
|
||||||
ImageURL: siteProduct.Image,
|
|
||||||
Regency: siteProduct.Regency,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
response := &entity.DiscoverySearchResp{
|
|
||||||
ExploreRegions: exploreRegions,
|
|
||||||
ExploreDestinations: exploreDestinations,
|
|
||||||
MustVisit: mustVisits,
|
|
||||||
}
|
|
||||||
|
|
||||||
return response, total, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DiscoveryService) GetByID(ctx context.Context, id int64) (*entity.Site, error) {
|
|
||||||
site, err := s.repo.GetByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if site.Status != "Active" {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return site.ToSite(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DiscoveryService) GetProductsByID(ctx context.Context, id int64) ([]*entity.Product, error) {
|
|
||||||
site, err := s.repo.GetByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if site.Status == "Inactive" {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
product, err := s.product.GetProductsBySiteID(ctx, site.ID)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return product.ToProductList(), nil
|
|
||||||
}
|
|
||||||
@ -1,88 +0,0 @@
|
|||||||
package event
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
|
||||||
|
|
||||||
"enaklo-pos-be/internal/common/logger"
|
|
||||||
"enaklo-pos-be/internal/entity"
|
|
||||||
"enaklo-pos-be/internal/repository"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EventService struct {
|
|
||||||
repo repository.Event
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEventService(repo repository.Event) *EventService {
|
|
||||||
return &EventService{
|
|
||||||
repo: repo,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *EventService) Create(ctx context.Context, eventReq *entity.Event) (*entity.Event, error) {
|
|
||||||
eventDB := eventReq.ToEventDB()
|
|
||||||
|
|
||||||
eventDB, err := s.repo.CreateEvent(ctx, eventDB)
|
|
||||||
if err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when create event", zap.Error(err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return eventDB.ToEvent(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *EventService) Update(ctx context.Context, id int64, eventReq *entity.Event) (*entity.Event, error) {
|
|
||||||
existingEvent, err := s.repo.GetEventByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
existingEvent.ToUpdatedEvent(*eventReq)
|
|
||||||
|
|
||||||
updatedEventDB, err := s.repo.UpdateEvent(ctx, existingEvent.ToEventDB())
|
|
||||||
if err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when update event", zap.Error(err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return updatedEventDB.ToEvent(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *EventService) GetByID(ctx context.Context, id int64) (*entity.Event, error) {
|
|
||||||
eventDB, err := s.repo.GetEventByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when get event by id", zap.Error(err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return eventDB.ToEvent(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *EventService) GetAll(ctx context.Context, search entity.EventSearch) ([]*entity.Event, int, error) {
|
|
||||||
events, total, err := s.repo.GetAllEvents(ctx, search.Name, search.Limit, search.Offset)
|
|
||||||
if err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when get all events", zap.Error(err))
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return events.ToEventList(), total, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *EventService) Delete(ctx context.Context, id int64) error {
|
|
||||||
eventDB, err := s.repo.GetEventByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when get event by id", zap.Error(err))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
eventDB.SetDeleted()
|
|
||||||
|
|
||||||
_, err = s.repo.UpdateEvent(ctx, eventDB)
|
|
||||||
if err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when update event", zap.Error(err))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@ -4,17 +4,17 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"enaklo-pos-be/internal/common/mycontext"
|
"enaklo-pos-be/internal/common/mycontext"
|
||||||
"enaklo-pos-be/internal/services/balance"
|
"enaklo-pos-be/internal/services/balance"
|
||||||
"enaklo-pos-be/internal/services/discovery"
|
|
||||||
service "enaklo-pos-be/internal/services/license"
|
service "enaklo-pos-be/internal/services/license"
|
||||||
"enaklo-pos-be/internal/services/member"
|
"enaklo-pos-be/internal/services/member"
|
||||||
"enaklo-pos-be/internal/services/oss"
|
"enaklo-pos-be/internal/services/oss"
|
||||||
"enaklo-pos-be/internal/services/partner"
|
"enaklo-pos-be/internal/services/partner"
|
||||||
"enaklo-pos-be/internal/services/product"
|
"enaklo-pos-be/internal/services/product"
|
||||||
site "enaklo-pos-be/internal/services/sites"
|
site "enaklo-pos-be/internal/services/sites"
|
||||||
"enaklo-pos-be/internal/services/studio"
|
|
||||||
"enaklo-pos-be/internal/services/transaction"
|
"enaklo-pos-be/internal/services/transaction"
|
||||||
"enaklo-pos-be/internal/services/users"
|
"enaklo-pos-be/internal/services/users"
|
||||||
authSvc "enaklo-pos-be/internal/services/v2/auth"
|
authSvc "enaklo-pos-be/internal/services/v2/auth"
|
||||||
|
"enaklo-pos-be/internal/services/v2/cashier_session"
|
||||||
|
category "enaklo-pos-be/internal/services/v2/categories"
|
||||||
customerSvc "enaklo-pos-be/internal/services/v2/customer"
|
customerSvc "enaklo-pos-be/internal/services/v2/customer"
|
||||||
"enaklo-pos-be/internal/services/v2/inprogress_order"
|
"enaklo-pos-be/internal/services/v2/inprogress_order"
|
||||||
orderSvc "enaklo-pos-be/internal/services/v2/order"
|
orderSvc "enaklo-pos-be/internal/services/v2/order"
|
||||||
@ -29,14 +29,11 @@ import (
|
|||||||
"enaklo-pos-be/internal/entity"
|
"enaklo-pos-be/internal/entity"
|
||||||
"enaklo-pos-be/internal/repository"
|
"enaklo-pos-be/internal/repository"
|
||||||
"enaklo-pos-be/internal/services/auth"
|
"enaklo-pos-be/internal/services/auth"
|
||||||
"enaklo-pos-be/internal/services/event"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServiceManagerImpl struct {
|
type ServiceManagerImpl struct {
|
||||||
AuthSvc Auth
|
AuthSvc Auth
|
||||||
EventSvc Event
|
|
||||||
UserSvc User
|
UserSvc User
|
||||||
StudioSvc Studio
|
|
||||||
ProductSvc Product
|
ProductSvc Product
|
||||||
OSSSvc OSSService
|
OSSSvc OSSService
|
||||||
PartnerSvc Partner
|
PartnerSvc Partner
|
||||||
@ -44,7 +41,6 @@ type ServiceManagerImpl struct {
|
|||||||
LicenseSvc License
|
LicenseSvc License
|
||||||
Transaction Transaction
|
Transaction Transaction
|
||||||
Balance Balance
|
Balance Balance
|
||||||
DiscoverService DiscoverService
|
|
||||||
|
|
||||||
OrderV2Svc orderSvc.Service
|
OrderV2Svc orderSvc.Service
|
||||||
CustomerV2Svc customerSvc.Service
|
CustomerV2Svc customerSvc.Service
|
||||||
@ -53,6 +49,8 @@ type ServiceManagerImpl struct {
|
|||||||
InProgressSvc inprogress_order.InProgressOrderService
|
InProgressSvc inprogress_order.InProgressOrderService
|
||||||
AuthV2Svc authSvc.Service
|
AuthV2Svc authSvc.Service
|
||||||
UndianSvc undian.Service
|
UndianSvc undian.Service
|
||||||
|
CashierSvc cashier_session.Service
|
||||||
|
CategorySvc category.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl) *ServiceManagerImpl {
|
func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl) *ServiceManagerImpl {
|
||||||
@ -60,14 +58,16 @@ func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl)
|
|||||||
custSvcV2 := customerSvc.New(repo.CustomerRepo, repo.EmailService)
|
custSvcV2 := customerSvc.New(repo.CustomerRepo, repo.EmailService)
|
||||||
productSvcV2 := productSvc.New(repo.ProductRepo)
|
productSvcV2 := productSvc.New(repo.ProductRepo)
|
||||||
partnerSettings := partner_settings.NewPartnerSettingsService(repo.PartnerSetting)
|
partnerSettings := partner_settings.NewPartnerSettingsService(repo.PartnerSetting)
|
||||||
|
cashierSvc := cashier_session.New(repo.CashierSeasionRepo)
|
||||||
orderService := orderSvc.New(repo.OrderRepo, productSvcV2, custSvcV2, repo.TransactionRepo, repo.Crypto, &cfg.Order, repo.EmailService, partnerSettings, repo.UndianRepository)
|
orderService := orderSvc.New(repo.OrderRepo,
|
||||||
|
productSvcV2, custSvcV2, repo.TransactionRepo,
|
||||||
|
repo.Crypto, &cfg.Order, repo.EmailService, partnerSettings,
|
||||||
|
repo.UndianRepository, cashierSvc)
|
||||||
inprogressOrder := inprogress_order.NewInProgressOrderService(repo.OrderRepo, orderService, productSvcV2)
|
inprogressOrder := inprogress_order.NewInProgressOrderService(repo.OrderRepo, orderService, productSvcV2)
|
||||||
|
categorySvc := category.New(repo.CategoryRepository)
|
||||||
return &ServiceManagerImpl{
|
return &ServiceManagerImpl{
|
||||||
AuthSvc: auth.New(repo.Auth, repo.Crypto, repo.User, repo.EmailService, cfg.Email, repo.Trx, repo.License),
|
AuthSvc: auth.New(repo.Auth, repo.Crypto, repo.User, repo.EmailService, cfg.Email, repo.Trx, repo.License),
|
||||||
EventSvc: event.NewEventService(repo.Event),
|
|
||||||
UserSvc: users.NewUserService(repo.User),
|
UserSvc: users.NewUserService(repo.User),
|
||||||
StudioSvc: studio.NewStudioService(repo.Studio),
|
|
||||||
ProductSvc: product.NewProductService(repo.Product),
|
ProductSvc: product.NewProductService(repo.Product),
|
||||||
OSSSvc: oss.NewOSSService(repo.OSS),
|
OSSSvc: oss.NewOSSService(repo.OSS),
|
||||||
PartnerSvc: partner.NewPartnerService(
|
PartnerSvc: partner.NewPartnerService(
|
||||||
@ -76,14 +76,15 @@ func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl)
|
|||||||
LicenseSvc: service.NewLicenseService(repo.License),
|
LicenseSvc: service.NewLicenseService(repo.License),
|
||||||
Transaction: transaction.New(repo.Transaction, repo.Wallet, repo.Trx),
|
Transaction: transaction.New(repo.Transaction, repo.Wallet, repo.Trx),
|
||||||
Balance: balance.NewBalanceService(repo.Wallet, repo.Trx, repo.Crypto, &cfg.Withdraw, repo.Transaction),
|
Balance: balance.NewBalanceService(repo.Wallet, repo.Trx, repo.Crypto, &cfg.Withdraw, repo.Transaction),
|
||||||
DiscoverService: discovery.NewDiscoveryService(repo.Site, cfg.Discovery, repo.Product),
|
OrderV2Svc: orderSvc.New(repo.OrderRepo, productSvcV2, custSvcV2, repo.TransactionRepo, repo.Crypto, &cfg.Order, repo.EmailService, partnerSettings, repo.UndianRepository, cashierSvc),
|
||||||
OrderV2Svc: orderSvc.New(repo.OrderRepo, productSvcV2, custSvcV2, repo.TransactionRepo, repo.Crypto, &cfg.Order, repo.EmailService, partnerSettings, repo.UndianRepository),
|
|
||||||
MemberRegistrationSvc: member.NewMemberRegistrationService(repo.MemberRepository, repo.EmailService, custSvcV2, repo.Crypto),
|
MemberRegistrationSvc: member.NewMemberRegistrationService(repo.MemberRepository, repo.EmailService, custSvcV2, repo.Crypto),
|
||||||
CustomerV2Svc: custSvcV2,
|
CustomerV2Svc: custSvcV2,
|
||||||
InProgressSvc: inprogressOrder,
|
InProgressSvc: inprogressOrder,
|
||||||
ProductV2Svc: productSvcV2,
|
ProductV2Svc: productSvcV2,
|
||||||
AuthV2Svc: authSvc.New(repo.CustomerRepo, repo.Crypto),
|
AuthV2Svc: authSvc.New(repo.CustomerRepo, repo.Crypto),
|
||||||
UndianSvc: undian.New(repo.UndianRepository),
|
UndianSvc: undian.New(repo.UndianRepository),
|
||||||
|
CashierSvc: cashierSvc,
|
||||||
|
CategorySvc: categorySvc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,14 +94,6 @@ type Auth interface {
|
|||||||
ResetPassword(ctx mycontext.Context, oldPassword, newPassword string) error
|
ResetPassword(ctx mycontext.Context, oldPassword, newPassword string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Event interface {
|
|
||||||
Create(ctx context.Context, eventReq *entity.Event) (*entity.Event, error)
|
|
||||||
Update(ctx context.Context, id int64, eventReq *entity.Event) (*entity.Event, error)
|
|
||||||
GetByID(ctx context.Context, id int64) (*entity.Event, error)
|
|
||||||
GetAll(ctx context.Context, search entity.EventSearch) ([]*entity.Event, int, error)
|
|
||||||
Delete(ctx context.Context, id int64) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type User interface {
|
type User interface {
|
||||||
Create(ctx mycontext.Context, userReq *entity.User) (*entity.User, error)
|
Create(ctx mycontext.Context, userReq *entity.User) (*entity.User, error)
|
||||||
CreateWithTx(ctx mycontext.Context, tx *gorm.DB, userReq *entity.User) (*entity.User, error)
|
CreateWithTx(ctx mycontext.Context, tx *gorm.DB, userReq *entity.User) (*entity.User, error)
|
||||||
@ -112,13 +105,6 @@ type User interface {
|
|||||||
Delete(ctx mycontext.Context, id int64) error
|
Delete(ctx mycontext.Context, id int64) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Studio interface {
|
|
||||||
Create(ctx mycontext.Context, studioReq *entity.Studio) (*entity.Studio, error)
|
|
||||||
Update(ctx mycontext.Context, id int64, studioReq *entity.Studio) (*entity.Studio, error)
|
|
||||||
GetByID(ctx context.Context, id int64) (*entity.Studio, error)
|
|
||||||
Search(ctx context.Context, search entity.StudioSearch) ([]*entity.Studio, int, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Product interface {
|
type Product interface {
|
||||||
Create(ctx mycontext.Context, productReq *entity.Product) (*entity.Product, error)
|
Create(ctx mycontext.Context, productReq *entity.Product) (*entity.Product, error)
|
||||||
Update(ctx mycontext.Context, id int64, productReq *entity.Product) (*entity.Product, error)
|
Update(ctx mycontext.Context, id int64, productReq *entity.Product) (*entity.Product, error)
|
||||||
@ -128,23 +114,6 @@ type Product interface {
|
|||||||
Delete(ctx mycontext.Context, id int64) error
|
Delete(ctx mycontext.Context, id int64) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Order interface {
|
|
||||||
CreateOrder(ctx mycontext.Context, req *entity.OrderRequest) (*entity.OrderResponse, error)
|
|
||||||
CheckInInquiry(ctx mycontext.Context, qrCode string, partnerID *int64) (*entity.CheckinResponse, error)
|
|
||||||
CheckInExecute(ctx mycontext.Context,
|
|
||||||
token string, partnerID *int64) (*entity.CheckinExecute, error)
|
|
||||||
Execute(ctx mycontext.Context, req *entity.OrderExecuteRequest) (*entity.ExecuteOrderResponse, error)
|
|
||||||
ProcessCallback(ctx context.Context, req *entity.CallbackRequest) error
|
|
||||||
GetAllHistoryOrders(ctx mycontext.Context, req entity.OrderSearch) ([]*entity.HistoryOrder, int, error)
|
|
||||||
CountSoldOfTicket(ctx mycontext.Context, req entity.OrderSearch) (*entity.TicketSold, error)
|
|
||||||
SumAmount(ctx mycontext.Context, req entity.OrderSearch) (*entity.Order, error)
|
|
||||||
GetDailySales(ctx mycontext.Context, req entity.OrderSearch) ([]entity.ProductDailySales, error)
|
|
||||||
GetPaymentDistribution(ctx mycontext.Context, req entity.OrderSearch) ([]entity.PaymentTypeDistribution, error)
|
|
||||||
GetByID(ctx mycontext.Context, id int64, referenceID string) (*entity.Order, error)
|
|
||||||
GetPrintDetail(ctx mycontext.Context, id int64) (*entity.OrderPrintDetail, error)
|
|
||||||
ProcessLinkQuCallback(ctx context.Context, req *entity.LinkQuCallback) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type OSSService interface {
|
type OSSService interface {
|
||||||
UploadFile(ctx context.Context, req *entity.UploadFileRequest) (*entity.UploadFileResponse, error)
|
UploadFile(ctx context.Context, req *entity.UploadFileRequest) (*entity.UploadFileResponse, error)
|
||||||
}
|
}
|
||||||
@ -183,10 +152,3 @@ type Balance interface {
|
|||||||
WithdrawInquiry(ctx context.Context, req *entity.BalanceWithdrawInquiry) (*entity.BalanceWithdrawInquiryResponse, error)
|
WithdrawInquiry(ctx context.Context, req *entity.BalanceWithdrawInquiry) (*entity.BalanceWithdrawInquiryResponse, error)
|
||||||
WithdrawExecute(ctx mycontext.Context, req *entity.WalletWithdrawRequest) (*entity.WalletWithdrawResponse, error)
|
WithdrawExecute(ctx mycontext.Context, req *entity.WalletWithdrawRequest) (*entity.WalletWithdrawResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type DiscoverService interface {
|
|
||||||
Home(ctx context.Context, search *entity.DiscoverySearch) (*entity.DiscoverySearchResp, error)
|
|
||||||
Search(ctx context.Context, search *entity.DiscoverySearch) (*entity.DiscoverySearchResp, int64, error)
|
|
||||||
GetByID(ctx context.Context, id int64) (*entity.Site, error)
|
|
||||||
GetProductsByID(ctx context.Context, id int64) ([]*entity.Product, error)
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,70 +0,0 @@
|
|||||||
package studio
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"enaklo-pos-be/internal/common/logger"
|
|
||||||
"enaklo-pos-be/internal/common/mycontext"
|
|
||||||
"enaklo-pos-be/internal/entity"
|
|
||||||
"enaklo-pos-be/internal/repository"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StudioService struct {
|
|
||||||
repo repository.Studio
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewStudioService(repo repository.Studio) *StudioService {
|
|
||||||
return &StudioService{
|
|
||||||
repo: repo,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StudioService) Create(ctx mycontext.Context, studioReq *entity.Studio) (*entity.Studio, error) {
|
|
||||||
newStudioDB := studioReq.NewStudiosDB()
|
|
||||||
newStudioDB.CreatedBy = ctx.RequestedBy()
|
|
||||||
|
|
||||||
newStudioDB, err := s.repo.CreateStudio(ctx, newStudioDB)
|
|
||||||
if err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when creating studio", zap.Error(err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return newStudioDB.ToStudio(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StudioService) Update(ctx mycontext.Context, id int64, studioReq *entity.Studio) (*entity.Studio, error) {
|
|
||||||
existingStudio, err := s.repo.GetStudioByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
existingStudio.ToUpdatedStudio(ctx.RequestedBy(), *studioReq)
|
|
||||||
|
|
||||||
updatedStudioDB, err := s.repo.UpdateStudio(ctx, existingStudio.ToStudioDB())
|
|
||||||
if err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when updating studio", zap.Error(err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return updatedStudioDB.ToStudio(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StudioService) GetByID(ctx context.Context, id int64) (*entity.Studio, error) {
|
|
||||||
studioDB, err := s.repo.GetStudioByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when getting studio by id", zap.Error(err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return studioDB.ToStudio(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StudioService) Search(ctx context.Context, search entity.StudioSearch) ([]*entity.Studio, int, error) {
|
|
||||||
studios, total, err := s.repo.SearchStudios(ctx, search)
|
|
||||||
if err != nil {
|
|
||||||
logger.ContextLogger(ctx).Error("error when getting all studios", zap.Error(err))
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return studios.ToStudioList(), total, nil
|
|
||||||
}
|
|
||||||
99
internal/services/v2/cashier_session/casheer_session.go
Normal file
99
internal/services/v2/cashier_session/casheer_session.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package cashier_session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"enaklo-pos-be/internal/common/logger"
|
||||||
|
"enaklo-pos-be/internal/common/mycontext"
|
||||||
|
"enaklo-pos-be/internal/entity"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
OpenSession(ctx mycontext.Context, session *entity.CashierSession) (*entity.CashierSession, error)
|
||||||
|
CloseSession(ctx mycontext.Context, sessionID int64, closingAmount float64) (*entity.CashierSessionReport, error)
|
||||||
|
GetOpenSession(ctx mycontext.Context, cashierID int64) (*entity.CashierSession, error)
|
||||||
|
GetSessionReport(ctx mycontext.Context, sessionID int64) (*entity.CashierSessionReport, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
CreateSession(ctx mycontext.Context, session *entity.CashierSession) (*entity.CashierSession, error)
|
||||||
|
CloseSession(ctx mycontext.Context, sessionID int64, closingAmount, expectedAmount float64) error
|
||||||
|
GetOpenSessionByCashierID(ctx mycontext.Context, cashierID int64) (*entity.CashierSession, error)
|
||||||
|
GetSessionByID(ctx mycontext.Context, sessionID int64) (*entity.CashierSession, error)
|
||||||
|
GetPaymentSummaryBySessionID(ctx mycontext.Context, sessionID int64) ([]entity.PaymentSummary, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type cashierSessionSvc struct {
|
||||||
|
repo Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(repo Repository) Service {
|
||||||
|
return &cashierSessionSvc{repo: repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *cashierSessionSvc) OpenSession(ctx mycontext.Context, session *entity.CashierSession) (*entity.CashierSession, error) {
|
||||||
|
openSession, err := s.repo.GetOpenSessionByCashierID(ctx, session.CashierID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to check existing open session")
|
||||||
|
}
|
||||||
|
if openSession != nil {
|
||||||
|
return nil, errors.New("cashier already has an open session")
|
||||||
|
}
|
||||||
|
|
||||||
|
newSession, err := s.repo.CreateSession(ctx, session)
|
||||||
|
if err != nil {
|
||||||
|
logger.ContextLogger(ctx).Error("failed to create cashier session", zap.Error(err))
|
||||||
|
return nil, errors.Wrap(err, "failed to create cashier session")
|
||||||
|
}
|
||||||
|
|
||||||
|
return newSession, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *cashierSessionSvc) CloseSession(ctx mycontext.Context, sessionID int64, closingAmount float64) (*entity.CashierSessionReport, error) {
|
||||||
|
report, err := s.repo.GetPaymentSummaryBySessionID(ctx, sessionID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to get payment summary")
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectedAmount float64
|
||||||
|
for _, r := range report {
|
||||||
|
expectedAmount += r.TotalAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.repo.CloseSession(ctx, sessionID, closingAmount, expectedAmount); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to close session")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &entity.CashierSessionReport{
|
||||||
|
SessionID: sessionID,
|
||||||
|
ClosingAmount: closingAmount,
|
||||||
|
ExpectedAmount: expectedAmount,
|
||||||
|
Payments: report,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *cashierSessionSvc) GetOpenSession(ctx mycontext.Context, cashierID int64) (*entity.CashierSession, error) {
|
||||||
|
session, err := s.repo.GetOpenSessionByCashierID(ctx, cashierID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to get open session")
|
||||||
|
}
|
||||||
|
return session, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *cashierSessionSvc) GetSessionReport(ctx mycontext.Context, sessionID int64) (*entity.CashierSessionReport, error) {
|
||||||
|
report, err := s.repo.GetPaymentSummaryBySessionID(ctx, sessionID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to get payment summary")
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectedAmount float64
|
||||||
|
for _, r := range report {
|
||||||
|
expectedAmount += r.TotalAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
return &entity.CashierSessionReport{
|
||||||
|
SessionID: sessionID,
|
||||||
|
ExpectedAmount: expectedAmount,
|
||||||
|
Payments: report,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
88
internal/services/v2/categories/categories.go
Normal file
88
internal/services/v2/categories/categories.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package category
|
||||||
|
|
||||||
|
import (
|
||||||
|
"enaklo-pos-be/internal/common/logger"
|
||||||
|
"enaklo-pos-be/internal/common/mycontext"
|
||||||
|
"enaklo-pos-be/internal/entity"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
Create(ctx mycontext.Context, category *entity.Category) (*entity.Category, error)
|
||||||
|
GetByPartnerID(ctx mycontext.Context, partnerID int64) ([]*entity.Category, error)
|
||||||
|
Update(ctx mycontext.Context, category *entity.Category) error
|
||||||
|
Delete(ctx mycontext.Context, id int64) error
|
||||||
|
GetByID(ctx mycontext.Context, id int64) (*entity.Category, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
Create(ctx mycontext.Context, category *entity.Category) (*entity.Category, error)
|
||||||
|
GetByPartnerID(ctx mycontext.Context, partnerID int64) ([]*entity.Category, error)
|
||||||
|
Update(ctx mycontext.Context, category *entity.Category) error
|
||||||
|
Delete(ctx mycontext.Context, id int64) error
|
||||||
|
GetByID(ctx mycontext.Context, id int64) (*entity.Category, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type categorySvc struct {
|
||||||
|
repo Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(repo Repository) Service {
|
||||||
|
return &categorySvc{repo: repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *categorySvc) Create(ctx mycontext.Context, category *entity.Category) (*entity.Category, error) {
|
||||||
|
existing, err := s.repo.GetByPartnerID(ctx, category.PartnerID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to fetch categories")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cat := range existing {
|
||||||
|
if cat.Name == category.Name {
|
||||||
|
return nil, errors.New("category name already exists for this partner")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newCategory, err := s.repo.Create(ctx, category)
|
||||||
|
if err != nil {
|
||||||
|
logger.ContextLogger(ctx).Error("failed to create category", zap.Error(err))
|
||||||
|
return nil, errors.Wrap(err, "failed to create category")
|
||||||
|
}
|
||||||
|
|
||||||
|
return newCategory, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *categorySvc) GetByPartnerID(ctx mycontext.Context, partnerID int64) ([]*entity.Category, error) {
|
||||||
|
categories, err := s.repo.GetByPartnerID(ctx, partnerID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to get categories by partner")
|
||||||
|
}
|
||||||
|
return categories, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *categorySvc) Update(ctx mycontext.Context, category *entity.Category) error {
|
||||||
|
err := s.repo.Update(ctx, category)
|
||||||
|
if err != nil {
|
||||||
|
logger.ContextLogger(ctx).Error("failed to update category", zap.Error(err))
|
||||||
|
return errors.Wrap(err, "failed to update category")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *categorySvc) Delete(ctx mycontext.Context, id int64) error {
|
||||||
|
err := s.repo.Delete(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
logger.ContextLogger(ctx).Error("failed to delete category", zap.Error(err))
|
||||||
|
return errors.Wrap(err, "failed to delete category")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *categorySvc) GetByID(ctx mycontext.Context, id int64) (*entity.Category, error) {
|
||||||
|
category, err := s.repo.GetByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to get category by ID")
|
||||||
|
}
|
||||||
|
return category, nil
|
||||||
|
}
|
||||||
@ -12,6 +12,13 @@ import (
|
|||||||
|
|
||||||
func (s *orderSvc) CreateOrderInquiry(ctx mycontext.Context,
|
func (s *orderSvc) CreateOrderInquiry(ctx mycontext.Context,
|
||||||
req *entity.OrderRequest) (*entity.OrderInquiryResponse, error) {
|
req *entity.OrderRequest) (*entity.OrderInquiryResponse, error) {
|
||||||
|
|
||||||
|
cashierSession, err := s.cashierSvc.GetOpenSession(ctx, ctx.RequestedBy())
|
||||||
|
if err != nil {
|
||||||
|
logger.ContextLogger(ctx).Error("no open session found for cashier", zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
productIDs, filteredItems, err := s.ValidateOrderItems(ctx, req.OrderItems)
|
productIDs, filteredItems, err := s.ValidateOrderItems(ctx, req.OrderItems)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -60,6 +67,7 @@ func (s *orderSvc) CreateOrderInquiry(ctx mycontext.Context,
|
|||||||
req.PaymentProvider,
|
req.PaymentProvider,
|
||||||
req.TableNumber,
|
req.TableNumber,
|
||||||
req.OrderType,
|
req.OrderType,
|
||||||
|
cashierSession.ID,
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, item := range req.OrderItems {
|
for _, item := range req.OrderItems {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"enaklo-pos-be/internal/constants"
|
"enaklo-pos-be/internal/constants"
|
||||||
"enaklo-pos-be/internal/entity"
|
"enaklo-pos-be/internal/entity"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -36,6 +37,20 @@ func (s *orderSvc) ExecuteOrderInquiry(ctx mycontext.Context,
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *orderSvc) RefundRequest(ctx mycontext.Context, partnerID, orderID int64, reason string) error {
|
||||||
|
order, err := s.repo.FindByIDAndPartnerID(ctx, partnerID, orderID)
|
||||||
|
if err != nil {
|
||||||
|
logger.ContextLogger(ctx).Error("failed to create order", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if order.Status != "PAID" {
|
||||||
|
return errors.New("only paid order can be refund")
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.repo.UpdateOrder(ctx, order.ID, "REFUNDED", reason)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *orderSvc) processPostOrderActions(
|
func (s *orderSvc) processPostOrderActions(
|
||||||
ctx mycontext.Context,
|
ctx mycontext.Context,
|
||||||
order *entity.Order,
|
order *entity.Order,
|
||||||
|
|||||||
@ -12,6 +12,7 @@ type Repository interface {
|
|||||||
CreateInquiry(ctx mycontext.Context, inquiry *entity.OrderInquiry) (*entity.OrderInquiry, error)
|
CreateInquiry(ctx mycontext.Context, inquiry *entity.OrderInquiry) (*entity.OrderInquiry, error)
|
||||||
FindInquiryByID(ctx mycontext.Context, id string) (*entity.OrderInquiry, error)
|
FindInquiryByID(ctx mycontext.Context, id string) (*entity.OrderInquiry, error)
|
||||||
UpdateInquiryStatus(ctx mycontext.Context, id string, status string) error
|
UpdateInquiryStatus(ctx mycontext.Context, id string, status string) error
|
||||||
|
UpdateOrder(ctx mycontext.Context, id int64, status string, description string) error
|
||||||
GetOrderHistoryByPartnerID(ctx mycontext.Context, partnerID int64, req entity.SearchRequest) ([]*entity.Order, int64, error)
|
GetOrderHistoryByPartnerID(ctx mycontext.Context, partnerID int64, req entity.SearchRequest) ([]*entity.Order, int64, error)
|
||||||
GetOrderPaymentMethodBreakdown(
|
GetOrderPaymentMethodBreakdown(
|
||||||
ctx mycontext.Context,
|
ctx mycontext.Context,
|
||||||
@ -65,6 +66,7 @@ type Service interface {
|
|||||||
req *entity.OrderRequest) (*entity.OrderInquiryResponse, error)
|
req *entity.OrderRequest) (*entity.OrderInquiryResponse, error)
|
||||||
ExecuteOrderInquiry(ctx mycontext.Context,
|
ExecuteOrderInquiry(ctx mycontext.Context,
|
||||||
token string, paymentMethod, paymentProvider string, inProgressOrderID int64) (*entity.OrderResponse, error)
|
token string, paymentMethod, paymentProvider string, inProgressOrderID int64) (*entity.OrderResponse, error)
|
||||||
|
RefundRequest(ctx mycontext.Context, partnerID, orderID int64, reason string) error
|
||||||
GetOrderHistory(ctx mycontext.Context, partnerID int64, request entity.SearchRequest) ([]*entity.Order, int64, error)
|
GetOrderHistory(ctx mycontext.Context, partnerID int64, request entity.SearchRequest) ([]*entity.Order, int64, error)
|
||||||
CalculateOrderTotals(
|
CalculateOrderTotals(
|
||||||
ctx mycontext.Context,
|
ctx mycontext.Context,
|
||||||
@ -122,6 +124,10 @@ type VoucherUndianRepo interface {
|
|||||||
CreateUndianVouchers(ctx mycontext.Context, vouchers []*entity.UndianVoucherDB) error
|
CreateUndianVouchers(ctx mycontext.Context, vouchers []*entity.UndianVoucherDB) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CashierSvc interface {
|
||||||
|
GetOpenSession(ctx mycontext.Context, cashierID int64) (*entity.CashierSession, error)
|
||||||
|
}
|
||||||
|
|
||||||
type orderSvc struct {
|
type orderSvc struct {
|
||||||
repo Repository
|
repo Repository
|
||||||
product ProductService
|
product ProductService
|
||||||
@ -133,6 +139,7 @@ type orderSvc struct {
|
|||||||
partnerSetting PartnerSettings
|
partnerSetting PartnerSettings
|
||||||
inprogressOrder InProgressOrderRepository
|
inprogressOrder InProgressOrderRepository
|
||||||
voucherUndianRepo VoucherUndianRepo
|
voucherUndianRepo VoucherUndianRepo
|
||||||
|
cashierSvc CashierSvc
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(
|
func New(
|
||||||
@ -145,6 +152,7 @@ func New(
|
|||||||
notification NotificationService,
|
notification NotificationService,
|
||||||
partnerSetting PartnerSettings,
|
partnerSetting PartnerSettings,
|
||||||
voucherUndianRepo VoucherUndianRepo,
|
voucherUndianRepo VoucherUndianRepo,
|
||||||
|
cashierSvc CashierSvc,
|
||||||
) Service {
|
) Service {
|
||||||
return &orderSvc{
|
return &orderSvc{
|
||||||
repo: repo,
|
repo: repo,
|
||||||
@ -156,5 +164,6 @@ func New(
|
|||||||
notification: notification,
|
notification: notification,
|
||||||
partnerSetting: partnerSetting,
|
partnerSetting: partnerSetting,
|
||||||
voucherUndianRepo: voucherUndianRepo,
|
voucherUndianRepo: voucherUndianRepo,
|
||||||
|
cashierSvc: cashierSvc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user