flamingo.me/flamingo-commerce/v3@v3.11.0/cart/interfaces/controller/cartapicontroller.go (about)

     1  package controller
     2  
     3  import (
     4  	"context"
     5  	"net/url"
     6  	"strconv"
     7  
     8  	"go.opencensus.io/trace"
     9  
    10  	"flamingo.me/flamingo-commerce/v3/cart/domain/validation"
    11  
    12  	formDomain "flamingo.me/form/domain"
    13  
    14  	"flamingo.me/flamingo-commerce/v3/cart/interfaces/controller/forms"
    15  
    16  	"flamingo.me/flamingo/v3/framework/flamingo"
    17  	"flamingo.me/flamingo/v3/framework/web"
    18  
    19  	"flamingo.me/flamingo-commerce/v3/cart/application"
    20  	"flamingo.me/flamingo-commerce/v3/cart/domain/cart"
    21  )
    22  
    23  type (
    24  	// CartAPIController for cart api
    25  	CartAPIController struct {
    26  		responder                    *web.Responder
    27  		cartService                  *application.CartService
    28  		cartReceiverService          *application.CartReceiverService
    29  		logger                       flamingo.Logger
    30  		billingAddressFormController *forms.BillingAddressFormController
    31  		deliveryFormController       *forms.DeliveryFormController
    32  		simplePaymentFormController  *forms.SimplePaymentFormController
    33  	}
    34  
    35  	// CartAPIResult view data
    36  	CartAPIResult struct {
    37  		// Contains details if success is false
    38  		Error                *resultError
    39  		Success              bool
    40  		CartTeaser           *cart.Teaser
    41  		Data                 interface{}
    42  		DataValidationInfo   *formDomain.ValidationInfo `swaggertype:"object"`
    43  		CartValidationResult *validation.Result
    44  	}
    45  
    46  	getCartResult struct {
    47  		Cart                 *cart.Cart
    48  		CartValidationResult *validation.Result
    49  	}
    50  
    51  	resultError struct {
    52  		Message string
    53  		Code    string
    54  	} // @name cartResultError
    55  
    56  	messageCodeAvailable interface {
    57  		MessageCode() string
    58  	}
    59  
    60  	// PromotionFunction type takes ctx, cart, couponCode and applies the promotion
    61  	promotionFunc func(ctx context.Context, session *web.Session, couponCode string) (*cart.Cart, error)
    62  )
    63  
    64  // Inject dependencies
    65  func (cc *CartAPIController) Inject(
    66  	responder *web.Responder,
    67  	ApplicationCartService *application.CartService,
    68  	ApplicationCartReceiverService *application.CartReceiverService,
    69  	billingAddressFormController *forms.BillingAddressFormController,
    70  	deliveryFormController *forms.DeliveryFormController,
    71  	simplePaymentFormController *forms.SimplePaymentFormController,
    72  	Logger flamingo.Logger,
    73  ) {
    74  	cc.responder = responder
    75  	cc.cartService = ApplicationCartService
    76  	cc.cartReceiverService = ApplicationCartReceiverService
    77  	cc.logger = Logger.WithField("category", "CartApiController")
    78  	cc.billingAddressFormController = billingAddressFormController
    79  	cc.deliveryFormController = deliveryFormController
    80  	cc.simplePaymentFormController = simplePaymentFormController
    81  }
    82  
    83  // GetAction Get JSON Format of API
    84  // @Summary Get the current cart
    85  // @Tags Cart
    86  // @Produce json
    87  // @Success 200 {object} getCartResult
    88  // @Failure 500 {object} CartAPIResult
    89  // @Router /api/v1/cart [get]
    90  func (cc *CartAPIController) GetAction(ctx context.Context, r *web.Request) web.Result {
    91  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/GetAction")
    92  	defer span.End()
    93  
    94  	decoratedCart, e := cc.cartReceiverService.ViewDecoratedCart(ctx, r.Session())
    95  	if e != nil {
    96  		result := newResult()
    97  		result.SetError(e, "get_error")
    98  		cc.logger.WithContext(ctx).Error("cart.cartapicontroller.get: %v", e.Error())
    99  		return cc.responder.Data(result).Status(500)
   100  	}
   101  	validationResult := cc.cartService.ValidateCart(ctx, web.SessionFromContext(ctx), decoratedCart)
   102  	return cc.responder.Data(getCartResult{
   103  		CartValidationResult: &validationResult,
   104  		Cart:                 &decoratedCart.Cart,
   105  	})
   106  }
   107  
   108  // DeleteCartAction removes all cart content and returns a blank cart
   109  // @Summary Remove all stored cart information e.g. items, deliveries, billing address and returns the empty cart.
   110  // @Tags Cart
   111  // @Produce json
   112  // @Success 200 {object} CartAPIResult
   113  // @Failure 500 {object} CartAPIResult
   114  // @Router /api/v1/cart [delete]
   115  func (cc *CartAPIController) DeleteCartAction(ctx context.Context, r *web.Request) web.Result {
   116  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/DeleteCartAction")
   117  	defer span.End()
   118  
   119  	err := cc.cartService.Clean(ctx, r.Session())
   120  
   121  	result := newResult()
   122  	if err != nil {
   123  		cc.logger.WithContext(ctx).Error("cart.cartapicontroller.delete: %v", err.Error())
   124  
   125  		result.SetError(err, "delete_cart_error")
   126  		response := cc.responder.Data(result)
   127  		response.Status(500)
   128  		return response
   129  	}
   130  	cc.enrichResultWithCartInfos(ctx, &result)
   131  	return cc.responder.Data(result)
   132  }
   133  
   134  // AddAction Add Item to cart
   135  // @Summary Add Item to cart
   136  // @Tags Cart
   137  // @Produce json
   138  // @Success 200 {object} CartAPIResult
   139  // @Failure 500 {object} CartAPIResult
   140  // @Param deliveryCode path string true "the identifier for the delivery in the cart"
   141  // @Param marketplaceCode query string true "the product identifier that should be added"
   142  // @Param variantMarketplaceCode query string false "optional the product identifier of the variant (for configurable products) that should be added"
   143  // @Param qty query integer false "optional the qty that should be added"
   144  // @Router /api/v1/cart/delivery/{deliveryCode}/item [post]
   145  func (cc *CartAPIController) AddAction(ctx context.Context, r *web.Request) web.Result {
   146  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/AddAction")
   147  	defer span.End()
   148  
   149  	variantMarketplaceCode := r.Params["variantMarketplaceCode"]
   150  
   151  	qty, ok := r.Params["qty"]
   152  	if !ok {
   153  		qty = "1"
   154  	}
   155  	qtyInt, _ := strconv.Atoi(qty)
   156  	deliveryCode := r.Params["deliveryCode"]
   157  
   158  	addRequest := cc.cartService.BuildAddRequest(ctx, r.Params["marketplaceCode"], variantMarketplaceCode, qtyInt, nil)
   159  	_, err := cc.cartService.AddProduct(ctx, r.Session(), deliveryCode, addRequest)
   160  
   161  	result := newResult()
   162  	if err != nil {
   163  		cc.logger.WithContext(ctx).Error("cart.cartapicontroller.add: %v", err.Error())
   164  
   165  		result.SetError(err, "add_product_error")
   166  		response := cc.responder.Data(result)
   167  		response.Status(500)
   168  		return response
   169  	}
   170  	cc.enrichResultWithCartInfos(ctx, &result)
   171  	return cc.responder.Data(result)
   172  }
   173  
   174  // DeleteItemAction deletes an item from the cart
   175  // @Summary Delete item from cart
   176  // @Tags Cart
   177  // @Produce json
   178  // @Success 200 {object} CartAPIResult
   179  // @Failure 500 {object} CartAPIResult
   180  // @Param deliveryCode path string true "the identifier for the delivery in the cart"
   181  // @Param itemID query string true "the item that should be deleted"
   182  // @Router /api/v1/cart/delivery/{deliveryCode}/item [delete]
   183  func (cc *CartAPIController) DeleteItemAction(ctx context.Context, r *web.Request) web.Result {
   184  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/DeleteItemAction")
   185  	defer span.End()
   186  
   187  	itemID, _ := r.Query1("itemID")
   188  	deliveryCode := r.Params["deliveryCode"]
   189  
   190  	err := cc.cartService.DeleteItem(ctx, r.Session(), itemID, deliveryCode)
   191  
   192  	result := newResult()
   193  	if err != nil {
   194  		cc.logger.WithContext(ctx).Error("cart.cartapicontroller.delete: %v", err.Error())
   195  
   196  		result.SetError(err, "delete_item_error")
   197  		response := cc.responder.Data(result)
   198  		response.Status(500)
   199  		return response
   200  	}
   201  	cc.enrichResultWithCartInfos(ctx, &result)
   202  	return cc.responder.Data(result)
   203  }
   204  
   205  // UpdateItemAction updates the item qty in the current cart
   206  // @Summary Update item in the cart
   207  // @Tags Cart
   208  // @Produce json
   209  // @Success 200 {object} CartAPIResult
   210  // @Failure 500 {object} CartAPIResult
   211  // @Param deliveryCode path string true "the identifier for the delivery in the cart"
   212  // @Param itemID query string true "the item that should be updated"
   213  // @Param qty query integer true "the new qty"
   214  // @Router /api/v1/cart/delivery/{deliveryCode}/item [put]
   215  func (cc *CartAPIController) UpdateItemAction(ctx context.Context, r *web.Request) web.Result {
   216  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/UpdateItemAction")
   217  	defer span.End()
   218  
   219  	itemID, _ := r.Query1("itemID")
   220  	deliveryCode := r.Params["deliveryCode"]
   221  	qty, ok := r.Params["qty"]
   222  	if !ok {
   223  		qty = "1"
   224  	}
   225  	qtyInt, _ := strconv.Atoi(qty)
   226  
   227  	err := cc.cartService.UpdateItemQty(ctx, r.Session(), itemID, deliveryCode, qtyInt)
   228  
   229  	result := newResult()
   230  	if err != nil {
   231  		cc.logger.WithContext(ctx).Error("cart.cartapicontroller.updateItem: %v", err.Error())
   232  
   233  		result.SetError(err, "update_item_error")
   234  		response := cc.responder.Data(result)
   235  		response.Status(500)
   236  		return response
   237  	}
   238  	cc.enrichResultWithCartInfos(ctx, &result)
   239  	return cc.responder.Data(result)
   240  }
   241  
   242  // ApplyVoucherAndGetAction applies the given voucher and returns the cart
   243  // @Summary Apply Voucher Code
   244  // @Tags Cart
   245  // @Produce json
   246  // @Success 200 {object} CartAPIResult
   247  // @Failure 500 {object} CartAPIResult
   248  // @Param couponCode query string true "the couponCode that should be applied"
   249  // @Router /api/v1/cart/voucher [post]
   250  func (cc *CartAPIController) ApplyVoucherAndGetAction(ctx context.Context, r *web.Request) web.Result {
   251  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/ApplyVoucherAndGetAction")
   252  	defer span.End()
   253  
   254  	return cc.handlePromotionAction(ctx, r, "voucher_error", cc.cartService.ApplyVoucher)
   255  }
   256  
   257  // RemoveVoucherAndGetAction removes the given voucher and returns the cart
   258  // @Summary Remove Voucher Code
   259  // @Tags Cart
   260  // @Produce json
   261  // @Success 200 {object} CartAPIResult
   262  // @Failure 500 {object} CartAPIResult
   263  // @Param couponCode query string true "the couponCode that should be applied"
   264  // @Router /api/v1/cart/voucher [delete]
   265  func (cc *CartAPIController) RemoveVoucherAndGetAction(ctx context.Context, r *web.Request) web.Result {
   266  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/RemoveVoucherAndGetAction")
   267  	defer span.End()
   268  
   269  	return cc.handlePromotionAction(ctx, r, "voucher_error", cc.cartService.RemoveVoucher)
   270  }
   271  
   272  // DeleteAllItemsAction removes all cart items and returns the cart
   273  // @Summary Remove all cart items from all deliveries and return the cart, keeps the delivery info untouched.
   274  // @Tags Cart
   275  // @Produce json
   276  // @Success 200 {object} CartAPIResult
   277  // @Failure 500 {object} CartAPIResult
   278  // @Router /api/v1/cart/deliveries/items [delete]
   279  func (cc *CartAPIController) DeleteAllItemsAction(ctx context.Context, r *web.Request) web.Result {
   280  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/DeleteAllItemsAction")
   281  	defer span.End()
   282  
   283  	err := cc.cartService.DeleteAllItems(ctx, r.Session())
   284  	result := newResult()
   285  	if err != nil {
   286  		result.SetError(err, "delete_items_error")
   287  		response := cc.responder.Data(result)
   288  		response.Status(500)
   289  		return response
   290  	}
   291  	return cc.responder.Data(result)
   292  }
   293  
   294  // ApplyGiftCardAndGetAction applies the given gift card and returns the cart
   295  // the request needs a query string param "couponCode" which includes the corresponding gift card code
   296  // @Summary Apply Gift Card
   297  // @Tags Cart
   298  // @Produce json
   299  // @Success 200 {object} CartAPIResult
   300  // @Failure 500 {object} CartAPIResult
   301  // @Param couponCode query string true "the gift card code"
   302  // @Router /api/v1/cart/gift-card [post]
   303  func (cc *CartAPIController) ApplyGiftCardAndGetAction(ctx context.Context, r *web.Request) web.Result {
   304  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/ApplyGiftCardAndGetAction")
   305  	defer span.End()
   306  
   307  	return cc.handlePromotionAction(ctx, r, "giftcard_error", cc.cartService.ApplyGiftCard)
   308  }
   309  
   310  // ApplyCombinedVoucherGift applies a given code (which might be either a voucher or a Gift Card code) to the
   311  // cartService and returns the cart
   312  // @Summary Apply Gift Card or Voucher (auto detected)
   313  // @Description Use this if you have one user input and that input can be used to either enter a voucher or a gift card
   314  // @Tags Cart
   315  // @Produce json
   316  // @Success 200 {object} CartAPIResult
   317  // @Failure 500 {object} CartAPIResult
   318  // @Param couponCode query string true "the couponCode that should be applied as gift card or voucher"
   319  // @Router /api/v1/cart/voucher-gift-card [post]
   320  func (cc *CartAPIController) ApplyCombinedVoucherGift(ctx context.Context, r *web.Request) web.Result {
   321  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/ApplyCombinedVoucherGift")
   322  	defer span.End()
   323  
   324  	return cc.handlePromotionAction(ctx, r, "applyany_error", cc.cartService.ApplyAny)
   325  }
   326  
   327  // RemoveGiftCardAndGetAction removes the given gift card and returns the cart
   328  // the request needs a query string param "couponCode" which includes the corresponding gift card code
   329  // @Summary Remove Gift Card
   330  // @Tags Cart
   331  // @Produce json
   332  // @Success 200 {object} CartAPIResult
   333  // @Failure 500 {object} CartAPIResult
   334  // @Param couponCode query string true "the couponCode that should be deleted as gift card"
   335  // @Router /api/v1/cart/gift-card [delete]
   336  func (cc *CartAPIController) RemoveGiftCardAndGetAction(ctx context.Context, r *web.Request) web.Result {
   337  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/RemoveGiftCardAndGetAction")
   338  	defer span.End()
   339  
   340  	return cc.handlePromotionAction(ctx, r, "giftcard_error", cc.cartService.RemoveGiftCard)
   341  }
   342  
   343  // handles promotion action
   344  func (cc *CartAPIController) handlePromotionAction(ctx context.Context, r *web.Request, errorCode string, fn promotionFunc) web.Result {
   345  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/handlePromotionAction")
   346  	defer span.End()
   347  
   348  	couponCode := r.Params["couponCode"]
   349  	result := newResult()
   350  	_, err := fn(ctx, r.Session(), couponCode)
   351  	if err != nil {
   352  		cc.enrichResultWithCartInfos(ctx, &result)
   353  		result.SetError(err, errorCode)
   354  		response := cc.responder.Data(result)
   355  		response.Status(500)
   356  
   357  		return response
   358  	}
   359  	cc.enrichResultWithCartInfos(ctx, &result)
   360  	return cc.responder.Data(result)
   361  }
   362  
   363  // DeleteDelivery cleans the given delivery from the cart and returns the cleaned cart
   364  // @Summary Cleans the given delivery from the cart
   365  // @Tags Cart
   366  // @Produce json
   367  // @Success 200 {object} CartAPIResult
   368  // @Failure 500 {object} CartAPIResult
   369  // @Param deliveryCode path string true "the identifier for the delivery in the cart"
   370  // @Router /api/v1/cart/delivery/{deliveryCode} [delete]
   371  func (cc *CartAPIController) DeleteDelivery(ctx context.Context, r *web.Request) web.Result {
   372  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/DeleteDelivery")
   373  	defer span.End()
   374  
   375  	result := newResult()
   376  	deliveryCode := r.Params["deliveryCode"]
   377  	_, err := cc.cartService.DeleteDelivery(ctx, r.Session(), deliveryCode)
   378  	if err != nil {
   379  		result.SetError(err, "delete_delivery_error")
   380  		return cc.responder.Data(result).Status(500)
   381  	}
   382  	cc.enrichResultWithCartInfos(ctx, &result)
   383  	return cc.responder.Data(result)
   384  }
   385  
   386  // BillingAction adds billing infos
   387  // @Summary Adds billing infos to the current cart
   388  // @Tags Cart
   389  // @Accept x-www-form-urlencoded
   390  // @Produce json
   391  // @Success 200 {object} CartAPIResult
   392  // @Failure 500 {object} CartAPIResult
   393  // @Param vat formData string false "vat"
   394  // @Param firstname formData string true "firstname"
   395  // @Param lastname formData string true "lastname"
   396  // @Param middlename formData string false "middlename"
   397  // @Param title formData string false "title"
   398  // @Param salutation formData string false "salutation"
   399  // @Param street formData string false "street"
   400  // @Param streetNr formData string false "streetNr"
   401  // @Param addressLine1 formData string false "addressLine1"
   402  // @Param addressLine2 formData string false "addressLine2"
   403  // @Param company formData string false "company"
   404  // @Param postCode formData string false "postCode"
   405  // @Param city formData string false "city"
   406  // @Param state formData string false "state"
   407  // @Param regionCode formData string false "regionCode"
   408  // @Param country formData string false "country"
   409  // @Param countryCode formData string false "countryCode"
   410  // @Param phoneAreaCode formData string false "phoneAreaCode"
   411  // @Param phoneCountryCode formData string false "phoneCountryCode"
   412  // @Param phoneNumber formData string false "phoneNumber"
   413  // @Param email formData string true "email"
   414  // @Router /api/v1/cart/billing [put]
   415  func (cc *CartAPIController) BillingAction(ctx context.Context, r *web.Request) web.Result {
   416  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/BillingAction")
   417  	defer span.End()
   418  
   419  	result := newResult()
   420  	form, success, err := cc.billingAddressFormController.HandleFormAction(ctx, r)
   421  	result.Success = success
   422  	if err != nil {
   423  		result.SetError(err, "form_error")
   424  		return cc.responder.Data(result)
   425  	}
   426  
   427  	if form != nil {
   428  		result.Data = form.Data
   429  		result.DataValidationInfo = &form.ValidationInfo
   430  	}
   431  	cc.enrichResultWithCartInfos(ctx, &result)
   432  	return cc.responder.Data(result)
   433  }
   434  
   435  // UpdateDeliveryInfoAction updates the delivery info
   436  // @Summary Adds delivery infos, such as shipping address to the delivery for the cart
   437  // @Tags Cart
   438  // @Accept x-www-form-urlencoded
   439  // @Produce json
   440  // @Success 200 {object} CartAPIResult
   441  // @Failure 500 {object} CartAPIResult
   442  // @Param deliveryCode path string true "the identifier for the delivery in the cart"
   443  // @Param deliveryAddress.vat formData string false "vat"
   444  // @Param deliveryAddress.firstname formData string true "firstname"
   445  // @Param deliveryAddress.lastname formData string true "lastname"
   446  // @Param deliveryAddress.middlename formData string false "middlename"
   447  // @Param deliveryAddress.title formData string false "title"
   448  // @Param deliveryAddress.salutation formData string false "salutation"
   449  // @Param deliveryAddress.street formData string false "street"
   450  // @Param deliveryAddress.streetNr formData string false "streetNr"
   451  // @Param deliveryAddress.addressLine1 formData string false "addressLine1"
   452  // @Param deliveryAddress.addressLine2 formData string false "addressLine2"
   453  // @Param deliveryAddress.company formData string false "company"
   454  // @Param deliveryAddress.postCode formData string false "postCode"
   455  // @Param deliveryAddress.city formData string false "city"
   456  // @Param deliveryAddress.state formData string false "state"
   457  // @Param deliveryAddress.regionCode formData string false "regionCode"
   458  // @Param deliveryAddress.country formData string false "country"
   459  // @Param deliveryAddress.countryCode formData string false "countryCode"
   460  // @Param deliveryAddress.phoneAreaCode formData string false "phoneAreaCode"
   461  // @Param deliveryAddress.phoneCountryCode formData string false "phoneCountryCode"
   462  // @Param deliveryAddress.phoneNumber formData string false "phoneNumber"
   463  // @Param deliveryAddress.email formData string true "email"
   464  // @Param useBillingAddress formData bool false "useBillingAddress"
   465  // @Param shippingMethod formData string false "shippingMethod"
   466  // @Param shippingCarrier formData string false "shippingCarrier"
   467  // @Param locationCode formData string false "locationCode"
   468  // @Param desiredTime formData string false "desired date/time in RFC3339" format(date-time)
   469  // @Router /api/v1/cart/delivery/{deliveryCode} [put]
   470  func (cc *CartAPIController) UpdateDeliveryInfoAction(ctx context.Context, r *web.Request) web.Result {
   471  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/UpdateDeliveryInfoAction")
   472  	defer span.End()
   473  
   474  	result := newResult()
   475  	form, success, err := cc.deliveryFormController.HandleFormAction(ctx, r)
   476  	result.Success = success
   477  	if err != nil {
   478  		result.SetError(err, "form_error")
   479  		return cc.responder.Data(result)
   480  	}
   481  	if form != nil {
   482  		result.Data = form.Data
   483  		result.DataValidationInfo = &form.ValidationInfo
   484  	}
   485  	cc.enrichResultWithCartInfos(ctx, &result)
   486  	return cc.responder.Data(result)
   487  }
   488  
   489  // UpdatePaymentSelectionAction to set / update the cart payment selection
   490  // @Summary Update/set the PaymentSelection for the current cart
   491  // @Tags Cart
   492  // @Produce json
   493  // @Success 200 {object} CartAPIResult
   494  // @Failure 500 {object} CartAPIResult
   495  // @Param gateway query string true "name of the payment gateway - e.g. 'offline'"
   496  // @Param method query string true "name of the payment method - e.g. 'offlinepayment_cashondelivery'"
   497  // @Router /api/v1/cart/payment-selection [put]
   498  func (cc *CartAPIController) UpdatePaymentSelectionAction(ctx context.Context, r *web.Request) web.Result {
   499  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/UpdatePaymentSelectionAction")
   500  	defer span.End()
   501  
   502  	result := newResult()
   503  	gateway, _ := r.Query1("gateway")
   504  	method, _ := r.Query1("method")
   505  
   506  	urlValues := make(url.Values)
   507  	urlValues["gateway"] = []string{gateway}
   508  	urlValues["method"] = []string{method}
   509  	newRequest := web.CreateRequest(web.RequestFromContext(ctx).Request(), web.SessionFromContext(ctx))
   510  	newRequest.Request().Form = urlValues
   511  
   512  	form, success, err := cc.simplePaymentFormController.HandleFormAction(ctx, newRequest)
   513  	result.Success = success
   514  	if err != nil {
   515  		result.SetError(err, "form_error")
   516  		response := cc.responder.Data(result)
   517  		response.Status(500)
   518  		return response
   519  	}
   520  	if form != nil {
   521  		result.Data = form.Data
   522  		result.DataValidationInfo = &form.ValidationInfo
   523  	}
   524  	cc.enrichResultWithCartInfos(ctx, &result)
   525  	return cc.responder.Data(result)
   526  }
   527  
   528  func (cc *CartAPIController) enrichResultWithCartInfos(ctx context.Context, result *CartAPIResult) {
   529  	ctx, span := trace.StartSpan(ctx, "cart/CartAPIController/enrichResultWithCartInfos")
   530  	defer span.End()
   531  
   532  	session := web.SessionFromContext(ctx)
   533  	decoratedCart, err := cc.cartReceiverService.ViewDecoratedCart(ctx, session)
   534  	if err != nil {
   535  		result.SetError(err, "view_cart_error")
   536  
   537  	}
   538  	validationResult := cc.cartService.ValidateCart(ctx, session, decoratedCart)
   539  	result.CartTeaser = decoratedCart.Cart.GetCartTeaser()
   540  	result.CartValidationResult = &validationResult
   541  }
   542  
   543  // newResult factory to get new CartApiResult (with success true)
   544  func newResult() CartAPIResult {
   545  	return CartAPIResult{
   546  		Success: true,
   547  	}
   548  }
   549  
   550  // SetErrorByCode sets the error on the CartApiResult data and success to false
   551  func (r *CartAPIResult) SetErrorByCode(message string, code string) *CartAPIResult {
   552  	r.Success = false
   553  	r.Error = &resultError{
   554  		Message: message,
   555  		Code:    code,
   556  	}
   557  	return r
   558  }
   559  
   560  // SetError updates the cart error field
   561  func (r *CartAPIResult) SetError(err error, fallbackCode string) *CartAPIResult {
   562  	if e, ok := err.(messageCodeAvailable); ok {
   563  		fallbackCode = e.MessageCode()
   564  	}
   565  	return r.SetErrorByCode(err.Error(), fallbackCode)
   566  }