apskel-pos-backend/internal/services/v2/order/create_order_inquiry.go
2025-03-08 00:35:23 +07:00

145 lines
3.9 KiB
Go

package order
import (
"enaklo-pos-be/internal/common/errors"
"enaklo-pos-be/internal/common/logger"
"enaklo-pos-be/internal/common/mycontext"
"enaklo-pos-be/internal/constants"
"enaklo-pos-be/internal/entity"
"go.uber.org/zap"
)
func (s *orderSvc) CreateOrderInquiry(ctx mycontext.Context,
req *entity.OrderRequest) (*entity.OrderInquiryResponse, error) {
productIDs, filteredItems, err := s.validateOrderItems(ctx, req.OrderItems)
if err != nil {
return nil, err
}
req.OrderItems = filteredItems
productDetails, err := s.product.GetProductDetails(ctx, productIDs, req.PartnerID)
if err != nil {
logger.ContextLogger(ctx).Error("failed to get product details", zap.Error(err))
return nil, err
}
orderCalculation, err := s.calculateOrderTotals(ctx, req.OrderItems, productDetails, req.Source)
if err != nil {
return nil, err
}
customerID, err := s.customer.ResolveCustomer(ctx, &entity.CustomerResolutionRequest{
ID: req.CustomerID,
Name: req.CustomerName,
Email: req.CustomerEmail,
PhoneNumber: req.CustomerPhoneNumber,
})
if err != nil {
logger.ContextLogger(ctx).Error("failed to resolve customer", zap.Error(err))
return nil, err
}
inquiry := entity.NewOrderInquiry(
req.PartnerID,
customerID,
orderCalculation.Subtotal,
orderCalculation.Fee,
orderCalculation.Total,
req.PaymentMethod,
req.Source,
req.CreatedBy,
req.CustomerName,
req.CustomerPhoneNumber,
req.CustomerEmail,
)
for _, item := range req.OrderItems {
product := productDetails.Products[item.ProductID]
inquiry.AddOrderItem(item, product)
}
savedInquiry, err := s.repo.CreateInquiry(ctx, inquiry)
if err != nil {
logger.ContextLogger(ctx).Error("failed to create order inquiry", zap.Error(err))
return nil, err
}
token, err := s.crypt.GenerateJWTOrderInquiry(savedInquiry)
if err != nil {
logger.ContextLogger(ctx).Error("failed to generate token", zap.Error(err))
return nil, err
}
return &entity.OrderInquiryResponse{
OrderInquiry: savedInquiry,
Token: token,
}, nil
}
func (s *orderSvc) validateOrderItems(ctx mycontext.Context, items []entity.OrderItemRequest) ([]int64, []entity.OrderItemRequest, error) {
var productIDs []int64
var filteredItems []entity.OrderItemRequest
for _, item := range items {
if item.Quantity <= 0 {
continue
}
productIDs = append(productIDs, item.ProductID)
filteredItems = append(filteredItems, item)
}
if len(productIDs) == 0 {
return nil, nil, errors.ErrorBadRequest
}
return productIDs, filteredItems, nil
}
func (s *orderSvc) calculateOrderTotals(
ctx mycontext.Context,
items []entity.OrderItemRequest,
productDetails *entity.ProductDetails,
source string,
) (*entity.OrderCalculation, error) {
subtotal := 0.0
for _, item := range items {
product, ok := productDetails.Products[item.ProductID]
if !ok {
return nil, errors.NewError(errors.ErrorInvalidRequest.ErrorType(), "product not found")
}
subtotal += product.Price * float64(item.Quantity)
}
fee := s.cfg.GetOrderFee(source)
return &entity.OrderCalculation{
Subtotal: subtotal,
Fee: fee,
Total: subtotal + fee,
}, nil
}
func (s *orderSvc) validateInquiry(ctx mycontext.Context, token string) (*entity.OrderInquiry, error) {
partnerID, inquiryID, err := s.crypt.ValidateJWTOrderInquiry(token)
if err != nil {
return nil, errors.NewError(errors.ErrorInvalidRequest.ErrorType(), "inquiry is not valid or expired")
}
if partnerID != *ctx.GetPartnerID() {
return nil, errors.NewError(errors.ErrorInvalidRequest.ErrorType(), "invalid request")
}
inquiry, err := s.repo.FindInquiryByID(ctx, inquiryID)
if err != nil {
logger.ContextLogger(ctx).Error("error when finding inquiry", zap.Error(err))
return nil, err
}
if inquiry.Status != constants.StatusPending {
return nil, errors.NewError(errors.ErrorInvalidRequest.ErrorType(), "inquiry is no longer pending")
}
return inquiry, nil
}