<?php
/*
* This file is part of EC-CUBE
*
* Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
*
* http://www.ec-cube.co.jp/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
*
* 2023/07/13
* カートに追加→注文手続き画面の間に留意点チェック画面、画像アップロード画面を追加
* cartとshoppingの間を想定
* 2024/02/05 k.saito
* ログイン画面とイメージ画像アップロード画面を逆(アップロード画面を先に表示する)
* 2024/02/13 k.saito
* 留意点、カートページを削除
* スペルの揺らぎを整理
* sendErrorNotifi ⇒ sendErrorNotifiService
* 2024/04/16 k.saito
* すでにアップロード画像があれば、再度アップロード画面に遷移する際に、fileListとしてデータ連携する(imageUpload関数内)
* 2024/04/24 k.saito
* 時間切れ、または予約不可のアラートメッセージを追加
* 2024/05/02 k.saito
* アラートメッセージに\nを含んでいた部分を削除
* 2024/05/06 k.saito
* 再アップロード対応(一度アップロード済なら、新たなアップロードがあれば更新、新たなアップロードがなくとも次の画面に遷移する)
* 2024/05/07 k.saito
* DBに項目 position を追加し、画像の表示順を管理・制御する
* 2024/06/20 k.saito
* 過去の、画像一時フォルダは削除する
*
*/
namespace Customize\Controller;
use Eccube\Controller\ShoppingController;
use Eccube\Entity\CustomerAddress;
use Eccube\Entity\Order;
use Eccube\Entity\Shipping;
use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Eccube\Exception\ShoppingException;
use Eccube\Form\Type\Front\CustomerLoginType;
use Eccube\Form\Type\Front\ShoppingShippingType;
use Eccube\Form\Type\Shopping\CustomerAddressType;
use Eccube\Form\Type\Shopping\OrderType;
use Eccube\Repository\OrderRepository;
use Eccube\Repository\TradeLawRepository;
//use Eccube\Service\CartService;
use Eccube\Service\MailService;
//use Eccube\Service\OrderHelper;
use Eccube\Service\Payment\PaymentDispatcher;
use Eccube\Service\Payment\PaymentMethodInterface;
use Eccube\Service\PurchaseFlow\PurchaseContext;
use Eccube\Service\PurchaseFlow\PurchaseFlow;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
//追加
//各フォーム用
use Customize\Form\Type\Shopping\AttentionCheckType; //留意点チェックフォーム
use Customize\Form\Type\Shopping\imageUploadType; //画像アップロードフォーム
use Customize\Entity\Image;
use Eccube\Entity\OrderItem; //DB:dtb_order_item
use Customize\Service\categorizationCountFormService;
use Doctrine\ORM\EntityManagerInterface;
use Customize\Service\imageUploadService; //画像に名前を付けて保存しファイル名を返す
use Customize\Service\imageUploadInfomationService; //画像アップロード用の情報を返す
use Customize\Form\Type\Shopping\CustomOrderType; //お届け日、時間帯設定のため
use Customize\Service\getProductOptionService;
use Customize\Service\CustomCartService as CartService;
use Customize\Service\CustomOrderHelper as OrderHelper;
//kintone連携用
use Customize\Service\sendErrorNotifiService; //エラー通知用
use Customize\Service\kintoneAddToClientAppService; //注文完了時に顧客アプリにレコードを追加する
use Customize\Service\kintoneAddToCaseAppService; //注文完了時に案件アプリにレコードを追加する
use Customize\Service\kintoneUpdToScheduleAppService; //注文完了時に予定アプリのレコードを更新する
use DateTime;
class CustomShoppingController extends ShoppingController
{
/**
* @var CartService
*/
protected $cartService;
/**
* @var MailService
*/
protected $mailService;
/**
* @var OrderHelper
*/
protected $orderHelper;
/**
* @var OrderRepository
*/
protected $orderRepository;
/**
* @var ContainerInterface
*/
protected $serviceContainer;
/**
* @var TradeLawRepository
*/
protected TradeLawRepository $tradeLawRepository;
//追加
//画像アップロードフォーム数判定用
/**
* @var categorizationCountFormService
*/
private $categorizationCountFormService;
/**
* @var EntityManagerInterface
*/
protected $entityManager;
/**
* @var imageUploadService
*/
private $imageUploadService;
/**
* @var imageUploadInfomationService
*/
private $imageUploadInfomationService;
/**
* @var getProductOptionService
*/
protected $getProductOptionService;
/**
* @var sendErrorNotifiService
*/
private $sendErrorNotifiService;
/**
* @var kintoneAddToClientAppService
* 注文完了時にkintone顧客アプリにレコードを登録する
*/
private $kintoneAddToClientAppService;
/**
* @var kintoneAddToCaseAppService
* 注文完了時にkintone案件アプリにレコードを登録する
*/
private $kintoneAddToCaseAppService;
/**
* @var kintoneUpdToScheduleAppService
* 注文完了時にkintone予定アプリのレコードを更新する
*/
private $kintoneUpdToScheduleAppService;
//追加 ここまで
public function __construct(
CartService $cartService,
MailService $mailService,
OrderRepository $orderRepository,
OrderHelper $orderHelper,
ContainerInterface $serviceContainer,
TradeLawRepository $tradeLawRepository,
//追加
categorizationCountFormService $categorizationCountFormService,
EntityManagerInterface $entityManager,
imageUploadService $imageUploadService,
imageUploadInfomationService $imageUploadInfomationService,
getProductOptionService $getProductOptionService,
sendErrorNotifiService $sendErrorNotifiService,
kintoneAddToClientAppService $kintoneAddToClientAppService,
kintoneAddToCaseAppService $kintoneAddToCaseAppService,
kintoneUpdToScheduleAppService $kintoneUpdToScheduleAppService
) {
$this->cartService = $cartService;
$this->mailService = $mailService;
$this->orderRepository = $orderRepository;
$this->orderHelper = $orderHelper;
$this->serviceContainer = $serviceContainer;
$this->tradeLawRepository = $tradeLawRepository;
//追加
$this->categorizationCountFormService = $categorizationCountFormService;
$this->entityManager = $entityManager; // EntityManager -> entityManager
$this->imageUploadService = $imageUploadService;
$this->imageUploadInfomationService = $imageUploadInfomationService;
$this->getProductOptionService = $getProductOptionService;
$this->sendErrorNotifiService = $sendErrorNotifiService;
$this->kintoneAddToClientAppService = $kintoneAddToClientAppService; //kintone顧客アプリにレコードを追加する
$this->kintoneAddToCaseAppService = $kintoneAddToCaseAppService; //kintone案件アプリにレコードを追加する
$this->kintoneUpdToScheduleAppService = $kintoneUpdToScheduleAppService; //kintone予定アプリのレコードを更新する
}
/**
* 注文手続き画面を表示する
*
* 未ログインまたはRememberMeログインの場合はログイン画面に遷移させる.
* ただし、非会員でお客様情報を入力済の場合は遷移させない.
*
* カート情報から受注データを生成し, `pre_order_id`でカートと受注の紐付けを行う.
* 既に受注が生成されている場合(pre_order_idで取得できる場合)は, 受注の生成を行わずに画面を表示する.
*
* purchaseFlowの集計処理実行後, warningがある場合はカートど同期をとるため, カートのPurchaseFlowを実行する.
*
* @Route("/shopping", name="shopping", methods={"GET"})
* @Template("Shopping/index.twig")
*/
public function index(PurchaseFlow $cartPurchaseFlow)
{
// カートチェック.
log_debug('カスタムカートへ移動');
$Cart = $this->cartService->getCart();
if (!($Cart && $this->orderHelper->verifyCart($Cart))) {
// フラッシュメッセージを設定する
$this->addFlash('worning', 'お手続き時間が超過したか、ご指定の工事日が予約不可となった可能性があります。申し訳ありませんが、再度お手続きをお願いいたします。');
log_info('[注文手続] カートが購入フローへ遷移できない状態のため, カート画面に遷移します.');
return $this->redirectToRoute('cart');
}
//ob_start();
//画像をアップロードしていない場合は留意点チェック画面に移動 -> 先の画面に進まない
$cartID = $Cart->getID();
$imageDbData = $this->entityManager->getRepository(Image::class)->findBy(['cart_id' => $cartID]);
//dump($imageDbData);
if (empty($imageDbData)) {
// log_info('DBに画像が存在しないので留意点チェック画面に移動_index');
// return $this->redirectToRoute('attention_check');
log_info('DBに画像が存在しないのでイメージアップロード画面に戻る');
return $this->redirectToRoute('image_upload');
}
log_info('画像アップロードあり、商品追加なし。通常移動');
//画像をアップロードしていない場合は留意点チェック画面に移動 end -> 先の画面に進まない
// ログイン状態のチェック.
if ($this->orderHelper->isLoginRequired()) {
log_info('[注文手続] 未ログインもしくはRememberMeログインのため, ログイン画面に遷移します.');
return $this->redirectToRoute('shopping_login');
}
// 受注の初期化.
log_info('[注文手続] 受注の初期化処理を開始します.');
$Customer = $this->getUser() ? $this->getUser() : $this->orderHelper->getNonMember();
$Order = $this->orderHelper->initializeOrder($Cart, $Customer);
// 集計処理.
log_info('[注文手続] 集計処理を開始します.', [$Order->getId()]);
$flowResult = $this->executePurchaseFlow($Order, false);
//dump($flowResult);
$this->entityManager->flush();
//追加 注文情報をImageDBにセットする
$orderID = $Order->getId();
foreach ($imageDbData as $targetImage) {
$targetImageId = $targetImage->getID();
$targetImageIdEntity = $this->entityManager->getRepository(Image::class)->find($targetImageId); //entityManager
//dump($targetImageIdEntity);
$targetImage->setOrder($Order);
}
$this->entityManager->persist($targetImage); // Docterineにプロジェクトの保存を伝える
$this->entityManager->flush(); // クエリ実行(インサート)
//追加 終わり
if ($flowResult->hasError()) {
log_info('[注文手続] Errorが発生したため購入エラー画面へ遷移します.', [$flowResult->getErrors()]);
return $this->redirectToRoute('shopping_error');
}
if ($flowResult->hasWarning()) {
log_info('[注文手続] Warningが発生しました.', [$flowResult->getWarning()]);
// 受注明細と同期をとるため, CartPurchaseFlowを実行する
$cartPurchaseFlow->validate($Cart, new PurchaseContext($Cart, $this->getUser()));
// 注文フローで取得されるカートの入れ替わりを防止する
// @see https://github.com/EC-CUBE/ec-cube/issues/4293
$this->cartService->setPrimary($Cart->getCartKey());
}
// マイページで会員情報が更新されていれば, Orderの注文者情報も更新する.
// getIdメソッドは実装されていない。オブジェクトで判定する。
// if ($Customer->getId()) {
if ($Customer != null) {
$this->orderHelper->updateCustomerInfo($Order, $Customer);
$this->entityManager->flush();
}
$activeTradeLaws = $this->tradeLawRepository->findBy(['displayOrderScreen' => true], ['sortNo' => 'ASC']);
//お届け日時、お届け時間帯を商品オプションの設置希望日、時間帯に設定する
//$form = $this->createForm(OrderType::class, $Order);
//追加 カスタマイズしたShippingTypeを使用するため
$form = $this->createForm(CustomOrderType::class, $Order);
//対象日・時間帯を非表示ブロックでテンプレートに表示させJSに設定してもらう
//追加 商品オプションIDから設置希望日、設置希望時間帯を取得する
//商品オプションのデータを取得
//dump($this->test());
//追加 商品オプションIDから設置希望日を取得する
//dump($Order);
//dump($orderID);
//dtb_order_itemから現在追加している商品を取得
$targetOrderItems = [];
$OrderItems = $this->entityManager->getRepository(OrderItem::class)->findBy(['Order' => $orderID]); //entityManager
foreach ($OrderItems as $OrderItem) {
if (!($OrderItem['product_name'] === '手数料' || $OrderItem['product_name'] === '送料')) {
$targetOrderItems[] = $OrderItem;
}
}
//dump($targetOrderItems);
$scheduleDateID = $this->serviceContainer->getParameter('option_schedule_date'); //設置希望日のDbIDを取得
$scheduleTimeID = $this->serviceContainer->getParameter('option_schedule_time'); //設置希望時間帯のDbIDを取得
//$scheduleData = $this->getScheduleData($scheduleOptionID, $targetOrderItems);
$schedule = [];
// $scheduleID = $this->container->getParameter($scheduleOption); //商品オプションのDbIDを取得
$productOption = '';
//$OrderItems = $Shipping->getProductOrderItems();
//$scheduleは1注文1商品が前提
foreach ($targetOrderItems as $targetOrderItem) {
$productOption = $targetOrderItem->getOptionSerial(); //商品オプションを取得
$scheduleDate = $this->getProductOptionService->getTextOptionData($productOption, $scheduleDateID);
$schedule['date'] = str_replace('-', '/', $scheduleDate);
$schedule['time'] = $this->getProductOptionService->getTextOptionData($productOption, $scheduleTimeID);
}
//dump($schedule);
//追加 ここまで
return [
'form' => $form->createView(),
'Order' => $Order,
'activeTradeLaws' => $activeTradeLaws,
'schedule' => $schedule
];
}
/**
* 留意点チェック画面
*
* @Route("/shopping/check", name="attention_check", methods={"POST","GET"})
* @Template("/Shopping/attention_check.twig")
*
*/
public function check(Request $request)
{
//全てのチェックが完了すると次の画面へ遷移する
log_info('留意点チェック画面');
$Cart = $this->cartService->getCart(); //現在のカート情報を取得
//セッションが切れた場合はカート画面へリダイレクトさせる
if (!($Cart && $this->orderHelper->verifyCart($Cart))) {
log_info('[注文手続] カートが購入フローへ遷移できない状態のため, カート画面に遷移します.');
return $this->redirectToRoute('cart');
}
$categoryId = $this->categorizationCountFormService->returnFormNumber(); //カテゴリのDBIDを取得
//dump($categoryId);
$formArray = array();
foreach ($categoryId as $categoryIdData) {
$fieldData = $this->imageUploadInfomationService->returnFormInfomation($categoryIdData);
//dump($fieldData);
if (is_array($fieldData)) {
$formArray[] = $fieldData;
}
}
foreach ($formArray as $formArrayData) {
$check_form_data = $formArrayData['check_data'];
}
$form = $this->createForm(AttentionCheckType::class, null, ['check_data' => $check_form_data]); //
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/*
$check1 = $form->get('1')->getData();
*/
log_info('全てチェック済み、画像アップロード画面に遷移する');
return $this->redirectToRoute('image_upload');
} else {
log_info('留意点チェックなし。警告を表示する');
}
return [
//'request' => $request,
'form' => $form->createView(),
'formArray' => $formArray
];
}
/**
* 画像アップロード画面
*
* @Route("/shopping/image_upload", name="image_upload", methods={"GET","POST"})
* @Template("/Shopping/image_upload.twig")
*/
public function imageUpload(Request $request)
{
//全てのチェックが完了すると次の画面へ遷移する
log_info('画像アップロード画面 imageUpload start');
//二重投稿になるためcartidがある場合は以前のデータを削除する
$Cart = $this->cartService->getCart(); //現在のカート情報を取得
//セッションが切れた場合はカート画面へリダイレクトさせる
if (!($Cart && $this->orderHelper->verifyCart($Cart))) {
// フラッシュメッセージを設定する
$this->addFlash('worning', 'お手続き時間が超過したか、ご指定の工事日が予約不可となった可能性があります。申し訳ありませんが、再度お手続きをお願いいたします。');
log_info('[注文手続] カートが購入フローへ遷移できない状態のため, カート画面に遷移します.');
return $this->redirectToRoute('cart');
}
$cartID = $Cart->getID();
//条件:cartID一致、upload_order 降順、position 昇順
$imageDbData = $this->entityManager->getRepository(Image::class)->findBy(['cart_id' => $cartID], ['upload_order' => 'desc', 'position' => 'asc']); //entityManager
//dump($imageDbData);
//アップロード画像があれば、一時フォルダ作成
$imagePath = $this->imageUploadService->getPriveteImagePath(); //from path;
log_info('imagePath: '.$imagePath);
$tempPathCart = '';
$tempPathCartForJs = '';
$fileList = [];
if (count($imageDbData) > 0) {
$tempPath = $this->imageUploadService->getTemporaryImagePath();
//日付が昨日以前のフォルダがあれば削除する
// 昨日の日付を取得
$yesterday = (new DateTime('yesterday'))->setTime(0, 0);
// 指定されたフォルダの下のサブフォルダを取得
$directories = array_filter(glob($tempPath . '/*'), 'is_dir');
foreach ($directories as $dir) {
log_info('dir: '.$dir);
// フォルダの作成日時を取得
$creationTime = filemtime($dir);
log_info('creationTime: '.$creationTime);
log_info('dir_timestamp: '.$yesterday->getTimestamp());
// 昨日までのフォルダのみ削除
if ($creationTime < $yesterday->getTimestamp()) {
$this->deleteDirectory($dir);
}
}
$tempPathCart = $tempPath.$cartID.'/';
$tempPathCartForJs = '/temp/'.$cartID.'/'; //homeのrootからのパス
log_info('tempPathCart: '.$tempPathCart);
if (!is_dir($tempPathCart)) { //フォルダがなかったら、作成
mkdir($tempPathCart, 0755); //カートIDのフォルダを生成 //to path
} else {
//内部のファイルを削除
$files = glob($tempPathCart.'*.*');
foreach ($files as $file) {
unlink($file);
log_info('delete file: '.$file);
}
}
$firstFlg = true;
$save_uploadOrder = '1';
foreach ($imageDbData as $imageData) {
if ($firstFlg) {
$save_uploadOrder = $imageData->getUploadOrder();
$firstFlg = false;
}
$uploadOrder = $imageData->getUploadOrder();
if ($uploadOrder != $save_uploadOrder) {
log_info('uploadOrderが変わった');
break; //uploadOrderが変わったら処理終了
}
log_info('ファイル名:');
log_info($imageData->getName());
log_info('UploadOrder:');
log_info($imageData->getUploadOrder());
$fileName = $imageData->getName();
//ファイルをコピー
copy($imagePath.$fileName, $tempPathCart.$fileName);
$fileList[] = $tempPathCartForJs.$fileName;
}
}
$uploadOrder = 1; //何回目の投稿か? 1回目の投稿
if (!empty($imageDbData)) {
log_info('カート情報が存在するので、判別の為に何回目の投稿かアップロード順を登録');
$uploadOrder = $imageDbData[0]->getUploadOrder();
$uploadOrder++;
}
$categoryId = $this->categorizationCountFormService->returnFormNumber();
//dump($categoryId);
$formArray = array();
foreach ($categoryId as $categoryIdData) {
$fieldData = $this->imageUploadInfomationService->returnFormInfomation($categoryIdData);
//dump($fieldData);
if (is_array($fieldData)) {
$formArray[] = $fieldData;
}
}
//dump($formArray);
//画像アップロードフォームの数 複数商品をカートに入れた場合はその分フォーム数を増やす(現在は1カート1商品のみなので増える事はない))
$upload_field_max = 0;
foreach ($formArray as $formArrayData) {
$upload_field_max += $formArrayData['upload_field_max'];
}
//dump($numberOfForms);
$Image = new Image;
$form = $this->createForm(imageUploadType::class, $Image, ['upload_field_max' => $upload_field_max]);
//form追加後
$form->handleRequest($request);
if (
$form->isSubmitted() && $form->isValid()
) {
//写真が新規にアップロードされた場合
if ($Image instanceof Image) {
log_info('Image2');
$file = array();
for ($i = 0; $i < $upload_field_max; $i++) {
$file[] = $form['image' . $i]->getData();
}
log_debug('image_dataの配列データ:');
log_debug(print_r($file, true));
if (!empty($file)) {
// カートサービスからカート内の商品情報を取得
$Cart = $this->cartService->getCart();
$cartID = $Cart->getID();
// ファイルアップロード
$count = 0;
foreach ($file as $upload_image) {
$count++;
log_debug($upload_image);
$filename = $this->imageUploadService->upload($upload_image);
//dump($filename);
//DBにファイル名とカートキーを書き込み
//dump($Cart);
$Image = new Image;
$Image->setCartID($cartID);
$Image->setName($filename);
$Image->setUploadOrder($uploadOrder);
$Image->setPosition($count - 1); //表示位置セット
//dump($Image);
$this->entityManager->persist($Image); // Docterineにプロジェクトの保存を伝える
$this->entityManager->flush(); // クエリ実行(インサート)
}
return $this->redirectToRoute('shopping');
}
} else {
log_error('画像がありません');
if (count($imageDbData) > 0) { //再アップロードなら、次画面に遷移
log_error('画像の変更なし');
return $this->redirectToRoute('shopping');
}
}
} else if ($form->isSubmitted()) {
// debug
//写真が再アップロードされた場合
log_info('debug image_upload: not isValid ');
if ($Image instanceof Image) {
$file = array();
for ($i = 0; $i < $upload_field_max; $i++) {
$file[] = $form['image' . $i]->getData();
}
log_debug('image_dataの配列データ:');
log_debug(print_r($file, true));
if (count($imageDbData) > 0) { //再アップロードなら、次画面に遷移
log_info('Image 再アップロード');
// カートサービスからカート内の商品情報を取得
$Cart = $this->cartService->getCart();
$cartID = $Cart->getID();
// ファイルアップロード
$count = 0;
foreach ($file as $upload_image) {
$count++;
if ($upload_image == '') {
//空白の場合は、orderのみ更新
log_info('orderのみ更新');
$Image = $imageDbData[$count - 1];
$Image->setUploadOrder($uploadOrder);
$Image->setPosition($count - 1); //表示位置セット
$this->entityManager->persist($Image); // Docterineにプロジェクトの保存を伝える
$this->entityManager->flush(); // クエリ実行(インサート)
} else {
//画像変更
log_debug($upload_image);
$filename = $this->imageUploadService->upload($upload_image);
//dump($filename);
//DBにファイル名とカートキーを書き込み
//dump($Cart);
$Image = new Image;
$Image->setCartID($cartID);
$Image->setPosition($count - 1); //表示位置セット
$Image->setName($filename);
$Image->setUploadOrder($uploadOrder);
//dump($Image);
$this->entityManager->persist($Image); // Docterineにプロジェクトの保存を伝える
$this->entityManager->flush(); // クエリ実行(インサート)
}
}
return $this->redirectToRoute('shopping');
}
}
} else {
//debug
log_info('debug image_upload: not isValid and not isSubmitted');
}
//form追加後 end
return [
'request' => $request,
'formArray' => $formArray,
'fileList' => $fileList,
'form' => $form->createView(),
];
}
/**
* 注文確認画面を表示する.
*
* ここではPaymentMethod::verifyがコールされます.
* PaymentMethod::verifyではクレジットカードの有効性チェック等, 注文手続きを進められるかどうかのチェック処理を行う事を想定しています.
* PaymentMethod::verifyでエラーが発生した場合は, 注文手続き画面へリダイレクトします.
*
* @Route("/shopping/confirm", name="shopping_confirm", methods={"POST"})
* @Template("Shopping/confirm.twig")
*/
public function confirm(Request $request)
{
log_info('注文確認画面 confirm(url: shopping_confirm) start');
// ログイン状態のチェック.
if ($this->orderHelper->isLoginRequired()) {
log_info('[注文確認] 未ログインもしくはRememberMeログインのため, ログイン画面に遷移します.');
return $this->redirectToRoute('shopping_login');
}
// 受注の存在チェック
$preOrderId = $this->cartService->getPreOrderId();
$Order = $this->orderHelper->getPurchaseProcessingOrder($preOrderId);
if (!$Order) {
log_info('[注文確認] 購入処理中の受注が存在しません.', [$preOrderId]);
return $this->redirectToRoute('shopping_error');
}
//画像をアップロードしていない場合は留意点チェック画面に移動⇒画像アップロード画面の移動する
//画像がある場合は画像のURLを配列に格納する
$orderId = $Order->getId();
$imageDbData = $this->entityManager->getRepository(Image::class)->findBy(['Order' => $orderId]); //entityManager
//dump($imageDbData);
if (empty($imageDbData)) {
log_info('DBに画像が存在しないので画像アップロード画面の移動');
// return $this->redirectToRoute('attention_check');
return $this->redirectToRoute('image_upload');
}
$imageNameArray = [];
foreach ($imageDbData as $imageData) {
$imageNameArray[] = $imageData->getName();
}
dump($imageNameArray);
//画像をアップロードしていない場合は留意点チェック画面に移動 end
$activeTradeLaws = $this->tradeLawRepository->findBy(['displayOrderScreen' => true], ['sortNo' => 'ASC']);
$form = $this->createForm(OrderType::class, $Order);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
log_info('[注文確認] 集計処理を開始します.', [$Order->getId()]);
$response = $this->executePurchaseFlow($Order);
$this->entityManager->flush();
if ($response) {
return $response;
}
log_info('[注文確認] PaymentMethod::verifyを実行します.', [$Order->getPayment()->getMethodClass()]);
$paymentMethod = $this->createPaymentMethod($Order, $form);
$PaymentResult = $paymentMethod->verify();
if ($PaymentResult) {
if (!$PaymentResult->isSuccess()) {
$this->entityManager->rollback();
foreach ($PaymentResult->getErrors() as $error) {
$this->addError($error);
}
log_info('[注文確認] PaymentMethod::verifyのエラーのため, 注文手続き画面へ遷移します.', [$PaymentResult->getErrors()]);
return $this->redirectToRoute('shopping');
}
$response = $PaymentResult->getResponse();
if ($response instanceof Response && ($response->isRedirection() || $response->isSuccessful())) {
$this->entityManager->flush();
log_info('[注文確認] PaymentMethod::verifyが指定したレスポンスを表示します.');
return $response;
}
}
dump('confirm start');
dump($Order);
$this->entityManager->flush();
dump('confirm 1');
log_info('[注文確認] 注文確認画面を表示します.');
return [
'form' => $form->createView(),
'Order' => $Order,
'activeTradeLaws' => $activeTradeLaws,
'imageNameArray' => $imageNameArray
];
}
dump($form->getErrors());
dump($form->getErrors(true));
log_info('[注文確認] フォームエラーのため, 注文手続画面を表示します.', [$Order->getId()]);
$template = new Template([
'owner' => [$this, 'confirm'],
'template' => 'Shopping/index.twig',
]);
$request->attributes->set('_template', $template);
return [
'form' => $form->createView(),
'Order' => $Order,
'activeTradeLaws' => $activeTradeLaws,
];
}
/**
* 注文処理を行う.
*
* 決済プラグインによる決済処理および注文の確定処理を行います.
*
* @Route("/shopping/checkout", name="shopping_checkout", methods={"POST"})
* @Template("Shopping/confirm.twig")
*/
public function checkout(Request $request)
{
// ログイン状態のチェック.
if ($this->orderHelper->isLoginRequired()) {
log_info('[注文処理] 未ログインもしくはRememberMeログインのため, ログイン画面に遷移します.');
return $this->redirectToRoute('shopping_login');
}
// 受注の存在チェック
$preOrderId = $this->cartService->getPreOrderId();
$Order = $this->orderHelper->getPurchaseProcessingOrder($preOrderId);
if (!$Order) {
log_info('[注文処理] 購入処理中の受注が存在しません.', [$preOrderId]);
return $this->redirectToRoute('shopping_error');
}
//画像をアップロードしていない場合は留意点チェック画面に移動⇒画像アップロード画面に移動する
$orderId = $Order->getId();
$imageDbData = $this->entityManager->getRepository(Image::class)->findBy(['Order' => $orderId]); //entityManager
//dump($imageDbData);
if (empty($imageDbData)) {
// log_info('DBに画像が存在しないので留意点チェック画面に移動_checkout');
log_info('DBに画像が存在しないので画像アップロード画面に移動');
// return $this->redirectToRoute('attention_check');
return $this->redirectToRoute('image_upload');
}
//画像をアップロードしていない場合は留意点チェック画面に移動 end
// フォームの生成.
$form = $this->createForm(OrderType::class, $Order, [
// 確認画面から注文処理へ遷移する場合は, Orderエンティティで値を引き回すためフォーム項目の定義をスキップする.
'skip_add_form' => true,
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
log_info('[注文処理] 注文処理を開始します.', [$Order->getId()]);
try {
/*
* 集計処理
*/
log_info('[注文処理] 集計処理を開始します.', [$Order->getId()]);
$response = $this->executePurchaseFlow($Order);
$this->entityManager->flush();
if ($response) {
return $response;
}
log_info('[注文処理] PaymentMethodを取得します.', [$Order->getPayment()->getMethodClass()]);
$paymentMethod = $this->createPaymentMethod($Order, $form);
/*
* 決済実行(前処理)
*/
log_info('[注文処理] PaymentMethod::applyを実行します.');
if ($response = $this->executeApply($paymentMethod)) {
return $response;
}
/*
* 決済実行
*
* PaymentMethod::checkoutでは決済処理が行われ, 正常に処理出来た場合はPurchaseFlow::commitがコールされます.
*/
log_info('[注文処理] PaymentMethod::checkoutを実行します.');
if ($response = $this->executeCheckout($paymentMethod)) {
return $response;
}
$this->entityManager->flush();
//修正 追加
/*
* 注文完了時に顧客アプリ、案件アプリ、予定アプリにkintoneにレコードを追加する
*/
$CustomerSearchKey = ''; //顧客検索キー
log_info('[注文処理] kintone顧客アプリに注文情報を追加します。', [$Order->getId()]);
dump('[注文処理] kintone顧客アプリに注文情報を追加します。', [$Order->getId()]);
dump($Order);
$CustomerSearchKey = $this->kintoneAddToClientAppService->insClientRecordFromShopping($Order);
dump($CustomerSearchKey);
if ($CustomerSearchKey === false) {
$errormsg = __LINE__ . '注文完了時:kintone顧客アプリのレコード追加でエラーが発生。';
log_error($errormsg);
$this->sendErrorNotifiService->errorNotifi($errormsg);
throw new ShoppingException('予期しないエラーが発生しました.');
}
//案件アプリにレコード追加。追加が完了した場合はコメントを投稿する
log_info('[注文処理] kintone案件アプリに注文情報を追加します。', [$Order->getId()]);
//追加に成功した際は追加した案件アプリのレコード番号、予定アプリで使用する情報が入る
$scheduleAppInfo = $this->kintoneAddToCaseAppService->insCaseRecordFromShopping($Order, $CustomerSearchKey);
if ($scheduleAppInfo === false) {
$errormsg = __LINE__ . '注文完了時:kintone案件アプリのレコード追加でエラーが発生。';
log_error($errormsg);
$this->sendErrorNotifiService->errorNotifi($errormsg);
throw new ShoppingException('予期しないエラーが発生しました.');
}
//予定アプリのレコード更新
log_info('[注文処理] kintone予定アプリに注文情報を追加します。', [$Order->getId()]);
$scheduleAppResult = $this->kintoneUpdToScheduleAppService->updScheduleRecordFromShopping($scheduleAppInfo);
if ($scheduleAppResult === false) {
$errormsg = __LINE__ . '注文完了時:kintone予定アプリのレコード更新でエラーが発生。';
log_error($errormsg);
$this->sendErrorNotifiService->errorNotifi($errormsg);
throw new ShoppingException('予期しないエラーが発生しました.');
}
//修正 終わり
log_info('[注文処理] 注文処理が完了しました.', [$Order->getId()]);
} catch (ShoppingException $e) {
log_error('[注文処理] 購入エラーが発生しました.', [$e->getMessage()]);
$this->entityManager->rollback();
$this->addError($e->getMessage());
return $this->redirectToRoute('shopping_error');
} catch (\Exception $e) {
log_error('[注文処理] 予期しないエラーが発生しました.', [$e->getMessage()]);
$this->entityManager->rollback(); //FIXME ユニットテストで There is no active transaction エラーになってしまう
$this->addError('front.shopping.system_error');
return $this->redirectToRoute('shopping_error');
}
// カート削除
log_info('[注文処理] カートをクリアします.', [$Order->getId()]);
$this->cartService->clear();
// 受注IDをセッションにセット
$this->session->set(OrderHelper::SESSION_ORDER_ID, $Order->getId());
// メール送信
log_info('[注文処理] 注文メールの送信を行います.', [$Order->getId()]);
$this->mailService->sendOrderMail($Order);
$this->entityManager->flush();
log_info('[注文処理] 注文処理が完了しました. 購入完了画面へ遷移します.', [$Order->getId()]);
return $this->redirectToRoute('shopping_complete');
}
log_info('[注文処理] フォームエラーのため, 購入エラー画面へ遷移します.', [$Order->getId()]);
return $this->redirectToRoute('shopping_error');
}
/**
* 購入完了画面を表示する.
*
* @Route("/shopping/complete", name="shopping_complete", methods={"GET"})
* @Template("Shopping/complete.twig")
*/
public function complete(Request $request)
{
log_info('[注文完了] 注文完了画面を表示します.');
// 受注IDを取得
$orderId = $this->session->get(OrderHelper::SESSION_ORDER_ID);
if (empty($orderId)) {
log_info('[注文完了] 受注IDを取得できないため, トップページへ遷移します.');
return $this->redirectToRoute('homepage');
}
$Order = $this->orderRepository->find($orderId);
$event = new EventArgs(
[
'Order' => $Order,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_SHOPPING_COMPLETE_INITIALIZE);
if ($event->getResponse() !== null) {
return $event->getResponse();
}
log_info('[注文完了] 購入フローのセッションをクリアします. ');
$this->orderHelper->removeSession();
$hasNextCart = !empty($this->cartService->getCarts());
log_info('[注文完了] 注文完了画面を表示しました. ', [$hasNextCart]);
return [
'Order' => $Order,
'hasNextCart' => $hasNextCart,
];
}
/**
* PaymentMethodをコンテナから取得する.
*
* @param Order $Order
* @param FormInterface $form
*
* @return PaymentMethodInterface
*/
private function createPaymentMethod(Order $Order, FormInterface $form)
{
$PaymentMethod = $this->serviceContainer->get($Order->getPayment()->getMethodClass());
$PaymentMethod->setOrder($Order);
$PaymentMethod->setFormType($form);
return $PaymentMethod;
}
/**
* PaymentMethod::applyを実行する.
*
* @param PaymentMethodInterface $paymentMethod
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
protected function executeApply(PaymentMethodInterface $paymentMethod)
{
$dispatcher = $paymentMethod->apply(); // 決済処理中.
// リンク式決済のように他のサイトへ遷移する場合などは, dispatcherに処理を移譲する.
if ($dispatcher instanceof PaymentDispatcher) {
$response = $dispatcher->getResponse();
$this->entityManager->flush();
// dispatcherがresponseを保持している場合はresponseを返す
if ($response instanceof Response && ($response->isRedirection() || $response->isSuccessful())) {
log_info('[注文処理] PaymentMethod::applyが指定したレスポンスを表示します.');
return $response;
}
// forwardすることも可能.
if ($dispatcher->isForward()) {
log_info(
'[注文処理] PaymentMethod::applyによりForwardします.',
[$dispatcher->getRoute(), $dispatcher->getPathParameters(), $dispatcher->getQueryParameters()]
);
return $this->forwardToRoute(
$dispatcher->getRoute(),
$dispatcher->getPathParameters(),
$dispatcher->getQueryParameters()
);
} else {
log_info(
'[注文処理] PaymentMethod::applyによりリダイレクトします.',
[$dispatcher->getRoute(), $dispatcher->getPathParameters(), $dispatcher->getQueryParameters()]
);
return $this->redirectToRoute(
$dispatcher->getRoute(),
array_merge($dispatcher->getPathParameters(), $dispatcher->getQueryParameters())
);
}
}
}
/**
* PaymentMethod::checkoutを実行する.
*
* @param PaymentMethodInterface $paymentMethod
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response|null
*/
protected function executeCheckout(PaymentMethodInterface $paymentMethod)
{
$PaymentResult = $paymentMethod->checkout();
$response = $PaymentResult->getResponse();
// PaymentResultがresponseを保持している場合はresponseを返す
if ($response instanceof Response && ($response->isRedirection() || $response->isSuccessful())) {
$this->entityManager->flush();
log_info('[注文処理] PaymentMethod::checkoutが指定したレスポンスを表示します.');
return $response;
}
// エラー時はロールバックして購入エラーとする.
if (!$PaymentResult->isSuccess()) {
$this->entityManager->rollback();
foreach ($PaymentResult->getErrors() as $error) {
$this->addError($error);
}
log_info('[注文処理] PaymentMethod::checkoutのエラーのため, 購入エラー画面へ遷移します.', [$PaymentResult->getErrors()]);
return $this->redirectToRoute('shopping_error');
}
return null;
}
// ディレクトリを削除する関数
protected function deleteDirectory($dirPath) {
if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
$dirPath .= '/';
}
$files = glob($dirPath . '*', GLOB_MARK);
foreach ($files as $file) {
unlink($file); //内部ファイルを削除
}
rmdir($dirPath); //フォルダ削除
}
}