132 lines
5.6 KiB
PHP
132 lines
5.6 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace Esun\CustomerCoupon\Plugin;
|
|
|
|
use Esun\CustomerCoupon\Model\AssignmentService;
|
|
use Magento\Customer\Model\ResourceModel\Customer\CollectionFactory as CustomerCollectionFactory;
|
|
use Magento\Framework\App\Config\ScopeConfigInterface;
|
|
use Magento\Framework\Escaper;
|
|
use Magento\Framework\Exception\LocalizedException;
|
|
use Magento\Framework\Json\Helper\Data as JsonHelper;
|
|
use Magento\SalesRule\Api\CouponManagementInterface;
|
|
use Magento\SalesRule\Api\Data\CouponGenerationSpecInterfaceFactory;
|
|
use Magento\SalesRule\Controller\Adminhtml\Promo\Quote\Generate;
|
|
use Magento\SalesRule\Model\Quote\GetCouponCodeLengthInterface;
|
|
use Magento\SalesRule\Model\Rule;
|
|
use Magento\SalesRule\Model\RuleFactory;
|
|
use Magento\Store\Model\ScopeInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
class GenerateAssignedCouponsPlugin
|
|
{
|
|
private const XML_CONFIG_COUPON_QUANTITY_LIMIT = 'promo/auto_generated_coupon_codes/quantity_limit';
|
|
|
|
public function __construct(
|
|
private readonly CouponGenerationSpecInterfaceFactory $generationSpecFactory,
|
|
private readonly CouponManagementInterface $couponManagement,
|
|
private readonly AssignmentService $assignmentService,
|
|
private readonly RuleFactory $ruleFactory,
|
|
private readonly CustomerCollectionFactory $customerCollectionFactory,
|
|
private readonly GetCouponCodeLengthInterface $getCouponCodeLength,
|
|
private readonly ScopeConfigInterface $scopeConfig,
|
|
private readonly JsonHelper $jsonHelper,
|
|
private readonly Escaper $escaper,
|
|
private readonly LoggerInterface $logger
|
|
) {
|
|
}
|
|
|
|
public function aroundExecute(Generate $subject, callable $proceed): mixed
|
|
{
|
|
$customerIds = $this->parseCustomerIds($subject->getRequest()->getParam('customer_ids'));
|
|
if (!$customerIds) {
|
|
return $proceed();
|
|
}
|
|
|
|
try {
|
|
$data = $subject->getRequest()->getParams();
|
|
$ruleId = (int)($data['rule_id'] ?? 0);
|
|
$rule = $this->ruleFactory->create()->load($ruleId);
|
|
if (!$rule->getId()) {
|
|
throw new LocalizedException(__('Rule is not defined.'));
|
|
}
|
|
if ((int)$rule->getCouponType() !== Rule::COUPON_TYPE_AUTO && !$rule->getUseAutoGeneration()) {
|
|
throw new LocalizedException(
|
|
__('The rule coupon settings changed. Please save the rule before using auto-generation.')
|
|
);
|
|
}
|
|
|
|
$this->validateCustomers($customerIds, $rule);
|
|
$quantityLimit = (int)$this->scopeConfig->getValue(
|
|
self::XML_CONFIG_COUPON_QUANTITY_LIMIT,
|
|
ScopeInterface::SCOPE_STORE
|
|
);
|
|
if ($quantityLimit > 0 && count($customerIds) > $quantityLimit) {
|
|
throw new LocalizedException(__('The selected customer count exceeds the configured coupon limit.'));
|
|
}
|
|
|
|
$data['qty'] = count($customerIds);
|
|
$data['quantity'] = count($customerIds);
|
|
if ((int)($data['length'] ?? 0) !== $this->getCouponCodeLength->fetchCouponCodeLength($data)) {
|
|
throw new LocalizedException(
|
|
__('The coupon code length is too short for the selected customer count.')
|
|
);
|
|
}
|
|
|
|
$specification = $this->generationSpecFactory->create(['data' => $data]);
|
|
$codes = $this->couponManagement->generate($specification);
|
|
try {
|
|
$this->assignmentService->assignCodes($codes, $customerIds, $ruleId);
|
|
} catch (\Throwable $exception) {
|
|
$this->couponManagement->deleteByCodes($codes);
|
|
throw $exception;
|
|
}
|
|
|
|
return $this->respond($subject, [
|
|
'messages' => '<div class="messages"><div class="message message-success success"><div>'
|
|
. $this->escaper->escapeHtml(
|
|
__('Generated and assigned %1 coupon(s).', count($customerIds))
|
|
)
|
|
. '</div></div></div>',
|
|
]);
|
|
} catch (LocalizedException $exception) {
|
|
return $this->respond($subject, ['error' => $exception->getMessage()]);
|
|
} catch (\Throwable $exception) {
|
|
$this->logger->critical($exception);
|
|
|
|
return $this->respond($subject, [
|
|
'error' => (string)__('Something went wrong while generating assigned coupons.'),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/** @return int[] */
|
|
private function parseCustomerIds(mixed $value): array
|
|
{
|
|
$values = is_array($value) ? $value : explode(',', (string)$value);
|
|
$ids = array_values(array_unique(array_filter(array_map('intval', $values))));
|
|
|
|
return $ids;
|
|
}
|
|
|
|
/** @param int[] $customerIds */
|
|
private function validateCustomers(array $customerIds, Rule $rule): void
|
|
{
|
|
$collection = $this->customerCollectionFactory->create();
|
|
$collection->addFieldToFilter('entity_id', ['in' => $customerIds]);
|
|
$collection->addFieldToFilter('website_id', ['in' => array_map('intval', $rule->getWebsiteIds())]);
|
|
$collection->addFieldToFilter('group_id', ['in' => array_map('intval', $rule->getCustomerGroupIds())]);
|
|
|
|
if ((int)$collection->getSize() !== count($customerIds)) {
|
|
throw new LocalizedException(
|
|
__('One or more selected customers are not eligible for this rule website or customer group.')
|
|
);
|
|
}
|
|
}
|
|
|
|
private function respond(Generate $subject, array $data): mixed
|
|
{
|
|
return $subject->getResponse()->representJson($this->jsonHelper->jsonEncode($data));
|
|
}
|
|
}
|