custom/plugins/WbfkExtensions/src/Subscriber/SendCustomerGroupApprovalPendingNotification.php line 59

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace WbfkExtensions\Subscriber;
  4. use Shopware\Core\Checkout\Customer\Aggregate\CustomerGroup\CustomerGroupCollection;
  5. use Shopware\Core\Checkout\Customer\CustomerEntity;
  6. use Shopware\Core\Checkout\Customer\Event\CustomerRegisterEvent;
  7. use Shopware\Core\Content\Mail\Service\AbstractMailService;
  8. use Shopware\Core\Content\MailTemplate\MailTemplateEntity;
  9. use Shopware\Core\Content\Media\MediaEntity;
  10. use Shopware\Core\Content\Media\MediaService;
  11. use Shopware\Core\Framework\Context;
  12. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  13. use Shopware\Core\Framework\DataAbstractionLayer\EntityWriteResult;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  17. use Shopware\Core\Framework\Routing\Exception\InvalidRequestParameterException;
  18. use Shopware\Core\System\SystemConfig\SystemConfigService;
  19. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  20. use Symfony\Component\HttpFoundation\RequestStack;
  21. use Symfony\Contracts\Translation\TranslatorInterface;
  22. class SendCustomerGroupApprovalPendingNotification implements EventSubscriberInterface
  23. {
  24.     public function __construct(
  25.         private readonly RequestStack $requestStack,
  26.         private readonly TranslatorInterface $translator,
  27.         private readonly EntityRepository $customerGroupRepository,
  28.         private readonly SystemConfigService $systemConfigService,
  29.         private readonly EntityRepository $customerRepository,
  30.         private readonly AbstractMailService $mailService,
  31.         private readonly EntityRepository $mailTemplateRepository,
  32.         private readonly EntityRepository $mediaRepository,
  33.         private readonly MediaService $mediaService,
  34.     ) {
  35.     }
  36.     public static function getSubscribedEvents(): array
  37.     {
  38.         return [
  39.             CustomerRegisterEvent::class => 'checkIfCustomerRegistrationRequiresGroupApproval',
  40.             'customer.written' => 'checkIfCustomerUpdateRequiresGroupApproval',
  41.         ];
  42.     }
  43.     public function checkIfCustomerRegistrationRequiresGroupApproval(CustomerRegisterEvent $event): void
  44.     {
  45.         $customer $event->getCustomer();
  46.         if ($customer->getRequestedGroupId() === null) {
  47.             return;
  48.         }
  49.         $this->customerGroupRequestedWorkflow($customer$event->getContext());
  50.     }
  51.     public function checkIfCustomerUpdateRequiresGroupApproval(EntityWrittenEvent $event): void
  52.     {
  53.         foreach ($event->getWriteResults() as $entityWriteResult) {
  54.             if (!$this->isCustomerUpdate($entityWriteResult)) {
  55.                 continue;
  56.             }
  57.             $payload $entityWriteResult->getPayload();
  58.             $requestedGroupId $payload['requestedGroupId'] ?? null;
  59.             if ($requestedGroupId === null) {
  60.                 continue;
  61.             }
  62.             $customerGroupId $payload['groupId'] ?? null;
  63.             if ($customerGroupId === $requestedGroupId) {
  64.                 continue;
  65.             }
  66.             $criteria = new Criteria([$entityWriteResult->getPrimaryKey()]);
  67.             $customer $this->customerRepository->search($criteria$event->getContext())->first();
  68.             $this->customerGroupRequestedWorkflow($customer$event->getContext());
  69.         }
  70.     }
  71.     public function customerGroupRequestedWorkflow(CustomerEntity $customerContext $context): void
  72.     {
  73.         $this->loadCurrentAndRequestedCustomerGroup($customer$context);
  74.         $this->notifyCustomerAboutPendingCustomerGroupApproval($customer);
  75.         $this->notifyAdminAboutPendingCustomerGroupApproval($customer$context);
  76.     }
  77.     private function notifyCustomerAboutPendingCustomerGroupApproval(
  78.         CustomerEntity $customer
  79.     ): void {
  80.         // Do not need to show guest customer about the warning, since they are shown form to convert to normal customer
  81.         // as guest customer cannot use customer groups that requires approval
  82.         if ($customer->getGuest()) {
  83.             return;
  84.         }
  85.         if (!$this->requestStack->getCurrentRequest()->hasSession()) {
  86.             return;
  87.         }
  88.         $this->requestStack->getCurrentRequest()->getSession()->getFlashBag()->add(
  89.             'warning',
  90.             $this->translator->trans('warning.b2bCustomerGroupPendingApproval', [
  91.                 '%currentCustomerGroup%' => $customer->getGroup()->getTranslated()['name'],
  92.                 '%requestedCustomerGroup%' => $customer->getRequestedGroup()->getTranslated()['name'],
  93.             ])
  94.         );
  95.     }
  96.     private function notifyAdminAboutPendingCustomerGroupApproval(CustomerEntity $customerContext $context): void
  97.     {
  98.         $data = [];
  99.         $data['recipients'] = [
  100.             $this->systemConfigService->get('core.basicInformation.email') => $this->systemConfigService->get(
  101.                 'core.basicInformation.shopName'
  102.             ),
  103.         ];
  104.         $data['salesChannelId'] = $customer->getSalesChannelId();
  105.         $data $this->addMailTemplateData($data$context);
  106.         $tradeLicenseMediaFileId $customer->getCustomFields()['wbfk_customer_trade_license'] ?? null;
  107.         if ($tradeLicenseMediaFileId !== null && strlen($tradeLicenseMediaFileId)) {
  108.             $data $this->addTradeLicenseAttachment($data$customer->getId(), $tradeLicenseMediaFileId$context);
  109.         }
  110.         $templateData = [];
  111.         $templateData['salesChannel'] = $customer->getSalesChannel();
  112.         $templateData['customer'] = $customer;
  113.         $templateData['currentCustomerGroup'] = $customer->getGroup();
  114.         $templateData['requestedCustomerGroup'] = $customer->getRequestedGroup();
  115.         $currentRequest $this->requestStack->getCurrentRequest();
  116.         $customerDetailUrl $currentRequest->getSchemeAndHttpHost().$currentRequest->getBasePath().
  117.             '/admin#/sw/customer/detail/'.$customer->getId().'/base';
  118.         $templateData['customerDetailUrl'] = $customerDetailUrl;
  119.         $this->mailService->send($data$context$templateData);
  120.     }
  121.     private function loadCurrentAndRequestedCustomerGroup(
  122.         CustomerEntity $customer,
  123.         Context $context
  124.     ): void {
  125.         /** @var CustomerGroupCollection $customerGroups */
  126.         $customerGroups $this->customerGroupRepository->search(
  127.             new Criteria([$customer->getGroupId(), $customer->getRequestedGroupId()]),
  128.             $context
  129.         );
  130.         $customer->setGroup($customerGroups->get($customer->getGroupId()));
  131.         $customer->setRequestedGroup($customerGroups->get($customer->getRequestedGroupId()));
  132.     }
  133.     private function isCustomerUpdate(EntityWriteResult $entityWriteResult
  134.     ): bool {
  135.         return $entityWriteResult->getOperation() === EntityWriteResult::OPERATION_UPDATE;
  136.     }
  137.     private function addMailTemplateData(array $dataContext $context): array
  138.     {
  139.         $criteria = new Criteria();
  140.         $criteria->addFilter(new EqualsFilter('mailTemplateType.technicalName''customer_group_request_admin_notification'));
  141.         $criteria->addAssociation('mailTemplateType');
  142.         /** @var MailTemplateEntity $template */
  143.         $template $context->scope(Context::SYSTEM_SCOPE, function (Context $context) use ($criteria) {
  144.             return $this->mailTemplateRepository->search($criteria$context)->first();
  145.         });
  146.         $data['contentHtml'] = $template->getContentHtml();
  147.         $data['contentPlain'] = $template->getContentPlain();
  148.         $data['subject'] = $template->getSubject();
  149.         $data['senderName'] = $template->getSenderName();
  150.         return $data;
  151.     }
  152.     private function addTradeLicenseAttachment(array $datastring $customerIdstring $tradeLicenseMediaFileIdContext $context): array
  153.     {
  154.         $attachment $context->scope(Context::SYSTEM_SCOPE, function (Context $context) use ($tradeLicenseMediaFileId$customerId) {
  155.             /** @var MediaEntity $media */
  156.             $criteria = new Criteria();
  157.             $criteria->addFilter(new EqualsFilter('id'$tradeLicenseMediaFileId));
  158.             $media $this->mediaRepository->search($criteria$context)->first();
  159.             if (!$media) {
  160.                 throw new InvalidRequestParameterException('tradeLicenseMediaFileId');
  161.             }
  162.             return [
  163.                 'content' => $this->mediaService->loadFile($tradeLicenseMediaFileId$context),
  164.                 'fileName' => 'trade-license-'.$customerId.'.'.$media->getFileExtension(),
  165.                 'mimeType' => $media->getMimeType(),
  166.             ];
  167.         });
  168.         if (!isset($data['binAttachments'])) {
  169.             $data['binAttachments'] = [];
  170.         }
  171.         $data['binAttachments'][] = $attachment;
  172.         return $data;
  173.     }
  174. }