flamingo.me/flamingo-commerce/v3@v3.11.0/cart/interfaces/graphql/mutationresolvers.go (about)

     1  package graphql
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"net/url"
     7  
     8  	formApplication "flamingo.me/form/application"
     9  	"flamingo.me/form/domain"
    10  
    11  	cartDomain "flamingo.me/flamingo-commerce/v3/cart/domain/cart"
    12  	"flamingo.me/flamingo-commerce/v3/cart/interfaces/controller/forms"
    13  	"flamingo.me/flamingo-commerce/v3/cart/interfaces/graphql/dto"
    14  
    15  	"flamingo.me/flamingo/v3/framework/web"
    16  
    17  	"flamingo.me/flamingo-commerce/v3/cart/application"
    18  )
    19  
    20  // CommerceCartMutationResolver resolves cart mutations
    21  type CommerceCartMutationResolver struct {
    22  	q                            *CommerceCartQueryResolver
    23  	cartService                  *application.CartService
    24  	cartReceiverService          *application.CartReceiverService
    25  	billingAddressFormController *forms.BillingAddressFormController
    26  	deliveryFormController       *forms.DeliveryFormController
    27  	simplePaymentFormController  *forms.SimplePaymentFormController
    28  	formDataEncoderFactory       formApplication.FormDataEncoderFactory
    29  }
    30  
    31  // Inject dependencies
    32  func (r *CommerceCartMutationResolver) Inject(q *CommerceCartQueryResolver,
    33  	billingAddressFormController *forms.BillingAddressFormController,
    34  	deliveryFormController *forms.DeliveryFormController,
    35  	formDataEncoderFactory formApplication.FormDataEncoderFactory,
    36  	simplePaymentFormController *forms.SimplePaymentFormController,
    37  	cartService *application.CartService,
    38  	cartReceiverService *application.CartReceiverService) *CommerceCartMutationResolver {
    39  	r.q = q
    40  	r.billingAddressFormController = billingAddressFormController
    41  	r.deliveryFormController = deliveryFormController
    42  	r.formDataEncoderFactory = formDataEncoderFactory
    43  	r.simplePaymentFormController = simplePaymentFormController
    44  	r.cartService = cartService
    45  	r.cartReceiverService = cartReceiverService
    46  	return r
    47  }
    48  
    49  // CommerceAddToCart mutation for adding products to the current users cart
    50  func (r *CommerceCartMutationResolver) CommerceAddToCart(ctx context.Context, graphqlAddRequest dto.AddToCart) (*dto.DecoratedCart, error) {
    51  	req := web.RequestFromContext(ctx)
    52  
    53  	if graphqlAddRequest.Qty < 0 {
    54  		graphqlAddRequest.Qty = 0
    55  	}
    56  
    57  	addRequest := cartDomain.AddRequest{
    58  		MarketplaceCode:        graphqlAddRequest.MarketplaceCode,
    59  		Qty:                    graphqlAddRequest.Qty,
    60  		VariantMarketplaceCode: graphqlAddRequest.VariantMarketplaceCode,
    61  		AdditionalData:         nil,
    62  		BundleConfiguration:    dto.MapBundleConfigToDomain(graphqlAddRequest.BundleConfiguration),
    63  	}
    64  
    65  	_, err := r.cartService.AddProduct(ctx, req.Session(), graphqlAddRequest.DeliveryCode, addRequest)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	return r.q.CommerceCart(ctx)
    71  }
    72  
    73  // CommerceDeleteItem resolver
    74  func (r *CommerceCartMutationResolver) CommerceDeleteItem(ctx context.Context, itemID string, deliveryCode string) (*dto.DecoratedCart, error) {
    75  	req := web.RequestFromContext(ctx)
    76  
    77  	err := r.cartService.DeleteItem(ctx, req.Session(), itemID, deliveryCode)
    78  
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  
    83  	return r.q.CommerceCart(ctx)
    84  }
    85  
    86  // CommerceDeleteCartDelivery mutation for removing deliveries from current users cart
    87  func (r *CommerceCartMutationResolver) CommerceDeleteCartDelivery(ctx context.Context, deliveryCode string) (*dto.DecoratedCart, error) {
    88  	req := web.RequestFromContext(ctx)
    89  	_, err := r.cartService.DeleteDelivery(ctx, req.Session(), deliveryCode)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	return r.q.CommerceCart(ctx)
    94  }
    95  
    96  // CommerceUpdateItemQty mutation for updating item quantity
    97  func (r *CommerceCartMutationResolver) CommerceUpdateItemQty(ctx context.Context, itemID string, deliveryCode string, qty int) (*dto.DecoratedCart, error) {
    98  	req := web.RequestFromContext(ctx)
    99  	err := r.cartService.UpdateItemQty(ctx, req.Session(), itemID, deliveryCode, qty)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	return r.q.CommerceCart(ctx)
   104  }
   105  
   106  // CommerceUpdateItemBundleConfig mutation for updating item quantity
   107  func (r *CommerceCartMutationResolver) CommerceUpdateItemBundleConfig(ctx context.Context, itemID string, bundleConfig []*dto.ChoiceConfiguration) (*dto.DecoratedCart, error) {
   108  	req := web.RequestFromContext(ctx)
   109  
   110  	var bundleConfigDto []dto.ChoiceConfiguration
   111  
   112  	for _, config := range bundleConfig {
   113  		bundleConfigDto = append(bundleConfigDto, *config)
   114  	}
   115  
   116  	bundleConfigDomain := dto.MapBundleConfigToDomain(bundleConfigDto)
   117  
   118  	updateCommand := cartDomain.ItemUpdateCommand{
   119  		ItemID:              itemID,
   120  		BundleConfiguration: bundleConfigDomain,
   121  	}
   122  
   123  	err := r.cartService.UpdateItemBundleConfig(ctx, req.Session(), updateCommand)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	return r.q.CommerceCart(ctx)
   129  }
   130  
   131  // CommerceCartUpdateBillingAddress resolver method
   132  func (r *CommerceCartMutationResolver) CommerceCartUpdateBillingAddress(ctx context.Context, address *forms.AddressForm) (*dto.BillingAddressForm, error) {
   133  	newRequest := web.CreateRequest(web.RequestFromContext(ctx).Request(), web.SessionFromContext(ctx))
   134  	v, err := r.formDataEncoderFactory.CreateByNamedEncoder("commerce.cart.billingFormService").Encode(ctx, address)
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  	newRequest.Request().Form = v
   139  
   140  	form, success, err := r.billingAddressFormController.HandleFormAction(ctx, newRequest)
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  	return mapCommerceBillingAddressForm(form, success)
   145  
   146  }
   147  
   148  // CommerceCartUpdateSelectedPayment resolver method
   149  func (r *CommerceCartMutationResolver) CommerceCartUpdateSelectedPayment(ctx context.Context, gateway string, method string) (*dto.SelectedPaymentResult, error) {
   150  	newRequest := web.CreateRequest(web.RequestFromContext(ctx).Request(), web.SessionFromContext(ctx))
   151  	urlValues := make(url.Values)
   152  	urlValues["gateway"] = []string{gateway}
   153  	urlValues["method"] = []string{method}
   154  	newRequest.Request().Form = urlValues
   155  
   156  	form, success, err := r.simplePaymentFormController.HandleFormAction(ctx, newRequest)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	return &dto.SelectedPaymentResult{
   162  		Processed: success,
   163  		ValidationInfo: dto.ValidationInfo{
   164  			GeneralErrors: form.ValidationInfo.GetGeneralErrors(),
   165  			FieldErrors:   mapFieldErrors(form.ValidationInfo),
   166  		},
   167  	}, nil
   168  
   169  }
   170  
   171  // CommerceCartApplyCouponCodeOrGiftCard – apply coupon code or gift card
   172  func (r *CommerceCartMutationResolver) CommerceCartApplyCouponCodeOrGiftCard(ctx context.Context, code string) (*dto.DecoratedCart, error) {
   173  	req := web.RequestFromContext(ctx)
   174  
   175  	_, err := r.cartService.ApplyAny(ctx, req.Session(), code)
   176  
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  
   181  	return r.q.CommerceCart(ctx)
   182  }
   183  
   184  // CommerceCartRemoveCouponCode - remove coupon code
   185  func (r *CommerceCartMutationResolver) CommerceCartRemoveCouponCode(ctx context.Context, couponCode string) (*dto.DecoratedCart, error) {
   186  	req := web.RequestFromContext(ctx)
   187  
   188  	_, err := r.cartService.RemoveVoucher(ctx, req.Session(), couponCode)
   189  
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  
   194  	return r.q.CommerceCart(ctx)
   195  }
   196  
   197  // CommerceCartRemoveGiftCard - remove gift card
   198  func (r *CommerceCartMutationResolver) CommerceCartRemoveGiftCard(ctx context.Context, giftCardCode string) (*dto.DecoratedCart, error) {
   199  	req := web.RequestFromContext(ctx)
   200  
   201  	_, err := r.cartService.RemoveGiftCard(ctx, req.Session(), giftCardCode)
   202  
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  
   207  	return r.q.CommerceCart(ctx)
   208  }
   209  
   210  // CommerceCartUpdateDeliveryAddresses can be used to update or set one or multiple delivery addresses, uses the delivery form controller
   211  func (r *CommerceCartMutationResolver) CommerceCartUpdateDeliveryAddresses(ctx context.Context, deliveryForms []*forms.DeliveryForm) ([]*dto.DeliveryAddressForm, error) {
   212  	result := make([]*dto.DeliveryAddressForm, 0, len(deliveryForms))
   213  	request := web.CreateRequest(web.RequestFromContext(ctx).Request(), web.SessionFromContext(ctx))
   214  	for _, deliveryForm := range deliveryForms {
   215  		encodedForm, err := r.formDataEncoderFactory.CreateByNamedEncoder("commerce.cart.billingFormService").Encode(ctx, deliveryForm)
   216  		if err != nil {
   217  			return nil, err
   218  		}
   219  		request.Request().Form = encodedForm
   220  		request.Params["deliveryCode"] = deliveryForm.LocationCode
   221  		form, success, err := r.deliveryFormController.HandleFormAction(ctx, request)
   222  		if err != nil {
   223  			return nil, err
   224  		}
   225  
   226  		deliveryAddressForm, err := mapCommerceDeliveryAddressForm(form, success)
   227  		if err != nil {
   228  			return nil, err
   229  		}
   230  
   231  		result = append(result, &deliveryAddressForm)
   232  	}
   233  
   234  	return result, nil
   235  }
   236  
   237  // CommerceCartUpdateDeliveryShippingOptions updates the method/carrier of one or multiple existing deliveries
   238  func (r *CommerceCartMutationResolver) CommerceCartUpdateDeliveryShippingOptions(ctx context.Context, shippingOptions []*dto.DeliveryShippingOption) (*dto.UpdateShippingOptionsResult, error) {
   239  	session := web.SessionFromContext(ctx)
   240  	cart, err := r.cartReceiverService.ViewCart(ctx, session)
   241  	if err != nil {
   242  		return nil, err
   243  	}
   244  
   245  	for _, shippingOption := range shippingOptions {
   246  		delivery, found := cart.GetDeliveryByCode(shippingOption.DeliveryCode)
   247  		if !found {
   248  			return nil, cartDomain.ErrDeliveryCodeNotFound
   249  		}
   250  
   251  		deliveryInfo := delivery.DeliveryInfo
   252  		deliveryInfo.Carrier = shippingOption.Carrier
   253  		deliveryInfo.Method = shippingOption.Method
   254  
   255  		err = r.cartService.UpdateDeliveryInfo(ctx, session, shippingOption.DeliveryCode, cartDomain.CreateDeliveryInfoUpdateCommand(deliveryInfo))
   256  		if err != nil {
   257  			return nil, err
   258  		}
   259  	}
   260  
   261  	return &dto.UpdateShippingOptionsResult{Processed: true}, nil
   262  }
   263  
   264  // CartClean clears users cart
   265  func (r *CommerceCartMutationResolver) CartClean(ctx context.Context) (bool, error) {
   266  	err := r.cartService.Clean(ctx, web.SessionFromContext(ctx))
   267  	if err != nil {
   268  		return false, err
   269  	}
   270  
   271  	return true, nil
   272  }
   273  
   274  // UpdateAdditionalData of cart
   275  func (r *CommerceCartMutationResolver) UpdateAdditionalData(ctx context.Context, additionalDataList []*dto.KeyValue) (*dto.DecoratedCart, error) {
   276  	session := web.SessionFromContext(ctx)
   277  	additionalDataMap := map[string]string{}
   278  	for _, additionalData := range additionalDataList {
   279  		additionalDataMap[additionalData.Key] = additionalData.Value
   280  	}
   281  
   282  	_, err := r.cartService.UpdateAdditionalData(ctx, session, additionalDataMap)
   283  	if err != nil {
   284  		return nil, err
   285  	}
   286  
   287  	return r.q.CommerceCart(ctx)
   288  }
   289  
   290  // UpdateDeliveriesAdditionalData of cart
   291  func (r *CommerceCartMutationResolver) UpdateDeliveriesAdditionalData(ctx context.Context, additionalDataList []*dto.DeliveryAdditionalData) (*dto.DecoratedCart, error) {
   292  	session := web.SessionFromContext(ctx)
   293  	for _, additionalData := range additionalDataList {
   294  		additionalDataMap := map[string]string{}
   295  		for _, deliveryAdditionalData := range additionalData.AdditionalData {
   296  			additionalDataMap[deliveryAdditionalData.Key] = deliveryAdditionalData.Value
   297  		}
   298  
   299  		_, err := r.cartService.UpdateDeliveryAdditionalData(ctx, session, additionalData.DeliveryCode, additionalDataMap)
   300  		if err != nil {
   301  			return nil, err
   302  		}
   303  	}
   304  
   305  	return r.q.CommerceCart(ctx)
   306  }
   307  
   308  func mapCommerceDeliveryAddressForm(form *domain.Form, success bool) (dto.DeliveryAddressForm, error) {
   309  	formData, ok := form.Data.(forms.DeliveryForm)
   310  	if !ok {
   311  		return dto.DeliveryAddressForm{}, errors.New("unexpected form data")
   312  	}
   313  
   314  	return dto.DeliveryAddressForm{
   315  		FormData:  formData.DeliveryAddress,
   316  		Processed: success,
   317  		ValidationInfo: dto.ValidationInfo{
   318  			GeneralErrors: form.ValidationInfo.GetGeneralErrors(),
   319  			FieldErrors:   mapFieldErrors(form.ValidationInfo),
   320  		},
   321  		UseBillingAddress: formData.UseBillingAddress,
   322  		DeliveryCode:      formData.LocationCode,
   323  		Method:            formData.ShippingMethod,
   324  		Carrier:           formData.ShippingCarrier,
   325  		DesiredTime:       formData.DesiredTime,
   326  	}, nil
   327  }
   328  
   329  // mapCommerceBillingAddressForm helper to map the graphql type Commerce_Cart_BillingAddressForm from common form
   330  func mapCommerceBillingAddressForm(form *domain.Form, success bool) (*dto.BillingAddressForm, error) {
   331  	billingFormData, ok := form.Data.(forms.BillingAddressForm)
   332  	if !ok {
   333  		return nil, errors.New("unexpected form data")
   334  	}
   335  
   336  	return &dto.BillingAddressForm{
   337  		FormData:  forms.AddressForm(billingFormData),
   338  		Processed: success,
   339  		ValidationInfo: dto.ValidationInfo{
   340  			GeneralErrors: form.ValidationInfo.GetGeneralErrors(),
   341  			FieldErrors:   mapFieldErrors(form.ValidationInfo),
   342  		},
   343  	}, nil
   344  }
   345  
   346  func mapFieldErrors(validationInfo domain.ValidationInfo) []dto.FieldError {
   347  	var fieldErrors []dto.FieldError
   348  	for fieldName, currentFieldErrors := range validationInfo.GetErrorsForAllFields() {
   349  		for _, currentFieldError := range currentFieldErrors {
   350  			fieldErrors = append(fieldErrors, dto.FieldError{
   351  				MessageKey:   currentFieldError.MessageKey,
   352  				DefaultLabel: currentFieldError.DefaultLabel,
   353  				FieldName:    fieldName,
   354  			})
   355  		}
   356  	}
   357  	return fieldErrors
   358  }