<?php
namespace App\Controller;
use App\Entity\IncomingOrder;
use App\Entity\Product;
use App\Entity\ProductIn;
use App\Form\ProductTestType;
use App\Form\ProductType;
use App\Form\ProductTypeFieldsType;
use App\Form\SearchProductByProductTypeType;
use App\Repository\IncomingOrderRepository;
use App\Repository\ProductFieldRepository;
use App\Repository\ProductRepository;
use App\Repository\ProductTypeRepository;
use App\Service\FileUploader;
use App\Service\ProductImportService;
use Doctrine\DBAL\Exception;
use Doctrine\ORM\EntityManagerInterface;
use Knp\Component\Pager\PaginatorInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Process\Process;
use Symfony\Component\Routing\Annotation\Route;
use App\Form\ProductImportType;
use Symfony\Component\Validator\ConstraintViolationInterface;
/**
* @Route("/admin/product")
*/
class ProductController extends AbstractController
{
private string $importTargetDirectory;
private string $projectDir;
public function __construct($importTargetDirectory, $projectDir)
{
$this->projectDir = $projectDir;
$this->importTargetDirectory = $importTargetDirectory;
}
/**
* @Route("/", name="product_index", methods={"GET"})
*/
public function index(ProductRepository $productRepository,
ProductTypeRepository $productTypeRepository,
PaginatorInterface $paginator, Request $request,
EntityManagerInterface $em): Response
{
$queryString = $request->query->get('query');
$advancedSearch = $request->query->get('advancedSearch');
if ($queryString){
$query = $productRepository->findBySearchQuery (['query' => $queryString]);
}else{
$queryParams = $this->get_params_from_search_query($request);
$query = $productRepository->findBySearchQuery($queryParams);
}
//$product = $query->getResult();
//$products = $productRepository->findAll();
$pagination = $paginator->paginate(
$query, /* query NOT result */
$request->query->getInt('page', 1), /*page number*/
20, /*limit per page*/
[
'defaultSortFieldName' => 'p.createdAt',
'defaultSortDirection' => 'desc'
]
);
$renderedForm = '';
$productType = null;
if (!empty($queryParams['product_type_id'])){
$options['submitted_data'] = $queryParams;
$form = $this->createForm(SearchProductByProductTypeType::class,
null,
$options);
$renderedForm = $this->renderView('product/search_by_product_type.html.twig', [
'form' => $form->createView(),
]);
$productType = $productTypeRepository->find($queryParams['product_type_id']);
}
return $this->render('product/index.html.twig', [
'pagination' => $pagination,
'productType' => $productType,
'search_by_type_form' => $renderedForm,
'advancedSearch' => $advancedSearch,
]);
}
/**
* @Route("/new", name="product_new", methods={"GET","POST"})
*/
public function new(Request $request): Response
{
$product = new Product();
$productTypeId = $request->request->get('product_type');
$fieldsOnly = $request->request->get('fields_only');
if (isset($fieldsOnly) &&
$fieldsOnly === 'true'){
$form = $this->createForm(ProductType::class, $product, ['is_fields_only' => true]);
$form->submit(['product_type' => $request->request->get('product_type')], false);
}else{
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request);
}
//$form = $this->createForm(ProductType::class, $product, ['new_product' => true]);
//$form->handleRequest($request);
$globalErrors = $form->getErrors();
if ($form->isSubmitted() && $form->isValid()) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($product);
$entityManager->flush();
return $this->redirectToRoute('product_index');
}
return $this->render('product/new.html.twig', [
'product' => $product,
'form' => $form->createView(),
'new' => true,
/*'isFieldsOnly' => true*/
]);
}
/**
* @Route ("/import", name="product_import", methods={"GET", "POST"})
*/
public function import(Request $request, FileUploader $fileUploader,
ProductImportService $productImportService, ProductTypeRepository $productTypeRepository): Response
{
$uploadedFile = $request->files->get('file');
if ($uploadedFile){
$msg = '';
//$mimeType = $uploadedFile->getMi
$uploadedFileName = $fileUploader->upload($uploadedFile);
if (is_string($uploadedFileName)){
return $this->json([
'result' => 'success',
'fileName' => $uploadedFileName
], 201);
}else{
if (0 !== count($uploadedFileName)) {
// there are errors, now you can show them
/* @var $violation ConstraintViolationInterface */
foreach ($uploadedFileName as $violation) {
//$test = 'getMessage';
//$msg .= $violation->$test().'<br>';
$msg .= $violation->getMessage();
}
}
}
return $this->json([
'result' => 'failure',
'msg' => $msg
], 400);
}
$productTypes = $productTypeRepository->findAll();
//$form = $this->createForm(ProductImportType::class);
return $this->render('product/import.html.twig', [
'importTargetDirectory' => $this->importTargetDirectory,
//'form' => $form->createView(),
'productTypes' => $productTypes
]);
}
/**
* @Route("/start_import", name="start_import", options={"expose"=true})
*/
public function start_import(Request $request, ProductImportService $productImportService): Response
{
// $fileName = 'beautifulthingsdaybookascolourstock-60ee4ac176486.csv';
$fileName = $request->request->get("fileName");
$productTypeId = $request->request->get("productType");
$user = $this->getUser();
$productImportServiceEntry = $productImportService->createImportEntry($fileName, $user);
$entryId = $productImportServiceEntry->getId();
$process = Process::fromShellCommandline('/usr/bin/php7.4 '.$this->projectDir.'/bin/console app:product-import '.$entryId.' '.$productTypeId. ' &');
$process->start();
/* exec('/usr/bin/php7.4 /home/www/stage-inventory.voom.co.nz/releases/4/bin/console app:product-import '.$entryId.
' >> '.$this->importTargetDirectory.'/temp.log &');*/
sleep(1);
return $this->json([
'csv_file_name' => $fileName,
'statusFileName' => $entryId.'_import_status.json'
]);
}
/**
* @Route("/get_product_types", name="get_product_types", methods={"GET"}, options={"expose"=true})
*/
public function getProductTypes(ProductTypeRepository $productTypeRepository):Response
{
$results = [];
$types = $productTypeRepository->findAll();
foreach ($types as $type){
/* @var \App\Entity\ProductType $type */
$results['results'][] = [
'id' => htmlspecialchars($type->getId(), \ENT_COMPAT | \ENT_HTML5),
'text' => htmlspecialchars($type->getName(),\ENT_COMPAT | \ENT_HTML5)
];
}
return $this->json($results);
}
/**
* @Route("/search_by_product_type", methods={"GET"}, name="search_by_product_type", options={"expose"=true})
*
*/
function search_by_product_type(Request $request, ProductTypeRepository $productTypeRepository
):Response
{
$productType = $productTypeRepository->find($request->get('product_type_id'));
if ($productType){
$form = $this->createForm(SearchProductByProductTypeType::class,
null,
['submitted_data' => [
'product_type_id' => $productType->getId()
]]
);
return $this->render('product/search_by_product_type.html.twig', [
'form' => $form->createView(),
]);
}
return new Response('Product Type NOT found.');
}
/**
* @Route("/{id}", name="product_show", methods={"GET"}, requirements={"id":"\d+"})
*/
public function show(Product $product): Response
{
return $this->render('product/show.html.twig', [
'product' => $product,
]);
}
/**
* @Route("/get_product_type_fields/new/{product_type_id}", name="new_get_product_type_fields",
* methods={"GET", "POST"}, options={"expose"=true})
* @ParamConverter("productType", options={"id" = "product_type_id"})
*/
public function new_get_product_type_fields(Request $request, \App\Entity\ProductType $productType,
EntityManagerInterface $entityManager,
ProductRepository $productRepository): Response
{
$product = new Product();
$form = $this->createForm(ProductTypeFieldsType::class, $product, [
'new_product' => true,
'product_type' => $productType
]);
//Pre populate data
//$form->get('size')->setData('Test');
$form->handleRequest($request);
return $this->render('product/product_type_fields_form.twig', [
'product' => $product,
'form' => $form->createView(),
//'productInOuts' => $productRepository->productInAndOut($product)
]);
}
/**
* @Route("/get_product_type_fields/{id}", name="get_product_type_fields", methods={"GET", "POST"}
* , options={"expose"=true})
*/
public function get_product_type_fields(Request $request, Product $product,
EntityManagerInterface $entityManager,
ProductRepository $productRepository): Response
{
$form = $this->createForm(ProductTypeFieldsType::class, $product);
//Pre populate data
//$form->get('size')->setData('Test');
$form->handleRequest($request);
return $this->render('product/product_type_fields_form.twig', [
'product' => $product,
'form' => $form->createView(),
//'productInOuts' => $productRepository->productInAndOut($product)
]);
}
/**
* @Route("/{id}/edit", name="product_edit", methods={"GET","POST"}, requirements={"id":"\d+"}, options={"expose"=true})
* @throws Exception
*/
public function edit(Request $request, Product $product, EntityManagerInterface $entityManager,
ProductRepository $productRepository): Response
{
//just return the form
$fieldsOnly = $request->request->get('fields_only');
if (isset($fieldsOnly) &&
$fieldsOnly === 'true'){
$form = $this->createForm(ProductType::class, $product, ['is_fields_only' => true]);
$form->submit(['product_type' => $request->request->get('product_type')], false);
}else{
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request);
}
if ($this->isCsrfTokenValid('delete'.$product->getId(), $request->request->get('_token'))) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->remove($product);
$entityManager->flush();
$this->addFlash('success', 'Product deleted.');
$this->redirectToRoute('product_index');
}
if ($form->isSubmitted() && $form->isValid()) {
/* $customFields = $product->getProductType()->getProductTypeFields()->getValues();
foreach ($customFields as $field){
//$productField = $productFieldRepository->find();
}*/
//dd($product);
$entityManager->flush();
$this->addFlash('success', 'Product updated.');
return $this->redirectToRoute('product_index');
}
return $this->render('product/edit.html.twig', [
'product' => $product,
'form' => $form->createView(),
'productInOuts' => $productRepository->productInAndOut($product)
]);
}
/**
* @Route("/{id}", name="product_delete", methods={"POST"}, requirements={"id":"\d+"})
*/
public function delete(Request $request, Product $product): Response
{
if ($this->isCsrfTokenValid('delete'.$product->getId(), $request->request->get('_token'))) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->remove($product);
$entityManager->flush();
}
return $this->redirectToRoute('product_index');
}
/**
* @Route("/api/get_stock/{code}")
*/
public function getStock(): Response
{
return $this->json(['test']);
}
/**
* @Route ("/{id}/update_hold_qty", name="product_update_hold_qty",
* methods={"POST"}, requirements={"id":"\d+"})
*/
public function updateHoldQty(Request $request, Product $product, EntityManagerInterface $entityManager): Response
{
$updateHoldQty = $request->request->get('qty');
$product->setHold($updateHoldQty);
$entityManager->flush();
return $this->json(['result' => 'success']);
}
/**
* @Route("/{id}/edit_test", name="product_edit_test", methods={"GET","POST"}, requirements={"id":"\d+"})
*/
public function editTest(Request $request, Product $product, EntityManagerInterface $entityManager,
ProductFieldRepository $productFieldRepository): Response
{
$fields = $product->getProductType()->getProductTypeFields();
$form = $this->createForm(ProductTestType::class, $product);
$form->handleRequest($request);
if ($this->isCsrfTokenValid('delete'.$product->getId(), $request->request->get('_token'))) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->remove($product);
$entityManager->flush();
$this->addFlash('success', 'Product deleted.');
$this->redirectToRoute('product_index');
}
if ($form->isSubmitted() && $form->isValid()) {
//dd($form->getData());
/* $customFields = $product->getProductType()->getProductTypeFields()->getValues();
foreach ($customFields as $field){
//$field->getName();
//$form->get($field->getName())->getData();
//$productField = $productFieldRepository->find();
}*/
$form->getData();
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', 'Product updated.');
return $this->redirectToRoute('product_index');
}
return $this->render('product/edit_test.html.twig', [
'product' => $product,
'form' => $form->createView(),
]);
}
/**
* @Route("/search_product", methods="GET", name="product_search_select2", options={"expose"=true})
*/
public function productSearchSelect2(Request $request, ProductRepository $products): JsonResponse
{
$query = $request->query->get('q', '');
$foundProducts = $products->findByNameOrCode($query);
$results = [];
foreach ($foundProducts as $product) {
/* @var $product Product */
$results['results'][] = [
'id' => htmlspecialchars($product->getId(), \ENT_COMPAT | \ENT_HTML5),
'text' => htmlspecialchars('[' . $product->getCode() . '] ' . $product->getName(),
\ENT_COMPAT | \ENT_HTML5)
];
}
return $this->json($results);
}
/**
* @Route ("/get_incoming_orders", methods="GET", name="get_incoming_orders")
*/
public function get_incoming_orders(IncomingOrderRepository $incomingOrderRepository): JsonResponse
{
//Get incoming pending orders
//$incomingOrders =
return $this->json($incomingOrderRepository->findBy(
['status' => 'pending']
),
200,
[],
['groups' => 'list_incoming_order']
);
}
/**
* @Route("/add_to_incoming_order", methods={"GET","POST","PUT"}, name="add_to_incoming_order")
*
*/
function add_to_incoming_order(Request $request, ProductRepository $productRepository,
IncomingOrderRepository $incomingOrderRepository, EntityManagerInterface $entityManager
):Response
{
if ($request->isXmlHttpRequest()){
$result = [
'result' => 'failed'
];
$incomingOrderId = $request->request->get('incoming_order_id');
$incomingOrder = $incomingOrderRepository->find($incomingOrderId);
if ($incomingOrder){
//see if it's all selected or checkbox selected.
$selectAll = $request->request->get('selectAll');
if ($selectAll == 1){
$queryParams = $this->get_params_from_search_query($request);
$products = $productRepository->findBySearchQuery($queryParams)->execute();
}else{
//get checkbox values
$checkedProductIds = $request->request->get('product_ids');
$products = $productRepository->findBy(['id' => $checkedProductIds]);
}
if (count($products) > 50){
$result = [
'result' => 'fail',
'msg' => 'Sorry, you cannot add more than 50 records to the order.'
];
}else{
$productCnt = 0;
foreach ($products as $product){
if (is_array($product)){
$product = $product[0];
}
$productIn = new ProductIn();
$productIn->setIncomingOrder($incomingOrder);
$productIn->setProduct($product);
$productQty = $product->getQty();
$productHoldQty = $product->getHold();
//$productInOrderQty = 0;
$productInOrderQty = $productHoldQty - $productQty;
$productIn->setQty($productInOrderQty);
$entityManager->persist($productIn);
$productCnt++;
}
$entityManager->flush();
$result = [
'result' => 'success',
'msg' => $productCnt. ($productCnt>1?' products':' product').' added to the order.'
];
}
}
return $this->json($result);
}
return new Response('This is not ajax!', 400);
}
private function get_params_from_search_query($request)
{
$result = [];
$result['code'] = trim($request->query->get('code'));
$result['name'] = trim($request->query->get('name'));
$result['description'] = trim($request->query->get('description'));
$result['qty_comparison'] = trim($request->query->get('qty_comparison'));
$result['qty'] = trim($request->query->get('qty'));
$result['price_comparison'] = trim($request->query->get('price_comparison'));
$result['price'] = trim($request->query->get('price'));
$result['shop_stock'] = trim($request->query->get('shop_stock'));
$result['hold'] = trim($request->query->get('hold'));
$result['hold_comparison'] = trim($request->query->get('hold_comparison'));
$result['less_than_hold'] = trim($request->query->get('less_than_hold'));
$result['product_type_id'] = trim($request->query->get('product_type_id'));
//Additional fields
/* @var $request Request */
$queries = $request->query->all();
foreach ($queries as $key => $val){
if (in_array($key,Product::ADDITIONAL_FIELDS)){
$result[$key] = $val;
}
}
return $result;
}
}