I am implementing custom stock management in Commerce.
I followed the following steps.
I have added a stock integer field in product variant.
I have written a event subscriber which reduce this stock field value after purchasing.
public static function getSubscribedEvents() {
$events['commerce_order.place.post_transition'] = ['orderCompleteHandler'];
return $events;
}
/**
* Reduces the stock value after purchase.
*
* @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event
* Event object.
*/
public function orderCompleteHandler(WorkflowTransitionEvent $event) {
/** @var \Drupal\commerce_order\Entity\OrderInterface $order */
$order = $event->getEntity();
// Order items in the cart.
$items = $order->getItems();
foreach ($items as $key => $item) {
$entity = $item->getPurchasedEntity();
$quantity = $item->getQuantity();
$stock_field_value = $entity->field_stock->value;
$entity->field_stock->value = $stock_field_value - $quantity;
$entity->save();
}
}
Then I have a stock checker which implements AvailabilityCheckerInterface
.
namespace Drupal\commerce_custom_stock;
use Drupal\commerce\Context;
use Drupal\commerce_order\AvailabilityCheckerInterface;
use Drupal\commerce_order\AvailabilityResult;
use Drupal\commerce_order\Entity\OrderItemInterface;
/**
* Class to check stock.
*/
class VariationAvailabilityChecker implements AvailabilityCheckerInterface {
/**
* {@inheritdoc}
*/
public function applies(OrderItemInterface $order_item) {
return TRUE;
}
/**
* {@inheritdoc}
*/
public function check(OrderItemInterface $order_item, Context $context) {
$entity = $order_item->getPurchasedEntity();
$quantity = $order_item->getQuantity();
// Order should not be placed if Stock is zero.
if ($entity->field_stock->value <= 0) {
$result = t('This product is out of stock.');
return AvailabilityResult::unavailable($result);
}
// Cart quantity should not be more than stock value.
if ($quantity > $entity->field_stock->value) {
$result = t('The quantity is more than the stock quantity');
return AvailabilityResult::unavailable($result);
}
return AvailabilityResult::neutral();
}
}
Two customers add the same product in the cart; one of them purchased and finished the stock. If the person tries to purchase it, a 403 error is shown. I want to show some message instead of the 403 error.
Is there any way to achieve this?