Add void print
This commit is contained in:
@@ -3,10 +3,13 @@ package order
|
||||
type OrderStatus string
|
||||
|
||||
const (
|
||||
New OrderStatus = "NEW"
|
||||
Paid OrderStatus = "PAID"
|
||||
Cancel OrderStatus = "CANCEL"
|
||||
Pending OrderStatus = "PENDING"
|
||||
New OrderStatus = "NEW"
|
||||
Paid OrderStatus = "PAID"
|
||||
Cancel OrderStatus = "CANCEL"
|
||||
Pending OrderStatus = "PENDING"
|
||||
Refunded OrderStatus = "REFUNDED"
|
||||
Voided OrderStatus = "VOIDED"
|
||||
Partial OrderStatus = "PARTIAL"
|
||||
)
|
||||
|
||||
func (b OrderStatus) toString() string {
|
||||
|
||||
@@ -6,6 +6,7 @@ const (
|
||||
New PaymentStatus = "NEW"
|
||||
Paid PaymentStatus = "PAID"
|
||||
Cancel PaymentStatus = "CANCEL"
|
||||
Refund PaymentStatus = "REFUND"
|
||||
)
|
||||
|
||||
func (b PaymentStatus) toString() string {
|
||||
|
||||
@@ -124,6 +124,30 @@ type OrderItemRequest struct {
|
||||
Notes string `json:"notes"`
|
||||
}
|
||||
|
||||
type PartialRefundItem struct {
|
||||
OrderItemID int64 `json:"order_item_id" validate:"required"`
|
||||
Quantity int `json:"quantity" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type VoidItem struct {
|
||||
OrderItemID int64 `json:"order_item_id" validate:"required"`
|
||||
Quantity int `json:"quantity" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type SplitBillSplit struct {
|
||||
CustomerName string `json:"customer_name" validate:"required"`
|
||||
CustomerID *int64 `json:"customer_id"`
|
||||
Items []SplitBillItem `json:"items,omitempty" validate:"required_if=Type ITEM,dive"`
|
||||
Amount float64 `json:"amount,omitempty" validate:"required_if=Type AMOUNT,min=0"`
|
||||
}
|
||||
|
||||
type SplitBillItem struct {
|
||||
OrderItemID int64 `json:"order_item_id" validate:"required"`
|
||||
Quantity int `json:"quantity" validate:"required,min=1"`
|
||||
CustomerName string `json:"customer_name" validate:"required"`
|
||||
CustomerID *int64 `json:"customer_id"`
|
||||
}
|
||||
|
||||
type OrderExecuteRequest struct {
|
||||
CreatedBy int64
|
||||
PartnerID int64
|
||||
|
||||
@@ -30,12 +30,15 @@ func (h *Handler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
|
||||
route.POST("/inquiry", jwt, h.Inquiry)
|
||||
route.POST("/execute", jwt, h.Execute)
|
||||
route.POST("/refund", jwt, h.Refund)
|
||||
route.POST("/partial-refund", jwt, h.PartialRefund)
|
||||
route.POST("/void", jwt, h.VoidOrder)
|
||||
route.POST("/split-bill", jwt, h.SplitBill)
|
||||
route.GET("/history", jwt, h.GetOrderHistory)
|
||||
route.GET("/refund-history", jwt, h.GetRefundHistory)
|
||||
route.GET("/payment-analysis", jwt, h.GetPaymentMethodAnalysis)
|
||||
route.GET("/revenue-overview", jwt, h.GetRevenueOverview)
|
||||
route.GET("/sales-by-category", jwt, h.GetSalesByCategory)
|
||||
route.GET("/popular-products", jwt, h.GetPopularProducts)
|
||||
|
||||
}
|
||||
|
||||
type InquiryRequest struct {
|
||||
@@ -77,6 +80,123 @@ type RefundRequest struct {
|
||||
Reason string `json:"reason" validate:"required"`
|
||||
}
|
||||
|
||||
type PartialRefundRequest struct {
|
||||
OrderID int64 `json:"order_id" validate:"required"`
|
||||
Reason string `json:"reason" validate:"required"`
|
||||
Items []PartialRefundItemRequest `json:"items" validate:"required,min=1,dive"`
|
||||
}
|
||||
|
||||
type PartialRefundItemRequest struct {
|
||||
OrderItemID int64 `json:"order_item_id" validate:"required"`
|
||||
Quantity int `json:"quantity" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type VoidOrderRequest struct {
|
||||
OrderID int64 `json:"order_id" validate:"required"`
|
||||
Reason string `json:"reason" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=ALL ITEM"`
|
||||
Items []VoidItemRequest `json:"items,omitempty" validate:"required_if=Type ITEM,dive"`
|
||||
}
|
||||
|
||||
type VoidItemRequest struct {
|
||||
OrderItemID int64 `json:"order_item_id" validate:"required"`
|
||||
Quantity int `json:"quantity" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type SplitBillRequest struct {
|
||||
OrderID int64 `json:"order_id" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=ITEM AMOUNT"`
|
||||
PaymentMethod string `json:"payment_method" validate:"required"`
|
||||
PaymentProvider string `json:"payment_provider"`
|
||||
Items []SplitBillItemRequest `json:"items,omitempty" validate:"required_if=Type ITEM,dive"`
|
||||
Amount float64 `json:"amount,omitempty" validate:"required_if=Type AMOUNT,min=0"`
|
||||
}
|
||||
|
||||
type SplitBillItemRequest struct {
|
||||
OrderItemID int64 `json:"order_item_id" validate:"required"`
|
||||
Quantity int `json:"quantity" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type RefundResponse struct {
|
||||
OrderID int64 `json:"order_id"`
|
||||
Status string `json:"status"`
|
||||
RefundAmount float64 `json:"refund_amount"`
|
||||
Reason string `json:"reason"`
|
||||
RefundedAt string `json:"refunded_at"`
|
||||
CustomerName string `json:"customer_name"`
|
||||
PaymentType string `json:"payment_type"`
|
||||
}
|
||||
|
||||
type RefundHistoryResponse struct {
|
||||
OrderID int64 `json:"order_id"`
|
||||
CustomerName string `json:"customer_name"`
|
||||
CustomerID *int64 `json:"customer_id"`
|
||||
IsMember bool `json:"is_member"`
|
||||
Status string `json:"status"`
|
||||
Amount float64 `json:"amount"`
|
||||
Total float64 `json:"total"`
|
||||
PaymentType string `json:"payment_type"`
|
||||
TableNumber string `json:"table_number"`
|
||||
OrderType string `json:"order_type"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
RefundedAt string `json:"refunded_at"`
|
||||
Tax float64 `json:"tax"`
|
||||
}
|
||||
|
||||
type PartialRefundResponse struct {
|
||||
OrderID int64 `json:"order_id"`
|
||||
Status string `json:"status"`
|
||||
RefundedAmount float64 `json:"refunded_amount"`
|
||||
RemainingAmount float64 `json:"remaining_amount"`
|
||||
Reason string `json:"reason"`
|
||||
RefundedAt string `json:"refunded_at"`
|
||||
CustomerName string `json:"customer_name"`
|
||||
PaymentType string `json:"payment_type"`
|
||||
RefundedItems []RefundedItemResponse `json:"refunded_items"`
|
||||
}
|
||||
|
||||
type RefundedItemResponse struct {
|
||||
OrderItemID int64 `json:"order_item_id"`
|
||||
ItemName string `json:"item_name"`
|
||||
Quantity int `json:"quantity"`
|
||||
UnitPrice float64 `json:"unit_price"`
|
||||
TotalPrice float64 `json:"total_price"`
|
||||
}
|
||||
|
||||
type VoidOrderResponse struct {
|
||||
OrderID int64 `json:"order_id"`
|
||||
Status string `json:"status"`
|
||||
Reason string `json:"reason"`
|
||||
VoidedAt string `json:"voided_at"`
|
||||
CustomerName string `json:"customer_name"`
|
||||
VoidedItems []VoidedItemResponse `json:"voided_items,omitempty"`
|
||||
}
|
||||
|
||||
type VoidedItemResponse struct {
|
||||
OrderItemID int64 `json:"order_item_id"`
|
||||
ItemName string `json:"item_name"`
|
||||
Quantity int `json:"quantity"`
|
||||
UnitPrice float64 `json:"unit_price"`
|
||||
TotalPrice float64 `json:"total_price"`
|
||||
}
|
||||
|
||||
type SplitBillResponse struct {
|
||||
OriginalOrderID int64 `json:"original_order_id"`
|
||||
SplitOrders []SplitOrderResponse `json:"split_orders"`
|
||||
SplitAt string `json:"split_at"`
|
||||
}
|
||||
|
||||
type SplitOrderResponse struct {
|
||||
OrderID int64 `json:"order_id"`
|
||||
CustomerName string `json:"customer_name"`
|
||||
CustomerID *int64 `json:"customer_id"`
|
||||
Amount float64 `json:"amount"`
|
||||
Total float64 `json:"total"`
|
||||
Tax float64 `json:"tax"`
|
||||
Status string `json:"status"`
|
||||
Items []response.OrderItemResponse `json:"items"`
|
||||
}
|
||||
|
||||
func (h *Handler) Inquiry(c *gin.Context) {
|
||||
ctx := request.GetMyContext(c)
|
||||
userID := ctx.RequestedBy()
|
||||
@@ -181,9 +301,30 @@ func (h *Handler) Refund(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
order, err := h.service.GetOrderByID(ctx, req.OrderID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Message: "Refund processed successfully",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
refundResponse := RefundResponse{
|
||||
OrderID: order.ID,
|
||||
Status: order.Status,
|
||||
RefundAmount: order.Total,
|
||||
Reason: req.Reason,
|
||||
RefundedAt: order.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
CustomerName: order.CustomerName,
|
||||
PaymentType: h.formatPayment(order.PaymentType, order.PaymentProvider),
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Data: refundResponse,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -488,3 +629,292 @@ func (h *Handler) GetPopularProducts(c *gin.Context) {
|
||||
Data: popularProducts,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) GetRefundHistory(c *gin.Context) {
|
||||
ctx := request.GetMyContext(c)
|
||||
partnerID := ctx.GetPartnerID()
|
||||
|
||||
limitStr := c.Query("limit")
|
||||
offsetStr := c.Query("offset")
|
||||
startDateStr := c.Query("start_date")
|
||||
endDateStr := c.Query("end_date")
|
||||
|
||||
searchReq := entity.SearchRequest{}
|
||||
|
||||
limit := 20
|
||||
if limitStr != "" {
|
||||
parsedLimit, err := strconv.Atoi(limitStr)
|
||||
if err == nil && parsedLimit > 0 {
|
||||
limit = parsedLimit
|
||||
}
|
||||
}
|
||||
|
||||
if limit > 100 {
|
||||
limit = 100
|
||||
}
|
||||
|
||||
searchReq.Limit = limit
|
||||
|
||||
offset := 0
|
||||
if offsetStr != "" {
|
||||
parsedOffset, err := strconv.Atoi(offsetStr)
|
||||
if err == nil && parsedOffset >= 0 {
|
||||
offset = parsedOffset
|
||||
}
|
||||
}
|
||||
|
||||
searchReq.Offset = offset
|
||||
|
||||
// Set status to REFUNDED to get only refunded orders
|
||||
searchReq.Status = "REFUNDED"
|
||||
|
||||
if startDateStr != "" {
|
||||
startDate, err := time.Parse(time.RFC3339, startDateStr)
|
||||
if err == nil {
|
||||
searchReq.Start = startDate
|
||||
}
|
||||
}
|
||||
|
||||
if endDateStr != "" {
|
||||
endDate, err := time.Parse(time.RFC3339, endDateStr)
|
||||
if err == nil {
|
||||
searchReq.End = endDate
|
||||
}
|
||||
}
|
||||
|
||||
orders, total, err := h.service.GetOrderHistory(ctx, *partnerID, searchReq)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
responseData := []RefundHistoryResponse{}
|
||||
for _, order := range orders {
|
||||
responseData = append(responseData, RefundHistoryResponse{
|
||||
OrderID: order.ID,
|
||||
CustomerName: order.CustomerName,
|
||||
CustomerID: order.CustomerID,
|
||||
IsMember: order.IsMemberOrder(),
|
||||
Status: order.Status,
|
||||
Amount: order.Amount,
|
||||
Total: order.Total,
|
||||
PaymentType: h.formatPayment(order.PaymentType, order.PaymentProvider),
|
||||
TableNumber: order.TableNumber,
|
||||
OrderType: order.OrderType,
|
||||
CreatedAt: order.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
RefundedAt: order.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
Tax: order.Tax,
|
||||
})
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Data: responseData,
|
||||
PagingMeta: &response.PagingMeta{
|
||||
Page: offset + 1,
|
||||
Total: int64(total),
|
||||
Limit: limit,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) PartialRefund(c *gin.Context) {
|
||||
ctx := request.GetMyContext(c)
|
||||
|
||||
var req PartialRefundRequest
|
||||
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
|
||||
}
|
||||
|
||||
items := make([]entity.PartialRefundItem, len(req.Items))
|
||||
for i, item := range req.Items {
|
||||
items[i] = entity.PartialRefundItem{
|
||||
OrderItemID: item.OrderItemID,
|
||||
Quantity: item.Quantity,
|
||||
}
|
||||
}
|
||||
|
||||
err := h.service.PartialRefundRequest(ctx, *ctx.GetPartnerID(), req.OrderID, req.Reason, items)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Get updated order to return details
|
||||
order, err := h.service.GetOrderByID(ctx, req.OrderID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Message: "Partial refund processed successfully",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Calculate refunded amount
|
||||
refundedAmount := 0.0
|
||||
var refundedItems []RefundedItemResponse
|
||||
|
||||
for _, reqItem := range req.Items {
|
||||
for _, orderItem := range order.OrderItems {
|
||||
if orderItem.ID == reqItem.OrderItemID {
|
||||
itemTotal := orderItem.Price * float64(reqItem.Quantity)
|
||||
refundedAmount += itemTotal
|
||||
|
||||
refundedItems = append(refundedItems, RefundedItemResponse{
|
||||
OrderItemID: orderItem.ID,
|
||||
ItemName: orderItem.ItemName,
|
||||
Quantity: reqItem.Quantity,
|
||||
UnitPrice: orderItem.Price,
|
||||
TotalPrice: itemTotal,
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partialRefundResponse := PartialRefundResponse{
|
||||
OrderID: order.ID,
|
||||
Status: order.Status,
|
||||
RefundedAmount: refundedAmount,
|
||||
RemainingAmount: order.Total,
|
||||
Reason: req.Reason,
|
||||
RefundedAt: order.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
CustomerName: order.CustomerName,
|
||||
PaymentType: h.formatPayment(order.PaymentType, order.PaymentProvider),
|
||||
RefundedItems: refundedItems,
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Data: partialRefundResponse,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) VoidOrder(c *gin.Context) {
|
||||
ctx := request.GetMyContext(c)
|
||||
|
||||
var req VoidOrderRequest
|
||||
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
|
||||
}
|
||||
|
||||
// Convert request items to entity items
|
||||
var items []entity.VoidItem
|
||||
if req.Type == "ITEM" {
|
||||
items = make([]entity.VoidItem, len(req.Items))
|
||||
for i, item := range req.Items {
|
||||
items[i] = entity.VoidItem{
|
||||
OrderItemID: item.OrderItemID,
|
||||
Quantity: item.Quantity,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err := h.service.VoidOrderRequest(ctx, *ctx.GetPartnerID(), req.OrderID, req.Reason, req.Type, items)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Get updated order to return details
|
||||
order, err := h.service.GetOrderByID(ctx, req.OrderID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Message: "Order voided successfully",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var voidedItems []VoidedItemResponse
|
||||
if req.Type == "ITEM" {
|
||||
for _, reqItem := range req.Items {
|
||||
for _, orderItem := range order.OrderItems {
|
||||
if orderItem.ID == reqItem.OrderItemID {
|
||||
itemTotal := orderItem.Price * float64(reqItem.Quantity)
|
||||
|
||||
voidedItems = append(voidedItems, VoidedItemResponse{
|
||||
OrderItemID: orderItem.ID,
|
||||
ItemName: orderItem.ItemName,
|
||||
Quantity: reqItem.Quantity,
|
||||
UnitPrice: orderItem.Price,
|
||||
TotalPrice: itemTotal,
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
voidOrderResponse := VoidOrderResponse{
|
||||
OrderID: order.ID,
|
||||
Status: order.Status,
|
||||
Reason: req.Reason,
|
||||
VoidedAt: order.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
CustomerName: order.CustomerName,
|
||||
VoidedItems: voidedItems,
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Data: voidOrderResponse,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) SplitBill(c *gin.Context) {
|
||||
ctx := request.GetMyContext(c)
|
||||
|
||||
var req SplitBillRequest
|
||||
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
|
||||
}
|
||||
|
||||
var items []entity.SplitBillItem
|
||||
if req.Type == "ITEM" {
|
||||
items = make([]entity.SplitBillItem, len(req.Items))
|
||||
for i, item := range req.Items {
|
||||
items[i] = entity.SplitBillItem{
|
||||
OrderItemID: item.OrderItemID,
|
||||
Quantity: item.Quantity,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
splitOrder, err := h.service.SplitBillRequest(ctx, *ctx.GetPartnerID(), req.OrderID, req.Type, req.PaymentMethod, req.PaymentProvider, items, req.Amount)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Data: response.MapToOrderResponse(&entity.OrderResponse{Order: splitOrder}),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"enaklo-pos-be/internal/handlers/request"
|
||||
"enaklo-pos-be/internal/handlers/response"
|
||||
"enaklo-pos-be/internal/services"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"net/http"
|
||||
@@ -50,6 +51,7 @@ func (h *Handler) Create(c *gin.Context) {
|
||||
|
||||
var req request.Product
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
fmt.Println(err)
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
type TransactionDB struct {
|
||||
ID string `gorm:"primaryKey;column:id"`
|
||||
ID string `gorm:"type:uuid;default:gen_random_uuid();primaryKey;column:id"`
|
||||
OrderID int64 `gorm:"column:order_id"`
|
||||
Amount float64 `gorm:"column:amount"`
|
||||
PaymentMethod string `gorm:"column:payment_method"`
|
||||
|
||||
@@ -41,6 +41,8 @@ type OrderRepository interface {
|
||||
GetOrderHistoryByUserID(ctx mycontext.Context, userID int64, req entity.SearchRequest) ([]*entity.Order, int64, error)
|
||||
FindByIDAndCustomerID(ctx mycontext.Context, id int64, customerID int64) (*entity.Order, error)
|
||||
UpdateOrder(ctx mycontext.Context, id int64, status string, description string) error
|
||||
UpdateOrderItem(ctx mycontext.Context, orderItemID int64, quantity int) error
|
||||
UpdateOrderTotals(ctx mycontext.Context, orderID int64, amount, tax, total float64) error
|
||||
}
|
||||
|
||||
type orderRepository struct {
|
||||
@@ -979,3 +981,47 @@ func (r *orderRepository) FindByIDAndCustomerID(ctx mycontext.Context, id int64,
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (r *orderRepository) UpdateOrderItem(ctx mycontext.Context, orderItemID int64, quantity int) error {
|
||||
now := time.Now()
|
||||
|
||||
result := r.db.Model(&models.OrderItemDB{}).
|
||||
Where("order_item_id = ?", orderItemID).
|
||||
Updates(map[string]interface{}{
|
||||
"quantity": quantity,
|
||||
"updated_at": now,
|
||||
})
|
||||
|
||||
if result.Error != nil {
|
||||
return errors.Wrap(result.Error, "failed to update order item")
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
logger.ContextLogger(ctx).Warn("no order item updated")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *orderRepository) UpdateOrderTotals(ctx mycontext.Context, orderID int64, amount, tax, total float64) error {
|
||||
now := time.Now()
|
||||
|
||||
result := r.db.Model(&models.OrderDB{}).
|
||||
Where("id = ?", orderID).
|
||||
Updates(map[string]interface{}{
|
||||
"amount": amount,
|
||||
"tax": tax,
|
||||
"total": total,
|
||||
"updated_at": now,
|
||||
})
|
||||
|
||||
if result.Error != nil {
|
||||
return errors.Wrap(result.Error, "failed to update order totals")
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
logger.ContextLogger(ctx).Warn("no order updated")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"enaklo-pos-be/internal/common/mycontext"
|
||||
"enaklo-pos-be/internal/entity"
|
||||
"enaklo-pos-be/internal/repository/models"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -51,7 +52,7 @@ func (r *transactionRepository) FindByOrderID(ctx mycontext.Context, orderID int
|
||||
|
||||
func (r *transactionRepository) toTransactionDBModel(transaction *entity.Transaction) models.TransactionDB {
|
||||
return models.TransactionDB{
|
||||
ID: transaction.ID,
|
||||
ID: uuid.New().String(),
|
||||
OrderID: transaction.OrderID,
|
||||
Amount: transaction.Amount,
|
||||
PaymentMethod: transaction.PaymentMethod,
|
||||
|
||||
@@ -0,0 +1,403 @@
|
||||
package order
|
||||
|
||||
import (
|
||||
"enaklo-pos-be/internal/common/logger"
|
||||
"enaklo-pos-be/internal/common/mycontext"
|
||||
"enaklo-pos-be/internal/entity"
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (s *orderSvc) PartialRefundRequest(ctx mycontext.Context, partnerID, orderID int64, reason string, items []entity.PartialRefundItem) error {
|
||||
order, err := s.repo.FindByIDAndPartnerID(ctx, orderID, partnerID)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to find order for partial refund", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
if order.Status != "PAID" && order.Status != "PARTIAL" {
|
||||
return errors.New("only paid order can be partially refunded")
|
||||
}
|
||||
|
||||
refundedAmount := 0.0
|
||||
orderItemMap := make(map[int64]*entity.OrderItem)
|
||||
|
||||
for _, item := range order.OrderItems {
|
||||
orderItemMap[item.ID] = &item
|
||||
}
|
||||
|
||||
for _, refundItem := range items {
|
||||
orderItem, exists := orderItemMap[refundItem.OrderItemID]
|
||||
if !exists {
|
||||
return errors.New(fmt.Sprintf("order item %d not found", refundItem.OrderItemID))
|
||||
}
|
||||
|
||||
if refundItem.Quantity > orderItem.Quantity {
|
||||
return errors.New(fmt.Sprintf("refund quantity %d exceeds available quantity %d for item %d",
|
||||
refundItem.Quantity, orderItem.Quantity, refundItem.OrderItemID))
|
||||
}
|
||||
|
||||
refundedAmount += orderItem.Price * float64(refundItem.Quantity)
|
||||
}
|
||||
|
||||
for _, refundItem := range items {
|
||||
orderItem := orderItemMap[refundItem.OrderItemID]
|
||||
newQuantity := orderItem.Quantity - refundItem.Quantity
|
||||
|
||||
if newQuantity == 0 {
|
||||
err = s.repo.UpdateOrderItem(ctx, refundItem.OrderItemID, 0)
|
||||
} else {
|
||||
err = s.repo.UpdateOrderItem(ctx, refundItem.OrderItemID, newQuantity)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to update order item", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
remainingAmount := order.Amount - refundedAmount
|
||||
remainingTax := (remainingAmount / order.Amount) * order.Tax
|
||||
remainingTotal := remainingAmount + remainingTax
|
||||
|
||||
err = s.repo.UpdateOrderTotals(ctx, orderID, remainingAmount, remainingTax, remainingTotal)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to update order totals", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
newStatus := "PARTIAL"
|
||||
if remainingAmount <= 0 {
|
||||
newStatus = "REFUNDED"
|
||||
}
|
||||
|
||||
err = s.repo.UpdateOrder(ctx, orderID, newStatus, reason)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to update order status", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
refundTransaction, err := s.createRefundTransaction(ctx, order, reason)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to create refund transaction", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
refundTransaction.Amount = -refundedAmount
|
||||
_, err = s.transaction.Create(ctx, refundTransaction)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to update refund transaction", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
logger.ContextLogger(ctx).Info("partial refund processed successfully",
|
||||
zap.Int64("orderID", orderID),
|
||||
zap.String("reason", reason),
|
||||
zap.Float64("refundedAmount", refundedAmount),
|
||||
zap.String("refundTransactionID", refundTransaction.ID))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// VoidOrderRequest handles voiding orders (for ongoing orders) or specific items
|
||||
func (s *orderSvc) VoidOrderRequest(ctx mycontext.Context, partnerID, orderID int64, reason string, voidType string, items []entity.VoidItem) error {
|
||||
order, err := s.repo.FindByIDAndPartnerID(ctx, orderID, partnerID)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to find order for void", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// Only allow voiding for NEW, PENDING orders
|
||||
if order.Status != "NEW" && order.Status != "PENDING" {
|
||||
return errors.New("only new or pending orders can be voided")
|
||||
}
|
||||
|
||||
if voidType == "ALL" {
|
||||
// Void entire order
|
||||
err = s.repo.UpdateOrder(ctx, orderID, "VOIDED", reason)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to void order", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
} else if voidType == "ITEM" {
|
||||
// Void specific items
|
||||
voidedAmount := 0.0
|
||||
orderItemMap := make(map[int64]*entity.OrderItem)
|
||||
|
||||
for _, item := range order.OrderItems {
|
||||
orderItemMap[item.ID] = &item
|
||||
}
|
||||
|
||||
for _, voidItem := range items {
|
||||
orderItem, exists := orderItemMap[voidItem.OrderItemID]
|
||||
if !exists {
|
||||
return errors.New(fmt.Sprintf("order item %d not found", voidItem.OrderItemID))
|
||||
}
|
||||
|
||||
if voidItem.Quantity > orderItem.Quantity {
|
||||
return errors.New(fmt.Sprintf("void quantity %d exceeds available quantity %d for item %d",
|
||||
voidItem.Quantity, orderItem.Quantity, voidItem.OrderItemID))
|
||||
}
|
||||
|
||||
voidedAmount += orderItem.Price * float64(voidItem.Quantity)
|
||||
}
|
||||
|
||||
// Update order items with reduced quantities
|
||||
for _, voidItem := range items {
|
||||
orderItem := orderItemMap[voidItem.OrderItemID]
|
||||
newQuantity := orderItem.Quantity - voidItem.Quantity
|
||||
|
||||
if newQuantity == 0 {
|
||||
// Remove item completely
|
||||
err = s.repo.UpdateOrderItem(ctx, voidItem.OrderItemID, 0)
|
||||
} else {
|
||||
// Update quantity
|
||||
err = s.repo.UpdateOrderItem(ctx, voidItem.OrderItemID, newQuantity)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to update order item", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Recalculate order totals
|
||||
remainingAmount := order.Amount - voidedAmount
|
||||
remainingTax := (remainingAmount / order.Amount) * order.Tax
|
||||
remainingTotal := remainingAmount + remainingTax
|
||||
|
||||
// Update order totals
|
||||
err = s.repo.UpdateOrderTotals(ctx, orderID, remainingAmount, remainingTax, remainingTotal)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to update order totals", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// Update order status to PARTIAL if some items remain, otherwise to VOIDED
|
||||
newStatus := "PARTIAL"
|
||||
if remainingAmount <= 0 {
|
||||
newStatus = "VOIDED"
|
||||
}
|
||||
|
||||
err = s.repo.UpdateOrder(ctx, orderID, newStatus, reason)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to update order status", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
logger.ContextLogger(ctx).Info("order voided successfully",
|
||||
zap.Int64("orderID", orderID),
|
||||
zap.String("reason", reason),
|
||||
zap.String("voidType", voidType))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SplitBillRequest handles splitting bills by items or amounts
|
||||
func (s *orderSvc) SplitBillRequest(ctx mycontext.Context, partnerID, orderID int64, splitType string, paymentMethod string, paymentProvider string, items []entity.SplitBillItem, amount float64) (*entity.Order, error) {
|
||||
order, err := s.repo.FindByIDAndPartnerID(ctx, orderID, partnerID)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to find order for split bill", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if order.Status != "NEW" && order.Status != "PENDING" {
|
||||
return nil, errors.New("only new or pending orders can be split")
|
||||
}
|
||||
|
||||
var splitOrder *entity.Order
|
||||
|
||||
if splitType == "ITEM" {
|
||||
splitOrder, err = s.splitByItems(ctx, order, paymentMethod, paymentProvider, items)
|
||||
} else if splitType == "AMOUNT" {
|
||||
splitOrder, err = s.splitByAmount(ctx, order, paymentMethod, paymentProvider, amount)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to split bill", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.ContextLogger(ctx).Info("bill split successfully",
|
||||
zap.Int64("orderID", orderID),
|
||||
zap.String("splitType", splitType),
|
||||
zap.Int64("splitOrderID", splitOrder.ID))
|
||||
|
||||
return splitOrder, nil
|
||||
}
|
||||
|
||||
func (s *orderSvc) splitByItems(ctx mycontext.Context, originalOrder *entity.Order, paymentMethod string, paymentProvider string, items []entity.SplitBillItem) (*entity.Order, error) {
|
||||
var splitOrderItems []entity.OrderItem
|
||||
orderItemMap := make(map[int64]*entity.OrderItem)
|
||||
|
||||
for _, item := range originalOrder.OrderItems {
|
||||
orderItemMap[item.ID] = &item
|
||||
}
|
||||
|
||||
assignedItems := make(map[int64]bool)
|
||||
|
||||
for _, item := range items {
|
||||
orderItem, exists := orderItemMap[item.OrderItemID]
|
||||
if !exists {
|
||||
return nil, errors.New(fmt.Sprintf("order item %d not found", item.OrderItemID))
|
||||
}
|
||||
|
||||
if item.Quantity > orderItem.Quantity {
|
||||
return nil, errors.New(fmt.Sprintf("split quantity %d exceeds available quantity %d for item %d",
|
||||
item.Quantity, orderItem.Quantity, item.OrderItemID))
|
||||
}
|
||||
|
||||
if assignedItems[item.OrderItemID] {
|
||||
return nil, errors.New(fmt.Sprintf("order item %d is already assigned to another split", item.OrderItemID))
|
||||
}
|
||||
|
||||
assignedItems[item.OrderItemID] = true
|
||||
|
||||
splitOrderItems = append(splitOrderItems, entity.OrderItem{
|
||||
ItemID: orderItem.ItemID,
|
||||
ItemType: orderItem.ItemType,
|
||||
Price: orderItem.Price,
|
||||
ItemName: orderItem.ItemName,
|
||||
Quantity: item.Quantity,
|
||||
CreatedBy: originalOrder.CreatedBy,
|
||||
Product: orderItem.Product,
|
||||
Notes: orderItem.Notes,
|
||||
})
|
||||
}
|
||||
|
||||
splitAmount := 0.0
|
||||
for _, item := range splitOrderItems {
|
||||
splitAmount += item.Price * float64(item.Quantity)
|
||||
}
|
||||
|
||||
splitTax := (splitAmount / originalOrder.Amount) * originalOrder.Tax
|
||||
splitTotal := splitAmount + splitTax
|
||||
|
||||
// Create new PAID order for the split
|
||||
splitOrder := &entity.Order{
|
||||
PartnerID: originalOrder.PartnerID,
|
||||
CustomerID: originalOrder.CustomerID,
|
||||
CustomerName: originalOrder.CustomerName,
|
||||
Status: "PAID",
|
||||
Amount: splitAmount,
|
||||
Tax: splitTax,
|
||||
Total: splitTotal,
|
||||
PaymentType: paymentMethod,
|
||||
PaymentProvider: paymentProvider,
|
||||
Source: originalOrder.Source,
|
||||
CreatedBy: originalOrder.CreatedBy,
|
||||
OrderItems: splitOrderItems,
|
||||
OrderType: originalOrder.OrderType,
|
||||
TableNumber: originalOrder.TableNumber,
|
||||
CashierSessionID: originalOrder.CashierSessionID,
|
||||
}
|
||||
|
||||
createdOrder, err := s.repo.Create(ctx, splitOrder)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to create split order", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Adjust original order items (reduce quantities)
|
||||
for _, item := range items {
|
||||
orderItem := orderItemMap[item.OrderItemID]
|
||||
newQuantity := orderItem.Quantity - item.Quantity
|
||||
|
||||
if newQuantity == 0 {
|
||||
// Remove item completely
|
||||
err = s.repo.UpdateOrderItem(ctx, item.OrderItemID, 0)
|
||||
} else {
|
||||
// Update quantity
|
||||
err = s.repo.UpdateOrderItem(ctx, item.OrderItemID, newQuantity)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to update original order item", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Recalculate original order totals
|
||||
remainingAmount := originalOrder.Amount - splitAmount
|
||||
remainingTax := (remainingAmount / originalOrder.Amount) * originalOrder.Tax
|
||||
remainingTotal := remainingAmount + remainingTax
|
||||
|
||||
// Update original order totals
|
||||
err = s.repo.UpdateOrderTotals(ctx, originalOrder.ID, remainingAmount, remainingTax, remainingTotal)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to update original order totals", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return createdOrder, nil
|
||||
}
|
||||
|
||||
// splitByAmount splits the order by assigning specific amounts to each split
|
||||
func (s *orderSvc) splitByAmount(ctx mycontext.Context, originalOrder *entity.Order, paymentMethod string, paymentProvider string, amount float64) (*entity.Order, error) {
|
||||
// Validate that split amount is less than original order total
|
||||
if amount >= originalOrder.Total {
|
||||
return nil, errors.New(fmt.Sprintf("split amount %.2f must be less than order total %.2f",
|
||||
amount, originalOrder.Total))
|
||||
}
|
||||
|
||||
// For amount-based split, we create a new order with all items
|
||||
var splitOrderItems []entity.OrderItem
|
||||
|
||||
for _, item := range originalOrder.OrderItems {
|
||||
splitOrderItems = append(splitOrderItems, entity.OrderItem{
|
||||
ItemID: item.ItemID,
|
||||
ItemType: item.ItemType,
|
||||
Price: item.Price,
|
||||
ItemName: item.ItemName,
|
||||
Quantity: item.Quantity,
|
||||
CreatedBy: originalOrder.CreatedBy,
|
||||
Product: item.Product,
|
||||
Notes: item.Notes,
|
||||
})
|
||||
}
|
||||
|
||||
splitAmount := amount
|
||||
splitTax := (splitAmount / originalOrder.Amount) * originalOrder.Tax
|
||||
splitTotal := splitAmount + splitTax
|
||||
|
||||
// Create new PAID order for the split
|
||||
splitOrder := &entity.Order{
|
||||
PartnerID: originalOrder.PartnerID,
|
||||
CustomerID: originalOrder.CustomerID,
|
||||
CustomerName: originalOrder.CustomerName,
|
||||
Status: "PAID",
|
||||
Amount: splitAmount,
|
||||
Tax: splitTax,
|
||||
Total: splitTotal,
|
||||
PaymentType: paymentMethod,
|
||||
PaymentProvider: paymentProvider,
|
||||
Source: originalOrder.Source,
|
||||
CreatedBy: originalOrder.CreatedBy,
|
||||
OrderItems: splitOrderItems,
|
||||
OrderType: originalOrder.OrderType,
|
||||
TableNumber: originalOrder.TableNumber,
|
||||
CashierSessionID: originalOrder.CashierSessionID,
|
||||
}
|
||||
|
||||
createdOrder, err := s.repo.Create(ctx, splitOrder)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to create split order", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Adjust original order amount
|
||||
remainingAmount := originalOrder.Amount - splitAmount
|
||||
remainingTax := (remainingAmount / originalOrder.Amount) * originalOrder.Tax
|
||||
remainingTotal := remainingAmount + remainingTax
|
||||
|
||||
// Update original order totals
|
||||
err = s.repo.UpdateOrderTotals(ctx, originalOrder.ID, remainingAmount, remainingTax, remainingTotal)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to update original order totals", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return createdOrder, nil
|
||||
}
|
||||
@@ -38,7 +38,7 @@ func (s *orderSvc) CreateOrderInquiry(ctx mycontext.Context,
|
||||
|
||||
customerID := int64(0)
|
||||
|
||||
if req.CustomerID != nil {
|
||||
if req.CustomerID != nil && *req.CustomerID != 0 {
|
||||
customer, err := s.customer.GetCustomer(ctx, *req.CustomerID)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("customer is not found", zap.Error(err))
|
||||
|
||||
@@ -38,9 +38,9 @@ func (s *orderSvc) ExecuteOrderInquiry(ctx mycontext.Context,
|
||||
}
|
||||
|
||||
func (s *orderSvc) RefundRequest(ctx mycontext.Context, partnerID, orderID int64, reason string) error {
|
||||
order, err := s.repo.FindByIDAndPartnerID(ctx, partnerID, orderID)
|
||||
order, err := s.repo.FindByIDAndPartnerID(ctx, orderID, partnerID)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to create order", zap.Error(err))
|
||||
logger.ContextLogger(ctx).Error("failed to find order for refund", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -48,7 +48,31 @@ func (s *orderSvc) RefundRequest(ctx mycontext.Context, partnerID, orderID int64
|
||||
return errors.New("only paid order can be refund")
|
||||
}
|
||||
|
||||
return s.repo.UpdateOrder(ctx, order.ID, "REFUNDED", reason)
|
||||
err = s.repo.UpdateOrder(ctx, order.ID, "REFUNDED", reason)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to update order status", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
refundTransaction, err := s.createRefundTransaction(ctx, order, reason)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to create refund transaction", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
if order.CustomerID != nil && *order.CustomerID > 0 {
|
||||
err = s.reverseCustomerVouchers(ctx, *order.CustomerID, int64(order.Total), order.ID)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Warn("failed to reverse customer vouchers", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
logger.ContextLogger(ctx).Info("refund processed successfully",
|
||||
zap.Int64("orderID", orderID),
|
||||
zap.String("reason", reason),
|
||||
zap.String("refundTransactionID", refundTransaction.ID))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *orderSvc) processPostOrderActions(
|
||||
@@ -262,3 +286,36 @@ func formatPaymentMethod(method string) string {
|
||||
}
|
||||
return method
|
||||
}
|
||||
|
||||
func (s *orderSvc) createRefundTransaction(ctx mycontext.Context, order *entity.Order, reason string) (*entity.Transaction, error) {
|
||||
transaction := &entity.Transaction{
|
||||
OrderID: order.ID,
|
||||
Amount: -order.Total,
|
||||
PaymentMethod: order.PaymentType,
|
||||
Status: "REFUND",
|
||||
CreatedAt: constants.TimeNow(),
|
||||
PartnerID: order.PartnerID,
|
||||
TransactionType: "REFUND",
|
||||
CreatedBy: ctx.RequestedBy(),
|
||||
UpdatedBy: ctx.RequestedBy(),
|
||||
}
|
||||
|
||||
_, err := s.transaction.Create(ctx, transaction)
|
||||
return transaction, err
|
||||
}
|
||||
|
||||
func (s *orderSvc) reverseCustomerVouchers(ctx mycontext.Context, customerID int64, total int64, orderID int64) error {
|
||||
// Find vouchers associated with this order and reverse them
|
||||
// This is a simplified implementation - in production you might want to track voucher-order relationships
|
||||
logger.ContextLogger(ctx).Info("reversing customer vouchers",
|
||||
zap.Int64("customerID", customerID),
|
||||
zap.Int64("orderID", orderID))
|
||||
|
||||
// TODO: Implement voucher reversal logic
|
||||
// This would involve:
|
||||
// 1. Finding vouchers created for this order
|
||||
// 2. Marking them as reversed/cancelled
|
||||
// 3. Optionally adjusting customer points
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ type Repository interface {
|
||||
FindInquiryByID(ctx mycontext.Context, id string) (*entity.OrderInquiry, error)
|
||||
UpdateInquiryStatus(ctx mycontext.Context, id string, status string) error
|
||||
UpdateOrder(ctx mycontext.Context, id int64, status string, description string) error
|
||||
UpdateOrderItem(ctx mycontext.Context, orderItemID int64, quantity int) error
|
||||
UpdateOrderTotals(ctx mycontext.Context, orderID int64, amount, tax, total float64) error
|
||||
GetOrderHistoryByPartnerID(ctx mycontext.Context, partnerID int64, req entity.SearchRequest) ([]*entity.Order, int64, error)
|
||||
GetOrderPaymentMethodBreakdown(
|
||||
ctx mycontext.Context,
|
||||
@@ -67,6 +69,9 @@ type Service interface {
|
||||
ExecuteOrderInquiry(ctx mycontext.Context,
|
||||
token string, paymentMethod, paymentProvider string, inProgressOrderID int64) (*entity.OrderResponse, error)
|
||||
RefundRequest(ctx mycontext.Context, partnerID, orderID int64, reason string) error
|
||||
PartialRefundRequest(ctx mycontext.Context, partnerID, orderID int64, reason string, items []entity.PartialRefundItem) error
|
||||
VoidOrderRequest(ctx mycontext.Context, partnerID, orderID int64, reason string, voidType string, items []entity.VoidItem) error
|
||||
SplitBillRequest(ctx mycontext.Context, partnerID, orderID int64, splitType string, paymentMethod string, paymentProvider string, items []entity.SplitBillItem, amount float64) (*entity.Order, error)
|
||||
GetOrderHistory(ctx mycontext.Context, partnerID int64, request entity.SearchRequest) ([]*entity.Order, int64, error)
|
||||
CalculateOrderTotals(
|
||||
ctx mycontext.Context,
|
||||
@@ -104,6 +109,7 @@ type Service interface {
|
||||
) ([]entity.PopularProductItem, error)
|
||||
GetCustomerOrderHistory(ctx mycontext.Context, userID int64, request entity.SearchRequest) ([]*entity.Order, int64, error)
|
||||
GetOrderByOrderAndCustomerID(ctx mycontext.Context, customerID int64, orderID int64) (*entity.Order, error)
|
||||
GetOrderByID(ctx mycontext.Context, orderID int64) (*entity.Order, error)
|
||||
}
|
||||
|
||||
type Config interface {
|
||||
|
||||
@@ -27,3 +27,15 @@ func (s *orderSvc) GetOrderByOrderAndCustomerID(ctx mycontext.Context, customerI
|
||||
|
||||
return orders, nil
|
||||
}
|
||||
|
||||
func (s *orderSvc) GetOrderByID(ctx mycontext.Context, orderID int64) (*entity.Order, error) {
|
||||
order, err := s.repo.FindByID(ctx, orderID)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to get order by ID",
|
||||
zap.Error(err),
|
||||
zap.Int64("orderID", orderID))
|
||||
return nil, errors.Wrap(err, "failed to get order")
|
||||
}
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user