custom/plugins/CioPurchaseVolumesLimits/src/Subscriber/PurchaseLimitsSubscriber.php line 51

Open in your IDE?
  1. <?php
  2. namespace CioPurchaseVolumesLimits\Subscriber;
  3. use CioBudget\Definition\Budget\BudgetEntity;
  4. use CioBudget\Definition\BudgetStore\BudgetStoreEntity;
  5. use CioBudget\Service\BudgetLoaderService;
  6. use CioBudget\Service\SessionService;
  7. use CioCustomerPermissionGroups\Event\CustomerGroupsLoadedEvent;
  8. use Shopware\Core\Checkout\Cart\LineItem\LineItem;
  9. use Shopware\Core\Checkout\Customer\CustomerEntity;
  10. use Shopware\Core\Checkout\Order\Aggregate\OrderCustomer\OrderCustomerEntity;
  11. use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
  12. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
  16. use Shopware\Core\System\SalesChannel\Entity\SalesChannelEntityLoadedEvent;
  17. use Shopware\Storefront\Event\StorefrontRenderEvent;
  18. use Symfony\Component\DependencyInjection\ContainerInterface;
  19. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  20. use CioCustomerPermissionGroups\Event\CustomerAclRolesEvent;
  21. use CioCustomerPermissionGroups\Service\CheckCustomerPermissionsService;
  22. use Symfony\Component\HttpFoundation\Session\Session;
  23. use Symfony\Component\Validator\Constraints\DateTime;
  24. use CioCustomerPermissionGroups\CioCustomerPermissionGroups;
  25. class PurchaseLimitsSubscriber implements EventSubscriberInterface
  26. {
  27.     private ContainerInterface $container;
  28.     private SessionService $sessionService;
  29.     private BudgetLoaderService $budgetLoaderService;
  30.     public function __construct(ContainerInterface $containerSessionService $sessionServiceBudgetLoaderService $budgetLoaderService)
  31.     {
  32.         $this->container $container;
  33.         $this->sessionService $sessionService;
  34.         $this->budgetLoaderService $budgetLoaderService;
  35.     }
  36.     public static function getSubscribedEvents(): array
  37.     {
  38.         // Return the events to listen to as array like this:  <event to listen to> => <method to execute>
  39.         return [
  40.             'sales_channel.product.loaded' => 'onSalesChannelEntityLoadedEvent',
  41.         ];
  42.     }
  43.     public function onSalesChannelEntityLoadedEvent(SalesChannelEntityLoadedEvent $event)
  44.     {
  45.         /** @var EntityRepository $budgetRepository */
  46.         $budgetRepository $this->container->get('cio_budget.repository');
  47.         /** @var EntityRepository $storeRepository */
  48.         $storeRepository $this->container->get('cio_budget_store.repository');
  49.         /** @var BudgetEntity|null $budget */
  50.         $budget null;
  51.         /** @var string|null $budgetId */
  52.         $budgetId $this->container->get('session')->get('cio_current_budget');
  53.         if ($budgetId) {
  54.             $searchResult $budgetRepository->search(new Criteria([$budgetId]), $event->getContext());
  55.             if ($searchResult->count() === 1) {
  56.                 $budget $searchResult->first();
  57.             }
  58.         }
  59.         foreach ($event->getEntities() as $loadedProduct) {
  60.             if ($loadedProduct instanceof SalesChannelProductEntity) {
  61.                 if ($budget) {
  62.                     /** @var BudgetStoreEntity $budgetStore */
  63.                     $budgetStore $storeRepository->search(new Criteria([$budget->getStoreId()]), $event->getContext())->first();
  64.                     if ($budgetStore) {
  65.                         if ($limit $this->matchingStoreLimit($loadedProduct$budgetStore->getSize())) {
  66.                             $loadedProduct->setCalculatedMaxPurchase(min([$limit['_limit'], $loadedProduct->getAvailableStock()]) - $this->currentVolumeByBudgetStore($loadedProduct$event->getSalesChannelContext()->getCustomer(), $limit$event->getContext()));
  67.                         }
  68.                     }
  69.                 }
  70.                 if ($event->getSalesChannelContext()->getCustomer() instanceof CustomerEntity) {
  71.                     if ($limit $this->matchingGroupLimit($event->getSalesChannelContext()->getCustomer(), $loadedProduct)) {
  72.                         $loadedProduct->setCalculatedMaxPurchase(min([$limit['_limit'], $loadedProduct->getAvailableStock()]) - $this->currentVolumeByCustomerId($loadedProduct$event->getSalesChannelContext()->getCustomer(), $limit$event->getContext()));
  73.                     }
  74.                 }
  75.             }
  76.         }
  77.     }
  78.     protected function matchingStoreLimit(SalesChannelProductEntity $productEntity$storeSize)
  79.     {
  80.         if (is_array($productEntity->getCustomFields()) && array_key_exists('cioStoreLimits'$productEntity->getCustomFields()) && is_array($productEntity->getCustomFields()['cioStoreLimits'])) {
  81.             foreach ($productEntity->getCustomFields()['cioStoreLimits'] as $limit) {
  82.                 if ($limit['_storeSize'] === $storeSize) {
  83.                     return $limit;
  84.                 }
  85.             }
  86.         }
  87.         return null;
  88.     }
  89.     protected function matchingGroupLimit(CustomerEntity $customerSalesChannelProductEntity $productEntity)
  90.     {
  91.         $resultLimit null;
  92.         if (is_array($productEntity->getCustomFields()) && array_key_exists('cioGroupLimits'$productEntity->getCustomFields()) && is_array($productEntity->getCustomFields()['cioGroupLimits'])) {
  93.             foreach ($productEntity->getCustomFields()['cioGroupLimits'] as $limit) {
  94.                 $limitGroupId $limit['_groupId'];
  95.                 $userGroupsIds = array();
  96.                 $userGroups $customer->getCustomFields()['custom_acl_roles'];
  97.                 $userGroupsIds CioCustomerPermissionGroups::getAclIds($userGroups);
  98.                 $eventDispatcher $this->container->get('event_dispatcher');
  99.                 $customerGroupsLodedEvent = new CustomerGroupsLoadedEvent($userGroupsIds$customer);
  100.                 $eventDispatcher->dispatch($customerGroupsLodedEvent);
  101.                 $userGroups $customerGroupsLodedEvent->getGroups();
  102.                 foreach ($userGroups as $userGroupId) {
  103.                     if ($limitGroupId === $userGroupId) {
  104.                         if ($resultLimit === null) {
  105.                             $resultLimit $limit;
  106.                         } else {
  107.                             if ($resultLimit['_limit'] < $limit['_limit']) {
  108.                                 $resultLimit $limit;
  109.                             }
  110.                         }
  111.                     }
  112.                 }
  113.             }
  114.             return $resultLimit;
  115.         }
  116.         return null;
  117.     }
  118.     protected function currentVolumeByBudgetStore(SalesChannelProductEntity $productEntityCustomerEntity $customerEntity$limit$context)
  119.     {
  120.         $currentSelectedBudgetId $this->sessionService->getBudgetIdFromSession();
  121.         $currentBudget $this->budgetLoaderService->getBudgetById($currentSelectedBudgetId);
  122.         /** @var EntityRepository $orderCustomerRepository */
  123.         $orderCustomerRepository $this->container->get('order_customer.repository');
  124.         if ($limit['_timePeriod'] === 'order') {
  125.             return 0;
  126.         } else if ($limit['_timePeriod'] === 'weekly') {
  127.             // get first day of current week
  128.             $day date('w') == date('w') - 1;
  129.             $start date('Y-m-d'strtotime("-{$day} days"));
  130.         } else if ($limit['_timePeriod'] === 'monthly') {
  131.             $start date('Y-m-01');
  132.         } else if ($limit['_timePeriod'] === 'quartily') {
  133.             $start self::datesOfQuarter('current'null'Y-m-d')['start'];
  134.         } else {
  135.             // yearly
  136.             $start date('Y-01-01');
  137.         }
  138.         $criteria = (new Criteria())
  139.             ->addFilter(new EqualsFilter('order.history.budget.store_id'$currentBudget->getStore()->getId()))
  140.             ->addFilter(new RangeFilter('order.orderDate', [
  141.                 RangeFilter::GTE => $start
  142.             ]))
  143.             ->addAssociation('order')->addAssociation('order.lineItems');
  144.         $orderCustomers $orderCustomerRepository->search($criteria$context);
  145.         $result 0;
  146.         /** @var OrderCustomerEntity $orderCustomer */
  147.         foreach ($orderCustomers as $orderCustomer) {
  148.             $order $orderCustomer->getOrder();
  149.             if ($order) {
  150.                 /** @var LineItem $lineItem */
  151.                 foreach ($order->getLineItems() as $lineItem) {
  152.                     if ($lineItem->getPayload()['productNumber'] === $productEntity->getProductNumber()) {
  153.                         $result $result $lineItem->getQuantity();
  154.                     }
  155.                 }
  156.             }
  157.         }
  158.         return $result;
  159.     }
  160.     protected function currentVolumeByCustomerId(SalesChannelProductEntity $productEntityCustomerEntity $customerEntity$limit$context)
  161.     {
  162.         /** @var EntityRepository $orderCustomerRepository */
  163.         $orderCustomerRepository $this->container->get('order_customer.repository');
  164.         if ($limit['_timePeriod'] === 'order') {
  165.             return 0;
  166.         } else if ($limit['_timePeriod'] === 'weekly') {
  167.             // get first day of current week
  168.             $day date('w') == date('w') - 1;
  169.             $start date('Y-m-d'strtotime("-{$day} days"));
  170.         } else if ($limit['_timePeriod'] === 'monthly') {
  171.             $start date('Y-m-01');
  172.         } else if ($limit['_timePeriod'] === 'quartily') {
  173.             $start self::datesOfQuarter('current'null'Y-m-d')['start'];
  174.         } else {
  175.             // yearly
  176.             $start date('Y-01-01');
  177.         }
  178.         $criteria = (new Criteria())
  179.             ->addFilter(new EqualsFilter('customerId'$customerEntity->getId()))
  180.             ->addFilter(new RangeFilter('order.orderDate', [
  181.                 RangeFilter::GTE => $start
  182.             ]))
  183.             ->addAssociation('order')->addAssociation('order.lineItems');
  184.         $orderCustomers $orderCustomerRepository->search($criteria$context);
  185.         $result 0;
  186.         /** @var OrderCustomerEntity $orderCustomer */
  187.         foreach ($orderCustomers as $orderCustomer) {
  188.             $order $orderCustomer->getOrder();
  189.             if ($order) {
  190.                 /** @var LineItem $lineItem */
  191.                 foreach ($order->getLineItems() as $lineItem) {
  192.                     if ($lineItem->getPayload()['productNumber'] === $productEntity->getProductNumber()) {
  193.                         $result $result $lineItem->getQuantity();
  194.                     }
  195.                 }
  196.             }
  197.         }
  198.         return $result;
  199.     }
  200.     protected static function datesOfQuarter($quarter 'current'$year null$format null)
  201.     {
  202.         if (!is_int($year)) {
  203.             $year = (new \DateTime)->format('Y');
  204.         }
  205.         $current_quarter ceil((new \DateTime)->format('n') / 3);
  206.         switch (strtolower($quarter)) {
  207.             case 'this':
  208.             case 'current':
  209.                 $quarter ceil((new \DateTime)->format('n') / 3);
  210.                 break;
  211.             case 'previous':
  212.                 $year = (new \DateTime)->format('Y');
  213.                 if ($current_quarter == 1) {
  214.                     $quarter 4;
  215.                     $year--;
  216.                 } else {
  217.                     $quarter $current_quarter 1;
  218.                 }
  219.                 break;
  220.             case 'first':
  221.                 $quarter 1;
  222.                 break;
  223.             case 'last':
  224.                 $quarter 4;
  225.                 break;
  226.             default:
  227.                 $quarter = (!is_int($quarter) || $quarter || $quarter 4) ? $current_quarter $quarter;
  228.                 break;
  229.         }
  230.         if ($quarter === 'this') {
  231.             $quarter ceil((new \DateTime)->format('n') / 3);
  232.         }
  233.         $start = new \DateTime($year '-' . ($quarter 2) . '-1 00:00:00');
  234.         $end = new \DateTime($year '-' . ($quarter) . '-' . ($quarter == || $quarter == 31 30) . ' 23:59:59');
  235.         return array(
  236.             'start' => $format $start->format($format) : $start,
  237.             'end' => $format $end->format($format) : $end,
  238.         );
  239.     }
  240. }