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 }