Files
esun3d/app/code/Esun/Reward/Observer/ReverseCreditmemoPoints.php
2026-09-15 10:35:56 +08:00

63 lines
4.1 KiB
PHP

<?php
declare(strict_types=1);
namespace Esun\Reward\Observer;
use Esun\Reward\Model\BalanceManager;
use Esun\Reward\Model\Config;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Sales\Model\Order\Creditmemo;
class ReverseCreditmemoPoints implements ObserverInterface
{
public function __construct(private readonly BalanceManager $balanceManager, private readonly Config $config) {}
public function execute(Observer $observer): void
{
/** @var Creditmemo|null $creditmemo */ $creditmemo = $observer->getEvent()->getCreditmemo();
$order = $creditmemo?->getOrder(); $customerId = (int)($order?->getCustomerId() ?? 0);
if (!$creditmemo || !$order || $customerId <= 0 || !$this->config->isEnabled((int)$order->getStoreId())) { return; }
$rewardShare = (float)$order->getBaseSubtotal() > 0
? (float)$order->getData('base_reward_discount_amount') * (float)$creditmemo->getBaseSubtotal() / (float)$order->getBaseSubtotal()
: 0.0;
$eligible = max(0.0, (float)$creditmemo->getBaseSubtotal() + (float)$creditmemo->getBaseDiscountAmount() - $rewardShare);
$multiplier = max(1.0, (float)$order->getData('reward_multiplier'));
$remainingEarned = max(0, (int)$order->getData('reward_points_earned') - (int)$order->getData('reward_points_reversed'));
$points = min($remainingEarned, (int)floor($eligible * $this->config->orderRate((int)$order->getStoreId()) * $multiplier));
$websiteId = (int)$order->getStore()->getWebsiteId();
if ($points > 0) {
$this->balanceManager->change($customerId, $websiteId, -$points, 'order_refund_reversal', 'creditmemo_reversal:' . (int)$creditmemo->getId(), [
'reference_type' => 'order', 'reference_id' => (int)$order->getId(), 'reason' => (string)__('Points reversed for refund on order %1', $order->getIncrementId()),
'metadata' => ['creditmemo_id' => (int)$creditmemo->getId()], 'allow_negative' => true
]);
$order->setData('reward_points_reversed', (int)$order->getData('reward_points_reversed') + $points);
}
$returnedProductPoints = 0;
foreach ($creditmemo->getAllItems() as $creditmemoItem) {
$orderItem = $creditmemoItem->getOrderItem();
if ($orderItem && (int)$orderItem->getData('reward_redemption')) {
$returnedProductPoints += (int)round((float)$creditmemoItem->getQty() * (int)$orderItem->getData('reward_points_cost'));
}
}
if ($returnedProductPoints > 0) {
$this->balanceManager->change($customerId, $websiteId, $returnedProductPoints, 'redemption_refund', 'creditmemo_redemption_refund:' . (int)$creditmemo->getId(), [
'reference_type' => 'order', 'reference_id' => (int)$order->getId(), 'reason' => (string)__('Product redemption points returned for order %1', $order->getIncrementId()),
'metadata' => ['creditmemo_id' => (int)$creditmemo->getId()]
]);
}
$remainingCashPoints = max(0, (int)$order->getData('reward_points_used') - (int)$order->getData('reward_points_refunded'));
$cashPointsToReturn = (float)$order->getBaseSubtotal() > 0
? min($remainingCashPoints, (int)round((int)$order->getData('reward_points_used') * (float)$creditmemo->getBaseSubtotal() / (float)$order->getBaseSubtotal()))
: 0;
if ($cashPointsToReturn > 0) {
$this->balanceManager->change($customerId, $websiteId, $cashPointsToReturn, 'checkout_refund', 'creditmemo_checkout_refund:' . (int)$creditmemo->getId(), [
'reference_type' => 'order', 'reference_id' => (int)$order->getId(), 'reason' => (string)__('Checkout points returned for order %1', $order->getIncrementId()),
'metadata' => ['creditmemo_id' => (int)$creditmemo->getId()]
]);
$order->setData('reward_points_refunded', (int)$order->getData('reward_points_refunded') + $cashPointsToReturn);
}
$order->save();
$this->balanceManager->addLifetimeSpend($customerId, $websiteId, -$eligible, (int)$order->getStoreId());
}
}