207 lines
5.8 KiB
Go
207 lines
5.8 KiB
Go
package orderService
|
|
|
|
import (
|
|
"strconv"
|
|
|
|
"git.ma-al.com/goc_daniel/b2b/app/actions/orderStatusActions"
|
|
"git.ma-al.com/goc_daniel/b2b/app/delivery/middleware/perms"
|
|
"git.ma-al.com/goc_daniel/b2b/app/model"
|
|
"git.ma-al.com/goc_daniel/b2b/app/model/enums"
|
|
"git.ma-al.com/goc_daniel/b2b/app/repos/cartsRepo"
|
|
"git.ma-al.com/goc_daniel/b2b/app/repos/ordersRepo"
|
|
"git.ma-al.com/goc_daniel/b2b/app/repos/productsRepo"
|
|
"git.ma-al.com/goc_daniel/b2b/app/service/addressesService"
|
|
"git.ma-al.com/goc_daniel/b2b/app/service/emailService"
|
|
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
|
|
"git.ma-al.com/goc_daniel/b2b/app/utils/logger"
|
|
"git.ma-al.com/goc_daniel/b2b/app/utils/query/filters"
|
|
"git.ma-al.com/goc_daniel/b2b/app/utils/query/find"
|
|
"git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors"
|
|
)
|
|
|
|
type OrderService struct {
|
|
ordersRepo ordersRepo.UIOrdersRepo
|
|
cartsRepo cartsRepo.UICartsRepo
|
|
productsRepo productsRepo.UIProductsRepo
|
|
addressesService *addressesService.AddressesService
|
|
emailService *emailService.EmailService
|
|
actionRegistry *orderStatusActions.ActionRegistry
|
|
}
|
|
|
|
func New() *OrderService {
|
|
return &OrderService{
|
|
ordersRepo: ordersRepo.New(),
|
|
cartsRepo: cartsRepo.New(),
|
|
productsRepo: productsRepo.New(),
|
|
addressesService: addressesService.New(),
|
|
emailService: emailService.NewEmailService(),
|
|
actionRegistry: &orderStatusActions.GlobalRegistry,
|
|
}
|
|
}
|
|
|
|
var ValidStatuses = map[enums.OrderStatus]bool{
|
|
enums.OrderStatusPending: true,
|
|
enums.OrderStatusConfirmed: true,
|
|
enums.OrderStatusProcessing: true,
|
|
enums.OrderStatusShipped: true,
|
|
enums.OrderStatusOutForDelivery: true,
|
|
enums.OrderStatusDelivered: true,
|
|
enums.OrderStatusCancelled: true,
|
|
enums.OrderStatusReturned: true,
|
|
enums.OrderStatusRefunded: true,
|
|
enums.OrderStatusFailed: true,
|
|
}
|
|
|
|
func (s *OrderService) Find(user *model.Customer, p find.Paging, filt *filters.FiltersList) (*find.Found[model.CustomerOrder], error) {
|
|
if !user.HasPermission(perms.OrdersViewAll) {
|
|
// append filter to view only this user's orders
|
|
idStr := strconv.FormatUint(uint64(user.ID), 10)
|
|
filt.Append(filters.Where("b2b_customer_orders.user_id = " + idStr))
|
|
}
|
|
|
|
list, err := s.ordersRepo.Find(user.ID, p, filt)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for i := 0; i < len(list.Items); i++ {
|
|
address_unparsed, err := s.addressesService.ValidateAddressJson(list.Items[i].AddressString, list.Items[i].CountryID)
|
|
if err != nil {
|
|
logger.Warn("failed to validate address",
|
|
"service", "orderService",
|
|
"order_id", list.Items[i].OrderID,
|
|
"error", err.Error(),
|
|
)
|
|
}
|
|
|
|
list.Items[i].AddressUnparsed = &address_unparsed
|
|
}
|
|
|
|
return list, nil
|
|
}
|
|
|
|
func (s *OrderService) PlaceNewOrder(user_id uint, cart_id uint, name string, country_id uint, address_info string, originalUserId uint) error {
|
|
_, err := s.addressesService.ValidateAddressJson(address_info, country_id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
exists, err := s.cartsRepo.UserHasCart(user_id, cart_id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !exists {
|
|
return responseErrors.ErrUserHasNoSuchCart
|
|
}
|
|
|
|
cart, err := s.cartsRepo.RetrieveCart(user_id, cart_id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(cart.Products) == 0 {
|
|
return responseErrors.ErrEmptyCart
|
|
}
|
|
|
|
if name == "" && cart.Name != nil {
|
|
name = *cart.Name
|
|
}
|
|
|
|
base_price, tax_incl, tax_excl, err := s.getOrderTotalPrice(user_id, cart_id, country_id)
|
|
|
|
// all checks passed
|
|
order, err := s.ordersRepo.PlaceNewOrder(cart, name, country_id, address_info, originalUserId, base_price, tax_incl, tax_excl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// from this point onward we do not cancel this order.
|
|
|
|
// if no error is returned, remove the cart. This should be smooth
|
|
err = s.cartsRepo.RemoveCart(user_id, cart_id)
|
|
if err != nil {
|
|
logger.Warn("failed to remove cart after order placement",
|
|
"service", "orderService",
|
|
"user_id", user_id,
|
|
"cart_id", cart_id,
|
|
"error", err.Error(),
|
|
)
|
|
}
|
|
|
|
return s.ChangeOrderStatus(user_id, order.OrderID, enums.OrderStatusPending)
|
|
|
|
}
|
|
|
|
func (s *OrderService) ChangeOrderAddress(user *model.Customer, order_id uint, country_id uint, address_info string) error {
|
|
_, err := s.addressesService.ValidateAddressJson(address_info, country_id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !user.HasPermission(perms.OrdersModifyAll) {
|
|
exists, err := s.ordersRepo.UserHasOrder(user.ID, order_id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !exists {
|
|
return responseErrors.ErrUserHasNoSuchOrder
|
|
}
|
|
}
|
|
|
|
return s.ordersRepo.ChangeOrderAddress(order_id, country_id, address_info)
|
|
}
|
|
|
|
func (s *OrderService) ChangeOrderStatus(userId, orderId uint, newStatus enums.OrderStatus) error {
|
|
order, err := s.ordersRepo.Get(orderId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if order == nil {
|
|
return responseErrors.ErrOrderNotFound
|
|
}
|
|
|
|
if !ValidStatuses[newStatus] {
|
|
return responseErrors.ErrInvalidStatus
|
|
}
|
|
|
|
err = s.ordersRepo.ChangeOrderStatus(order.OrderID, newStatus, userId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
actionCtx := orderStatusActions.ActionContext{
|
|
Order: order,
|
|
UserId: &userId,
|
|
EmailService: s.emailService,
|
|
}
|
|
|
|
go func() {
|
|
_ = s.actionRegistry.ExecuteForStatus(newStatus, actionCtx)
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *OrderService) getOrderTotalPrice(user_id uint, cart_id uint, country_id uint) (float64, float64, float64, error) {
|
|
cart, err := s.cartsRepo.RetrieveCart(user_id, cart_id)
|
|
if err != nil {
|
|
return 0.0, 0.0, 0.0, err
|
|
}
|
|
|
|
base_price := 0.0
|
|
tax_incl := 0.0
|
|
tax_excl := 0.0
|
|
|
|
for _, product := range cart.Products {
|
|
prices, err := s.productsRepo.GetPrice(product.ProductID, product.ProductAttributeID, constdata.SHOP_ID, user_id, country_id, product.Amount)
|
|
if err != nil {
|
|
return 0.0, 0.0, 0.0, err
|
|
}
|
|
|
|
base_price += prices.Base
|
|
tax_incl += prices.FinalTaxIncl
|
|
tax_excl += prices.FinalTaxExcl
|
|
}
|
|
|
|
return base_price, tax_incl, tax_excl, nil
|
|
}
|