TL;DR: how to create and add a LineItem from an existing product to the cart in a plugin?
I’m trying to write a plugin to add a Product to a cart when it’s not in it already, e.g. to always have it in a cart (a fee for Paypal, costing nothing when the billingMethod is not Paypal and otherwise the Paypal fee).
I have a Subscriber listening on AfterLineItemAddedEvent successfully triggering on that event, so no problems there. This is my code:
public function onItemAdded(AfterLineItemAddedEvent $event) {
//$cart = $event->getCart();
$cart = $this->cartservice->getCart($event->getCart()->getToken(), $event->getSalesChannelContext());
if ($cart->getLineItems()->filter(function (LineItem $item) {
if ($item->getPayload()['productNumber'] === "PP")
return $item;
})->count() !== 0)
return;
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('productNumber', 'PP'));
$product = $this->productRepository->search($criteria, $event->getContext())->first();
$paypalFeeLineItem = (new LineItem('paypalfee', LineItem::PRODUCT_LINE_ITEM_TYPE, $product->getId(), 1))
->setRemovable(false)
->setStackable(false);
//$cart->add($paypalFeeLineItem);
//$this->persister->save($cart, $event->getSalesChannelContext());
$this->cartservice->add($cart, $paypalFeeLineItem, $event->getSalesChannelContext());
}
This leads to an endless loop, since the cartservice->add triggers more AfterLineItemAddedEvents. If I use the commented-out methods (e.g. using a persister with the event-cart, not the cartservice) this does not trigger events, not leading to my product in the cart but my cart in the browser shows "Item added successfully" (the normal product I added) AND "product not found" (probably my PayPalFee attempt) in the top of the cart.
-> I think this means my problem is either that the LineItem is not correctly added, or that it is incorrectly built.
So, how would I do this the correct way?
2
Answers
Solved my own question:
It was not correctly added, because the underlying product was not activated and made available to the storefront channel. My bad. So it adds the lineitem, but the
persister->save()
discards the item, but the controller still generates an AfterLineItemAdded event, as it is technically after adding a line item. This leads to the endless loop, as the cart still does not contain the product, trying to build it again, etc etcAll the methods above worked to add a LineItem into a cart, the error message "Invalid Product" on the cart was the relevant help.
This is just a general observation since you provide zero information in respect to what framework or cart script you are working with.
In most event driven workflows the event manager, dispatcher or the event object itself will expose a mechanism for allowing you to stop the propagation of an event based on some criteria. I’m curious to whether if you stopped the propagation of that event if your action would have been performed and it solved your issue.
Often times in this type of situation the most productive approach is to just breakpoint the workflow until you find your offending code.