<?php
/*
役割:UI制御・警告表示
*/
namespace Plugin\SDream\EventSubscriber;
use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Psr\Log\LoggerInterface;
use Eccube\Service\CartService;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
use Symfony\Component\Routing\RouterInterface;
use Plugin\SDream\Service\CustomerGuard;
use Plugin\SDream\Service\CartRuleChecker;
use Plugin\SDream\Service\ProductPurchaseRuleChecker;
use Plugin\SDream\Service\PurchaseHistoryLimiter;
use Plugin\SDream\Service\PaymentRestrictionService;
use Symfony\Component\Security\Core\Security;
use Eccube\Entity\Customer;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Eccube\Service\OrderHelper;
class CartSubscriber implements EventSubscriberInterface
{
private Security $security;
private CartService $cartService;
private OrderHelper $orderHelper;
private CustomerGuard $customerGuard;
private CartRuleChecker $cartRuleChecker;
private ProductPurchaseRuleChecker $productPurchaseRuleChecker;
private PurchaseHistoryLimiter $purchaseHistoryLimiter;
private PaymentRestrictionService $paymentRestrictionService;
private FlashBagInterface $flashBag;
private RouterInterface $router;//ルート名から URL を生成するためのサービス
private LoggerInterface $logger;
public function __construct(
Security $security,
CartService $cartService,
OrderHelper $orderHelper,
CustomerGuard $customerGuard,
CartRuleChecker $cartRuleChecker,
ProductPurchaseRuleChecker $productPurchaseRuleChecker,
PurchaseHistoryLimiter $purchaseHistoryLimiter,
PaymentRestrictionService $paymentRestrictionService,
FlashBagInterface $flashBag,
LoggerInterface $logger,
RouterInterface $router
) {
$this->security = $security;
$this->flashBag = $flashBag;
$this->orderHelper = $orderHelper;
$this->customerGuard = $customerGuard;
$this->cartRuleChecker = $cartRuleChecker;
$this->productPurchaseRuleChecker = $productPurchaseRuleChecker;
$this->purchaseHistoryLimiter = $purchaseHistoryLimiter;
$this->paymentRestrictionService = $paymentRestrictionService;
$this->cartService = $cartService;
$this->logger = $logger;
$this->router = $router;
}
private function getCurrentCustomer(): ?Customer
{
$user = $this->security->getUser();
return $user instanceof Customer ? $user : null;
}
public static function getSubscribedEvents()
{
return [
//EccubeEvents::FRONT_CART_BUYSTEP_INITIALIZE => 'onBuyStep', エラー時にカートが止まらない
EccubeEvents::FRONT_CART_BUYSTEP_COMPLETE => 'onBuyStep',
];
}
/**
*
* カート
* → チェックをする ・・・ ここでこれを実施
* → レジに進む
*
* チェックする内容
* ・不定貫なら カード決済、Paid は与信のみ
* 再与信対象(ペイドの再与信はどうやるか??不明のまま)
* ・定貫・不定貫が混ざっている場合はエラー
* ・複数配送先が混ざっている場合はエラー
* ・例えば、冷凍は代引きNGとかでもできる
*
*
*
*/
public function onBuyStep(EventArgs $event)
{
//$this->logger->info('onBuyStep called');
// ★ Cart は service から取得
$Cart = $this->cartService->getCart();
if (!$Cart) {
return;
}
//チェックする
$errors = [];
//ログインユーザー
$Customer =
$this->getCurrentCustomer() ?: $this->orderHelper->getNonMember();
//1.会員状態・会員区分チェック
try {
$this->customerGuard->assertPurchasable($Customer);
} catch (AccessDeniedException $e) {
$errors[] = $e->getMessage();
}
//2.カート構成ルール(Cart全体)
//3.商品購入可否ルール(商品×会員)
//4.購入履歴制限(時間制限)
$errors = array_merge(
$errors,
$this->cartRuleChecker->validate($Cart),
$this->productPurchaseRuleChecker->validate($Cart, $Customer),
$this->purchaseHistoryLimiter->validate($Cart, $Customer)
);
// 5.決済ドメインルール(共通決済)
$allowedPayments =
$this->paymentRestrictionService
->resolveAllowedPayments($Cart, $Customer);
if (empty($allowedPayments)) {
$errors[] =
'同じ支払方法で購入できない商品が含まれています。' .
'恐れ入りますが、商品を分けてご購入ください。';
}
if (!empty($errors)) {
foreach ($errors as $message) {
$this->flashBag->add(
'eccube.front.cart.error',
$message
);
}
// STOP!「レジに進む」へ「進ませない」
//$event->stopPropagation();
$event->setResponse(
new RedirectResponse($this->router->generate('cart'))
);
return;
}
}
//強制中止確認用・・・画面メッセージ
public function onBuyStepDEBUG(EventArgs $event)
{
$this->logger->info('onBuyStep called (force reject test)');
// ★ Cart 画面で表示される Flash キー
$this->flashBag->add(
'eccube.front.cart.error',
'【テスト】現在このカートではレジに進めません。'
);
/*
index.twigの以下の表示される
{% for error in app.session.flashbag.get('eccube.front.cart.error') %}
<div class="ec-cartRole__error">
<div class="ec-alert-warning">
<div class="ec-alert-warning__icon">
<img src="{{ asset('assets/icon/exclamation-white.svg') }}">
</div>
<div class="ec-alert-warning__text">
{{ error|trans|nl2br }}
</div>
</div>
</div>
{% endfor %}
*/
$event->setResponse(
new RedirectResponse($this->router->generate('cart'))
);
}
private function hasVariableWeightItem($Cart): bool
{
foreach ($Cart->getCartItems() as $cartItem) {
$productClass = $cartItem->getProductClass();
if (!$productClass) {
continue;
}
$product = $productClass->getProduct();
if ($product && $product->isVariableWeight()) {
return true;
}
}
return false;
}
}