app/Customize/Controller/Admin/AdminController.php line 132

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of EC-CUBE
  4.  *
  5.  * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
  6.  *
  7.  * http://www.ec-cube.co.jp/
  8.  *
  9.  * For the full copyright and license information, please view the LICENSE
  10.  * file that was distributed with this source code.
  11.  */
  12. namespace Customize\Controller\Admin;
  13. use Carbon\Carbon;
  14. use Doctrine\Common\Collections\Criteria;
  15. use Doctrine\ORM\NoResultException;
  16. use Doctrine\ORM\Query\ResultSetMapping;
  17. use Eccube\Controller\AbstractController;
  18. use Eccube\Entity\Master\CustomerStatus;
  19. use Eccube\Entity\Master\OrderStatus;
  20. use Eccube\Entity\Master\ProductStatus;
  21. use Eccube\Entity\ProductStock;
  22. use Eccube\Event\EccubeEvents;
  23. use Eccube\Event\EventArgs;
  24. use Eccube\Exception\PluginApiException;
  25. use Eccube\Form\Type\Admin\ChangePasswordType;
  26. use Eccube\Form\Type\Admin\LoginType;
  27. use Eccube\Repository\CustomerRepository;
  28. use Eccube\Repository\Master\OrderStatusRepository;
  29. use Eccube\Repository\MemberRepository;
  30. use Eccube\Repository\OrderRepository;
  31. use Eccube\Repository\ProductRepository;
  32. use Eccube\Service\PluginApiService;
  33. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
  34. use Symfony\Component\HttpFoundation\Request;
  35. use Symfony\Component\Routing\Annotation\Route;
  36. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  37. use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
  38. use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
  39. class AdminController extends AbstractController
  40. {
  41.     /**
  42.      * @var AuthorizationCheckerInterface
  43.      */
  44.     protected $authorizationChecker;
  45.     /**
  46.      * @var AuthenticationUtils
  47.      */
  48.     protected $helper;
  49.     /**
  50.      * @var MemberRepository
  51.      */
  52.     protected $memberRepository;
  53.     /**
  54.      * @var EncoderFactoryInterface
  55.      */
  56.     protected $encoderFactory;
  57.     /**
  58.      * @var OrderRepository
  59.      */
  60.     protected $orderRepository;
  61.     /**
  62.      * @var OrderStatusRepository
  63.      */
  64.     protected $orderStatusRepository;
  65.     /**
  66.      * @var CustomerRepository
  67.      */
  68.     protected $customerRepository;
  69.     /**
  70.      * @var ProductRepository
  71.      */
  72.     protected $productRepository;
  73.     /** @var PluginApiService */
  74.     protected $pluginApiService;
  75.     /**
  76.      * @var array 売り上げ状況用受注状況
  77.      */
  78.     private $excludes = [OrderStatus::CANCELOrderStatus::PENDINGOrderStatus::PROCESSINGOrderStatus::RETURNED];
  79.     /**
  80.      * AdminController constructor.
  81.      *
  82.      * @param AuthorizationCheckerInterface $authorizationChecker
  83.      * @param AuthenticationUtils $helper
  84.      * @param MemberRepository $memberRepository
  85.      * @param EncoderFactoryInterface $encoderFactory
  86.      * @param OrderRepository $orderRepository
  87.      * @param OrderStatusRepository $orderStatusRepository
  88.      * @param CustomerRepository $custmerRepository
  89.      * @param ProductRepository $productRepository
  90.      * @param PluginApiService $pluginApiService
  91.      */
  92.     public function __construct(
  93.         AuthorizationCheckerInterface $authorizationChecker,
  94.         AuthenticationUtils $helper,
  95.         MemberRepository $memberRepository,
  96.         EncoderFactoryInterface $encoderFactory,
  97.         OrderRepository $orderRepository,
  98.         OrderStatusRepository $orderStatusRepository,
  99.         CustomerRepository $custmerRepository,
  100.         ProductRepository $productRepository,
  101.         PluginApiService $pluginApiService
  102.     ) {
  103.         $this->authorizationChecker $authorizationChecker;
  104.         $this->helper $helper;
  105.         $this->memberRepository $memberRepository;
  106.         $this->encoderFactory $encoderFactory;
  107.         $this->orderRepository $orderRepository;
  108.         $this->orderStatusRepository $orderStatusRepository;
  109.         $this->customerRepository $custmerRepository;
  110.         $this->productRepository $productRepository;
  111.         $this->pluginApiService $pluginApiService;
  112.     }
  113.     /**
  114.      * @Route("/%eccube_admin_route%/login", name="admin_login", methods={"GET", "POST"})
  115.      * @Template("@admin/login.twig")
  116.      */
  117.     public function login(Request $request)
  118.     {
  119.         if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) {
  120.             return $this->redirectToRoute('admin_auction');
  121.         }
  122.         /* @var $form \Symfony\Component\Form\FormInterface */
  123.         $builder $this->formFactory->createNamedBuilder(''LoginType::class);
  124.         $event = new EventArgs(
  125.             [
  126.                 'builder' => $builder,
  127.             ],
  128.             $request
  129.         );
  130.         $this->eventDispatcher->dispatch($eventEccubeEvents::ADMIN_ADMIM_LOGIN_INITIALIZE);
  131.         $form $builder->getForm();
  132.         return [
  133.             'error' => $this->helper->getLastAuthenticationError(),
  134.             'form' => $form->createView(),
  135.         ];
  136.     }
  137.     /**
  138.      * 管理画面ホーム
  139.      *
  140.      * @param Request $request
  141.      *
  142.      * @return array
  143.      *
  144.      * @throws NoResultException
  145.      * @throws \Doctrine\ORM\NonUniqueResultException
  146.      *
  147.      * @Route("/%eccube_admin_route%/", name="admin_homepage", methods={"GET"})
  148.      * @Template("@admin/index.twig")
  149.      */
  150.     public function index(Request $request)
  151.     {
  152.         return $this->redirectToRoute('admin_auction');
  153.         // $adminRoute = $this->eccubeConfig['eccube_admin_route'];
  154.         //
  155.         // $is_danger_admin_url = false;
  156.         // if ($adminRoute === 'admin') {
  157.         //     $is_danger_admin_url = true;
  158.         // }
  159.         // /**
  160.         //  * 受注状況.
  161.         //  */
  162.         // $excludes = [];
  163.         // $excludes[] = OrderStatus::CANCEL;
  164.         // $excludes[] = OrderStatus::DELIVERED;
  165.         // $excludes[] = OrderStatus::PENDING;
  166.         // $excludes[] = OrderStatus::PROCESSING;
  167.         // $excludes[] = OrderStatus::RETURNED;
  168.         //
  169.         // $event = new EventArgs(
  170.         //     [
  171.         //         'excludes' => $excludes,
  172.         //     ],
  173.         //     $request
  174.         // );
  175.         // $this->eventDispatcher->dispatch($event, EccubeEvents::ADMIN_ADMIM_INDEX_ORDER);
  176.         // $excludes = $event->getArgument('excludes');
  177.         //
  178.         // // 受注ステータスごとの受注件数.
  179.         // $Orders = $this->getOrderEachStatus($excludes);
  180.         //
  181.         // // 受注ステータスの一覧.
  182.         // $Criteria = new Criteria();
  183.         // $Criteria
  184.         //     ->where($Criteria::expr()->notIn('id', $excludes))
  185.         //     ->orderBy(['sort_no' => 'ASC']);
  186.         // $OrderStatuses = $this->orderStatusRepository->matching($Criteria);
  187.         //
  188.         // /**
  189.         //  * 売り上げ状況
  190.         //  */
  191.         // $event = new EventArgs(
  192.         //     [
  193.         //         'excludes' => $this->excludes,
  194.         //     ],
  195.         //     $request
  196.         // );
  197.         // $this->eventDispatcher->dispatch($event, EccubeEvents::ADMIN_ADMIM_INDEX_SALES);
  198.         // $this->excludes = $event->getArgument('excludes');
  199.         //
  200.         // // 今日の売上/件数
  201.         // $salesToday = $this->getSalesByDay(new \DateTime());
  202.         // // 昨日の売上/件数
  203.         // $salesYesterday = $this->getSalesByDay(new \DateTime('-1 day'));
  204.         // // 今月の売上/件数
  205.         // $salesThisMonth = $this->getSalesByMonth(new \DateTime());
  206.         //
  207.         // /**
  208.         //  * ショップ状況
  209.         //  */
  210.         // // 在庫切れ商品数
  211.         // $countNonStockProducts = $this->countNonStockProducts();
  212.         //
  213.         // // 取り扱い商品数
  214.         // $countProducts = $this->countProducts();
  215.         //
  216.         // // 本会員数
  217.         // $countCustomers = $this->countCustomers();
  218.         //
  219.         // $event = new EventArgs(
  220.         //     [
  221.         //         'Orders' => $Orders,
  222.         //         'OrderStatuses' => $OrderStatuses,
  223.         //         'salesThisMonth' => $salesThisMonth,
  224.         //         'salesToday' => $salesToday,
  225.         //         'salesYesterday' => $salesYesterday,
  226.         //         'countNonStockProducts' => $countNonStockProducts,
  227.         //         'countProducts' => $countProducts,
  228.         //         'countCustomers' => $countCustomers,
  229.         //     ],
  230.         //     $request
  231.         // );
  232.         // $this->eventDispatcher->dispatch($event, EccubeEvents::ADMIN_ADMIM_INDEX_COMPLETE);
  233.         //
  234.         // // 推奨プラグイン
  235.         // $recommendedPlugins = [];
  236.         // try {
  237.         //     $recommendedPlugins = $this->pluginApiService->getRecommended();
  238.         // } catch (PluginApiException $ignore) {
  239.         // }
  240.         //
  241.         // return [
  242.         //     'Orders' => $Orders,
  243.         //     'OrderStatuses' => $OrderStatuses,
  244.         //     'salesThisMonth' => $salesThisMonth,
  245.         //     'salesToday' => $salesToday,
  246.         //     'salesYesterday' => $salesYesterday,
  247.         //     'countNonStockProducts' => $countNonStockProducts,
  248.         //     'countProducts' => $countProducts,
  249.         //     'countCustomers' => $countCustomers,
  250.         //     'recommendedPlugins' => $recommendedPlugins,
  251.         //     'is_danger_admin_url' => $is_danger_admin_url,
  252.         // ];
  253.     }
  254.     /**
  255.      * 売上状況の取得
  256.      *
  257.      * @param Request $request
  258.      *
  259.      * @Route("/%eccube_admin_route%/sale_chart", name="admin_homepage_sale", methods={"GET"})
  260.      *
  261.      * @return \Symfony\Component\HttpFoundation\JsonResponse
  262.      */
  263.     public function sale(Request $request)
  264.     {
  265.         if (!($request->isXmlHttpRequest() && $this->isTokenValid())) {
  266.             return $this->json(['status' => 'NG'], 400);
  267.         }
  268.         $event = new EventArgs(
  269.             [
  270.                 'excludes' => $this->excludes,
  271.             ],
  272.             $request
  273.         );
  274.         $this->eventDispatcher->dispatch($eventEccubeEvents::ADMIN_ADMIM_INDEX_SALES);
  275.         $this->excludes $event->getArgument('excludes');
  276.         // 週間の売上金額
  277.         $toDate Carbon::now();
  278.         $fromDate Carbon::today()->subWeek();
  279.         $rawWeekly $this->getData($fromDate$toDate'Y/m/d');
  280.         // 月間の売上金額
  281.         $fromDate Carbon::now()->startOfMonth();
  282.         $rawMonthly $this->getData($fromDate$toDate'Y/m/d');
  283.         // 年間の売上金額
  284.         $fromDate Carbon::now()->subYear()->startOfMonth();
  285.         $rawYear $this->getData($fromDate$toDate'Y/m');
  286.         $datas = [$rawWeekly$rawMonthly$rawYear];
  287.         return $this->json($datas);
  288.     }
  289.     /**
  290.      * パスワード変更画面
  291.      *
  292.      * @Route("/%eccube_admin_route%/change_password", name="admin_change_password", methods={"GET", "POST"})
  293.      * @Template("@admin/change_password.twig")
  294.      *
  295.      * @param Request $request
  296.      *
  297.      * @return \Symfony\Component\HttpFoundation\RedirectResponse|array
  298.      */
  299.     public function changePassword(Request $request)
  300.     {
  301.         $builder $this->formFactory
  302.             ->createBuilder(ChangePasswordType::class);
  303.         $event = new EventArgs(
  304.             [
  305.                 'builder' => $builder,
  306.             ],
  307.             $request
  308.         );
  309.         $this->eventDispatcher->dispatch($eventEccubeEvents::ADMIN_ADMIM_CHANGE_PASSWORD_INITIALIZE);
  310.         $form $builder->getForm();
  311.         $form->handleRequest($request);
  312.         if ($form->isSubmitted() && $form->isValid()) {
  313.             $Member $this->getUser();
  314.             $salt $Member->getSalt();
  315.             $password $form->get('change_password')->getData();
  316.             $encoder $this->encoderFactory->getEncoder($Member);
  317.             // 2系からのデータ移行でsaltがセットされていない場合はsaltを生成.
  318.             if (empty($salt)) {
  319.                 $salt $encoder->createSalt();
  320.             }
  321.             $password $encoder->encodePassword($password$salt);
  322.             $Member
  323.                 ->setPassword($password)
  324.                 ->setSalt($salt);
  325.             $this->memberRepository->save($Member);
  326.             $event = new EventArgs(
  327.                 [
  328.                     'form' => $form,
  329.                     'Member' => $Member,
  330.                 ],
  331.                 $request
  332.             );
  333.             $this->eventDispatcher->dispatch($eventEccubeEvents::ADMIN_ADMIN_CHANGE_PASSWORD_COMPLETE);
  334.             $this->addSuccess('admin.change_password.password_changed''admin');
  335.             return $this->redirectToRoute('admin_change_password');
  336.         }
  337.         return [
  338.             'form' => $form->createView(),
  339.         ];
  340.     }
  341.     /**
  342.      * 在庫なし商品の検索結果を表示する.
  343.      *
  344.      * @Route("/%eccube_admin_route%/search_nonstock", name="admin_homepage_nonstock", methods={"GET"})
  345.      *
  346.      * @param Request $request
  347.      *
  348.      * @return \Symfony\Component\HttpFoundation\Response
  349.      */
  350.     public function searchNonStockProducts(Request $request)
  351.     {
  352.         // 在庫なし商品の検索条件をセッションに付与し, 商品マスタへリダイレクトする.
  353.         $searchData = [];
  354.         $searchData['stock'] = [ProductStock::OUT_OF_STOCK];
  355.         $session $request->getSession();
  356.         $session->set('eccube.admin.product.search'$searchData);
  357.         return $this->redirectToRoute('admin_product_page', [
  358.             'page_no' => 1,
  359.         ]);
  360.     }
  361.     /**
  362.      * 本会員の検索結果を表示する.
  363.      *
  364.      * @Route("/%eccube_admin_route%/search_customer", name="admin_homepage_customer", methods={"GET"})
  365.      *
  366.      * @param Request $request
  367.      *
  368.      * @return \Symfony\Component\HttpFoundation\Response
  369.      */
  370.     public function searchCustomer(Request $request)
  371.     {
  372.         $searchData = [];
  373.         $searchData['customer_status'] = [CustomerStatus::REGULAR];
  374.         $session $request->getSession();
  375.         $session->set('eccube.admin.customer.search'$searchData);
  376.         return $this->redirectToRoute('admin_customer_page', [
  377.             'page_no' => 1,
  378.         ]);
  379.     }
  380.     /**
  381.      * @param \Doctrine\ORM\EntityManagerInterface $em
  382.      * @param array $excludes
  383.      *
  384.      * @return Request|null
  385.      */
  386.     protected function getOrderEachStatus(array $excludes)
  387.     {
  388.         $sql 'SELECT
  389.                     t1.order_status_id as status,
  390.                     COUNT(t1.id) as count
  391.                 FROM
  392.                     dtb_order t1
  393.                 WHERE
  394.                     t1.order_status_id NOT IN (:excludes)
  395.                 GROUP BY
  396.                     t1.order_status_id
  397.                 ORDER BY
  398.                     t1.order_status_id';
  399.         $rsm = new ResultSetMapping();
  400.         $rsm->addScalarResult('status''status');
  401.         $rsm->addScalarResult('count''count');
  402.         $query $this->entityManager->createNativeQuery($sql$rsm);
  403.         $query->setParameters([':excludes' => $excludes]);
  404.         $result $query->getResult();
  405.         $orderArray = [];
  406.         foreach ($result as $row) {
  407.             $orderArray[$row['status']] = $row['count'];
  408.         }
  409.         return $orderArray;
  410.     }
  411.     /**
  412.      * @param \DateTime $dateTime
  413.      *
  414.      * @return array|mixed
  415.      *
  416.      * @throws \Doctrine\ORM\NonUniqueResultException
  417.      */
  418.     protected function getSalesByDay($dateTime)
  419.     {
  420.         $dateTimeStart = clone $dateTime;
  421.         $dateTimeStart->setTime(0000);
  422.         $dateTimeEnd = clone $dateTimeStart;
  423.         $dateTimeEnd->modify('+1 days');
  424.         $qb $this->orderRepository
  425.             ->createQueryBuilder('o')
  426.             ->select('
  427.             SUM(o.payment_total) AS order_amount,
  428.             COUNT(o) AS order_count')
  429.             ->setParameter(':excludes'$this->excludes)
  430.             ->setParameter(':targetDateStart'$dateTimeStart)
  431.             ->setParameter(':targetDateEnd'$dateTimeEnd)
  432.             ->andWhere(':targetDateStart <= o.order_date and o.order_date < :targetDateEnd')
  433.             ->andWhere('o.OrderStatus NOT IN (:excludes)');
  434.         $q $qb->getQuery();
  435.         $result = [];
  436.         try {
  437.             $result $q->getSingleResult();
  438.         } catch (NoResultException $e) {
  439.             // 結果がない場合は空の配列を返す.
  440.         }
  441.         return $result;
  442.     }
  443.     /**
  444.      * @param \DateTime $dateTime
  445.      *
  446.      * @return array|mixed
  447.      *
  448.      * @throws \Doctrine\ORM\NonUniqueResultException
  449.      */
  450.     protected function getSalesByMonth($dateTime)
  451.     {
  452.         $dateTimeStart = clone $dateTime;
  453.         $dateTimeStart->setTime(0000);
  454.         $dateTimeStart->modify('first day of this month');
  455.         $dateTimeEnd = clone $dateTime;
  456.         $dateTimeEnd->setTime(0000);
  457.         $dateTimeEnd->modify('first day of 1 month');
  458.         $qb $this->orderRepository
  459.             ->createQueryBuilder('o')
  460.             ->select('
  461.             SUM(o.payment_total) AS order_amount,
  462.             COUNT(o) AS order_count')
  463.             ->setParameter(':excludes'$this->excludes)
  464.             ->setParameter(':targetDateStart'$dateTimeStart)
  465.             ->setParameter(':targetDateEnd'$dateTimeEnd)
  466.             ->andWhere(':targetDateStart <= o.order_date and o.order_date < :targetDateEnd')
  467.             ->andWhere('o.OrderStatus NOT IN (:excludes)');
  468.         $q $qb->getQuery();
  469.         $result = [];
  470.         try {
  471.             $result $q->getSingleResult();
  472.         } catch (NoResultException $e) {
  473.             // 結果がない場合は空の配列を返す.
  474.         }
  475.         return $result;
  476.     }
  477.     /**
  478.      * 在庫切れ商品数を取得
  479.      *
  480.      * @return mixed
  481.      *
  482.      * @throws \Doctrine\ORM\NonUniqueResultException
  483.      */
  484.     protected function countNonStockProducts()
  485.     {
  486.         $qb $this->productRepository->createQueryBuilder('p')
  487.             ->select('count(DISTINCT p.id)')
  488.             ->innerJoin('p.ProductClasses''pc')
  489.             ->where('pc.stock_unlimited = :StockUnlimited AND pc.stock = 0')
  490.             ->andWhere('pc.visible = :visible')
  491.             ->setParameter('StockUnlimited'false)
  492.             ->setParameter('visible'true);
  493.         return $qb->getQuery()->getSingleScalarResult();
  494.     }
  495.     /**
  496.      * 商品数を取得
  497.      *
  498.      * @return mixed
  499.      *
  500.      * @throws \Doctrine\ORM\NonUniqueResultException
  501.      */
  502.     protected function countProducts()
  503.     {
  504.         $qb $this->productRepository->createQueryBuilder('p')
  505.             ->select('count(p.id)')
  506.             ->where('p.Status in (:Status)')
  507.             ->setParameter('Status', [ProductStatus::DISPLAY_SHOWProductStatus::DISPLAY_HIDE]);
  508.         return $qb->getQuery()->getSingleScalarResult();
  509.     }
  510.     /**
  511.      * 本会員数を取得
  512.      *
  513.      * @return mixed
  514.      *
  515.      * @throws \Doctrine\ORM\NonUniqueResultException
  516.      */
  517.     protected function countCustomers()
  518.     {
  519.         $qb $this->customerRepository->createQueryBuilder('c')
  520.             ->select('count(c.id)')
  521.             ->where('c.Status = :Status')
  522.             ->setParameter('Status'CustomerStatus::REGULAR);
  523.         return $qb->getQuery()->getSingleScalarResult();
  524.     }
  525.     /**
  526.      * 期間指定のデータを取得
  527.      *
  528.      * @param Carbon $fromDate
  529.      * @param Carbon $toDate
  530.      * @param $format
  531.      *
  532.      * @return array
  533.      */
  534.     protected function getData(Carbon $fromDateCarbon $toDate$format)
  535.     {
  536.         $qb $this->orderRepository->createQueryBuilder('o')
  537.             ->andWhere('o.order_date >= :fromDate')
  538.             ->andWhere('o.order_date <= :toDate')
  539.             ->andWhere('o.OrderStatus NOT IN (:excludes)')
  540.             ->setParameter(':excludes'$this->excludes)
  541.             ->setParameter(':fromDate'$fromDate->copy())
  542.             ->setParameter(':toDate'$toDate->copy())
  543.             ->orderBy('o.order_date');
  544.         $result $qb->getQuery()->getResult();
  545.         return $this->convert($result$fromDate$toDate$format);
  546.     }
  547.     /**
  548.      * 期間毎にデータをまとめる
  549.      *
  550.      * @param $result
  551.      * @param Carbon $fromDate
  552.      * @param Carbon $toDate
  553.      * @param $format
  554.      *
  555.      * @return array
  556.      */
  557.     protected function convert($resultCarbon $fromDateCarbon $toDate$format)
  558.     {
  559.         $raw = [];
  560.         for ($date $fromDate$date <= $toDate$date $date->addDay()) {
  561.             $raw[$date->format($format)]['price'] = 0;
  562.             $raw[$date->format($format)]['count'] = 0;
  563.         }
  564.         foreach ($result as $Order) {
  565.             $raw[$Order->getOrderDate()->format($format)]['price'] += $Order->getPaymentTotal();
  566.             ++$raw[$Order->getOrderDate()->format($format)]['count'];
  567.         }
  568.         return $raw;
  569.     }
  570. }