Files
2026-09-15 10:35:56 +08:00

70 lines
2.5 KiB
PHP

<?php
declare(strict_types=1);
namespace Esun\CustomerCoupon\Model;
use Esun\CustomerCoupon\Api\CouponNotifierInterface;
use Esun\CustomerCoupon\Model\ResourceModel\Assignment as AssignmentResource;
use Magento\Framework\Exception\LocalizedException;
use Magento\SalesRule\Model\CouponFactory;
class AssignmentService
{
public function __construct(
private readonly AssignmentFactory $assignmentFactory,
private readonly AssignmentResource $assignmentResource,
private readonly CouponFactory $couponFactory,
private readonly CouponNotifierInterface $couponNotifier
) {
}
/**
* Assign generated coupon codes to customers.
*
* @param string[] $codes
* @param int[] $customerIds
* @param int $ruleId
* @param string|null $source Stable source key used to make automatic grants idempotent
*/
public function assignCodes(array $codes, array $customerIds, int $ruleId, ?string $source = null): void
{
if (count($codes) !== count($customerIds)) {
throw new LocalizedException(__('The generated coupon count does not match the selected customer count.'));
}
$connection = $this->assignmentResource->getConnection();
$assignmentIds = [];
$connection->beginTransaction();
try {
foreach (array_values($codes) as $index => $code) {
$coupon = $this->couponFactory->create()->load($code, 'code');
if (!$coupon->getId()) {
throw new LocalizedException(__('The generated coupon "%1" could not be loaded.', $code));
}
$assignment = $this->assignmentFactory->create();
$assignment->setData([
'coupon_id' => (int)$coupon->getId(),
'rule_id' => $ruleId,
'customer_id' => (int)$customerIds[$index],
'source' => $source,
]);
$this->assignmentResource->save($assignment);
$assignmentIds[] = (int)$assignment->getId();
}
$connection->commit();
} catch (\Throwable $exception) {
$connection->rollBack();
throw $exception;
}
foreach ($assignmentIds as $assignmentId) {
try {
$this->couponNotifier->notify($assignmentId);
} catch (\Throwable) {
// Notification delivery is best-effort and must not invalidate an assigned coupon.
}
}
}
}