<?php
namespace Customize\Controller;
use Customize\Entity\TextWarning;
use Customize\Enum\DataStatus;
use Customize\Enum\SeasonCode;
use Customize\Enum\SendDataMethod;
use Customize\Repository\ProductRepository;
use Customize\Service\CustomCartService;
use Customize\Service\CustomPurchaseFlow;
use Eccube\Controller\AbstractController;
use Customize\Repository\PriceRepository;
use Customize\Repository\SeasonRepository;
use Symfony\Component\HttpFoundation\Request;
use Eccube\Entity\Product;
use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Eccube\Form\Type\AddCartType;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Eccube\Service\CartService;
use Eccube\Service\PurchaseFlow\PurchaseFlow;
use Eccube\Service\PurchaseFlow\PurchaseContext;
use Eccube\Entity\Master\ProductStatus;
use Eccube\Repository\BaseInfoRepository;
use Eccube\Repository\CartItemRepository;
use Eccube\Service\OrderHelper;
use Eccube\Util\CacheUtil;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Customize\Repository\OrderOptionRepository;
use Customize\Repository\SendDataMethodCategoryRepository;
use Customize\Repository\StepOptionRepository;
use Customize\Repository\TextWarningRepository;
use Customize\Service\CustomOrderHelper;
use Eccube\Entity\CustomerAddress;
use Eccube\Entity\Master\OrderStatus;
use Eccube\Entity\Shipping;
use Eccube\Repository\OrderItemRepository;
use Eccube\Repository\OrderRepository;
use Eccube\Repository\CartRepository;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Eccube\Form\Type\Shopping\CustomerAddressType;
use Customize\Repository\SimulatorLinkRepository;
use Customize\Repository\WorkingTimeRepository;
class CustomCartController extends AbstractController
{
/**
* @var PurchaseFlow
*/
protected $purchaseFlow;
/**
* @var CustomCartService
*/
protected $cartService;
/**
* @var ProductRepository
*/
protected $productRepository;
protected $customPurchaseFlow;
protected $baseInfo;
protected $cartItemRepo;
protected $orderItemRepo;
protected $orderRepo;
protected $cartRepo;
protected $orderOptionRepository;
protected $sendDataMethodCategoryRepository;
/**
* @var StepOptionRepository
*/
protected $stepOptionRepository;
protected $priceRepository;
protected $seasonRepository;
protected $textWarningRepository;
protected $orderHelper;
private $customOrderHelper;
protected $simulatorLinkRepository;
protected $workingTimeRepository;
public function __construct(
PurchaseFlow $cartPurchaseFlow,
CustomCartService $cartService,
ProductRepository $productRepository,
CustomPurchaseFlow $customCartPurchaseFlow,
BaseInfoRepository $baseInfoRepository,
CartItemRepository $cartItemRepository,
StepOptionRepository $stepOptionRepository,
OrderItemRepository $orderItemRepository,
SendDataMethodCategoryRepository $sendDataMethodCategoryRepository,
PriceRepository $priceRepository,
SeasonRepository $seasonRepository,
OrderOptionRepository $orderOptionRepository,
OrderRepository $orderRepository,
CartRepository $cartRepository,
TextWarningRepository $textWarningRepository,
OrderHelper $orderHelper,
CustomOrderHelper $customOrderHelper,
SimulatorLinkRepository $simulatorLinkRepository,
WorkingTimeRepository $workingTimeRepository
) {
$this->purchaseFlow = $cartPurchaseFlow;
$this->cartService = $cartService;
$this->productRepository = $productRepository;
$this->customPurchaseFlow = $customCartPurchaseFlow;
$this->baseInfo = $baseInfoRepository->get();
$this->cartItemRepo = $cartItemRepository;
$this->orderItemRepo = $orderItemRepository;
$this->orderOptionRepository = $orderOptionRepository;
$this->sendDataMethodCategoryRepository = $sendDataMethodCategoryRepository;
$this->stepOptionRepository = $stepOptionRepository;
$this->seasonRepository = $seasonRepository;
$this->priceRepository = $priceRepository;
$this->orderRepo = $orderRepository;
$this->cartRepo = $cartRepository;
$this->textWarningRepository = $textWarningRepository;
$this->orderHelper = $orderHelper;
$this->customOrderHelper = $customOrderHelper;
$this->simulatorLinkRepository = $simulatorLinkRepository;
$this->workingTimeRepository = $workingTimeRepository;
}
/**
* カートに追加.
*
* @Route("/custom/products/add_cart/{id}", name="custom_add_cart", methods={"POST"}, requirements={"id" = "\d+"})
* @return JsonResponse
*/
public function addCart(Request $request, $id)
{
$quantity = $request->get('total_item');
$send_data_method_id = $request->get('send_data_method_id');
$file_quantity = $request->get('file_quantity');
$designs_new = $request->get('designs_new');
$files = SendDataMethod::SimulationID == $send_data_method_id ? $request->get('files') : $request->files->get('files');
$design_files = [];
if ($designs_new) {
if ($files) {
$paths_new = $this->uploadImage($files);
if (!$paths_new || count($paths_new) == 0) {
return $this->json([], 500);
}
foreach ($designs_new as $key => $design_json) {
$design_data = json_decode($design_json, true);
if ($design_data) {
$design_files[] = [
'quantity' => $design_data['quantity'],
'path' => $paths_new[$key] ?? $design_data['path'],
'design_id' => $design_data['design_id'] ?? null,
'id' => uniqid('', true),
'admin_design' => null,
];
}
}
} else {
foreach ($designs_new as $design_json) {
$design_data = json_decode($design_json, true);
if ($design_data) {
$design_files[] = [
'quantity' => $design_data['quantity'],
'path' => $design_data['path'],
'design_id' => $design_data['design_id'] ?? null,
'id' => uniqid('', true),
'admin_design' => null,
];
}
}
}
}
if($files && !$designs_new) {
if (SendDataMethod::SimulationID == $send_data_method_id) {
foreach ($files as $key => $item) {
$design_files[] = ['quantity' => $file_quantity[$key], 'path' => null, 'design_id' => $item];
}
} else {
$paths = $this->uploadImage($files);
if (!$file_quantity || !$paths || count($paths) == 0 || count($file_quantity) == 0) {
return $this->json([], 500);
}
foreach ($paths as $key => $path) {
$design_files[] = ['quantity' => $file_quantity[$key], 'path' => $path, 'design_id' => null, 'id' => uniqid('', true), 'admin_design' => null];
}
}
}
$total_delivery_item = $request->get('total_delivery_item');
$add_day = $request->get('add_day');
$item_price_option = $request->get('item_price_option');
$plan = $request->get('plan');
$product_options = $request->get('product_options');
$order_options = $request->get('order_options');
$item_price = $request->get('item_price');
$data = [
'quantity' => (int) $quantity,
'total_delivery_item' => (int) $total_delivery_item,
'add_day' => (int) $add_day,
'item_price_option' => (int) $item_price_option,
'plan' => $plan,
'product_options' => $product_options,
'quantity_designs' => $file_quantity ? count($file_quantity) : 0,
'send_data_method_id' => (int) $send_data_method_id,
'order_options' => $order_options,
'item_price' => (int) $item_price,
'design_files' => $design_files,
'price_send_data' => (int) $request->get('price_send_data')
];
$Product = $this->productRepository->findWithSortedClassCategories($id);
if ($Product->getIsSample()) {
return $this->json(['error' => 'Can not add simple product'], 500);
}
$product_class_id1 = $Product->getProductClasses()[0]->getId();
$this->cartService->customAddProduct($product_class_id1, $data);
$Carts = $this->cartService->getCarts();
$errorMessages = [];
$this->cartService->save();
return $this->json(['error' => $errorMessages]);
}
/**
* カートに追加.
*
* @Route("/custom/products/add_cart_sample_product/{id}", name="custom_add_cart_sample", methods={"POST"}, requirements={"id" = "\d+"})
* @return JsonResponse
*/
public function addCartSampleProduct($id)
{
$Product = $this->productRepository->findWithSortedClassCategories($id);
if (!$Product->getIsSample()) {
return $this->json(['error' => 'Only for add simple product'], 500);
}
if ($Product->getStatus()->getId() !== ProductStatus::DISPLAY_SHOW) {
return $this->json(['error' => 'Product is not visiable'], 500);
;
}
$product_class = $Product->getProductClasses()[0];
$this->cartService->addSampleProduct($product_class, 1);
$this->cartService->save();
return $this->json([]);
}
/**
* 閲覧可能な商品かどうかを判定
*
* @param Product $Product
*
* @return boolean 閲覧可能な場合はtrue
*/
protected function checkVisibility(Product $Product)
{
$is_admin = $this->session->has('_security_admin');
if (!$is_admin) {
if ($Product->getStatus()->getId() !== ProductStatus::DISPLAY_SHOW) {
return false;
}
}
return true;
}
public function uploadImage(array $files)
{
if (!$files || count($files) == 0) {
return false;
}
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/octet-stream'];
$maxFileSize = 200 * 1024 * 1024;
$paths = [];
foreach ($files as $file) {
if (!$file || $file->getSize() == 0) {
$paths[] = null;
} else {
// if (!in_array($file->getClientMimeType(), $allowedTypes)) {
// return false;
// }
if ($file->getSize() && $file->getSize() > $maxFileSize) {
return false;
}
$name = $file->getClientOriginalName();
$fileName = uniqid() . '-' . $name;
$uploadDir = $this->getParameter('kernel.project_dir') . '/html/upload/design';
$file->move($uploadDir, $fileName);
$path = '/html/upload/design/' . $fileName;
$paths[] = $path;
}
}
return $paths;
}
/**
* @Method("GET")
* @Route("/cart_index", name="cart_index")
* @Template("@user_data/cart_index.twig")
*/
public function cart_index(Request $request)
{
// カートを取得して明細の正規化を実行
$Carts = $this->cartService->getCarts();
// $this->execPurchaseFlow($Carts);
// TODO itemHolderから取得できるように
$least = [];
$quantity = [];
$isDeliveryFree = [];
$totalPrice = 0;
$totalQuantity = 0;
foreach ($Carts as $Cart) {
$quantity[$Cart->getCartKey()] = 0;
$isDeliveryFree[$Cart->getCartKey()] = false;
if ($this->baseInfo->getDeliveryFreeQuantity()) {
if ($this->baseInfo->getDeliveryFreeQuantity() > $Cart->getQuantity()) {
$quantity[$Cart->getCartKey()] = $this->baseInfo->getDeliveryFreeQuantity() - $Cart->getQuantity();
} else {
$isDeliveryFree[$Cart->getCartKey()] = true;
}
}
if ($this->baseInfo->getDeliveryFreeAmount()) {
if (!$isDeliveryFree[$Cart->getCartKey()] && $this->baseInfo->getDeliveryFreeAmount() <= $Cart->getTotalPrice()) {
$isDeliveryFree[$Cart->getCartKey()] = true;
} else {
$least[$Cart->getCartKey()] = $this->baseInfo->getDeliveryFreeAmount() - $Cart->getTotalPrice();
}
}
$totalPrice += $Cart->getTotalPrice();
$totalQuantity += $Cart->getQuantity();
}
// カートが分割された時のセッション情報を削除
$request->getSession()->remove(OrderHelper::SESSION_CART_DIVIDE_FLAG);
$workingTime = $this->workingTimeRepository->getTopWorkingTime();
return [
'totalPrice' => $totalPrice,
'totalQuantity' => $totalQuantity,
// 空のカートを削除し取得し直す
'Carts' => $this->cartService->getCarts(true),
'least' => $least,
'quantity' => $quantity,
'is_delivery_free' => $isDeliveryFree,
'working_time' => $workingTime,
];
}
/**
* @Method("GET")
* @Route("/cart_login_amazon", name="cart_login_amazon")
* @return JsonResponse
*/
public function cart_login_amazon(Request $request)
{
$this->setLoginTargetPath($this->generateUrl('cart_index', [], UrlGeneratorInterface::ABSOLUTE_URL));
return $this->redirectToRoute('mypage-login');
}
/**
*
* @Route(
* path="/cart_index/{cartItemId}/delete",
* name="cart_remove_item",
* methods={"DELETE"},
* requirements={
* "cartItemId": "\d+"
* }
* )
* @return JsonResponse
*/
public function removeCartItem($cartItemId)
{
$this->isTokenValid();
$cartItem = $this->cartItemRepo->find($cartItemId);
if (is_null($cartItem)) {
return $this->redirectToRoute('cart_index');
}
$Cart = $cartItem->getCart();
$Customer = $this->getUser() ? $this->getUser() : $this->orderHelper->getNonMember();
$Order = $Customer ? $this->customOrderHelper->customInitializeOrder($Cart, $Customer) : null;
if($Order){
$this->orderRepo->delete($Order);
}
$this->cartItemRepo->delete($cartItem);
$this->entityManager->flush();
$this->cartService->handleDeleteCart();
return $this->json([]);
}
/**
* @param $Carts
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse|null
*/
protected function execPurchaseFlow($Carts, $custom = false)
{
/** @var PurchaseFlowResult[] $flowResults */
if ($custom) {
$flowResults = array_map(function ($Cart) {
$purchaseContext = new PurchaseContext($Cart, $this->getUser());
return $this->customPurchaseFlow->customValidate($Cart, $purchaseContext);
}, $Carts);
} else {
$flowResults = array_map(function ($Cart) {
$purchaseContext = new PurchaseContext($Cart, $this->getUser());
return $this->purchaseFlow->validate($Cart, $purchaseContext);
}, $Carts);
}
// 復旧不可のエラーが発生した場合はカートをクリアして再描画
$hasError = false;
foreach ($flowResults as $result) {
if ($result->hasError()) {
$hasError = true;
foreach ($result->getErrors() as $error) {
$this->addRequestError($error->getMessage());
}
}
}
if ($hasError) {
$this->cartService->clear();
return $this->redirectToRoute('cart_index');
}
$this->cartService->save();
foreach ($flowResults as $index => $result) {
foreach ($result->getWarning() as $warning) {
if ($Carts[$index]->getItems()->count() > 0) {
$cart_key = $Carts[$index]->getCartKey();
$this->addRequestError($warning->getMessage(), "front.cart.${cart_key}");
} else {
// キーが存在しない場合はグローバルにエラーを表示する
$this->addRequestError($warning->getMessage());
}
}
}
return null;
}
/**
* @Method("GET")
* @Route("/detail/{id}/{type}", name="detail")
* @Template("@user_data/detail.twig")
*/
public function detail($id, $type)
{
$item = null;
$Product = null;
$current_user = $this->getUser();
$order_date = null;
if ($type == 'cart') {
$item = $this->cartItemRepo->find($id);
if (!$item) {
throw new NotFoundHttpException();
}
$Product = $this->productRepository->findWithSortedClassCategories($item['ProductClass']['Product']['id']);
} else if ($type == 'order') {
if (!$current_user) {
throw new NotFoundHttpException();
}
$item = $this->orderItemRepo->find($id);
if (!$item || $item['Order']['Customer']['id'] != $current_user['id']) {
throw new NotFoundHttpException();
}
$order_date = $item->getOrder()->getCreateDate() ?? null;
$Product = $this->productRepository->findWithSortedClassCategories($item['Product']['id']);
} else {
throw new NotFoundHttpException();
}
if($Product->getIsSample()){
return $this->redirect('/sample');
}
if (!$this->checkVisibility($Product)) {
throw new NotFoundHttpException();
}
$Category = $Product->getProductCategories()[0];
if (!$Category) {
throw new NotFoundHttpException();
}
$season = $this->seasonRepository->findActiveSeason()->getCode() ?? SeasonCode::Normal;
$orderOptions = $this->orderOptionRepository->getOrderOptionCategory($Category->getCateGoryId(), $Product->getId());
$sendDataMethods = $this->sendDataMethodCategoryRepository->getSendDataMethodsProduct($Category->getCateGoryId(), $Product->getId());
$warningText = $this->textWarningRepository->getOrderText($Product->getId(), $item['send_data_method_id']);
$option_ids_arr = str_replace(',', '-', $item['option_ids']);
$option_ids_arr = $option_ids_arr ? explode("-",$option_ids_arr) : [];
$resultNewPrice = $this->priceRepository->getLatestPrice($Product->getId(), $option_ids_arr, $item['plan_delivery'], $item['order_options']['quantity_view'], $season);
$newPrice = null;
$fromQuantity = null;
$toQuantity = null;
$price_id = null;
if ($resultNewPrice !== null) {
$price_id = $resultNewPrice['id'];
$newPrice = $resultNewPrice['price'];
$fromQuantity = $resultNewPrice['from_quantity'];
$toQuantity = $resultNewPrice['to_quantity'];
}
if (!$price_id && isset($item['price'])) {
$price_id = $item['price'];
}
$workingTime = $this->workingTimeRepository->getTopWorkingTime();
$option_ids= $item['option_ids'];
$product_id= $Product->getId();
$requestArray = [
'options' => $option_ids,
'price_id' => $price_id,
'product_id' => $product_id,
];
$order_code = $requestArray;
$options = $this->handleOptionCode($order_code, $product_id);
return [
'OrderOptions' => $orderOptions,
'SendDataMethods' => $sendDataMethods,
"Product" => $Product,
"Category" => $Category,
"item" => $item,
'new_price' => $newPrice,
'fromQuantity' => $fromQuantity,
'toQuantity' => $toQuantity,
"Options" => $options,
'WorkingTime' => $workingTime,
'add_day_delivery' => $item->getAddDayDelivery(),
'type' => $type,
'id' => $id,
'inprogress' => OrderStatus::IN_PROGRESS,
'SIMULATION' => SendDataMethod::SimulationID,
'warningText' => $warningText,
'order_date' => $order_date
];
}
/**
* @Method("POST")
* @Route("/detail/{id}/{type}", name="change_design")
* @return JsonResponse
*/
public function changeDesign(Request $request, CacheUtil $cacheUtil, $id, $type)
{
$current_user = $this->getUser();
$this->isTokenValid();
$item = null;
if ($type == 'cart') {
$item = $this->cartItemRepo->find($id);
if (!$item) {
throw new NotFoundHttpException();
}
} else if ($type == 'order') {
if (!$current_user) {
throw new NotFoundHttpException();
}
$item = $this->orderItemRepo->find($id);
if (!$item || $item['Order']['Customer']['id'] != $current_user['id']) {
throw new NotFoundHttpException();
}
if ($item['Order']['OrderStatus']['id'] == OrderStatus::IN_PROGRESS) {
throw new NotFoundHttpException();
}
} else {
throw new NotFoundHttpException();
}
$index = $request->get('index');
$designs = $item['designs'];
if ($item['designs'][$index]['design_id']) {
$design_id = $request->get('design_id' . $index);
$designs[$index]['design_id'] = $design_id;
$item->setDesigns($designs);
} else {
$files = $request->files->get('path' . $index);
$paths = $this->uploadImage([$files]);
$designs[$index]['path'] = $paths[0];
$item->setDesigns($designs);
}
$this->cartItemRepo->save($item);
$data_status = DataStatus::CONFIRMING_DATA;
foreach ($item['designs'] as $design) {
if (!$design['design_id'] && !$design['path']) {
$data_status = DataStatus::WAITING_DATA;
break;
}
}
if ($type == 'cart') {
$cart = $item->getCart();
$this->orderRepo->save($cart);
} else if($type == 'order') {
$order = $item->getOrder();
$order->setDataStatusId($data_status);
$this->orderRepo->save($order);
}
$this->entityManager->flush();
return $this->json([]);
}
/**
* @Method("GET")
* @Route("/text-warning-order/{product_id}/{send_data_method_id}")
* @return JsonResponse
*/
public function getTextWarningOrder(int $product_id, int $send_data_method_id){
$data = $this->textWarningRepository->getOrderText($product_id, $send_data_method_id);
return $this->json(['data' => $data ? $data->getWarning() : null]);
}
/**
* お届け先選択画面.
*
* 会員ログイン時, お届け先を選択する画面を表示する
* 非会員の場合はこの画面は使用しない。
*
* @Route("/order/shipping/{id}", name="order_shipping", requirements={"id" = "\d+"}, methods={"GET", "POST"})
* @Template("@user_data/change_shipping.twig")
*/
public function shipping(Request $request, Shipping $Shipping)
{
if ($this->orderHelper->isLoginRequired()) {
$this->setLoginTargetPath($this->generateUrl('cart_input', [], UrlGeneratorInterface::ABSOLUTE_URL));
return $this->redirectToRoute('mypage-login');
}
// 受注の存在チェック
$preOrderId = $this->cartService->getPreOrderId();
$Order = $this->orderHelper->getPurchaseProcessingOrder($preOrderId);
if (!$Order) {
throw new NotFoundHttpException();
}
// 受注に紐づくShippingかどうかのチェック.
if (!$Order->findShipping($Shipping->getId())) {
throw new NotFoundHttpException();
}
$builder = $this->formFactory->createBuilder(CustomerAddressType::class, null, [
'customer' => $this->getUser(),
'shipping' => $Shipping,
]);
$form = $builder->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
log_info('お届先情報更新開始', [$Shipping->getId()]);
/** @var CustomerAddress $CustomerAddress */
$CustomerAddress = $form['addresses']->getData();
// お届け先情報を更新
$Shipping->setFromCustomerAddress($CustomerAddress);
// 合計金額の再計算
// $response = $this->executePurchaseFlow($Order);
$this->entityManager->flush();
// if ($response) {
// return $response;
// }
$event = new EventArgs(
[
'Order' => $Order,
'Shipping' => $Shipping,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_SHOPPING_SHIPPING_COMPLETE);
log_info('お届先情報更新完了', [$Shipping->getId()]);
return $this->redirectToRoute('cart_input');
}
return [
'form' => $form->createView(),
'Customer' => $this->getUser(),
'shippingId' => $Shipping->getId(),
];
}
private function handleOptionCode($optionCode, $productID)
{
$options = $optionCode;
if (!$options || !isset($options['product_id']) || !isset($options['price_id']) || !isset($options['options'])) {
throw new NotFoundHttpException();
}
if($options['product_id'] !== $productID){
throw new NotFoundHttpException();
}
$price = $this->priceRepository->queryOrder($options['price_id']);
$options['options'] = array_map('trim', explode(',', $options['options']));
$option_list = $this->stepOptionRepository->whereIn($options['options']);
if($price->getProductId() != $productID){
throw new NotFoundHttpException();
}
$simulator_link = $this->simulatorLinkRepository->getProductSimulatorLink($productID, $price->getOptionIds());
$delivery_time = null;
$season = $this->seasonRepository->findActiveSeason()->getCode() ?? SeasonCode::Normal;
if ($season == SeasonCode::Normal) {
$delivery_time = $price->getDeliveryTimeNormalSession();
}
if ($season == SeasonCode::Peak) {
$delivery_time = $price->getDeliveryTimePeakSession();
}
if ($season == SeasonCode::Low) {
$delivery_time = $price->getDeliveryTimeLowSession();
}
$plans = [];
$plan_selected = $price->getPlan();
$price_list = $this->priceRepository->queryOrder($options['price_id'], true);
foreach($price_list as $price_plan){
if($price_plan['plan'] != $plan_selected){
$delivery_time_plan = 0;
if ($season == SeasonCode::Normal) {
$delivery_time_plan = $price_plan['delivery_time_normal_session'];
}
if ($season == SeasonCode::Peak) {
$delivery_time_plan = $price_plan['delivery_time_peak_session'];
}
if ($season == SeasonCode::Low) {
$delivery_time_plan = $price_plan['delivery_time_low_session'];
}
if($delivery_time_plan != 0){
$plans[] = [
'plan' => $price_plan['plan'],
'delivery_time' => $delivery_time_plan
];
}
}
}
return [
'quantity_from' => $price->getFromQuantity(),
'quantity_to' => $price->getToQuantity(),
'quantity_view' => $price->getQuantityView(),
'plan' => $plan_selected,
'plans' => $plans,
'price' => $price->getPrice(),
'delivery_time' => $delivery_time,
'options' => $option_list,
'price_list' => $price_list,
'simulator_link' => $simulator_link
];
}
}