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

42 lines
3.2 KiB
PHP

<?php
declare(strict_types=1);
namespace Esun\Reward\Controller\Product;
use Esun\Reward\Model\BalanceManager;
use Esun\Reward\Model\ReservationManager;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Checkout\Model\Cart;
use Magento\Customer\Model\Session;
use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Controller\Result\RedirectFactory;
use Magento\Framework\Data\Form\FormKey\Validator;
use Magento\Framework\DataObject;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Serialize\Serializer\Json;
use Magento\Framework\Message\ManagerInterface;
class Redeem implements HttpPostActionInterface
{
public function __construct(private readonly RequestInterface $request,private readonly Validator $formKey,private readonly RedirectFactory $redirects,private readonly Session $session,private readonly ProductRepositoryInterface $products,private readonly Cart $cart,private readonly BalanceManager $balances,private readonly ReservationManager $reservations,private readonly Json $json,private readonly ManagerInterface $messages) {}
public function execute()
{
$redirect=$this->redirects->create()->setPath('reward/product/index');
try {
if(!$this->formKey->validate($this->request)||!$this->session->isLoggedIn()){throw new LocalizedException(__('Please sign in to redeem products.'));}
$product=$this->products->getById((int)$this->request->getParam('product_id'));$cost=(int)$product->getData('reward_points_cost');
if(!(bool)$product->getData('reward_redeemable')||$cost<=0||$product->getTypeId()!=='simple'){throw new LocalizedException(__('This product is not available for points redemption.'));}
$quote=$this->cart->getQuote();$customerId=(int)$this->session->getCustomerId();$existing=(int)$quote->getData('reward_product_points');$cash=(int)$quote->getData('reward_points_used');
if((int)$this->balances->getAccount($customerId,(int)$quote->getStore()->getWebsiteId())['balance']<$existing+$cash+$cost){throw new LocalizedException(__('You do not have enough points for this product.'));}
$product->addCustomOption('reward_redemption', '1');
$item=$this->cart->addProduct($product,new DataObject(['qty'=>1,'reward_redemption'=>1]));if(is_string($item)){throw new LocalizedException(__($item));}
$item->setCustomPrice(0)->setOriginalCustomPrice(0)->setData('reward_redemption',1)->setData('reward_points_cost',$cost);$item->getProduct()->setIsSuperMode(true);
$item->addOption(['code'=>'additional_options','value'=>$this->json->serialize([['label'=>(string)__('Points Redemption'),'value'=>(string)__('%1 points',$cost)]])]);
$quote->setData('reward_product_points',$existing+$cost);$this->reservations->reserve($customerId,(int)$quote->getStore()->getWebsiteId(),(int)$quote->getId(),$cash+$existing+$cost);$this->cart->save();
$this->messages->addSuccessMessage(__('The redemption product was added to your cart.'));
} catch(\Throwable $e){$this->messages->addErrorMessage($e->getMessage());return $redirect;}
return $redirect->setPath('checkout/cart');
}
}