src/Controller/ProductController.php line 325

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\IncomingOrder;
  4. use App\Entity\Product;
  5. use App\Entity\ProductIn;
  6. use App\Form\ProductTestType;
  7. use App\Form\ProductType;
  8. use App\Form\ProductTypeFieldsType;
  9. use App\Form\SearchProductByProductTypeType;
  10. use App\Repository\IncomingOrderRepository;
  11. use App\Repository\ProductFieldRepository;
  12. use App\Repository\ProductRepository;
  13. use App\Repository\ProductTypeRepository;
  14. use App\Service\FileUploader;
  15. use App\Service\ProductImportService;
  16. use Doctrine\DBAL\Exception;
  17. use Doctrine\ORM\EntityManagerInterface;
  18. use Knp\Component\Pager\PaginatorInterface;
  19. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  20. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  21. use Symfony\Component\HttpFoundation\JsonResponse;
  22. use Symfony\Component\HttpFoundation\Request;
  23. use Symfony\Component\HttpFoundation\Response;
  24. use Symfony\Component\Process\Process;
  25. use Symfony\Component\Routing\Annotation\Route;
  26. use App\Form\ProductImportType;
  27. use Symfony\Component\Validator\ConstraintViolationInterface;
  28. /**
  29.  * @Route("/admin/product")
  30.  */
  31. class ProductController extends AbstractController
  32. {
  33.     private string $importTargetDirectory;
  34.     private string $projectDir;
  35.     public function __construct($importTargetDirectory$projectDir)
  36.     {
  37.         $this->projectDir $projectDir;
  38.         $this->importTargetDirectory $importTargetDirectory;
  39.     }
  40.     /**
  41.      * @Route("/", name="product_index", methods={"GET"})
  42.      */
  43.     public function index(ProductRepository $productRepository,
  44.                           ProductTypeRepository $productTypeRepository,
  45.                           PaginatorInterface $paginatorRequest $request,
  46.                           EntityManagerInterface $em): Response
  47.     {
  48.         $queryString $request->query->get('query');
  49.         $advancedSearch $request->query->get('advancedSearch');
  50.         if ($queryString){
  51.             $query $productRepository->findBySearchQuery (['query' => $queryString]);
  52.         }else{
  53.             $queryParams $this->get_params_from_search_query($request);
  54.             $query $productRepository->findBySearchQuery($queryParams);
  55.         }
  56.         //$product = $query->getResult();
  57.         //$products = $productRepository->findAll();
  58.         $pagination $paginator->paginate(
  59.             $query/* query NOT result */
  60.             $request->query->getInt('page'1), /*page number*/
  61.             20/*limit per page*/
  62.             [
  63.                 'defaultSortFieldName'      => 'p.createdAt',
  64.                 'defaultSortDirection' => 'desc'
  65.             ]
  66.         );
  67.         $renderedForm '';
  68.         $productType null;
  69.         if (!empty($queryParams['product_type_id'])){
  70.             $options['submitted_data'] = $queryParams;
  71.             $form $this->createForm(SearchProductByProductTypeType::class,
  72.                 null,
  73.                 $options);
  74.             $renderedForm $this->renderView('product/search_by_product_type.html.twig', [
  75.                 'form' => $form->createView(),
  76.             ]);
  77.             $productType $productTypeRepository->find($queryParams['product_type_id']);
  78.         }
  79.         return $this->render('product/index.html.twig', [
  80.             'pagination' => $pagination,
  81.             'productType' => $productType,
  82.             'search_by_type_form' => $renderedForm,
  83.             'advancedSearch' => $advancedSearch,
  84.         ]);
  85.     }
  86.     /**
  87.      * @Route("/new", name="product_new", methods={"GET","POST"})
  88.      */
  89.     public function new(Request $request): Response
  90.     {
  91.         $product = new Product();
  92.         $productTypeId $request->request->get('product_type');
  93.         $fieldsOnly $request->request->get('fields_only');
  94.         if (isset($fieldsOnly) &&
  95.             $fieldsOnly === 'true'){
  96.             $form $this->createForm(ProductType::class, $product, ['is_fields_only' => true]);
  97.             $form->submit(['product_type' => $request->request->get('product_type')], false);
  98.         }else{
  99.             $form $this->createForm(ProductType::class, $product);
  100.             $form->handleRequest($request);
  101.         }
  102.         //$form = $this->createForm(ProductType::class, $product, ['new_product' => true]);
  103.         //$form->handleRequest($request);
  104.         $globalErrors $form->getErrors();
  105.         if ($form->isSubmitted() && $form->isValid()) {
  106.             $entityManager $this->getDoctrine()->getManager();
  107.             $entityManager->persist($product);
  108.             $entityManager->flush();
  109.             return $this->redirectToRoute('product_index');
  110.         }
  111.         return $this->render('product/new.html.twig', [
  112.             'product' => $product,
  113.             'form' => $form->createView(),
  114.             'new' => true,
  115.             /*'isFieldsOnly' => true*/
  116.         ]);
  117.     }
  118.     /**
  119.      * @Route ("/import", name="product_import", methods={"GET", "POST"})
  120.      */
  121.     public function import(Request $requestFileUploader $fileUploader,
  122.                            ProductImportService $productImportServiceProductTypeRepository $productTypeRepository): Response
  123.     {
  124.         $uploadedFile $request->files->get('file');
  125.         if ($uploadedFile){
  126.             $msg '';
  127.             //$mimeType = $uploadedFile->getMi
  128.             $uploadedFileName $fileUploader->upload($uploadedFile);
  129.             if (is_string($uploadedFileName)){
  130.                 return $this->json([
  131.                     'result' => 'success',
  132.                     'fileName' => $uploadedFileName
  133.                 ], 201);
  134.             }else{
  135.                 if (!== count($uploadedFileName)) {
  136.                     // there are errors, now you can show them
  137.                     /* @var $violation  ConstraintViolationInterface  */
  138.                     foreach ($uploadedFileName as $violation) {
  139.                         //$test = 'getMessage';
  140.                         //$msg .= $violation->$test().'<br>';
  141.                         $msg .= $violation->getMessage();
  142.                     }
  143.                 }
  144.             }
  145.             return $this->json([
  146.                 'result' => 'failure',
  147.                 'msg' => $msg
  148.             ], 400);
  149.         }
  150.         $productTypes $productTypeRepository->findAll();
  151.         //$form = $this->createForm(ProductImportType::class);
  152.         return $this->render('product/import.html.twig', [
  153.             'importTargetDirectory' => $this->importTargetDirectory,
  154.             //'form' => $form->createView(),
  155.             'productTypes' => $productTypes
  156.         ]);
  157.     }
  158.     /**
  159.      * @Route("/start_import", name="start_import", options={"expose"=true})
  160.      */
  161.     public function start_import(Request $requestProductImportService $productImportService): Response
  162.     {
  163.         // $fileName = 'beautifulthingsdaybookascolourstock-60ee4ac176486.csv';
  164.         $fileName $request->request->get("fileName");
  165.         $productTypeId $request->request->get("productType");
  166.         $user $this->getUser();
  167.         $productImportServiceEntry $productImportService->createImportEntry($fileName$user);
  168.         $entryId $productImportServiceEntry->getId();
  169.         $process Process::fromShellCommandline('/usr/bin/php7.4 '.$this->projectDir.'/bin/console app:product-import '.$entryId.' '.$productTypeId' &');
  170.         $process->start();
  171.         /*        exec('/usr/bin/php7.4 /home/www/stage-inventory.voom.co.nz/releases/4/bin/console app:product-import '.$entryId.
  172.                     ' >> '.$this->importTargetDirectory.'/temp.log &');*/
  173.         sleep(1);
  174.         return $this->json([
  175.                 'csv_file_name' => $fileName,
  176.                 'statusFileName' => $entryId.'_import_status.json'
  177.             ]);
  178.     }
  179.     /**
  180.      * @Route("/get_product_types", name="get_product_types", methods={"GET"}, options={"expose"=true})
  181.      */
  182.     public function getProductTypes(ProductTypeRepository $productTypeRepository):Response
  183.     {
  184.         $results = [];
  185.         $types $productTypeRepository->findAll();
  186.         foreach ($types as $type){
  187.             /* @var \App\Entity\ProductType $type */
  188.             $results['results'][] = [
  189.                 'id' => htmlspecialchars($type->getId(), \ENT_COMPAT | \ENT_HTML5),
  190.                 'text' => htmlspecialchars($type->getName(),\ENT_COMPAT | \ENT_HTML5)
  191.             ];
  192.         }
  193.         return $this->json($results);
  194.     }
  195.     /**
  196.      * @Route("/search_by_product_type", methods={"GET"}, name="search_by_product_type", options={"expose"=true})
  197.      *
  198.      */
  199.     function search_by_product_type(Request $requestProductTypeRepository $productTypeRepository
  200.     ):Response
  201.     {
  202.         $productType $productTypeRepository->find($request->get('product_type_id'));
  203.         if ($productType){
  204.             $form $this->createForm(SearchProductByProductTypeType::class,
  205.                 null,
  206.                 ['submitted_data' => [
  207.                     'product_type_id' => $productType->getId()
  208.                 ]]
  209.             );
  210.             return $this->render('product/search_by_product_type.html.twig', [
  211.                 'form' => $form->createView(),
  212.             ]);
  213.         }
  214.         return new Response('Product Type NOT found.');
  215.     }
  216.     /**
  217.      * @Route("/{id}", name="product_show", methods={"GET"}, requirements={"id":"\d+"})
  218.      */
  219.     public function show(Product $product): Response
  220.     {
  221.         return $this->render('product/show.html.twig', [
  222.             'product' => $product,
  223.         ]);
  224.     }
  225.     /**
  226.      * @Route("/get_product_type_fields/new/{product_type_id}", name="new_get_product_type_fields",
  227.      *     methods={"GET", "POST"}, options={"expose"=true})
  228.      * @ParamConverter("productType", options={"id" = "product_type_id"})
  229.      */
  230.     public function new_get_product_type_fields(Request $request, \App\Entity\ProductType $productType,
  231.                                             EntityManagerInterface $entityManager,
  232.                                             ProductRepository $productRepository): Response
  233.     {
  234.         $product = new Product();
  235.         $form $this->createForm(ProductTypeFieldsType::class, $product, [
  236.             'new_product' => true,
  237.             'product_type' => $productType
  238.         ]);
  239.         //Pre populate data
  240.         //$form->get('size')->setData('Test');
  241.         $form->handleRequest($request);
  242.         return $this->render('product/product_type_fields_form.twig', [
  243.             'product' => $product,
  244.             'form' => $form->createView(),
  245.             //'productInOuts' => $productRepository->productInAndOut($product)
  246.         ]);
  247.     }
  248.     /**
  249.      * @Route("/get_product_type_fields/{id}", name="get_product_type_fields", methods={"GET", "POST"}
  250.      *     , options={"expose"=true})
  251.      */
  252.     public function get_product_type_fields(Request $requestProduct $product,
  253.                                             EntityManagerInterface $entityManager,
  254.                          ProductRepository $productRepository): Response
  255.     {
  256.         $form $this->createForm(ProductTypeFieldsType::class, $product);
  257.         //Pre populate data
  258.         //$form->get('size')->setData('Test');
  259.         $form->handleRequest($request);
  260.         return $this->render('product/product_type_fields_form.twig', [
  261.             'product' => $product,
  262.             'form' => $form->createView(),
  263.             //'productInOuts' => $productRepository->productInAndOut($product)
  264.         ]);
  265.     }
  266.     /**
  267.      * @Route("/{id}/edit", name="product_edit", methods={"GET","POST"}, requirements={"id":"\d+"}, options={"expose"=true})
  268.      * @throws Exception
  269.      */
  270.     public function edit(Request $requestProduct $productEntityManagerInterface $entityManager,
  271.                          ProductRepository $productRepository): Response
  272.     {
  273.         //just return the form
  274.         $fieldsOnly $request->request->get('fields_only');
  275.         if (isset($fieldsOnly) &&
  276.             $fieldsOnly === 'true'){
  277.             $form $this->createForm(ProductType::class, $product, ['is_fields_only' => true]);
  278.             $form->submit(['product_type' => $request->request->get('product_type')], false);
  279.         }else{
  280.             $form $this->createForm(ProductType::class, $product);
  281.             $form->handleRequest($request);
  282.         }
  283.         if ($this->isCsrfTokenValid('delete'.$product->getId(), $request->request->get('_token'))) {
  284.             $entityManager $this->getDoctrine()->getManager();
  285.             $entityManager->remove($product);
  286.             $entityManager->flush();
  287.             $this->addFlash('success''Product deleted.');
  288.             $this->redirectToRoute('product_index');
  289.         }
  290.         if ($form->isSubmitted() && $form->isValid()) {
  291.           /*  $customFields = $product->getProductType()->getProductTypeFields()->getValues();
  292.             foreach ($customFields as $field){
  293.                 //$productField = $productFieldRepository->find();
  294.             }*/
  295.             //dd($product);
  296.             $entityManager->flush();
  297.             $this->addFlash('success''Product updated.');
  298.             return $this->redirectToRoute('product_index');
  299.         }
  300.         return $this->render('product/edit.html.twig', [
  301.             'product' => $product,
  302.             'form' => $form->createView(),
  303.             'productInOuts' => $productRepository->productInAndOut($product)
  304.         ]);
  305.     }
  306.     /**
  307.      * @Route("/{id}", name="product_delete", methods={"POST"}, requirements={"id":"\d+"})
  308.      */
  309.     public function delete(Request $requestProduct $product): Response
  310.     {
  311.         if ($this->isCsrfTokenValid('delete'.$product->getId(), $request->request->get('_token'))) {
  312.             $entityManager $this->getDoctrine()->getManager();
  313.             $entityManager->remove($product);
  314.             $entityManager->flush();
  315.         }
  316.         return $this->redirectToRoute('product_index');
  317.     }
  318.     /**
  319.      * @Route("/api/get_stock/{code}")
  320.      */
  321.     public function getStock(): Response
  322.     {
  323.         return $this->json(['test']);
  324.     }
  325.     /**
  326.      * @Route ("/{id}/update_hold_qty", name="product_update_hold_qty",
  327.      *     methods={"POST"}, requirements={"id":"\d+"})
  328.      */
  329.     public function updateHoldQty(Request $requestProduct $productEntityManagerInterface $entityManager): Response
  330.     {
  331.         $updateHoldQty $request->request->get('qty');
  332.         $product->setHold($updateHoldQty);
  333.         $entityManager->flush();
  334.         return $this->json(['result' => 'success']);
  335.     }
  336.     /**
  337.      * @Route("/{id}/edit_test", name="product_edit_test", methods={"GET","POST"}, requirements={"id":"\d+"})
  338.      */
  339.     public function editTest(Request $requestProduct $productEntityManagerInterface $entityManager,
  340.                          ProductFieldRepository $productFieldRepository): Response
  341.     {
  342.         $fields $product->getProductType()->getProductTypeFields();
  343.         $form $this->createForm(ProductTestType::class, $product);
  344.         $form->handleRequest($request);
  345.         if ($this->isCsrfTokenValid('delete'.$product->getId(), $request->request->get('_token'))) {
  346.             $entityManager $this->getDoctrine()->getManager();
  347.             $entityManager->remove($product);
  348.             $entityManager->flush();
  349.             $this->addFlash('success''Product deleted.');
  350.             $this->redirectToRoute('product_index');
  351.         }
  352.         if ($form->isSubmitted() && $form->isValid()) {
  353.             //dd($form->getData());
  354.             /*  $customFields = $product->getProductType()->getProductTypeFields()->getValues();
  355.               foreach ($customFields as $field){
  356.                   //$field->getName();
  357.                   //$form->get($field->getName())->getData();
  358.                   //$productField = $productFieldRepository->find();
  359.               }*/
  360.             $form->getData();
  361.             $this->getDoctrine()->getManager()->flush();
  362.             $this->addFlash('success''Product updated.');
  363.             return $this->redirectToRoute('product_index');
  364.         }
  365.         return $this->render('product/edit_test.html.twig', [
  366.             'product' => $product,
  367.             'form' => $form->createView(),
  368.         ]);
  369.     }
  370.     /**
  371.      * @Route("/search_product", methods="GET", name="product_search_select2", options={"expose"=true})
  372.      */
  373.     public function productSearchSelect2(Request $requestProductRepository $products): JsonResponse
  374.     {
  375.         $query $request->query->get('q''');
  376.         $foundProducts $products->findByNameOrCode($query);
  377.         $results = [];
  378.         foreach ($foundProducts as $product) {
  379.             /* @var $product Product */
  380.             $results['results'][] = [
  381.                 'id' => htmlspecialchars($product->getId(), \ENT_COMPAT | \ENT_HTML5),
  382.                 'text' => htmlspecialchars('[' $product->getCode() . '] ' $product->getName(),
  383.                     \ENT_COMPAT | \ENT_HTML5)
  384.             ];
  385.         }
  386.         return $this->json($results);
  387.     }
  388.     /**
  389.      * @Route ("/get_incoming_orders", methods="GET", name="get_incoming_orders")
  390.      */
  391.     public function get_incoming_orders(IncomingOrderRepository $incomingOrderRepository): JsonResponse
  392.     {
  393.         //Get incoming pending orders
  394.         //$incomingOrders =
  395.         return $this->json($incomingOrderRepository->findBy(
  396.             ['status' => 'pending']
  397.         ),
  398.             200,
  399.             [],
  400.             ['groups' => 'list_incoming_order']
  401.         );
  402.     }
  403.     /**
  404.      * @Route("/add_to_incoming_order", methods={"GET","POST","PUT"}, name="add_to_incoming_order")
  405.      *
  406.      */
  407.     function add_to_incoming_order(Request $requestProductRepository $productRepository,
  408.        IncomingOrderRepository $incomingOrderRepositoryEntityManagerInterface $entityManager
  409.     ):Response
  410.     {
  411.         if ($request->isXmlHttpRequest()){
  412.             $result = [
  413.                 'result' => 'failed'
  414.             ];
  415.             $incomingOrderId $request->request->get('incoming_order_id');
  416.             $incomingOrder $incomingOrderRepository->find($incomingOrderId);
  417.             if ($incomingOrder){
  418.                 //see if it's all selected or checkbox selected.
  419.                 $selectAll $request->request->get('selectAll');
  420.                 if ($selectAll == 1){
  421.                     $queryParams $this->get_params_from_search_query($request);
  422.                     $products $productRepository->findBySearchQuery($queryParams)->execute();
  423.                 }else{
  424.                     //get checkbox values
  425.                     $checkedProductIds $request->request->get('product_ids');
  426.                     $products $productRepository->findBy(['id' => $checkedProductIds]);
  427.                 }
  428.                 if (count($products) > 50){
  429.                     $result = [
  430.                         'result' => 'fail',
  431.                         'msg' => 'Sorry, you cannot add more than 50 records to the order.'
  432.                     ];
  433.                 }else{
  434.                     $productCnt 0;
  435.                     foreach ($products as $product){
  436.                         if (is_array($product)){
  437.                             $product $product[0];
  438.                         }
  439.                         $productIn = new ProductIn();
  440.                         $productIn->setIncomingOrder($incomingOrder);
  441.                         $productIn->setProduct($product);
  442.                         $productQty $product->getQty();
  443.                         $productHoldQty $product->getHold();
  444.                         //$productInOrderQty = 0;
  445.                         $productInOrderQty $productHoldQty $productQty;
  446.                         $productIn->setQty($productInOrderQty);
  447.                         $entityManager->persist($productIn);
  448.                         $productCnt++;
  449.                     }
  450.                     $entityManager->flush();
  451.                     $result = [
  452.                         'result' => 'success',
  453.                         'msg' => $productCnt. ($productCnt>1?' products':' product').' added to the order.'
  454.                     ];
  455.                 }
  456.             }
  457.             return $this->json($result);
  458.         }
  459.         return new Response('This is not ajax!'400);
  460.     }
  461.     private function get_params_from_search_query($request)
  462.     {
  463.         $result = [];
  464.         $result['code'] = trim($request->query->get('code'));
  465.         $result['name'] = trim($request->query->get('name'));
  466.         $result['description'] = trim($request->query->get('description'));
  467.         $result['qty_comparison'] = trim($request->query->get('qty_comparison'));
  468.         $result['qty'] = trim($request->query->get('qty'));
  469.         $result['price_comparison'] = trim($request->query->get('price_comparison'));
  470.         $result['price'] = trim($request->query->get('price'));
  471.         $result['shop_stock'] = trim($request->query->get('shop_stock'));
  472.         $result['hold'] = trim($request->query->get('hold'));
  473.         $result['hold_comparison'] = trim($request->query->get('hold_comparison'));
  474.         $result['less_than_hold'] = trim($request->query->get('less_than_hold'));
  475.         $result['product_type_id'] = trim($request->query->get('product_type_id'));
  476.         //Additional fields
  477.         /* @var $request Request */
  478.         $queries $request->query->all();
  479.         foreach ($queries as $key => $val){
  480.             if (in_array($key,Product::ADDITIONAL_FIELDS)){
  481.                 $result[$key] = $val;
  482.             }
  483.         }
  484.         return $result;
  485.     }
  486. }