app/Plugin/NZMailSystem42/Event.php line 63

Open in your IDE?
  1. <?php
  2. namespace Plugin\NZMailSystem42;
  3. use Eccube\Event\EccubeEvents;
  4. use Eccube\Event\EventArgs;
  5. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  6. use Eccube\Common\EccubeConfig;
  7. use Eccube\Repository\PaymentRepository;
  8. use Eccube\Service\MailService;
  9. use Eccube\Repository\OrderRepository;
  10. use Eccube\Repository\BaseInfoRepository;
  11. use Eccube\Repository\MailHistoryRepository;
  12. use Eccube\Entity\Order;
  13. use Eccube\Entity\MailHistory;
  14. use Eccube\Entity\Master\OrderStatus;
  15. use Doctrine\ORM\EntityManagerInterface;
  16. use Symfony\Component\DependencyInjection\ContainerInterface;
  17. use Twig\Environment;
  18. class Event implements EventSubscriberInterface
  19. {
  20.     /**
  21.      * @var MailService
  22.      */
  23.     protected $mailService;
  24.     
  25.     /**
  26.      * @var OrderRepository
  27.      */
  28.     protected $orderRepository;
  29.     
  30.     /**
  31.      * @var BaseInfoRepository
  32.      */
  33.     protected $baseInfoRepository;
  34.     
  35.     /**
  36.      * @var MailHistoryRepository
  37.      */
  38.     protected $mailHistoryRepository;
  39.     
  40.     /**
  41.      * @var PaymentRepository
  42.      */
  43.     protected $paymentRepository;
  44.     
  45.     /**
  46.      * @var EntityManagerInterface
  47.      */
  48.     protected $entityManager;
  49.     
  50.     /**
  51.      * @var Environment
  52.      */
  53.     protected $twig;
  54.     
  55.     /**
  56.      * @var EccubeConfig
  57.      */
  58.     protected $eccubeConfig;
  59.     public function __construct(
  60.         MailService $mailService,
  61.         OrderRepository $orderRepository,
  62.         BaseInfoRepository $baseInfoRepository,
  63.         MailHistoryRepository $mailHistoryRepository,
  64.         PaymentRepository $paymentRepository,
  65.         EntityManagerInterface $entityManager,
  66.         Environment $twig,
  67.         EccubeConfig $eccubeConfig
  68.     ) {
  69.         $this->mailService $mailService;
  70.         $this->orderRepository $orderRepository;
  71.         $this->baseInfoRepository $baseInfoRepository;
  72.         $this->mailHistoryRepository $mailHistoryRepository;
  73.         $this->paymentRepository $paymentRepository;
  74.         $this->entityManager $entityManager;
  75.         $this->twig $twig;
  76.         $this->eccubeConfig $eccubeConfig;
  77.     }
  78.     /**
  79.      * @return array
  80.      */
  81.     public static function getSubscribedEvents()
  82.     {
  83.         return [
  84.             // 注文完了時のイベント(購入完了画面表示前)
  85.             EccubeEvents::FRONT_SHOPPING_COMPLETE_INITIALIZE => 'onShoppingComplete',
  86.             
  87.             // 注文確定後のイベント
  88.             'eccube.event.order.complete' => 'onOrderComplete',
  89.             
  90.             // 管理画面の注文編集画面拡張
  91.             '@admin/Order/edit.twig' => 'onAdminOrderEditTwig',
  92.             
  93.             // 手動送信用のカスタムイベント
  94.             'nz.mail.payment.confirm' => 'sendPaymentConfirmMail',
  95.             'nz.mail.payment.received' => 'sendPaymentReceivedMail',
  96.             'nz.mail.order.cancel' => 'sendCancellationMail',
  97.         ];
  98.     }
  99.     /**
  100.      * 注文完了時の自動メール送信処理
  101.      * 銀行振込・代金引換以外の決済方法の場合に自動送信
  102.      */
  103.     public function onShoppingComplete(EventArgs $event)
  104.     {
  105.         $Order $event->getArgument('Order');
  106.         
  107.         if (!$Order instanceof Order) {
  108.             return;
  109.         }
  110.         // 決済方法をチェック
  111.         if ($this->shouldSendAutoMail($Order)) {
  112.             // プラグイン設定を確認
  113.             $Config $this->getPluginConfig();
  114.             if (!$Config || !$Config->isAutoSendEnabled()) {
  115.                 return;
  116.             }
  117.             // 決済完了メールを送信
  118.             $this->sendPaymentCompleteMail($Order);
  119.         }
  120.     }
  121.     /**
  122.      * 注文確定後の処理(別のタイミングでも送信可能にするため)
  123.      */
  124.     public function onOrderComplete(EventArgs $event)
  125.     {
  126.         if (!$event->hasArgument('Order')) {
  127.             return;
  128.         }
  129.         
  130.         $Order $event->getArgument('Order');
  131.         
  132.         if (!$Order instanceof Order) {
  133.             return;
  134.         }
  135.         // 決済方法をチェックして必要なら送信
  136.         if ($this->shouldSendAutoMail($Order)) {
  137.             $Config $this->getPluginConfig();
  138.             if ($Config && $Config->isAutoSendEnabled()) {
  139.                 // すでに送信済みかチェック
  140.                 if (!$this->isAlreadySent($Order'payment_complete')) {
  141.                     $this->sendPaymentCompleteMail($Order);
  142.                 }
  143.             }
  144.         }
  145.     }
  146.     /**
  147.      * 自動メール送信が必要かどうかを判定
  148.      */
  149.     private function shouldSendAutoMail(Order $Order)
  150.     {
  151.         $Payment $Order->getPayment();
  152.         if (!$Payment) {
  153.             return false;
  154.         }
  155.         $paymentMethod $Payment->getMethod();
  156.         
  157.         // 銀行振込、代金引換以外の場合はtrue
  158.         // ※決済方法名は環境により異なる可能性があるため、適宜調整してください
  159.         $excludedPayments = [
  160.             '銀行振込',
  161.             '銀行振込み',
  162.             'bank_transfer',
  163.             '代金引換',
  164.             '代引き',
  165.             'cod',
  166.             'cash_on_delivery'
  167.         ];
  168.         foreach ($excludedPayments as $excluded) {
  169.             if (stripos($paymentMethod$excluded) !== false) {
  170.                 return false;
  171.             }
  172.         }
  173.         // クレジットカード、コンビニ決済、電子マネーなどの場合はtrue
  174.         return true;
  175.     }
  176.     /**
  177.      * 決済完了メール送信(クレジット等の即時決済用)
  178.      */
  179.     public function sendPaymentCompleteMail(Order $Order)
  180.     {
  181.         $Customer $Order->getCustomer();
  182.         if (!$Customer) {
  183.             return false;
  184.         }
  185.         try {
  186.             $body $this->renderMailTemplate('payment_complete', [
  187.                 'Order' => $Order,
  188.                 'Customer' => $Customer,
  189.                 'BaseInfo' => $this->baseInfoRepository->get()
  190.             ]);
  191.             
  192.             $message = (new \Swift_Message())
  193.                 ->setSubject($this->getMailSubject('payment_complete'$Order))
  194.                 ->setFrom($this->getFromAddress())
  195.                 ->setTo([$Customer->getEmail()])
  196.                 ->setBcc($this->getBccAddress())
  197.                 ->setBody($body);
  198.             $this->mailService->sendMail($message);
  199.             
  200.             // 送信履歴を保存
  201.             $this->saveMailHistory($Order'payment_complete'$body);
  202.             
  203.             // ログに記録
  204.             log_info('NZMailSystem42: 決済完了メール送信', [
  205.                 'order_id' => $Order->getId(),
  206.                 'order_no' => $Order->getOrderNo(),
  207.                 'payment' => $Order->getPayment()->getMethod()
  208.             ]);
  209.             
  210.             return true;
  211.         } catch (\Exception $e) {
  212.             log_error('NZMailSystem42: メール送信エラー', [$e->getMessage()]);
  213.             return false;
  214.         }
  215.     }
  216.     /**
  217.      * 決済確認メール送信(銀行振込等の手動確認用)
  218.      */
  219.     public function sendPaymentConfirmMail($Order)
  220.     {
  221.         if ($Order instanceof EventArgs) {
  222.             $Order $Order->getArgument('Order');
  223.         }
  224.         
  225.         $Customer $Order->getCustomer();
  226.         if (!$Customer) {
  227.             return false;
  228.         }
  229.         try {
  230.             $body $this->renderMailTemplate('payment_confirm', [
  231.                 'Order' => $Order,
  232.                 'Customer' => $Customer,
  233.                 'BaseInfo' => $this->baseInfoRepository->get()
  234.             ]);
  235.             
  236.             $message = (new \Swift_Message())
  237.                 ->setSubject($this->getMailSubject('payment_confirm'$Order))
  238.                 ->setFrom($this->getFromAddress())
  239.                 ->setTo([$Customer->getEmail()])
  240.                 ->setBcc($this->getBccAddress())
  241.                 ->setBody($body);
  242.             $this->mailService->sendMail($message);
  243.             
  244.             // 送信履歴を保存
  245.             $this->saveMailHistory($Order'payment_confirm'$body);
  246.             
  247.             return true;
  248.         } catch (\Exception $e) {
  249.             log_error('NZMailSystem42: メール送信エラー', [$e->getMessage()]);
  250.             return false;
  251.         }
  252.     }
  253.     /**
  254.      * 入金確認済みメール送信
  255.      */
  256.     public function sendPaymentReceivedMail($Order)
  257.     {
  258.         if ($Order instanceof EventArgs) {
  259.             $Order $Order->getArgument('Order');
  260.         }
  261.         
  262.         $Customer $Order->getCustomer();
  263.         if (!$Customer) {
  264.             return false;
  265.         }
  266.         try {
  267.             $body $this->renderMailTemplate('payment_received', [
  268.                 'Order' => $Order,
  269.                 'Customer' => $Customer,
  270.                 'BaseInfo' => $this->baseInfoRepository->get()
  271.             ]);
  272.             
  273.             $message = (new \Swift_Message())
  274.                 ->setSubject($this->getMailSubject('payment_received'$Order))
  275.                 ->setFrom($this->getFromAddress())
  276.                 ->setTo([$Customer->getEmail()])
  277.                 ->setBcc($this->getBccAddress())
  278.                 ->setBody($body);
  279.             $this->mailService->sendMail($message);
  280.             
  281.             // 送信履歴を保存
  282.             $this->saveMailHistory($Order'payment_received'$body);
  283.             
  284.             return true;
  285.         } catch (\Exception $e) {
  286.             log_error('NZMailSystem42: メール送信エラー', [$e->getMessage()]);
  287.             return false;
  288.         }
  289.     }
  290.     /**
  291.      * キャンセルメール送信
  292.      */
  293.     public function sendCancellationMail($Order)
  294.     {
  295.         if ($Order instanceof EventArgs) {
  296.             $Order $Order->getArgument('Order');
  297.         }
  298.         
  299.         $Customer $Order->getCustomer();
  300.         if (!$Customer) {
  301.             return false;
  302.         }
  303.         try {
  304.             $body $this->renderMailTemplate('order_cancel', [
  305.                 'Order' => $Order,
  306.                 'Customer' => $Customer,
  307.                 'BaseInfo' => $this->baseInfoRepository->get()
  308.             ]);
  309.             
  310.             $message = (new \Swift_Message())
  311.                 ->setSubject($this->getMailSubject('order_cancel'$Order))
  312.                 ->setFrom($this->getFromAddress())
  313.                 ->setTo([$Customer->getEmail()])
  314.                 ->setBcc($this->getBccAddress())
  315.                 ->setBody($body);
  316.             $this->mailService->sendMail($message);
  317.             
  318.             // 送信履歴を保存
  319.             $this->saveMailHistory($Order'order_cancel'$body);
  320.             
  321.             return true;
  322.         } catch (\Exception $e) {
  323.             log_error('NZMailSystem42: メール送信エラー', [$e->getMessage()]);
  324.             return false;
  325.         }
  326.     }
  327.     /**
  328.      * 管理画面の注文編集画面にボタンを追加
  329.      */
  330.     public function onAdminOrderEditTwig(EventArgs $event)
  331.     {
  332.         $twig '@NZMailSystem42/admin/order_extension.twig';
  333.         $event->addSnippet($twig);
  334.     }
  335.     /**
  336.      * メールテンプレートのレンダリング
  337.      */
  338.     private function renderMailTemplate($type$params)
  339.     {
  340.         $template '@NZMailSystem42/mail/' $type '.twig';
  341.         
  342.         // テンプレートが存在しない場合はデフォルトテキストを生成
  343.         try {
  344.             return $this->twig->render($template$params);
  345.         } catch (\Exception $e) {
  346.             return $this->createDefaultMailBody($type$params);
  347.         }
  348.     }
  349.     /**
  350.      * デフォルトのメール本文生成
  351.      */
  352.     private function createDefaultMailBody($type$params)
  353.     {
  354.         $Order $params['Order'];
  355.         $Customer $params['Customer'];
  356.         $BaseInfo $params['BaseInfo'];
  357.         
  358.         $body "※このメールは自動配信メールです。\n\n";
  359.         $body .= "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
  360.         
  361.         switch ($type) {
  362.             case 'payment_complete':
  363.                 $body .= " ご注文ありがとうございます\n";
  364.                 break;
  365.             case 'payment_confirm':
  366.                 $body .= " ご入金確認のお知らせ\n";
  367.                 break;
  368.             case 'payment_received':
  369.                 $body .= " ご入金完了のお知らせ\n";
  370.                 break;
  371.             case 'order_cancel':
  372.                 $body .= " ご注文キャンセルのお知らせ\n";
  373.                 break;
  374.         }
  375.         
  376.         $body .= "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
  377.         
  378.         $body .= $Customer->getName01() . " " $Customer->getName02() . " 様\n\n";
  379.         $body .= "この度は" $BaseInfo->getShopName() . "をご利用いただき、誠にありがとうございます。\n\n";
  380.         
  381.         switch ($type) {
  382.             case 'payment_complete':
  383.                 $body .= "ご注文および決済が完了いたしました。\n";
  384.                 $body .= "商品の発送準備を進めさせていただきます。\n\n";
  385.                 break;
  386.             case 'payment_confirm':
  387.                 $body .= "お客様のご注文の決済処理を確認中です。\n";
  388.                 $body .= "入金確認が完了次第、商品の発送準備に入らせていただきます。\n\n";
  389.                 break;
  390.             case 'payment_received':
  391.                 $body .= "お客様のご入金を確認いたしました。\n";
  392.                 $body .= "商品の発送準備を進めさせていただきます。\n\n";
  393.                 break;
  394.             case 'order_cancel':
  395.                 $body .= "お客様のご注文をキャンセルいたしました。\n";
  396.                 $body .= "またのご利用を心よりお待ちしております。\n\n";
  397.                 
  398.                 // 返金に関する注意事項を追加
  399.                 $paymentMethod $Order->getPayment()->getMethod();
  400.                 if (preg_match('/(クレジット|credit|card)/i'$paymentMethod)) {
  401.                     $body .= "【クレジットカード決済の場合】\n";
  402.                     $body .= "決済のキャンセル処理を行っております。\n";
  403.                     $body .= "カード会社によって返金のタイミングが異なりますので、\n";
  404.                     $body .= "詳細はご利用のカード会社にお問い合わせください。\n\n";
  405.                 } elseif (preg_match('/(銀行振込|振込|bank)/i'$paymentMethod)) {
  406.                     $body .= "【銀行振込の返金について】\n";
  407.                     $body .= "すでにお振込みいただいている場合は、返金手続きをさせていただきます。\n";
  408.                     $body .= "返金先口座情報をお知らせください。\n\n";
  409.                     $body .= "<重要>返金に関するご案内\n";
  410.                     $body .= "・お客様都合によるキャンセルの場合、返金額は銀行所定の振込手数料を\n";
  411.                     $body .= " 差し引かせていただいた金額となります。\n";
  412.                     $body .= "・お支払い金額と返金金額に差異がある場合は、上記の処理が行われて\n";
  413.                     $body .= " いることをご了承ください。\n";
  414.                     $body .= "・振込手数料は各金融機関により異なりますが、通常220円~880円程度\n";
  415.                     $body .= " となります。\n\n";
  416.                 }
  417.                 break;
  418.         }
  419.         
  420.         $body .= "【ご注文情報】\n";
  421.         $body .= "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
  422.         $body .= "ご注文番号:" $Order->getOrderNo() . "\n";
  423.         $body .= "ご注文日時:" $Order->getOrderDate()->format('Y年m月d日 H:i') . "\n";
  424.         $body .= "お支払い金額:" number_format($Order->getPaymentTotal()) . "円\n";
  425.         $body .= "お支払い方法:" $Order->getPayment()->getMethod() . "\n\n";
  426.         
  427.         $body .= "【ご注文商品】\n";
  428.         foreach ($Order->getOrderItems() as $OrderItem) {
  429.             if ($OrderItem->isProduct()) {
  430.                 $body .= "・" $OrderItem->getProductName() . " × " $OrderItem->getQuantity() . "\n";
  431.                 $body .= "  " number_format($OrderItem->getPrice()) . "円\n";
  432.             }
  433.         }
  434.         
  435.         $body .= "\n";
  436.         $body .= "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
  437.         $body .= $BaseInfo->getShopName() . "\n";
  438.         $body .= "URL: https://noiezam.com\n";
  439.         $body .= "Email: " $BaseInfo->getEmail01() . "\n";
  440.         
  441.         return $body;
  442.     }
  443.     /**
  444.      * メール件名の取得
  445.      */
  446.     private function getMailSubject($typeOrder $Order)
  447.     {
  448.         $BaseInfo $this->baseInfoRepository->get();
  449.         $shopName $BaseInfo->getShopName();
  450.         
  451.         switch ($type) {
  452.             case 'payment_complete':
  453.                 return '[' $shopName '] ご注文ありがとうございます';
  454.             case 'payment_confirm':
  455.                 return '[' $shopName '] ご入金確認のお知らせ';
  456.             case 'payment_received':
  457.                 return '[' $shopName '] ご入金を確認いたしました';
  458.             case 'order_cancel':
  459.                 return '[' $shopName '] ご注文キャンセルのお知らせ';
  460.             default:
  461.                 return '[' $shopName '] ご注文について';
  462.         }
  463.     }
  464.     /**
  465.      * 送信元アドレスの取得
  466.      */
  467.     private function getFromAddress()
  468.     {
  469.         $BaseInfo $this->baseInfoRepository->get();
  470.         return [$BaseInfo->getEmail01() => $BaseInfo->getShopName()];
  471.     }
  472.     /**
  473.      * BCCアドレスの取得
  474.      */
  475.     private function getBccAddress()
  476.     {
  477.         $BaseInfo $this->baseInfoRepository->get();
  478.         return $BaseInfo->getEmail01();
  479.     }
  480.     /**
  481.      * メール送信履歴の保存
  482.      */
  483.     private function saveMailHistory(Order $Order$mailType$body)
  484.     {
  485.         $MailHistory = new MailHistory();
  486.         $MailHistory->setOrder($Order);
  487.         $MailHistory->setSendDate(new \DateTime());
  488.         $MailHistory->setSubject($this->getMailSubject($mailType$Order));
  489.         $MailHistory->setMailBody($body);
  490.         $this->entityManager->persist($MailHistory);
  491.         $this->entityManager->flush();
  492.     }
  493.     /**
  494.      * 同じタイプのメールがすでに送信済みかチェック
  495.      */
  496.     private function isAlreadySent(Order $Order$mailType)
  497.     {
  498.         $subject $this->getMailSubject($mailType$Order);
  499.         
  500.         $qb $this->entityManager->createQueryBuilder();
  501.         $qb->select('COUNT(mh.id)')
  502.             ->from(MailHistory::class, 'mh')
  503.             ->where('mh.Order = :order')
  504.             ->andWhere('mh.subject = :subject')
  505.             ->setParameter('order'$Order)
  506.             ->setParameter('subject'$subject);
  507.         
  508.         $count $qb->getQuery()->getSingleScalarResult();
  509.         
  510.         return $count 0;
  511.     }
  512.     /**
  513.      * プラグイン設定の取得
  514.      */
  515.     private function getPluginConfig()
  516.     {
  517.         $qb $this->entityManager->createQueryBuilder();
  518.         $qb->select('c')
  519.             ->from('Plugin\NZMailSystem42\Entity\Config''c')
  520.             ->where('c.id = :id')
  521.             ->setParameter('id'1);
  522.         
  523.         try {
  524.             return $qb->getQuery()->getSingleResult();
  525.         } catch (\Exception $e) {
  526.             // デフォルト設定を返す
  527.             $Config = new \Plugin\NZMailSystem42\Entity\Config();
  528.             $Config->setAutoSendEnabled(true);
  529.             return $Config;
  530.         }
  531.     }
  532. }