mlodhi
mlodhi

Reputation: 732

Shopware 6 Plugin - How to show shipping costs of sales channel's default country

I am developing a Shopware 6 plugin and have the CustomsProductDetailRoute that sets the shipping cost of a product on its product details page.

I set up a rule for shipping to France. Now, when I:

This shouldn't happen. I want to show the shipping costs to the default country of the sales channel.

  /**
     * @Entity("product")
     * @Route("/store-api/product/{productId}", name="store-api.detail", methods={"POST"})
     */
    public function load(string $productId, Request $request, SalesChannelContext $context, Criteria $criteria): ProductDetailRouteResponse
    {
        // We must call this function when using the decorator approach
        $productDetailResponse = $this->decorated->load($productId, $request, $context, $criteria);
        
        //Get the current Cart(CartService) and add a product as a new line item
        $cart = $this->cartService->getCart(self::DUMMY_TOKEN, $context);
//       dd($cart->getShippingCosts());
        
//        To avoid the cart from being persisted after the calculation, you can set a dummy value as token for the cart 
        $cart->setToken(self::DUMMY_TOKEN);
//        Get the default shipping address for the current sales channel from the SalesChannelContext
//        dd($context->getSalesChannel()->getCountryId());
        
//        Create a new lineItem of product
        $productLineItem = new LineItem($productId, LineItem::PRODUCT_LINE_ITEM_TYPE, $productId);
        
        $productLineItem->setGood(true);
        $productLineItem->setStackable(true);
        $productLineItem->setRemovable(true);
        
        $cart->add($productLineItem);
        
//        Setting the isRecalculation flag of CartBehavior should prevent cart to be persisted 
        $behaviorContext = new CartBehavior([], true, true);
        
        $cartLoaded = $this->cartRuleLoader->loadByCart($context, $cart, $behaviorContext)->getCart();
        
//        Access calculated shipping cost from the cart for the specific product
        $expectedShippingCosts = $cartLoaded->getShippingCosts();

//        Set the expected shipping cost to the extension of the $productDetailResponse's object variable
//        dd($productDetailResponse->getResult());
        $productDetailResponse->getProduct()->addExtension(
                'expectedShippingCosts', $expectedShippingCosts);
        
        return $productDetailResponse; 
    }

I am trying to get the default shipping address for the current sales channel from the SalesChannelContext using $context->getSalesChannel()->getCountryId(). I am not sure how I can associate it with the cart. Since $cart does not have a method to set the shipping country. How can I modify the code to always show the shipping costs calculated for the sales channel's default country? I want it to ignore the user's default shipping address country.

Regards, Lodhi

Upvotes: 1

Views: 573

Answers (1)

dneustadt
dneustadt

Reputation: 13161

You can compare the current shipping method id with the default shipping method id of the sales channel. If it differs, use the injected shipping_method.repository to fetch the ShippingMethodEntity by the latter. You can then clone the instance of SalesChannelContext (to avoid mutating the object for the rest of the stack). On the cloned context you can then replace the shipping method to be used by calling the assign method.

$defaultShippingMethodId = $context->getSalesChannel()->getShippingMethodId();
if ($defaultShippingMethodId !== $context->getShippingMethod()->getId()) {
    $context = clone $context;
    
    $shippingMethod = $this->shippingMethodRepository->search(
        new Criteria([$defaultShippingMethodId]),
        $context->getContext()
    )->first();
    
    $context->assign([
        'shippingMethod' => $shippingMethod,
    ]);
}

$cartLoaded = $this->cartRuleLoader->loadByCart($context, $cart, $behavior);

If the country of the shipping location should also be set to the default country, you can extend the above behavior to also replace the country of the shipping location with the default country assigned to the sales channel. To fetch the instance of CountryEntity inject country.repository.

$defaultShippingMethodId = $context->getSalesChannel()->getShippingMethodId();
$defaultCountryId = $context->getSalesChannel()->getCountryId();
if (
    $defaultShippingMethodId !== $context->getShippingMethod()->getId()
    || $defaultCountryId !== $context->getShippingLocation()->getCountry()->getId()
) {
    $context = clone $context;
}

// set to default shipping method if necessary

if ($defaultCountryId !== $context->getShippingLocation()->getCountry()->getId()) {
    $shippingLocation = clone $context->getShippingLocation();
    $country = $this->countryRepository->search(
        new Criteria([$defaultCountryId]),
        $context->getContext()
    )->first();

    $shippingLocation->assign([
        'country' => $country,
    ]);
    $context->assign([
        'shippingLocation' => $shippingLocation,
    ]);
}

Upvotes: 1

Related Questions