116 lines
4.4 KiB
PHP
116 lines
4.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace Esun\CustomerCoupon\Model;
|
|
|
|
use Esun\CustomerCoupon\Model\ResourceModel\Assignment as AssignmentResource;
|
|
use Esun\PromotionPopup\Model\Config as PromotionConfig;
|
|
use Magento\Framework\Exception\LocalizedException;
|
|
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
|
|
use Magento\SalesRule\Api\CouponManagementInterface;
|
|
use Magento\SalesRule\Api\Data\CouponGenerationSpecInterface;
|
|
use Magento\SalesRule\Api\Data\CouponGenerationSpecInterfaceFactory;
|
|
use Magento\SalesRule\Model\Rule;
|
|
use Magento\SalesRule\Model\RuleFactory;
|
|
use Magento\Store\Model\StoreManagerInterface;
|
|
|
|
class RegistrationSubscriptionCouponService
|
|
{
|
|
public const ASSIGNMENT_SOURCE = 'registration_newsletter';
|
|
|
|
public function __construct(
|
|
private readonly Config $config,
|
|
private readonly RuleFactory $ruleFactory,
|
|
private readonly CouponGenerationSpecInterfaceFactory $generationSpecFactory,
|
|
private readonly CouponManagementInterface $couponManagement,
|
|
private readonly AssignmentService $assignmentService,
|
|
private readonly AssignmentResource $assignmentResource,
|
|
private readonly TimezoneInterface $timezone,
|
|
private readonly StoreManagerInterface $storeManager,
|
|
private readonly PromotionConfig $promotionConfig
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Generate and assign the one-time registration subscription coupon.
|
|
*
|
|
* @throws LocalizedException
|
|
*/
|
|
public function grant(int $customerId, int $websiteId, int $customerGroupId, int $storeId): bool
|
|
{
|
|
if ($customerId <= 0
|
|
|| !$this->promotionConfig->isCampaignActive()
|
|
|| !$this->promotionConfig->isRegistrationNewsletterCouponPromotion()
|
|
|| $this->hasAlreadyBeenGranted($customerId)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
$ruleId = $this->config->getRegistrationSubscriptionRuleId($storeId ?: null);
|
|
if ($ruleId <= 0) {
|
|
return false;
|
|
}
|
|
|
|
/** @var Rule $rule */
|
|
$rule = $this->ruleFactory->create()->load($ruleId);
|
|
$scope = $storeId > 0 ? $this->storeManager->getStore($storeId) : $this->storeManager->getStore();
|
|
if (!$rule->getId()
|
|
|| !$rule->getIsActive()
|
|
|| ((int)$rule->getCouponType() !== Rule::COUPON_TYPE_AUTO && !$rule->getUseAutoGeneration())
|
|
|| !in_array($websiteId, array_map('intval', $rule->getWebsiteIds()), true)
|
|
|| !in_array($customerGroupId, array_map('intval', $rule->getCustomerGroupIds()), true)
|
|
|| !$this->timezone->isScopeDateInInterval($scope, $rule->getFromDate(), $rule->getToDate())
|
|
) {
|
|
throw new LocalizedException(
|
|
__('The configured registration subscription coupon rule is not eligible for this customer.')
|
|
);
|
|
}
|
|
|
|
/** @var CouponGenerationSpecInterface $specification */
|
|
$specification = $this->generationSpecFactory->create();
|
|
$specification->setRuleId($ruleId)
|
|
->setQuantity(1)
|
|
->setLength(12)
|
|
->setFormat(CouponGenerationSpecInterface::COUPON_FORMAT_ALPHANUMERIC)
|
|
->setPrefix('WELCOME-')
|
|
->setDelimiterAtEvery(0);
|
|
|
|
$codes = $this->couponManagement->generate($specification);
|
|
if (count($codes) !== 1) {
|
|
if ($codes) {
|
|
$this->couponManagement->deleteByCodes($codes);
|
|
}
|
|
throw new LocalizedException(__('The registration subscription coupon could not be generated.'));
|
|
}
|
|
|
|
try {
|
|
$this->assignmentService->assignCodes(
|
|
$codes,
|
|
[$customerId],
|
|
$ruleId,
|
|
self::ASSIGNMENT_SOURCE
|
|
);
|
|
} catch (\Throwable $exception) {
|
|
$this->couponManagement->deleteByCodes($codes);
|
|
if ($this->hasAlreadyBeenGranted($customerId)) {
|
|
return true;
|
|
}
|
|
throw $exception;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private function hasAlreadyBeenGranted(int $customerId): bool
|
|
{
|
|
$connection = $this->assignmentResource->getConnection();
|
|
$select = $connection->select()
|
|
->from($this->assignmentResource->getMainTable(), ['entity_id'])
|
|
->where('customer_id = ?', $customerId)
|
|
->where('source = ?', self::ASSIGNMENT_SOURCE)
|
|
->limit(1);
|
|
|
|
return (bool)$connection->fetchOne($select);
|
|
}
|
|
}
|