<?php
declare(strict_types=1);
namespace WbfkExtensions\Subscriber;
use Shopware\Core\Checkout\Customer\Aggregate\CustomerGroup\CustomerGroupCollection;
use Shopware\Core\Checkout\Customer\CustomerEntity;
use Shopware\Core\Checkout\Customer\Event\CustomerRegisterEvent;
use Shopware\Core\Content\Mail\Service\AbstractMailService;
use Shopware\Core\Content\MailTemplate\MailTemplateEntity;
use Shopware\Core\Content\Media\MediaEntity;
use Shopware\Core\Content\Media\MediaService;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\EntityWriteResult;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Routing\Exception\InvalidRequestParameterException;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Contracts\Translation\TranslatorInterface;
class SendCustomerGroupApprovalPendingNotification implements EventSubscriberInterface
{
public function __construct(
private readonly RequestStack $requestStack,
private readonly TranslatorInterface $translator,
private readonly EntityRepository $customerGroupRepository,
private readonly SystemConfigService $systemConfigService,
private readonly EntityRepository $customerRepository,
private readonly AbstractMailService $mailService,
private readonly EntityRepository $mailTemplateRepository,
private readonly EntityRepository $mediaRepository,
private readonly MediaService $mediaService,
) {
}
public static function getSubscribedEvents(): array
{
return [
CustomerRegisterEvent::class => 'checkIfCustomerRegistrationRequiresGroupApproval',
'customer.written' => 'checkIfCustomerUpdateRequiresGroupApproval',
];
}
public function checkIfCustomerRegistrationRequiresGroupApproval(CustomerRegisterEvent $event): void
{
$customer = $event->getCustomer();
if ($customer->getRequestedGroupId() === null) {
return;
}
$this->customerGroupRequestedWorkflow($customer, $event->getContext());
}
public function checkIfCustomerUpdateRequiresGroupApproval(EntityWrittenEvent $event): void
{
foreach ($event->getWriteResults() as $entityWriteResult) {
if (!$this->isCustomerUpdate($entityWriteResult)) {
continue;
}
$payload = $entityWriteResult->getPayload();
$requestedGroupId = $payload['requestedGroupId'] ?? null;
if ($requestedGroupId === null) {
continue;
}
$customerGroupId = $payload['groupId'] ?? null;
if ($customerGroupId === $requestedGroupId) {
continue;
}
$criteria = new Criteria([$entityWriteResult->getPrimaryKey()]);
$customer = $this->customerRepository->search($criteria, $event->getContext())->first();
$this->customerGroupRequestedWorkflow($customer, $event->getContext());
}
}
public function customerGroupRequestedWorkflow(CustomerEntity $customer, Context $context): void
{
$this->loadCurrentAndRequestedCustomerGroup($customer, $context);
$this->notifyCustomerAboutPendingCustomerGroupApproval($customer);
$this->notifyAdminAboutPendingCustomerGroupApproval($customer, $context);
}
private function notifyCustomerAboutPendingCustomerGroupApproval(
CustomerEntity $customer
): void {
// Do not need to show guest customer about the warning, since they are shown form to convert to normal customer
// as guest customer cannot use customer groups that requires approval
if ($customer->getGuest()) {
return;
}
if (!$this->requestStack->getCurrentRequest()->hasSession()) {
return;
}
$this->requestStack->getCurrentRequest()->getSession()->getFlashBag()->add(
'warning',
$this->translator->trans('warning.b2bCustomerGroupPendingApproval', [
'%currentCustomerGroup%' => $customer->getGroup()->getTranslated()['name'],
'%requestedCustomerGroup%' => $customer->getRequestedGroup()->getTranslated()['name'],
])
);
}
private function notifyAdminAboutPendingCustomerGroupApproval(CustomerEntity $customer, Context $context): void
{
$data = [];
$data['recipients'] = [
$this->systemConfigService->get('core.basicInformation.email') => $this->systemConfigService->get(
'core.basicInformation.shopName'
),
];
$data['salesChannelId'] = $customer->getSalesChannelId();
$data = $this->addMailTemplateData($data, $context);
$tradeLicenseMediaFileId = $customer->getCustomFields()['wbfk_customer_trade_license'] ?? null;
if ($tradeLicenseMediaFileId !== null && strlen($tradeLicenseMediaFileId)) {
$data = $this->addTradeLicenseAttachment($data, $customer->getId(), $tradeLicenseMediaFileId, $context);
}
$templateData = [];
$templateData['salesChannel'] = $customer->getSalesChannel();
$templateData['customer'] = $customer;
$templateData['currentCustomerGroup'] = $customer->getGroup();
$templateData['requestedCustomerGroup'] = $customer->getRequestedGroup();
$currentRequest = $this->requestStack->getCurrentRequest();
$customerDetailUrl = $currentRequest->getSchemeAndHttpHost().$currentRequest->getBasePath().
'/admin#/sw/customer/detail/'.$customer->getId().'/base';
$templateData['customerDetailUrl'] = $customerDetailUrl;
$this->mailService->send($data, $context, $templateData);
}
private function loadCurrentAndRequestedCustomerGroup(
CustomerEntity $customer,
Context $context
): void {
/** @var CustomerGroupCollection $customerGroups */
$customerGroups = $this->customerGroupRepository->search(
new Criteria([$customer->getGroupId(), $customer->getRequestedGroupId()]),
$context
);
$customer->setGroup($customerGroups->get($customer->getGroupId()));
$customer->setRequestedGroup($customerGroups->get($customer->getRequestedGroupId()));
}
private function isCustomerUpdate(EntityWriteResult $entityWriteResult
): bool {
return $entityWriteResult->getOperation() === EntityWriteResult::OPERATION_UPDATE;
}
private function addMailTemplateData(array $data, Context $context): array
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('mailTemplateType.technicalName', 'customer_group_request_admin_notification'));
$criteria->addAssociation('mailTemplateType');
/** @var MailTemplateEntity $template */
$template = $context->scope(Context::SYSTEM_SCOPE, function (Context $context) use ($criteria) {
return $this->mailTemplateRepository->search($criteria, $context)->first();
});
$data['contentHtml'] = $template->getContentHtml();
$data['contentPlain'] = $template->getContentPlain();
$data['subject'] = $template->getSubject();
$data['senderName'] = $template->getSenderName();
return $data;
}
private function addTradeLicenseAttachment(array $data, string $customerId, string $tradeLicenseMediaFileId, Context $context): array
{
$attachment = $context->scope(Context::SYSTEM_SCOPE, function (Context $context) use ($tradeLicenseMediaFileId, $customerId) {
/** @var MediaEntity $media */
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('id', $tradeLicenseMediaFileId));
$media = $this->mediaRepository->search($criteria, $context)->first();
if (!$media) {
throw new InvalidRequestParameterException('tradeLicenseMediaFileId');
}
return [
'content' => $this->mediaService->loadFile($tradeLicenseMediaFileId, $context),
'fileName' => 'trade-license-'.$customerId.'.'.$media->getFileExtension(),
'mimeType' => $media->getMimeType(),
];
});
if (!isset($data['binAttachments'])) {
$data['binAttachments'] = [];
}
$data['binAttachments'][] = $attachment;
return $data;
}
}