<?php
namespace App\Controller;
use App\Entity\ComponentInventoryItem;
use App\Form\Type\ComponentInventory\BatchSetQuantityType;
use App\Form\Type\ComponentInventory\BatchDecreaseQuantityType;
use App\Form\Type\ComponentInventory\BatchIncreaseQuantityType;
use App\Form\Type\ComponentInventory\DecreaseQuantityType;
use App\Form\Type\ComponentInventory\IncreaseQuantityType;
use App\Form\Type\ComponentInventory\ItemCreateType;
use App\Form\Type\ComponentInventory\ItemUpdateType;
use App\Form\Type\ComponentInventory\LogFilterType;
use App\Model\ComponentInventory\BatchSetQuantity;
use App\Model\ComponentInventory\BatchDecreaseQuantity;
use App\Model\ComponentInventory\BatchIncreaseQuantity;
use App\Model\ComponentInventory\DecreaseQuantity;
use App\Model\ComponentInventory\IncreaseQuantity;
use App\Model\ComponentInventory\ItemCreate;
use App\Model\ComponentInventory\ItemUpdate;
use App\Model\DateRange;
use App\Model\ModalResponse;
use App\Repository\ComponentInventoryItemRepository;
use App\Repository\ComponentInventoryLogEntryRepository;
use App\Service\ComponentInventoryService;
use Exception;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
#[Route('/component-inventory')]
class ComponentInventoryController extends AbstractController
{
const BATCH_DECREASE_DATA_KEY = 'batchDecreaseData';
const BATCH_INCREASE_DATA_KEY = 'batchIncreaseData';
const BATCH_SET_DATA_KEY = 'batchSetData';
const HIDE_ZERO_QUANTITY_KEY = 'hideZeroQuantity';
protected ComponentInventoryItemRepository $componentInventoryItemRepository;
protected ComponentInventoryLogEntryRepository $componentInventoryLogEntryRepository;
protected ComponentInventoryService $componentInventoryService;
public function __construct(
ComponentInventoryItemRepository $componentInventoryItemRepository,
ComponentInventoryLogEntryRepository $componentInventoryLogEntryRepository,
ComponentInventoryService $componentInventoryService
) {
$this->componentInventoryItemRepository = $componentInventoryItemRepository;
$this->componentInventoryLogEntryRepository = $componentInventoryLogEntryRepository;
$this->componentInventoryService = $componentInventoryService;
}
/**
* @Route(
* "/{item}/delete",
* name="app.component_inventory.delete",
* requirements={"item" = "\d+"},
* methods={"GET"}
* )
*
* @param ComponentInventoryItem $item
*
* @return Response
*/
public function deleteAction(ComponentInventoryItem $item): Response
{
$this->assertAdmin();
try {
$this->componentInventoryItemRepository->delete($item);
$this->flashSuccess('ui.success.delete', [], 'ComponentInventoryItem');
} catch (Exception $e) {
$this->flashError('ui.error.delete', [], 'ComponentInventoryItem');
if ($this->getCurrentUser()->isSuperAdmin()) {
$this->flashError($e->getMessage());
}
}
return $this->redirectResponse('app.component_inventory.index');
}
/**
* @Route(
* "/excel",
* name="app.component_inventory.excel"
* )
*
* @return Response
*/
public function excelAction(): Response
{
try {
return $this->componentInventoryService->getInventoryExcelFile()->getResponse();
} catch (Exception $e) {
$this->flashError($e->getMessage());
$this->flashError($e->getPrevious()->getMessage());
return $this->redirectResponse('app.component_inventory.index');
}
}
/**
* @Route(
* "/",
* name="app.component_inventory.index"
* )
*
* @param Request $request
* @return Response
*/
public function indexAction(Request $request): Response
{
return $this->render(
'ComponentInventory/index.html.twig',
[
'items' => $this->componentInventoryItemRepository->findAll(),
'hideZeroQuantity' => $request->getSession()->get(self::HIDE_ZERO_QUANTITY_KEY, true),
]
);
}
/**
* @Route(
* "/toggle-hide-zero-quantity",
* name="app.component_inventory.index.toggle_hide_zero_quantity"
* )
*
* @param Request $request
* @return Response
*/
public function indexToggleHideZeroQuantityAction(Request $request): Response
{
$request->getSession()->set(
self::HIDE_ZERO_QUANTITY_KEY,
!$request->getSession()->get(self::HIDE_ZERO_QUANTITY_KEY, true)
);
return $this->redirectResponse('app.component_inventory.index');
}
/**
* @Route(
* "/{item}/log",
* name="app.component_inventory.item_log",
* requirements={"item" = "\d+"}
* )
*
* @param ComponentInventoryItem $item
* @return Response
*/
public function itemLogAction(ComponentInventoryItem $item): Response
{
return $this->render(
'ComponentInventory/itemLog.html.twig',
[
'item' => $item,
]
);
}
/**
* @Route(
* "/log",
* name="app.component_inventory.log"
* )
*
* @param Request $request
*
* @return Response
*/
public function logAction(Request $request): Response
{
$form = $this->createForm(
LogFilterType::class,
null,
[
'action' => $this->generateUrl('app.component_inventory.log'),
]
);
$period = null;
$showZeroQuantity = false;
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
/* @var DateRange $period */
$period = $form->get('period')->getData();
$showZeroQuantity = $form->get('showZeroQuantity')->getData();
try {
if ($form->get('excel')->isClicked()) {
return $this->componentInventoryService->getEventLogExcelFile(
$period, $showZeroQuantity
)->getResponse();
}
} catch (Exception $e) {
$this->flashError($e->getMessage());
if (null !== $previous = $e->getPrevious()) {
$this->flashError($previous->getMessage());
}
}
}
}
return $this->render(
'ComponentInventory/log.html.twig',
[
'logEntries' => $this->componentInventoryLogEntryRepository->findByCreated($period, $showZeroQuantity),
'form' => $form->createView(),
]
);
}
/**
* @Route(
* "/log/excel",
* name="app.component_inventory.log.excel"
* )
*
* @return Response
*/
public function logExcelAction(): Response
{
try {
return $this->componentInventoryService->getEventLogExcelFile()->getResponse();
} catch (Exception $e) {
$this->flashError($e->getMessage());
$this->flashError($e->getPrevious()->getMessage());
return $this->redirectResponse('app.component_inventory.index');
}
}
/**
* @Route(
* "/batch-decrease-quantity",
* name="app.component_inventory.batch_decrease_quantity.modal"
* )
*
* @param Request $request
*
* @return ModalResponse
*/
public function modalBatchDecreaseQuantityAction(Request $request): ModalResponse
{
$response = new ModalResponse();
$response->setSubmit(true);
$response->setTitle(
$this->trans('ui.batchDecreaseQuantity', [], 'ComponentInventoryItem')
);
$form = $this->createForm(
BatchDecreaseQuantityType::class,
null,
[
'action' => $this->generateUrl(
'app.component_inventory.batch_decrease_quantity.modal'
)
]
);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
try {
/* @var BatchDecreaseQuantity $data */
$data = $form->getData();
$import = $request->getSession()->get(self::BATCH_DECREASE_DATA_KEY);
foreach ($import['items'] as $item) {
if (null !== $obj = $this->componentInventoryItemRepository->findByCode($item['code'])) {
$data->updateItem($obj, $item['quantity'], $import['file']);
$this->componentInventoryItemRepository->save($obj);
}
}
$response->setRedirect(
$this->generateUrl('app.component_inventory.index')
);
} catch (Exception $e) {
$response->setError($e->getMessage());
}
}
}
$response->setBody(
$this->renderView(
'ComponentInventory/batchDecreaseQuantityForm.html.twig',
[
'form' => $form->createView(),
]
)
);
return $response;
}
/**
* @Route(
* "/batch-decrease-quantity/preview",
* name="app.component_inventory.batch_decrease_quantity.preview"
* )
*
* @param Request $request
*
* @return Response
*/
public function modalBatchDecreaseQuantityPreviewAction(Request $request): Response
{
/* @var UploadedFile $file */
$file = $request->files->get('excel');
try {
$fileName = $file->getClientOriginalName();
$items = $this->componentInventoryService->parseBatchDecreaseExcel($file);
$hasErrors = false;
foreach ($items as $item) {
if (null !== $item['error']) {
$hasErrors = true;
break;
}
}
$request->getSession()->remove(self::BATCH_DECREASE_DATA_KEY);
if (!$hasErrors) {
$data = [
'items' => $items,
'file' => $fileName,
];
$request->getSession()->set(self::BATCH_DECREASE_DATA_KEY, $data);
}
return $this->render(
'ComponentInventory/batchDecreaseQuantityPreview.html.twig',
[
'items' => $items,
'hasErrors' => $hasErrors,
]
);
} catch (Exception $e) {
return $this->render(
'ComponentInventory/excelError.html.twig',
[
'error' => $e->getMessage(),
],
new Response('', 400)
);
}
}
/**
* @Route(
* "/batch-increase-quantity",
* name="app.component_inventory.batch_increase_quantity.modal"
* )
*
* @param Request $request
*
* @return ModalResponse
*/
public function modalBatchIncreaseQuantityAction(Request $request): ModalResponse
{
$response = new ModalResponse();
$response->setSubmit(true);
$response->setTitle(
$this->trans('ui.batchIncreaseQuantity', [], 'ComponentInventoryItem')
);
$form = $this->createForm(
BatchIncreaseQuantityType::class,
null,
[
'action' => $this->generateUrl(
'app.component_inventory.batch_increase_quantity.modal'
)
]
);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
try {
/* @var BatchIncreaseQuantity $data */
$data = $form->getData();
$import = $request->getSession()->get(self::BATCH_INCREASE_DATA_KEY);
foreach ($import['items'] as $item) {
if (null !== $obj = $this->componentInventoryItemRepository->findByCode($item['code'])) {
$data->updateItem($obj, $item['description'], $item['quantity'], $item['unitPrice'], $import['file']);
} else {
$obj = (new ItemCreate(
$item['code'],
$item['type'],
$item['quantity'],
$item['unitPrice'],
$item['description'],
$data->getLogEntryNote(),
$data->getPurchaseOrderNumber(),
$import['file']
))->toItem();
}
$this->componentInventoryItemRepository->save($obj);
}
$response->setRedirect(
$this->generateUrl('app.component_inventory.index')
);
} catch (Exception $e) {
$response->setError($e->getMessage());
}
}
}
$response->setBody(
$this->renderView(
'ComponentInventory/batchIncreaseQuantityForm.html.twig',
[
'form' => $form->createView(),
]
)
);
return $response;
}
/**
* @Route(
* "/batch-increase-quantity/preview",
* name="app.component_inventory.batch_increase_quantity.preview"
* )
*
* @param Request $request
*
* @return Response
*/
public function modalBatchIncreaseQuantityPreviewAction(Request $request): Response
{
/* @var UploadedFile $file */
$file = $request->files->get('excel');
try {
$fileName = $file->getClientOriginalName();
$items = $this->componentInventoryService->parseBatchIncreaseExcel($file);
$hasErrors = false;
foreach ($items as $item) {
if (null !== $item['error']) {
$hasErrors = true;
break;
}
}
$request->getSession()->remove(self::BATCH_INCREASE_DATA_KEY);
if (!$hasErrors) {
$data = [
'items' => $items,
'file' => $fileName,
];
$request->getSession()->set(self::BATCH_INCREASE_DATA_KEY, $data);
}
return $this->render(
'ComponentInventory/batchIncreaseQuantityPreview.html.twig',
[
'items' => $items,
'hasErrors' => $hasErrors,
]
);
} catch (Exception $e) {
return $this->render(
'ComponentInventory/excelError.html.twig',
[
'error' => $e->getMessage(),
],
new Response('', 400)
);
}
}
/**
* @Route(
* "/batch-set-quantity",
* name="app.component_inventory.batch_set_quantity.modal"
* )
*
* @param Request $request
*
* @return ModalResponse
*/
public function modalBatchSetQuantityAction(Request $request): ModalResponse
{
$response = new ModalResponse();
$response->setSubmit(true);
$response->setTitle(
$this->trans('ui.batchSetQuantity', [], 'ComponentInventoryItem')
);
$form = $this->createForm(
BatchSetQuantityType::class,
null,
[
'action' => $this->generateUrl(
'app.component_inventory.batch_set_quantity.modal'
)
]
);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
try {
/* @var BatchSetQuantity $data */
$data = $form->getData();
$import = $request->getSession()->get(self::BATCH_SET_DATA_KEY);
$codes = [];
foreach ($import['items'] as $item) {
$codes[] = $item['code'];
if (null !== $obj = $this->componentInventoryItemRepository->findByCode($item['code'])) {
if (null !== $item['description']) {
$obj->setDescription($item['description']);
}
$data->updateItem($obj, $item['quantity'], $import['file']);
$this->componentInventoryItemRepository->save($obj);
}
}
// Set quantity zero to all codes that are not listed in the batch
foreach ($this->componentInventoryItemRepository->findByMissingCodes($codes) as $obj) {
$data->updateItem($obj, 0, $import['file']);
$this->componentInventoryItemRepository->save($obj);
}
$response->setRedirect(
$this->generateUrl('app.component_inventory.index')
);
} catch (Exception $e) {
$response->setError($e->getMessage());
}
}
}
$response->setBody(
$this->renderView(
'ComponentInventory/batchSetQuantityForm.html.twig',
[
'form' => $form->createView(),
]
)
);
return $response;
}
/**
* @Route(
* "/batch-set-quantity/preview",
* name="app.component_inventory.batch_set_quantity.preview"
* )
*
* @param Request $request
*
* @return Response
*/
public function modalBatchSetQuantityPreviewAction(Request $request): Response
{
/* @var UploadedFile $file */
$file = $request->files->get('excel');
try {
$fileName = $file->getClientOriginalName();
$items = $this->componentInventoryService->parseBatchSetExcel($file);
$hasErrors = false;
foreach ($items as $item) {
if (null !== $item['error']) {
$hasErrors = true;
break;
}
}
$request->getSession()->remove(self::BATCH_SET_DATA_KEY);
if (!$hasErrors) {
$data = [
'items' => $items,
'file' => $fileName,
];
$request->getSession()->set(self::BATCH_SET_DATA_KEY, $data);
}
return $this->render(
'ComponentInventory/batchSetQuantityPreview.html.twig',
[
'items' => $items,
'hasErrors' => $hasErrors,
]
);
} catch (Exception $e) {
return $this->render(
'ComponentInventory/excelError.html.twig',
[
'error' => $e->getMessage(),
],
new Response('', 400)
);
}
}
/**
* @Route(
* "/{item}/decrease-quantity",
* name="app.component_inventory.decrease_quantity.modal",
* requirements={"item" = "\d+"}
* )
*
* @param Request $request
* @param ComponentInventoryItem $item
*
* @return ModalResponse
*/
public function modalDecreaseQuantityAction(Request $request, ComponentInventoryItem $item): ModalResponse
{
$response = new ModalResponse();
$response->setSubmit(true);
$response->setTitle(
$this->trans('ui.decreaseQuantity', [], 'ComponentInventoryItem')
);
$response->setLabel($item->getCode());
$form = $this->createForm(
DecreaseQuantityType::class,
null,
[
'action' => $this->generateUrl(
'app.component_inventory.decrease_quantity.modal',
[
'item' => $item->getId(),
]
)
]
);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
try {
/* @var DecreaseQuantity $data */
$data = $form->getData();
$data->updateItem($item);
$this->componentInventoryItemRepository->save($item);
$response->setRedirect(
$this->generateUrl('app.component_inventory.index')
);
} catch (Exception $e) {
$response->setError($e->getMessage());
}
}
}
$response->setBody(
$this->renderView(
'ComponentInventory/decreaseQuantityForm.html.twig',
[
'form' => $form->createView(),
]
)
);
return $response;
}
/**
* @Route(
* "/{item}/increase-quantity",
* name="app.component_inventory.increase_quantity.modal",
* requirements={"item" = "\d+"}
* )
*
* @param Request $request
* @param ComponentInventoryItem $item
*
* @return ModalResponse
*/
public function modalIncreaseQuantityAction(Request $request, ComponentInventoryItem $item): ModalResponse
{
$response = new ModalResponse();
$response->setSubmit(true);
$response->setTitle(
$this->trans('ui.increaseQuantity', [], 'ComponentInventoryItem')
);
$response->setLabel($item->getCode());
$form = $this->createForm(
IncreaseQuantityType::class,
null,
[
'action' => $this->generateUrl(
'app.component_inventory.increase_quantity.modal',
[
'item' => $item->getId(),
]
)
]
);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
try {
/* @var IncreaseQuantity $data */
$data = $form->getData();
$data->updateItem($item);
$this->componentInventoryItemRepository->save($item);
$response->setRedirect(
$this->generateUrl('app.component_inventory.index')
);
} catch (Exception $e) {
$response->setError($e->getMessage());
}
}
}
$response->setBody(
$this->renderView(
'ComponentInventory/increaseQuantityForm.html.twig',
[
'form' => $form->createView(),
]
)
);
return $response;
}
/**
* @Route(
* "/create",
* name="app.component_inventory.create.modal"
* )
*
* @param Request $request
*
* @return ModalResponse
*/
public function modalCreateAction(Request $request): ModalResponse
{
$response = new ModalResponse();
$response->setSubmit(true);
$response->setTitle(
$this->trans('ui.create', [], 'ComponentInventoryItem')
);
$form = $this->createForm(
ItemCreateType::class,
null,
[
'action' => $this->generateUrl(
'app.component_inventory.create.modal'
)
]
);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
try {
/* @var ItemCreate $data */
$data = $form->getData();
$this->componentInventoryItemRepository->save($data->toItem());
$response->setRedirect(
$this->generateUrl('app.component_inventory.index')
);
} catch (Exception $e) {
$response->setError($e->getMessage());
}
}
}
$response->setBody(
$this->renderView(
'ComponentInventory/form.html.twig',
[
'form' => $form->createView(),
]
)
);
return $response;
}
/**
* @Route(
* "/{item}/update",
* name="app.component_inventory.update.modal",
* requirements={"item" = "\d+"}
* )
*
* @param Request $request
* @param ComponentInventoryItem $item
*
* @return ModalResponse
*/
public function modalUpdateAction(Request $request, ComponentInventoryItem $item): ModalResponse
{
$response = new ModalResponse();
$response->setSubmit(true);
$response->setTitle(
$this->trans('ui.update', [], 'ComponentInventoryItem')
);
$response->setLabel($item->getCode());
$form = $this->createForm(
ItemUpdateType::class,
ItemUpdate::fromItem($item),
[
'action' => $this->generateUrl(
'app.component_inventory.update.modal',
[
'item' => $item->getId(),
]
)
]
);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
try {
/* @var ItemUpdate $data */
$data = $form->getData();
$data->updateItem($item);
$this->componentInventoryItemRepository->save($item);
$response->setRedirect(
$this->generateUrl('app.component_inventory.index')
);
} catch (Exception $e) {
$response->setError($e->getMessage());
}
}
}
$response->setBody(
$this->renderView(
'ComponentInventory/updateForm.html.twig',
[
'form' => $form->createView(),
]
)
);
return $response;
}
}