<?php
namespace App\Controller;
use App\Entity\Company;
use App\Entity\CompanyAddress;
use App\Entity\Order;
use App\Entity\OrderMessage;
use App\Entity\Part;
use App\Entity\Supplier;
use App\Entity\User;
use App\Entity\CompanySupplier;
use App\Form\OrderFilesType;
use App\Form\OrderPrototypeType;
use App\Form\OrderSearchType;
use App\Form\OrderType;
use App\Form\OrderSupplierType;
use App\Form\OrderBudgetType;
use App\Repository\OrderRepository;
use App\Security\Voter\OrderVoter;
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Routing\Annotation\Route;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Knp\Snappy\Pdf;
use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
use App\Service\UtilService;
use App\Service\OrderService;
use App\Service\PartService;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\Filesystem\Exception\IOExceptionInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\String\Slugger\AsciiSlugger;
use Doctrine\Persistence\ManagerRegistry;
use App\Service\EncryptDecryptService;
/**
* @Route({"en": "/order",
* "es": "/orden"})
*/
class OrderController extends AbstractController
{
private $emailApp;
public const PAGE_ELEMENTS = 25;
private $translator;
private $orderRepository;
private $util;
private $pdf;
private $orderService;
private $partService;
private $em;
private $partDir;
public function __construct(
string $emailApp,
TranslatorInterface $translator,
OrderRepository $orderRepository,
UtilService $utilService,
OrderService $orderService,
PartService $partService,
Pdf $knpSnappyPdf,
ManagerRegistry $doctrine,
string $partDir,
private EncryptDecryptService $encryptDecryptService)
{
$this->emailApp = $emailApp;
$this->translator = $translator;
$this->util = $utilService;
$this->pdf = $knpSnappyPdf;
$this->orderRepository = $orderRepository;
$this->orderService = $orderService;
$this->partService = $partService;
$this->em = $doctrine->getManager();
$this->partDir = $partDir;
}
/**
* @Route({"en": "/list",
* "es": "/listado"}, name="order_index", methods={"GET","POST"})
*/
public function index(Request $request, OrderRepository $orderRepository, PaginatorInterface $paginator): Response
{
$admin =$this->getUser();
$ms = $this->util->getLicenseField($admin->getCompany(),'multi_select') && $admin->getRole()!='ROLE_CLIENT';
if($admin == NULL){
return $this->redirectToRoute('app_login');
}
$search = [];
$form = $this->createForm(OrderSearchType::class, $search, ['user_admin' => $admin,'method' => 'GET']);
$form->handleRequest($request);
$orderBy = null;
$filters = [
['field'=>'company','title'=>'Empresa'],
['field'=>'ref','title'=>'Referencia'],
['field'=>'part','title'=>'Pieza'],
['field'=>'supplier','title'=>'Centro de trabajo'],
['field'=>'units','title'=>'Unidades'],
['field'=>'updated_at','title'=>'Última modificación'],
['field'=>'state','title'=>'Estado']
];
if ($form->isSubmitted() && $form->isValid())
{
$orderBy = $request->query->get('order_by');
$orders = $orderRepository->findByName($form->getData(), $admin, $orderBy);
} else {
$orders = $orderRepository->buscarTodos($admin);
}
if($request->isMethod('POST')){
if($request->request->get('orders_delete')){
$delIds = $request->request->get('delIds',null);
if($delIds){
$orders = explode(',', $delIds);
$successMsg = '';
$errorMsg = '';
foreach($orders as $orderId){
$order = $this->em->getRepository(Order::class)->find($orderId);
if($order){
$rmOrder = $this->rmOrder($order);
if($rmOrder['error']){
$errorMsg.= $this->translator->trans('Error orden {ref} : ',['{ref}'=>$order->getRef()]) . $rmOrder['msg'].'<br>';
}
else{
$successMsg.= $this->translator->trans('Orden {ref} eliminada correctamente',['{ref}'=>$order->getRef()]).'<br>';
}
}
}
if($successMsg){
$this->addFlash('success', $successMsg);
}
if($errorMsg){
$this->addFlash('danger', $successMsg);
}
return $this->redirectToRoute('order_index');
}
}
}
// Creating pagnination
$pagination = $paginator->paginate(
$orders,
$request->query->getInt('page', 1),
self::PAGE_ELEMENTS
);
return $this->render('order/index.html.twig', [
'pagination' => $pagination,
'search_form' => $form->createView(),
'filters' => $filters,
'order_by' => $orderBy,
'ms' => $ms,
'user' => $this->getUser(),
'navbarTitle' => $this->translator->trans("Órdenes de trabajo")
]);
}
/**
* @Route({"en": "/new/prototype",
* "es": "/nuevo/prototipo"}, name="order_prototype_new", methods={"GET","POST"})
*/
public function ºnewPrototype(Request $request, MailerInterface $mailer, OrderRepository $orderRepository): Response
{
$em = $this->em;
$admin = $this->getUser();
$order = new Order();
$order->setUnits(1);
$order->setType(2);
$this->denyAccessUnlessGranted(OrderVoter::CREATE, $order);
$fileMaxsizes = $this->util->getCompanyFileMaxsizes($admin->getCompany());
$cs = $em->getRepository(CompanySupplier::class)->findOneBy(['company'=>$this->getUser()->getCompany(),'supplier'=>$order->getSupplier()]);
$form = $this->createForm(OrderPrototypeType::class, $order, ['user_admin' => $admin, 'part' => null, 'cs'=>$cs,'file_maxsizes' => $fileMaxsizes]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$createOrder = $this->createOrder($order);
if($createOrder['error']) {
$this->addFlash('danger', 'error: ' . $createOrder['msg']);
}
$this->processOtherFiles($form, $order, 5);
$em->persist($order);
$em->flush();
return $this->redirectToRoute('order_index');
}
return $this->render('order/new.html.twig', [
'order' => $order,
//'cs' => $cs,
'form' => $form->createView(),
'user' => $this->getUser(),
'navbarTitle' => $this->translator->trans("Solicitar presupuesto")
]);
}
/**
* @Route({"en": "/new/{part}",
* "es": "/nueva/{part}"}, name="order_new", methods={"GET","POST"})
*/
public function new(Request $request, MailerInterface $mailer, Part $part, OrderRepository $orderRepository): Response
{
$em = $this->em;
$admin = $this->getUser();
$order = new Order();
$order->setType(1);
$this->denyAccessUnlessGranted(OrderVoter::CREATE, $order);
$cs = $em->getRepository(CompanySupplier::class)->findOneBy(['company'=>$part->getCompany(),'supplier'=>$part->getSupplier()]);
$form = $this->createForm(OrderType::class, $order, ['user_admin' => $admin, 'part' => $part, 'cs'=>$cs]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$initMsg = $this->translator->trans('Pieza') . ' ' . $part->getRef() . ': ';
$createOrder = $this->createOrder($order);
if($createOrder['error']){
$this->addFlash('danger', $initMsg . $createOrder['msg']);
}
else{
$this->addFlash('success', $initMsg . $this->translator->trans('Orden creada correctamente'));
}
return $this->redirectToRoute('order_index');
}
return $this->render('order/new.html.twig', [
'order' => $order,
'cs' => $cs,
'form' => $form->createView(),
'user' => $this->getUser(),
'navbarTitle' => $this->translator->trans("Solicitar presupuesto")
]);
}
private function processOtherFiles(FormInterface $form, Order $order, $limit=5){
$files = $form->get('filesOrder')->getData();
if(count($files)>0){
$slugger = new AsciiSlugger();
$filenames = !empty($order->getFilesOrder()) ? explode(',',$order->getFilesOrder()) : [];
try {
foreach($files as $file)
{
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
$safeFilename = $slugger->slug($originalFilename);
$newFilename = $safeFilename.'-'.uniqid().'.'.$file->getClientOriginalExtension();
if(!in_array($newFilename,$filenames)){
if(count($filenames)>$limit){
$this->addFlash('warning', $this->translator->trans('Se excedió el ḿaximo de archivos que se pueden cargar'));
break;
}
else{
$file->move($this->partDir, $newFilename);
$filenames[]=$newFilename;
$order->setFilesOrder(implode(',',$filenames));
}
}
}
}
catch (FileException $e) {
$this->addFlash('danger', $this->translator->trans('Fallo en la carga de fichero'));
}
}
}
/**
* @Route({"en": "/new/bulk/{partIds}",
* "es": "/nueva/masiva/{partIds}"}, name="order_bulk_new", methods={"GET","POST"})
*/
public function newBulk(Request $request, OrderRepository $orderRepository, string $partIds): Response
{
$user =$this->getUser();
$em = $this->em;
$qb = $em->createQueryBuilder();
if($user == NULL){
return $this->redirectToRoute('app_login');
}
$decodedPartIds = explode(',',base64_decode($partIds));
$parts = [];
foreach($decodedPartIds as $partId){
$part = $this->em->getRepository(Part::class)->find($partId);
if($part && $part->getSupplier() && $part->getCompany()==$user->getCompany() && !$part->getLocked()){
$parts[] = $part;
}
}
if(empty($parts)){
$this->addFlash('danger', $this->translator->trans('Error inesperado'));
return $this->redirectToRoute('part_index');
}
if($request->isMethod('POST')){
$orders = (array) $request->request->get('orders');
if(!empty($orders) && count($orders)==4){
$errorMsg = [];
$successMsg = [];
for($i=0;$i<count($orders['parts']);$i++){
$partId = $orders['parts'][$i];
$part = $em->getRepository(Part::class)->find($partId);
if(!empty($part)){
$shippingAddress = null;
if(!empty($orders['shipping_address'][$i])){
$shippingAddress = $em->getRepository(CompanyAddress::class)->find($orders['shipping_address'][$i]);
}
$order = new Order();
$order->setPart($part);
$order->setCompany($part->getCompany());
$order->setSupplier($part->getSupplier());
$order->setUser($user);
$order->setShippingAddress($shippingAddress);
$order->setUnits($orders['units'][$i]);
$order->setObservations($orders['observations'][$i]);
$initMsg = $this->translator->trans('Pieza') . ' ' . $part->getRef() . ': ';
$createOrder = $this->createOrder($order);
if($createOrder['error']){
$errorMsg[] = $initMsg . $createOrder['msg'];
}
else{
$successMsg[]=$initMsg . $this->translator->trans('Orden creada correctamente');
}
}
else{
$errorMsg[] = $this->translator->trans('Pieza') . ' [' . $partId . ']: ' . $this->translator->trans('Error inesperado');
}
}
if($errorMsg){
$this->addFlash('danger', implode('<br>',$errorMsg));
}
if($successMsg){
$this->addFlash('success', implode('<br>',$successMsg));
}
return $this->redirectToRoute('order_index');
}
else{
$this->addFlash('danger', $this->translator->trans('Error inesperado'));
return $this->redirectToRoute('order_bulk_new',['partIds'=>$partIds]);
}
}
return $this->render('order/bulk_new.html.twig', [
'parts' => $parts,
'user' => $user,
'navbarTitle' => $this->translator->trans("Nuevas órdenes de trabajo")
]);
}
private function createOrder(Order $order){
$em = $this->em;
$orderRepository = $this->orderRepository;
if($order->getPart()) {
$part = $order->getPart();
}
$user = $this->getUser();
$roleClient = $user->getRole()=='ROLE_CLIENT';
$result = ['error'=>false,'msg'=>''];
if($order->getType() == 1) {
$company = $part->getCompany();
} else {
$company = $user->getCompany();
}
$lastRef = $orderRepository->findLastRef($company);
if($order->getType() == 1) {
$supplierId = $part->getSupplier();
} else {
$supplierId = $order->getSupplier();
}
$cs = $em->getRepository(CompanySupplier::class)->findOneBy(['company'=>$company,'supplier'=> $supplierId]);
$budgetRequired = $cs ? $cs->getConfigStepBudget() : true;
$chiefConfirm = $cs ? $cs->getConfigStepChiefConfirm() : true;
$order->setRef($lastRef);
$order->setChiefConfirm($chiefConfirm);
$order->setBudgetRequired($budgetRequired);
$order->setUnitsDecrypted($order->getUnits());
try
{
if(!$order->getId()){
$em->persist($order);
}
//Bloqueo de pieza
if($order->getType() == 1) {
$part = $order->getPart();
$part->setLocked(true);
$part->setLockedAt(new \DateTime());
$part->setLockedUser(null);
}
$em->flush();
$data['message']='Nueva orden creada';
$data['reference']=$order->getRef();
$data['path_name']='order_show';
$data['path_parameters']='id:'.$order->getId();
//Notificaciones - cliente
$this->util->notifications($order->getCompany(), 3, $data, $this->getUser(), $order->getId());
if(!$roleClient && $order->getCompany()!=$order->getSupplier()->getCompany()){
//Notificaciones - proveedor
$this->util->notifications($order->getSupplier()->getCompany(), 3, $data, $this->getUser(), $order->getId());
}
} catch ( UniqueConstraintViolationException $e) {
$result['error']=true;
$result['msg'] = $this->translator->trans('Ya existe una orden de trabajo para esta pieza');
}
return $result;
}
/**
* @Route({"en": "/show/{id}",
* "es": "/mostrar/{id}"}, name="order_show", methods={"GET","POST"})
*/
public function show(Request $request, Order $order, OrderRepository $orderRepository): Response
{
$this->denyAccessUnlessGranted(OrderVoter::VIEW, $order);
$em = $this->em;
$fs = new Filesystem();
$slugger = new AsciiSlugger();
$ds = DIRECTORY_SEPARATOR;
$ordersDir = $this->getParameter('kernel.project_dir').$ds.'public'.$ds.'orders';
$user = $this->getUser();
$role = $user->getRole();
if($order->getType() == 1){
$company = $order->getPart()->getCompany();
} else {
$company = $order->getCompany();
}
$fileMaxsizes = $this->util->getCompanyFileMaxsizes($company);
//Formulario envío de presupuesto
$formBudget = $this->createForm(OrderBudgetType::class, $order, ['user' => $user, 'file_maxsizes' => $fileMaxsizes]);
//Formulario envío de presupuesto
$formFiles = $this->createForm(OrderFilesType::class, $order, [ 'file_maxsizes' => $fileMaxsizes]);
//Formulario observaciones y carga archivos proveedor
$form = $this->createForm(OrderSupplierType::class, $order, ['user' => $user, 'part' => $order->getPart(), 'file_maxsizes' => $fileMaxsizes]);
if(!in_array($role,['ROLE_SUPPLIER_CHIEF','ROLE_SUPPLIER'])) {
$formFiles->handleRequest($request);
if ($formFiles->isSubmitted()) {
if ($formFiles->isValid()) {
$this->processOtherFiles($formFiles, $order, 5);
$em->persist($order);
$em->flush();
} else {
$this->addFlash('danger', $this->translator->trans('Ha habido un error al procesar el formulario, revise los campos'));
}
}
}
if(in_array($role,['ROLE_SUPPLIER_CHIEF','ROLE_SUPPLIER'])){
//Formulario envío de presupuesto
$formBudget->handleRequest($request);
if($formBudget->isSubmitted()){
if($formBudget->isValid()){
$files = $request->files->get('order_budget')['files_budget'];
$payTermsId = $form->getData()->getPaymentTermsId();
$filenames = !empty($order->getFilesBudget()) ? explode(',',$order->getFilesBudget()) : [];
$filesLimit = 5;
if(count($files)>0){
try {
if(!$fs->exists($ordersDir)){
$fs->mkdir($ordersDir);
}
foreach($files as $file)
{
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
$safeFilename = $slugger->slug($originalFilename);
$newFilename = $safeFilename.'-budget-'.uniqid().'.'.$file->getClientOriginalExtension();
if(!in_array($newFilename,$filenames)){
$filenames[]=$newFilename;
if(count($filenames)>$filesLimit){
$this->addFlash('warning', $this->translator->trans('Se excedió el ḿaximo de archivos que se pueden cargar'));
break;
}
else{
$file->move($ordersDir, $newFilename);
$order->setFilesBudget(implode(',',$filenames));
}
}
}
}
catch (FileException $e) {
$this->addFlash('danger', $this->translator->trans('Fallo en la carga de fichero'));
}
catch (IOExceptionInterface $e) {
$this->addFlash('danger', $this->translator->trans('No se ha podido generar el directorio').' : '.$e->getPath());
}
}
$order->setState(1);
$order->setBudgetDate(new \DateTime());
$order->markAsAproved();
$order->setPaymentTerms($orderRepository->getPaymentTermsText($payTermsId));
$em->persist($order);
$em->flush();
$this->addFlash('success', $this->translator->trans('Presupuesto enviado correctamente'));
return $this->redirectToRoute('order_index');
}
else{
$this->addFlash('danger', $this->translator->trans('Ha habido un error al procesar el formulario, revise los campos'));
}
}
//Formulario observaciones y carga archivos proveedor
$form->handleRequest($request);
if($form->isSubmitted()){
if($form->isValid()){
$obs = $request->get('order_supplier');
$files = $request->files->get('order_supplier')['files'];
$filenames = !empty($order->getFilesSupplier()) ? explode(',',$order->getFilesSupplier()) : [];
$filesLimit = 5;
if(count($files)>0){
try {
if(!$fs->exists($ordersDir)){
$fs->mkdir($ordersDir);
}
foreach($files as $file)
{
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
$safeFilename = $slugger->slug($originalFilename);
$newFilename = $safeFilename.'-report-'.uniqid().'.'.$file->getClientOriginalExtension();
if(!in_array($newFilename,$filenames)){
$filenames[]=$newFilename;
if(count($filenames)>$filesLimit){
$this->addFlash('warning', $this->translator->trans('Se excedió el ḿaximo de archivos que se pueden cargar'));
break;
}
else{
$file->move($ordersDir, $newFilename);
$order->setFilesSupplier(implode(',',$filenames));
}
}
}
}
catch (FileException $e) {
$this->addFlash('danger', $this->translator->trans('Fallo en la carga de fichero'));
}
catch (IOExceptionInterface $e) {
$this->addFlash('danger', $this->translator->trans('No se ha podido generar el directorio').' : '.$e->getPath());
}
}
$em->persist($order);
$em->flush();
$this->addFlash('success', $this->translator->trans('Orden editada correctamente'));
return $this->redirectToRoute('order_show',['id'=>$order->getId()]);
}
else{
$this->addFlash('danger', $this->translator->trans('Ha habido un error al procesar el formulario, revise los campos'));
}
}
if($request->query->has('rm')){
$type = $request->query->has('type') && $request->query->get('type')==1 ? 1 : 2;
$filenames = explode(',',($type==1 ? $order->getFilesBudget() : $order->getFilesSupplier()));
$index = $request->query->get('rm');
if(!empty($filenames[$index])){
$fileToRemove = $filenames[$index];
if($fs->exists($ordersDir.$ds.$fileToRemove)){
try {
$fs->remove($ordersDir.$ds.$fileToRemove);
unset($filenames[$index]);
if($type==1){
$order->setFilesBudget(implode(',',$filenames));
}
else{
$order->setFilesSupplier(implode(',',$filenames));
}
$em->flush();
$this->addFlash('success', $this->translator->trans('Archivo eliminado correctamente'));
} catch (IOExceptionInterface $exception) {
$this->addFlash('danger',$this->translator->trans('No se ha podido eliminar el archivo'));
}
}
}
return $this->redirectToRoute('order_show',['id'=>$order->getId()]);
}
}
if($request->query->get('download')){
$url = $this->generateUrl('order_show',['id'=>$order->getId()], UrlGeneratorInterface::ABSOLUTE_URL);
$qr = $this->util->generateQrCode($url);
if($request->query->get('download')==1){
$options = [
'page-size' => 'A6',
'orientation'=>'Landscape'
];
$html =$this->renderView('order/pdf/tag.html.twig', [
'order' => $order,
'qr' => $qr,
'user' => $user
]);
return new PdfResponse(
$this->pdf->getOutputFromHtml($html, $options),
$order->getRef().'_'.$this->translator->trans('etiqueta').'.pdf'
);
}
else{
$header = $this->renderView( 'order/pdf/report_header.html.twig',[
'order' => $order,
'partByCat' => $this->partService->getPartByCat($order->getPart()),
'qr' => $qr,
'preview' => $order->getPart()->getFilePreview() ? $this->partDir . DIRECTORY_SEPARATOR . $order->getPart()->getFilePreview() : '',
'user' => $user
] );
$footer = $this->renderView( 'order/pdf/report_footer.html.twig',[
'order' => $order,
'partByCat' => $this->partService->getPartByCat($order->getPart()),
'qr' => $qr,
'user' => $user
] );
$options = [
'header-html' => $header,
'footer-html' => $footer,
'page-size' => 'A4'
];
$html =$this->renderView('order/pdf/report.html.twig', [
'order' => $order,
'sum' => $this->orderService->getOrderSummary($order),
'partByCat' => $this->partService->getPartByCat($order->getPart()),
'qr' => $qr,
'user' => $user
]);
return new PdfResponse(
$this->pdf->getOutputFromHtml($html, $options),
$order->getRef().'_'.$this->translator->trans('hoja_produccion').'.pdf'
);
}
}
if ($request->getMethod()=='POST') {
if ($this->isCsrfTokenValid('initiate'.$order->getId(), $request->request->get('_token'))) {
$said = $request->request->get('shipping_address');
$type = $request->request->get('request_order') ? 1 : 2;
if($type==1){
if($said>0){
$shipping_address = $em->getRepository(CompanyAddress::class)->find($said);
$order->setShippingAddress($shipping_address);
}
$order->setState(0);
}
else{
$order->setState(6);
$order->setRejectUser($user);
$order->setRejectDate(new \DateTime());
}
$order->markAsAproved(); //updated
$em->flush();
$data['message']='Orden de cliente solicitada';
$data['reference']=$order->getRef();
$data['path_name']='order_show';
$data['path_parameters']='id:'.$order->getId();
//Notificaciones - cliente
$this->util->notifications($order->getCompany(), 3, $data, $this->getUser(), $order->getId());
if($order->getCompany()!=$order->getSupplier()->getCompany()){
//Notificaciones - proveedor
$this->util->notifications($order->getSupplier()->getCompany(), 3, $data, $this->getUser(), $order->getId());
}
$this->addFlash('success', $this->translator->trans('Orden de cliente solicitada'));
return $this->redirectToRoute('order_index');
}
}
$addresses = null;
if($order->getState()==7 and $order->getPart()){
$addresses = $em->createQueryBuilder()
->select('ca')
->from(CompanyAddress::class,'ca')
->where("ca.company = {$order->getPart()->getSupplier()->getCompany()->getId()}")
->orderBy('ca.name', 'ASC')->getQuery()->getResult();
}
$prototypes = null;
$canCreateProto = true;
if($order->getType() == 2) {
$prototypes = $em->getRepository(Part::class)->findBy(['prototypeOrder'=>$order->getId()]);
if($prototypes) {
foreach ($prototypes as $prototype) {
if($prototype->getPrototypeStatus() != Part::REFUSED ) {
$canCreateProto = false;
}
}
}
}
return $this->render('order/show.html.twig', [
'order' => $order,
'cs' => $em->getRepository(CompanySupplier::class)->findOneBy(['company'=>$company,'supplier'=>$order->getSupplier()]),
'user' => $user,
'fileMaxsizes' => $fileMaxsizes,
'form' => $form ? $form->createView() : null,
'formBudget' => $formBudget->createView(),
'formFiles' => $formFiles->createView(),
'addresses' => $addresses,
'navbarTitle' => $this->translator->trans("Orden de trabajo").' - '.$order->getRef(),
'prototypes' => $prototypes,
'canCreateProto' => $canCreateProto
]);
}
/**
* @Route({"en": "/edit/{id}/{part}",
* "es": "/editar/{id}/{part}"}, name="order_edit", methods={"GET","POST"})
*/
public function edit(Request $request, Order $order, Part $part): Response
{
$this->denyAccessUnlessGranted(OrderVoter::EDIT, $order);
$admin = $this->getUser();
$form = $this->createForm(OrderType::class, $order, ['user_admin' => $admin, 'part' => $part]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$order->markAsAproved();
$this->em->flush();
$this->addFlash('success', $this->translator->trans('Orden editada correctamente'));
return $this->redirectToRoute('order_index');
}
return $this->render('order/edit.html.twig', [
'order' => $order,
'form' => $form->createView(),
'user' => $this->getUser(),
'navbarTitle' => $this->translator->trans("Editar orden").' - '.$order->getRef()
]);
}
/**
* @Route({"en": "/accept/{id}",
* "es": "/aceptar/{id}"}, name="order_accept", methods={"POST"})
*/
public function accept(Request $request, MailerInterface $mailer, Order $order, OrderRepository $orderRepository): Response
{
$this->denyAccessUnlessGranted(OrderVoter::ACCEPT, $order);
if ($this->isCsrfTokenValid('accept'.$order->getId(), $request->request->get('_token'))) {
$entityManager = $this->em;
$user = $this->getUser();
$role = $user->getRole();
$currentState = $order->getState();
if(!in_array($order->getState(),[1,2])){
$this->addFlash('danger', $this->translator->trans('El presupuesto ya estaba aceptado'));
return $this->redirectToRoute('order_index');
}
if($order->getState()==2 && $order->getChiefConfirm() && $role=='ROLE_USER'){
$this->addFlash('danger', $this->translator->trans('Requiere confirmación del usuario administrador'));
return $this->redirectToRoute('order_index');
}
$state = $order->getState() == 1 ? 2 : 3;
// we dont want that a client use basket
if($role=='ROLE_CLIENT') {
$state = 3;
}
$acceptRef=null;
if($state==3){
$acceptRef = $orderRepository->getNewAcceptRef($order->getCompany());
}
$order->setState($state);
$order->setAcceptRef($acceptRef);
$order->markAsAproved();
$order->setApproveDate(new \DateTime());
if($role=='ROLE_USER'){
$order->setApproveUserUser($user);
$order->setApproveUserDate(new \DateTime());
}
else{
$order->setApproveChiefUser($user);
$order->setApproveChiefDate(new \DateTime());
}
$entityManager->persist($order);
$entityManager->flush();
if($state==3 && $order->getType() == 1){
try {
//Si existen archivos encriptados se les asignan los grants correspondientes
$this->encryptDecryptService->encryptPartGrants($order->getPart(), $order->getUnits());
} catch (\Exception $e) {
$this->addFlash('warning', $e->getMessage());
}
}
$adminEmail = $this->em->getRepository(User::class)->findOneBy(['role' => 'ROLE_ADMIN'])->getEmail();
$email = (new TemplatedEmail())
->from(new Address($this->emailApp, 'Addvance3D'))
->to($order->getUser()->getEmail())
->bcc($adminEmail)
->subject('Orden de trabajo aceptada')
->htmlTemplate('order/email/acceptedEmail.html.twig')
->context([
'order' => $order,
'user' => $user
]);
$mailer->send($email);
$this->addFlash('success', $this->translator->trans('Presupuesto aceptado'));
$data['message']='Presupuesto aceptado';
$data['reference']=$order->getRef();
$data['path_name']='order_show';
$data['path_parameters']='id:'.$order->getId();
//Notificaciones - cliente
$this->util->notifications($order->getCompany(), 3, $data, $this->getUser(), $order->getId());
if($order->getCompany()!=$order->getSupplier()->getCompany() && $state==3){
//Notificaciones - proveedor
$this->util->notifications($order->getSupplier()->getCompany(), 3, $data, $this->getUser(), $order->getId());
}
}
return $this->redirectToRoute('order_index');
}
/**
* @Route({"en": "/accept/supplier/{id}",
* "es": "/aceptar/proveedor/{id}"}, name="order_accept_supplier", methods={"POST"})
*/
public function acceptSupplier(Request $request, MailerInterface $mailer, Order $order, OrderRepository $orderRepository): Response
{
$this->denyAccessUnlessGranted(OrderVoter::ACCEPT_SUPPLIER, $order);
if ($this->isCsrfTokenValid('accept'.$order->getId(), $request->request->get('_token'))) {
$entityManager = $this->em;
$user = $this->getUser();
$role = $user->getRole();
$currentState = $order->getState();
if ($currentState==0)
{
$acceptRef = $orderRepository->getNewAcceptRef($order->getCompany());
$order->setState(3);
$order->setAcceptRef($acceptRef);
$order->markAsAproved();
$order->setApproveSupplierUser($user);
$order->setApproveSupplierDate(new \DateTime());
$order->setApproveDate(new \DateTime());
$entityManager->persist($order);
$entityManager->flush();
try {
//Si existen archivos encriptados se les asignan los grants correspondientes para fabricacion
if($order->getType() == 1) {
$this->encryptDecryptService->encryptPartGrants($order->getPart(), $order->getUnits());
}
} catch (\Exception $e) {
$this->addFlash('warning', $e->getMessage());
}
$adminEmail = $this->em->getRepository(User::class)->findOneBy(['role' => 'ROLE_ADMIN'])->getEmail();
$email = (new TemplatedEmail())
->from(new Address($this->emailApp, 'Addvance3D'))
->to($adminEmail)
->addTo($order->getUser()->getEmail())
->subject('Orden de trabajo aceptada')
->htmlTemplate('order/email/acceptedEmail.html.twig')
->context([
'order' => $order,
'user' => $user
]);
$mailer->send($email);
$this->addFlash('success', $this->translator->trans('Orden de trabajo aceptada'));
$data['message']='Orden de trabajo aceptada';
$data['reference']=$order->getRef();
$data['path_name']='order_show';
$data['path_parameters']='id:'.$order->getId();
//Notificaciones - cliente
$this->util->notifications($order->getCompany(), 3, $data, $this->getUser(), $order->getId());
if($order->getCompany()!=$order->getSupplier()->getCompany()){
//Notificaciones - proveedor
$this->util->notifications($order->getSupplier()->getCompany(), 3, $data, $this->getUser(), $order->getId());
}
}else{
$this->addFlash('danger', $this->translator->trans('La orden de trabajo ya estaba aceptada'));
}
}
return $this->redirectToRoute('order_index');
}
/**
* @Route({"en": "/reject/{id}",
* "es": "/rechazar/{id}"}, name="order_reject", methods={"POST"})
*/
public function reject(Request $request, MailerInterface $mailer, Order $order): Response
{
$this->denyAccessUnlessGranted(OrderVoter::REJECT, $order);
if ($this->isCsrfTokenValid('reject'.$order->getId(), $request->request->get('_token'))) {
$entityManager = $this->em;
$user = $this->getUser();
$role = $user->getRole();
$currentState = $order->getState();
if ($currentState!=6)
{
$order->setState(6);
$order->markAsAproved();
$order->setRejectUser($user);
$order->setRejectDate(new \DateTime());
$entityManager->persist($order);
$entityManager->flush();
$adminEmail = $this->em->getRepository(User::class)->findOneBy(['role' => 'ROLE_ADMIN'])->getEmail();
$email = (new TemplatedEmail())
->from(new Address($this->emailApp, 'Addvance3D'))
->to($adminEmail)
->addTo($order->getUser()->getEmail())
->subject('Orden de trabajo rechazada')
->htmlTemplate('order/email/rejectedEmail.html.twig')
->context([
'order' => $order,
]);
$mailer->send($email);
$this->addFlash('success', $this->translator->trans('Presupuesto rechazado'));
$data['message']='Presupuesto rechazado';
$data['reference']=$order->getRef();
$data['path_name']='order_show';
$data['path_parameters']='id:'.$order->getId();
//Notificaciones - cliente
$this->util->notifications($order->getCompany(), 3, $data, $this->getUser(), $order->getId());
if($order->getCompany()!=$order->getSupplier()->getCompany()){
//Notificaciones - proveedor
$this->util->notifications($order->getSupplier()->getCompany(), 3, $data, $this->getUser(), $order->getId());
}
}else{
$this->addFlash('danger', $this->translator->trans('El presupuesto ya estaba rechazado'));
}
}
return $this->redirectToRoute('order_index');
}
/**
* @Route("/bulk/accept_reject", name="order_bulk_accept_reject", methods={"POST"})
*/
public function bulk(Request $request, MailerInterface $mailer, OrderRepository $orderRepository): Response
{
if ($this->isCsrfTokenValid('bulk_accept_reject', $request->request->get('_token'))) {
$em = $this->em;
$user = $this->getUser();
$role = $user->getRole();
$state = $request->request->get('type') == 1 ? 3 : 6;
$orders = explode(',',$request->request->get('orders'));
if ($this->isGranted('ROLE_USER') && !empty($state) && !empty($orders))
{
$lastSupplierId=null;
$acceptRef=null;
$ordersRef=[];
foreach($orders as $oid){
$order = $em->getRepository(Order::class)->find($oid);
$order->setState($state);
$order->markAsAproved();
if($state==3){
$order->setApproveDate(new \DateTime());
if($role=='ROLE_USER'){
$order->setApproveUserUser($user);
$order->setApproveUserDate(new \DateTime());
}
else{
$order->setApproveChiefUser($user);
$order->setApproveChiefDate(new \DateTime());
}
}
else{
$order->setRejectUser($user);
$order->setRejectDate(new \DateTime());
}
if($state==3 && empty($acceptRef)){
$acceptRef = $orderRepository->getNewAcceptRef($order->getCompany());
}
$order->setAcceptRef($acceptRef);
if(empty($lastSupplierId)){
$lastSupplierId = $order->getSupplier()->getId();
}
elseif($lastSupplierId != $order->getSupplier()->getId()){
$lastSupplierId = null;
break;
}
$ordersRef[]=$order->getRef();
}
if(!empty($lastSupplierId)){
$em->flush();
if($state==3){
foreach($orders as $oid){
$order = $em->getRepository(Order::class)->find($oid);
try {
//Si existen archivos encriptados se les asignan los grants correspondientes
if($order->getType() == 1) {
$this->encryptDecryptService->encryptPartGrants($order->getPart(), $order->getUnits());
}
} catch (\Exception $e) {
$this->addFlash('warning', $e->getMessage());
}
}
}
$subject = $msgFlash = $state==3 ? 'Presupuestos aceptados' : 'Presupuestos rechazados';
$msgType = $state==3 ? 'aprobado' : 'rechazado';
$msg = "El usuario {$user->getName()} {$user->getSurname()} ha $msgType los siguientes presupuestos : ";
$msg.='<ul>';
foreach($ordersRef as $ref){
$msg.="<li>$ref</li>";
}
$msg.='</ul>';
$adminEmail = $this->em->getRepository(User::class)->findOneBy(['role' => 'ROLE_ADMIN'])->getEmail();
$email = (new TemplatedEmail())
->from(new Address($this->emailApp, 'Addvance3D'))
->to($adminEmail)
->subject($this->translator->trans($subject))
->htmlTemplate('order/email/bulkAcceptedRejectedEmail.html.twig')
->context([
'msg' => $msg,
'user' => $user
]);
$mailer->send($email);
$this->addFlash('success', $this->translator->trans($msgFlash));
$data['message']=$msgFlash;
//Notificaciones - cliente
$this->util->notifications($order->getCompany(), 3, $data, $this->getUser(), $order->getId());
if($order->getCompany()!=$order->getSupplier()->getCompany()){
//Notificaciones - proveedor
$this->util->notifications($order->getSupplier()->getCompany(), 3, $data, $this->getUser(), $order->getId());
}
}
else{
$this->addFlash('danger', $this->translator->trans('No se pueden aceptar/rechazar presupuestos de distintos centros de trabajo de forma masiva'));
}
}else{
$this->addFlash('danger', $this->translator->trans('Error inesperado'));
}
}
return $this->redirectToRoute('order_shopping');
}
/**
* @Route({"en": "/send/{id}",
* "es": "/enviar/{id}"}, name="order_send", methods={"POST"})
*/
public function send(Request $request, MailerInterface $mailer, Order $order): Response
{
$this->denyAccessUnlessGranted(OrderVoter::SEND, $order);
if ($this->isCsrfTokenValid('send'.$order->getId(), $request->request->get('_token'))) {
$entityManager = $this->em;
$user = $this->getUser();
$role = $user->getRole();
$currentState = $order->getState();
if ($currentState!=4)
{
$order->setState(4);
$order->markAsAproved();
$order->setSendUser($user);
$order->setSendDate(new \DateTime());
$entityManager->persist($order);
$entityManager->flush();
$this->addFlash('success', $this->translator->trans('Orden de trabajo enviada'));
$data['message']='Orden de trabajo enviada';
$data['reference']=$order->getRef();
$data['path_name']='order_show';
$data['path_parameters']='id:'.$order->getId();
//Notificaciones - cliente
$this->util->notifications($order->getCompany(), 3, $data, $this->getUser(), $order->getId());
if($order->getCompany()!=$order->getSupplier()->getCompany()){
//Notificaciones - proveedor
$this->util->notifications($order->getSupplier()->getCompany(), 3, $data, $this->getUser(), $order->getId());
}
}else{
$this->addFlash('danger', $this->translator->trans('La orden de trabajo ya estaba enviada'));
}
}
return $this->redirectToRoute('order_index');
}
/**
* @Route({"en": "/complete/{id}",
* "es": "/completar/{id}"}, name="order_complete", methods={"POST"})
*/
public function complete(Request $request, MailerInterface $mailer, Order $order): Response
{
$this->denyAccessUnlessGranted(OrderVoter::COMPLETE, $order);
if ($this->isCsrfTokenValid('complete'.$order->getId(), $request->request->get('_token'))) {
$em = $this->em;
$user = $this->getUser();
$cs = $em->getRepository(CompanySupplier::class)->findOneBy(['company'=>$order->getCompany(),'supplier'=>$order->getSupplier()]);
$configInDelivery = $cs ? $cs->getConfigStepInDelivery() : true;
if ($order->getState() == 4 || ($order->getState()==3 && !$configInDelivery))
{
$order->setState(5);
$order->markAsCompleted();
$order->setCompleteUser($user);
$order->setCompleteDate(new \DateTime());
$em->persist($order);
$em->flush();
$adminEmail = $this->em->getRepository(User::class)->findOneBy(['role' => 'ROLE_ADMIN'])->getEmail();
$email = (new TemplatedEmail())
->from(new Address($this->emailApp, 'Addvance3D'))
->to($adminEmail)
->subject('Orden de trabajo completada')
->htmlTemplate('order/email/completedEmail.html.twig')
->context([
'order' => $order,
]);
if($order->getType()== 2) {
$prototype = $em->getRepository(Part::class)->findOneBy(array('prototypeOrder' => $order->getId(),'prototypeStatus' => Part::UNDER_VALIDATION));
$part = clone ($prototype);
$part->setType(1);
$part->setName($order->getPrototypeName());
$part->setSupplier(null);
$em->persist($part);
$prototype->setPrototypeStatus(Part::VALIDATED);
$em->persist($prototype);
$em->flush();
}
$mailer->send($email);
$this->addFlash('success', $this->translator->trans('Orden de trabajo completada'));
$data['message']='Orden de trabajo completada';
$data['reference']=$order->getRef();
$data['path_name']='order_show';
$data['path_parameters']='id:'.$order->getId();
//Notificaciones - cliente
$this->util->notifications($order->getCompany(), 3, $data, $this->getUser(), $order->getId());
if($order->getCompany()!=$order->getSupplier()->getCompany()){
//Notificaciones - proveedor
$this->util->notifications($order->getSupplier()->getCompany(), 3, $data, $this->getUser(), $order->getId());
}
}else{
$this->addFlash('danger', $this->translator->trans('La orden debe estar en entrega'));
}
}
return $this->redirectToRoute('order_index');
}
/**
* @Route({"en": "/delete/{id}",
* "es": "/borrar/{id}"}, name="order_delete", methods={"DELETE"})
*/
public function delete(Request $request, Order $order): Response
{
$this->denyAccessUnlessGranted(OrderVoter::DELETE, $order);
if ($this->isCsrfTokenValid('delete'.$order->getId(), $request->request->get('_token'))) {
$rmOrder = $this->rmOrder($order);
if($rmOrder['error']){
$this->addFlash('danger', $rmOrder['msg']);
}
else{
$this->addFlash('success', $this->translator->trans('Orden eliminada correctamente'));
}
}
return $this->redirectToRoute('order_index');
}
private function rmOrder(Order $order){
$em = $this->em;
$result = ['error'=>false,'msg'=>''];
try {
$em->remove($order);
$em->flush();
} catch (ForeignKeyConstraintViolationException $e) {
$result = ['error'=>true, 'msg'=>$this->translator->trans('No se puede eliminar una orden asociada')];
}
return $result;
}
/**
* @Route({"en": "/shopping",
* "es": "/cesta"}, name="order_shopping", methods={"GET"})
*/
public function shopping(Request $request, OrderRepository $orderRepository): Response
{
$admin =$this->getUser();
if($admin == NULL){
return $this->redirectToRoute('app_login');
}
$orders = $orderRepository->getShoppingCar($admin);
return $this->render('order/shopping.html.twig', [
'orders' => $orders,
'navbarTitle' => $this->translator->trans("Cesta")
]);
}
/**
* @Route("/chat/message", name="order_chat_message", methods={"POST"})
*/
public function chatMessage(Request $request, MailerInterface $mailer, OrderRepository $orderRepository): JsonResponse
{
$result = ['error'=>false,'msg'=>'','data'=>[]];
$em = $this->em;
$user = $this->getUser();
$type = $request->request->get('type',1); //1:Read, 2:Send/read
$message = $request->request->get('message');
$oid = $request->request->get('oid');
if (empty($oid) || empty($user))
{
$result = ['error'=>true,'msg'=>$this->translator->trans("Error inesperado")];
}
elseif($type==2 && empty($message)){
$result = ['error'=>true,'msg'=>$this->translator->trans("El mensaje no puede estar vacío")];
}
else{
$order = $em->getRepository(Order::class)->find($oid);
if(empty($order)){
$result = ['error'=>true,'msg'=>$this->translator->trans("Error inesperado")];
}
else{
if($type==2){
$om = new OrderMessage();
$om->setOrder($order);
$om->setUser($user);
$om->setDateAdded(new \DateTime());
$om->setMessage($message);
$em->persist($om);
$em->flush();
$messages = $em->getRepository(OrderMessage::class)->findBy(['order_'=>$order,'user'=>$user],['date_added'=>'DESC'],2);
if(count($messages)<2 || ($messages[0]->getDateAdded()->format('U') - $messages[1]->getDateAdded()->format('U') > 300)){
$data['message']='Nuevo mensaje de chat';
$data['reference']=$order->getRef();
$data['path_name']='order_show';
$data['path_parameters']='id:'.$order->getId();
if($user->getCompany()->getType()==2){
//Msg generado por proveedor, Notificaciones - cliente
$this->util->notifications($order->getCompany(), 3, $data, $this->getUser(), $order->getId());
}
else{
//Msg generado por proveedor, Notificaciones - proveedor
$this->util->notifications($order->getSupplier()->getCompany(), 3, $data, $this->getUser(), $order->getId());
}
}
}
$messages = $qb = $em->createQueryBuilder()
->select('o,u,om')
->from(OrderMessage::class,'om')
->join('om.order_','o')
->join('om.user','u')
->where('om.order_ = :order')
->orderBy('om.date_added','ASC')
->setParameters(['order'=>$order])
->getQuery()->getArrayResult();
$result['data']=$messages;
}
}
return new JsonResponse($result);
}
/**
* @Route({"en": "/export/{id}",
* "es": "/exportar/{id}"}, defaults={"id" = null}, name="order_export", methods={"GET"})
*/
public function export(OrderRepository $orderRepository, Order $order = null)
{
$trans = $this->translator;
if (null !== $order)
{
$filename = $trans->trans("AD2_orden_"). $order->getRef() . '_' . time() . ".xlsx";
}else
{
$filename = $trans->trans("AD2_ordenes_"). time() . ".xlsx";
}
$admin =$this->getUser();
$company = $admin->getCompany();
$colorARGB = $company && $company->getCorporateColor() ? str_replace('#','',$company->getCorporateColor()) : 'DD9933';
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
//$sheet->setTitle('Addvance Users');
$sheet->getCell('A1')->setValue($trans->trans('Referencia orden'));
$sheet->getCell('B1')->setValue($trans->trans('Empresa'));
$sheet->getCell('C1')->setValue($trans->trans('Pieza'));
$sheet->getCell('D1')->setValue($trans->trans('Referencia pieza'));
$sheet->getCell('E1')->setValue($trans->trans('Centro de trabajo'));
$sheet->getCell('F1')->setValue($trans->trans('Unidades'));
$sheet->getCell('G1')->setValue($trans->trans('Estado'));
$sheet->getCell('H1')->setValue($trans->trans('Pedido'));
$sheet->getCell('I1')->setValue($trans->trans('Autor'));
$sheet->getCell('J1')->setValue($trans->trans('Fecha de creación'));
$sheet->getCell('K1')->setValue($trans->trans('Fecha Revisión'));
$sheet->getCell('L1')->setValue($trans->trans('Fecha de finalización'));
$sheet->getCell('M1')->setValue($trans->trans('Observaciones'));
$styleArrayFirstRow = [
'font' => [
'bold' => true,
'color' => array('rgb' => 'FFFFFF'),
]
];
$highestColumn = $sheet->getHighestColumn();
$sheet->getStyle('A1:M1')->applyFromArray($styleArrayFirstRow);
//$sheet->getStyle('A')->applyFromArray($styleArrayFirstRow);
//$sheet->getColumnDimension('A')->setWidth(30);
//$sheet->getStyle('A')->getFont()->setBold(true);
$sheet->getDefaultColumnDimension()->setWidth(30);
$sheet
->getStyle('A1:M1')
->getFill()
->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
->getStartColor()
->setARGB($colorARGB);
if (null!== $order)
{
$sheet->fromArray($orderRepository->generateExport($admin, $order),null, 'A2', true);
}else
{
$sheet->fromArray($orderRepository->generateExport($admin),null, 'A2', true);
}
$writer = new Xlsx($spreadsheet);
$response = new StreamedResponse(
function () use ($writer) {
$writer->save('php://output');
}
);
$response->headers->set('Content-Type', 'application/vnd.ms-excel');
$response->headers->set('Content-Disposition', 'attachment;filename="'.$filename.'"');
$response->headers->set('Cache-Control','max-age=0');
return $response;
}
}