src/Controller/CallcenterController.php line 64

  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Cabecera;
  4. use App\Entity\ClienteBitcubo;
  5. use App\Entity\ClienteEnvioBitcubo;
  6. use App\Entity\Configuracion;
  7. use App\Entity\CabeceraStatus;
  8. use App\Entity\CabeceraLinkdepago;
  9. use App\Entity\Domicilios;
  10. use App\Entity\Lineas;
  11. use App\Entity\Sucursal;
  12. use App\Form\Type\CabeceraType;
  13. use App\Form\Type\Cabecera2Type;
  14. use App\Form\Type\CabeceraEmailLinkdepagoType;
  15. use App\Form\Type\LineasType;
  16. use App\Repository\ArticulosRepository;
  17. use App\Repository\ClientesRepository;
  18. use App\Repository\ClienteBitcuboRepository;
  19. use App\Repository\FavoritoscabRepository;
  20. use App\Repository\LineasRepository;
  21. use App\Repository\ModificadoreslinRepository;
  22. use App\Repository\SucursalRepository;
  23. use App\Service\EstadisticasArticulosService;
  24. use App\Utils\Status;
  25. use App\Utils\Xml;
  26. use Doctrine\ORM\EntityManagerInterface;
  27. use Doctrine\Persistence\ManagerRegistry;
  28. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  29. use Symfony\Component\Filesystem\Filesystem;
  30. use Symfony\Component\Form\Extension\Core\Type\TextType;
  31. use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
  32. use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
  33. use Symfony\Component\Form\Extension\Core\Type\SubmitType;
  34. use Symfony\Component\HttpFoundation\Request;
  35. use Symfony\Component\HttpFoundation\Response;
  36. // use Symfony\Component\HttpFoundation\Session\Session;
  37. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  38. use Symfony\Component\Routing\Annotation\Route;
  39. use App\Controller\Admin\CabeceraCrudController;
  40. use App\Repository\ImpuestosRepository;
  41. use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
  42. use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
  43. use App\Service\ClienteManager;
  44. use App\Service\GlobalPayService;
  45. use App\Service\MailerService;
  46. use App\Service\XmlGeneratorService;
  47. use App\Service\ConectorPlusCatalogService;
  48. use Psr\Log\LoggerInterface;
  49. // use ParagonIE\Halite\KeyFactory;
  50. class CallcenterController extends AbstractController
  51. {
  52.     use Status;
  53.     private $adminUrlGenerator;
  54.     public function __construct(
  55.         private ManagerRegistry $doctrine,
  56.         AdminUrlGenerator $adminUrlGenerator,
  57.         private ConectorPlusCatalogService $catalogService,
  58.         private LoggerInterface $logger,
  59.     ) {
  60.         $this->doctrine $doctrine;
  61.         $this->adminUrlGenerator $adminUrlGenerator;
  62.     }
  63.     #[Route('/'name'callcenter')]
  64.     public function index(Request $request): Response
  65.     
  66.         // $keyPath = $this->getParameter('kernel.project_dir') . '/config/encryption.key';
  67.         // if (file_exists($keyPath)) {
  68.         //     return new Response('La clave de cifrado ya existe. No se generó una nueva clave.', 403);
  69.         // }
  70.         // $encryptionKey = KeyFactory::generateEncryptionKey();
  71.         // KeyFactory::save($encryptionKey, $keyPath);
  72.         // $keyPath = $this->getParameter('encryption_key_path');
  73.         // dd($keyPath);
  74.         $dataFromRequest  $request->get('data');
  75.         $formData = [];
  76.         if ($dataFromRequest) {
  77.             $formData = [
  78.                 'type' => $dataFromRequest['type'], // Usar valores por defecto si las claves no existen
  79.                 'text' => $dataFromRequest['text'] ?? '',
  80.                 'factura_electronica' => $dataFromRequest['fe'] ? true false,
  81.             ];
  82.         }
  83.         if (!array_key_exists('type'$formData)) {
  84.             $formData['type'] = 1;
  85.         }
  86.         $form $this->createFormBuilder($formData)
  87.             ->add('type'ChoiceType::class, [
  88.                 'choices' => [
  89.                     'Telefono' => 1,
  90.                     'Documento' => 2
  91.                 ],
  92.                 'expanded' => true,
  93.                 'multiple' => false,
  94.             ])
  95.             ->add('text'TextType::class)
  96.             ->add('factura_electronica'CheckboxType::class, [
  97.                 'required' => false,
  98.             ])
  99.             ->add('buscar'SubmitType::class)
  100.             ->getForm();
  101.         $form->handleRequest($request);
  102.         if ($form->isSubmitted() && $form->isValid()) {
  103.             $data $form->getData();
  104.             return $this->redirectToRoute(
  105.                 'seleccionCliente',
  106.                 array(
  107.                     'type' => $data['type'],
  108.                     'text' => $data['text'],
  109.                     'fe' => $data['factura_electronica'] ? '1' '0',
  110.                 )
  111.             );
  112.         }
  113.         return $this->render('callcenter/index.html.twig', [
  114.             'form' => $form->createView(),
  115.         ]);
  116.     }
  117.     #[Route('/selecciondecliente/{type}/{text}/{fe}'name'seleccionCliente')]
  118.     public function seleccionCliente(
  119.         int $type,
  120.         string $text,
  121.         string $fe,
  122.         ClientesRepository $clienteRepository,
  123.         ClienteBitcuboRepository $clienteBitcuboRepository,
  124.         SessionInterface $session
  125.     ): Response {
  126.         $data = [
  127.             'type' => $type,
  128.             'text' => $text,
  129.             'fe' => filter_var($feFILTER_VALIDATE_BOOLEAN)
  130.         ];
  131.         $cliente $this->buscarCliente($data$clienteRepository$clienteBitcuboRepository);
  132.         if (empty($cliente)) {
  133.             return $this->manejarClienteNoEncontrado($data$session);
  134.         }
  135.         if (count($cliente) === 1) {
  136.             return $this->manejarClienteUnico($cliente[0], $data['fe'], $session);
  137.         }
  138.         return $this->manejarMultiplesClientes($cliente$data$session);
  139.     }
  140.     private function buscarCliente(array $dataClientesRepository $clienteRepositoryClienteBitcuboRepository $clienteBitcuboRepository): array
  141.     {
  142.         $cliente $clienteRepository->findClient($data);
  143.         if (!$data['fe'] && empty($cliente)) {
  144.             // Buscar en ClienteBitcuboRepository si no hay resultados en ClientesRepository
  145.             if ($data['type'] === 1) {
  146.                 $clienteBitcubo $clienteBitcuboRepository->findBy(['telefonocliente' => $data['text']]);
  147.             } else {
  148.                 $clienteBitcubo $clienteBitcuboRepository->findBy(['nifcliente' => $data['text']]);
  149.             }
  150.             if (!empty($clienteBitcubo)) {
  151.                 $cliente array_map(function($bitcubo) {
  152.                     $ultima_direccion $bitcubo->getDirecciones()->isEmpty() ? null $bitcubo->getDirecciones()->last();
  153.                     return [
  154.                         'codcliente' => $bitcubo->getId(),
  155.                         'nombrecliente' => $bitcubo->getNombres() . ' ' $bitcubo->getApellidos(),
  156.                         // 'apellidos' => $bitcubo->getApellidos(),
  157.                         'telefono1' => $bitcubo->getTelefonocliente(),
  158.                         'emailcliente' => $bitcubo->getEmailcliente(),
  159.                         'nif20' => $bitcubo->getNifcliente(),
  160.                         'alias' => null,
  161.                         'direccion1' => $ultima_direccion $ultima_direccion->getDireccion() : '',
  162.                         'direccion_2' => $ultima_direccion $ultima_direccion->getComplemento() : '',
  163.                         'cl_nombre_1' => $bitcubo->getNombres(),
  164.                         'otros_nombres' => null,
  165.                         'cl_apellido_1' => $bitcubo->getApellidos(),
  166.                         'cl_apellido_2' => null,
  167.                         'tipo_de_documento' => null,
  168.                         'tipopersona' => null,
  169.                         'fe_det_tributario' => null,
  170.                         'fe_responsabilidades' => null,
  171.                         'direcciones_bitcubo' => $bitcubo->getDirecciones(),
  172.                         'es_cliente_bitcubo' => true,
  173.                     ];
  174.                 }, $clienteBitcubo);
  175.             }
  176.         }
  177.         return $cliente;
  178.     }
  179.     private function manejarClienteNoEncontrado(array $dataSessionInterface $session): Response
  180.     {
  181.         if ($data['fe']) {
  182.             $qrRoute 'https://qrmde.crepesywaffles.com/qrcc/qrmde.php';
  183.             $this->addFlash(
  184.                 'notice',
  185.                 'DEBES CREAR EL CLIENTE PRIMERO EN EL QR PARA FACTURA ELECTRÓNICA <a class="alert-link" href="' $qrRoute '" target="_blank">Crear QR</a>'
  186.             );
  187.             return $this->redirectToRoute('callcenter', ['data' => $data]);
  188.         }
  189.         $session->set('clienteData'$data);
  190.         $session->set('fe'$data['fe']);
  191.         // Temporal: redirect a cliente_v2 para probar la nueva versión
  192.         return $this->redirectToRoute('cliente_v2');
  193.     }
  194.     private function manejarClienteUnico(array $clientebool $feSessionInterface $session): Response
  195.     {
  196.         $session->set('clienteData'$cliente);
  197.         $session->set('fe'$fe);
  198.         // Temporal: redirect a cliente_v2 para probar la nueva versión
  199.         return $this->redirectToRoute('cliente_v2');
  200.     }
  201.     private function manejarMultiplesClientes(array $clientes, array $dataSessionInterface $session): Response
  202.     {
  203.         $session->set('clienteData'$clientes);
  204.         return $this->render('callcenter/clienteSelect.html.twig', [
  205.             'clientes' => $clientes,
  206.             'data' => $data
  207.         ]);
  208.     }
  209.         // $feBool = filter_var($fe, FILTER_VALIDATE_BOOLEAN);
  210.         // $data = ['type' => $type, 'text' => $text, 'fe' => $feBool];
  211.         // $cliente = $clienteRepository->findClient($data);
  212.         // if (empty($cliente)) {
  213.         //     if ($feBool) {
  214.         //         $qrRoute = 'https://qrmde.crepesywaffles.com/qrcc/qrmde.php';
  215.         //         $this->addFlash(
  216.         //             'notice',
  217.         //             'DEBES CREAR EL CLIENTE PRIMERO EN EL QR PARA FACTURA ELECTRÓNICA <a class="alert-link" href="' . $qrRoute . '" target="_blank">Crear QR</a>'
  218.         //         );
  219.         //         return $this->redirectToRoute('callcenter', ['data' => $data]);
  220.         //     } else {
  221.         //         $session->set('clienteData', $data); // Guardar en sesión
  222.         //         $session->set('fe', $data['fe']); // Guardar en sesión
  223.         //         return $this->redirectToRoute('cliente');
  224.         //     }
  225.         // } elseif (count($cliente) === 1) {
  226.         //     $session->set('clienteData', $cliente[0]); // Guardar en sesión
  227.         //     $session->set('fe', $data['fe']); // Guardar en sesión
  228.         //     return $this->redirectToRoute('cliente');
  229.         // }
  230.         // $session->set('clienteData', $cliente);
  231.         // return $this->render('callcenter/clienteSelect.html.twig', ['clientes' => $cliente, 'data' => $data]);
  232.     // }
  233.     #[Route('/cliente-v2'name'cliente_v2')]
  234.     public function clienteV2(Request $requestSessionInterface $sessionClienteManager $clienteManagerSucursalRepository $sucursalRepository): Response
  235.     {
  236.         $clienteData $session->get('clienteData');
  237.         $fe $session->get('fe');
  238.         $clienteData $clienteData[$request->get('index')]  ?? $clienteData;
  239.         $cabecera $clienteManager->procesarDatosCliente($clienteData);
  240.         $cabecera->setFacturaelectronica($fe 0);
  241.         if (isset($clienteData['es_cliente_bitcubo'])) {
  242.             $editable false;
  243.         } else {
  244.             $editable = isset($clienteData['alias']) ? !($clienteData['alias'] === "1") : true;
  245.         }
  246.         $form $this->createForm(CabeceraType::class, $cabecera, ['editable_mode' => $editable]);
  247.         $form->handleRequest($request);
  248.         // Obtener sucursales disponibles (solo las que tienen catálogo configurado)
  249.         $sucursales $sucursalRepository->findAvailable();
  250.         if ($form->isSubmitted() && $form->isValid()) {
  251.             // Lógica de guardado
  252.             $entityManager $this->doctrine->getManager();
  253.             if (!isset($clienteData['es_cliente_bitcubo']) and !isset($clienteData['codcliente'])) {
  254.                 // Verificar si ya existe un cliente con el mismo nifcliente para evitar duplicados
  255.                 $cliente_bitcubo $entityManager->getRepository(ClienteBitcubo::class)->findOneBy([
  256.                     'nifcliente' => $cabecera->getNifcliente()
  257.                 ]);
  258.                 if (!$cliente_bitcubo) {
  259.                     // Solo crear si no existe
  260.                     $cliente_bitcubo = new ClienteBitcubo();
  261.                     $cliente_bitcubo->setNombres($cabecera->getNombres());
  262.                     $cliente_bitcubo->setApellidos($cabecera->getApellidos());
  263.                     $cliente_bitcubo->setTelefonocliente($cabecera->getTelefonocliente());
  264.                     $cliente_bitcubo->setEmailcliente($cabecera->getEmailcliente());
  265.                     $cliente_bitcubo->setNifcliente($cabecera->getNifcliente());
  266.                     $entityManager->persist($cliente_bitcubo);
  267.                     $entityManager->flush();
  268.                 }
  269.                 $clienteData['codcliente'] = $cliente_bitcubo->getId();
  270.                 // Agregar dirección si no existe
  271.                 $direccionExistente $entityManager->getRepository(ClienteEnvioBitcubo::class)->findOneBy([
  272.                     'cliente_bitcubo' => $cliente_bitcubo,
  273.                     'direccion' => $cabecera->getDireccionCliente(),
  274.                     'complemento' => $cabecera->getDireccion2Cliente(),
  275.                 ]);
  276.                 if (!$direccionExistente) {
  277.                     $cliente_envio_bitcubo = new ClienteEnvioBitcubo();
  278.                     $cliente_envio_bitcubo->setDireccion($cabecera->getDireccionCliente());
  279.                     $cliente_envio_bitcubo->setComplemento($cabecera->getDireccion2Cliente());
  280.                     $cliente_envio_bitcubo->setLatitud($cabecera->getLatitud());
  281.                     $cliente_envio_bitcubo->setLongitud($cabecera->getLongitud());
  282.                     $cliente_bitcubo->addDireccion($cliente_envio_bitcubo);
  283.                     $entityManager->persist($cliente_envio_bitcubo);
  284.                     $entityManager->flush();
  285.                 }
  286.             } else {
  287.                 $cliente_bitcubo $entityManager->getRepository(ClienteBitcubo::class)->find($clienteData['codcliente']);
  288.                 if ($cliente_bitcubo) {
  289.                     $direccionExistente $entityManager->getRepository(ClienteEnvioBitcubo::class)->findOneBy([
  290.                         'cliente_bitcubo' => $cliente_bitcubo,
  291.                         'direccion' => $cabecera->getDireccionCliente(),
  292.                         'complemento' => $cabecera->getDireccion2Cliente(),
  293.                     ]);
  294.                     if (!$direccionExistente) {
  295.                         $cliente_envio_bitcubo = new ClienteEnvioBitcubo();
  296.                         $cliente_envio_bitcubo->setDireccion($cabecera->getDireccionCliente());
  297.                         $cliente_envio_bitcubo->setComplemento($cabecera->getDireccion2Cliente());
  298.                         $cliente_envio_bitcubo->setLatitud($cabecera->getLatitud());
  299.                         $cliente_envio_bitcubo->setLongitud($cabecera->getLongitud());
  300.                         $cliente_bitcubo->addDireccion($cliente_envio_bitcubo);
  301.                         $entityManager->persist($cliente_envio_bitcubo);
  302.                         $entityManager->flush();
  303.                     }
  304.                 }
  305.             }
  306.             if ($cabecera->getNombreReceptor() === null || $cabecera->getNombreReceptor() === '') {
  307.                 $cabecera->setNombreReceptor($cabecera->getNombrecliente());
  308.             }
  309.             if ($cabecera->getTelefonoReceptor() === null || $cabecera->getTelefonoReceptor() === '') {
  310.                 $cabecera->setTelefonoReceptor($cabecera->getTelefonocliente());
  311.             }
  312.             $clienteManager->guardarCabecera($cabecera$this->getuser());
  313.             return $this->redirectToRoute('cc_favoritos', ['id' => $cabecera->getId()]);
  314.         }
  315.         // Parámetros de tiempo mínimo para reservas (desde config/services/bitcubo.yaml)
  316.         // Se pasan a JavaScript para validación en frontend
  317.         $horareserva $this->getParameter('app.bc.horareserva'); // +60 minutos para DOMICILIO/PROGRAMAR
  318.         $horaclienterecoge $this->getParameter('app.bc.horaclienterecoge'); // +30 minutos para RECOGER
  319.         return $this->render('callcenter/cliente_v2.html.twig', [
  320.             'cliente' => $clienteData,
  321.             'form' => $form->createView(),
  322.             'sucursales' => $sucursales,
  323.             'horareserva' => $horareserva,
  324.             'horaclienterecoge' => $horaclienterecoge,
  325.         ]);
  326.     }
  327.     #[Route('/cliente'name'cliente')]
  328.     public function cliente(Request $requestSessionInterface $sessionClienteManager $clienteManagerSucursalRepository $sucursalRepository): Response
  329.     {
  330.         $clienteData $session->get('clienteData');
  331.         $fe $session->get('fe');
  332.         $clienteData $clienteData[$request->get('index')]  ?? $clienteData;
  333.         $cabecera $clienteManager->procesarDatosCliente($clienteData);
  334.         $cabecera->setFacturaelectronica($fe 0);
  335.         if (isset($clienteData['es_cliente_bitcubo'])) {
  336.             $editable false;
  337.         } else {
  338.             $editable = isset($clienteData['alias']) ? !($clienteData['alias'] === "1") : true;
  339.         }
  340.         $form $this->createForm(CabeceraType::class, $cabecera, ['editable_mode' => $editable]);
  341.         $form->handleRequest($request);
  342.         if ($form->isSubmitted() && $form->isValid()) {
  343.             // Guarda si el cliente es nuevo en cliente_bitcubo
  344.             $entityManager $this->doctrine->getManager();
  345.             if (!isset($clienteData['es_cliente_bitcubo']) and !isset($clienteData['codcliente'])) {
  346.                 // Verificar si ya existe un cliente con el mismo nifcliente para evitar duplicados
  347.                 $cliente_bitcubo $entityManager->getRepository(ClienteBitcubo::class)->findOneBy([
  348.                     'nifcliente' => $cabecera->getNifcliente()
  349.                 ]);
  350.                 if (!$cliente_bitcubo) {
  351.                     // Solo crear si no existe
  352.                     $cliente_bitcubo = new ClienteBitcubo();
  353.                     $cliente_bitcubo->setNombres($cabecera->getNombres());
  354.                     $cliente_bitcubo->setApellidos($cabecera->getApellidos());
  355.                     $cliente_bitcubo->setTelefonocliente($cabecera->getTelefonocliente());
  356.                     $cliente_bitcubo->setEmailcliente($cabecera->getEmailcliente());
  357.                     $cliente_bitcubo->setNifcliente($cabecera->getNifcliente());
  358.                     $entityManager->persist($cliente_bitcubo);
  359.                     $entityManager->flush();
  360.                 }
  361.                 $clienteData['codcliente'] = $cliente_bitcubo->getId();
  362.                 // Agregar dirección si no existe
  363.                 $direccionExistente $entityManager->getRepository(ClienteEnvioBitcubo::class)->findOneBy([
  364.                     'cliente_bitcubo' => $cliente_bitcubo,
  365.                     'direccion' => $cabecera->getDireccionCliente(),
  366.                     'complemento' => $cabecera->getDireccion2Cliente(),
  367.                 ]);
  368.                 if (!$direccionExistente) {
  369.                     $cliente_envio_bitcubo = new ClienteEnvioBitcubo();
  370.                     $cliente_envio_bitcubo->setDireccion($cabecera->getDireccionCliente());
  371.                     $cliente_envio_bitcubo->setComplemento($cabecera->getDireccion2Cliente());
  372.                     $cliente_envio_bitcubo->setLatitud($cabecera->getLatitud());
  373.                     $cliente_envio_bitcubo->setLongitud($cabecera->getLongitud());
  374.                     $cliente_bitcubo->addDireccion($cliente_envio_bitcubo);
  375.                     $entityManager->persist($cliente_envio_bitcubo);
  376.                     $entityManager->flush();
  377.                 }
  378.             } else {
  379.                 $cliente_bitcubo $entityManager->getRepository(ClienteBitcubo::class)->find($clienteData['codcliente']);
  380.                 if ($cliente_bitcubo) {
  381.                     // Verificar si la dirección ya existe para este cliente
  382.                     $direccionExistente $entityManager->getRepository(ClienteEnvioBitcubo::class)->findOneBy([
  383.                         'cliente_bitcubo' => $cliente_bitcubo,
  384.                         'direccion' => $cabecera->getDireccionCliente(),
  385.                         'complemento' => $cabecera->getDireccion2Cliente(),
  386.                     ]);
  387.                     if (!$direccionExistente) {
  388.                         // La dirección no existe, se agrega
  389.                         $cliente_envio_bitcubo = new ClienteEnvioBitcubo();
  390.                         $cliente_envio_bitcubo->setDireccion($cabecera->getDireccionCliente());
  391.                         $cliente_envio_bitcubo->setComplemento($cabecera->getDireccion2Cliente());
  392.                         $cliente_envio_bitcubo->setLatitud($cabecera->getLatitud());
  393.                         $cliente_envio_bitcubo->setLongitud($cabecera->getLongitud());
  394.                         $cliente_bitcubo->addDireccion($cliente_envio_bitcubo);
  395.                         $entityManager->persist($cliente_envio_bitcubo);
  396.                         $entityManager->flush();
  397.                     }
  398.                 }
  399.             }
  400.             if ($cabecera->getNombreReceptor() === null || $cabecera->getNombreReceptor() === '') {
  401.                 $cabecera->setNombreReceptor($cabecera->getNombrecliente());
  402.             }
  403.             if ($cabecera->getTelefonoReceptor() === null || $cabecera->getTelefonoReceptor() === '') {
  404.                 $cabecera->setTelefonoReceptor($cabecera->getTelefonocliente());
  405.             }
  406.             $clienteManager->guardarCabecera($cabecera$this->getuser());
  407.             return $this->redirectToRoute('cc_favoritos', ['id' => $cabecera->getId()]);
  408.         }
  409.         $sucursales $sucursalRepository->findAvailable();
  410.         return $this->render('callcenter/cliente.html.twig', [
  411.             'cliente' => $clienteData,
  412.             'form' => $form->createView(),
  413.             'sucursales' => $sucursales,
  414.         ]);
  415.     }
  416. // Todo cliente nuevo o sin alias 1 debe crearse en bitcubo
  417. // ?? que pasa con la dirección nueva de un cliente con factura electrónica, si pide el mismo día.??
  418. // --------------------
  419. // Top 10: cambiar la forma en la que se graba el codcliente y tener en cuenta los de bitcubo. para poder buscar todas las cabeceras de dicho cliente
  420. //
  421.     #[Route('/cabecera/{id}/editar'name'cliente_editar')]
  422.     public function clienteEdit(SucursalRepository $sucursalRepositoryRequest $requestint $id): Response
  423.     {
  424.         $cabecera $this->doctrine->getRepository(Cabecera::class)->find($id);
  425.         $editable $cabecera->getAlias() === "1" false true;
  426.         if ($cabecera->getAlias() === "1") {
  427.             $editable false;
  428.         } else if($cabecera->getCodcliente()) {
  429.             $editable false;
  430.         } else {
  431.             $editable true;
  432.         }
  433.         if (!$cabecera) {
  434.             throw $this->createNotFoundException(
  435.                 'Cabecera no encontrada'
  436.             );
  437.         }
  438.         $estados = array('INICIADO''EDICION');
  439.         if (!in_array($cabecera->getEstado(), $estados)) {
  440.             throw $this->createNotFoundException(
  441.                 'NO SE PUEDE EDITAR ESTE PEDIDO'
  442.             );
  443.         }
  444.         $sucursales $sucursalRepository->findAvailable();
  445.         $form $this->createForm(CabeceraType::class, $cabecera, ['editable_mode' => $editable]);
  446.         $form->handleRequest($request);
  447.         if ($form->isSubmitted() && $form->isValid()) {
  448.             $cabecera $form->getData();
  449.             $entityManager $this->doctrine->getManager();
  450.             $entityManager->persist($cabecera);
  451.             $entityManager->flush();
  452.             return $this->redirectToRoute('cc_favoritos', [
  453.                 'id' => $cabecera->getId()
  454.             ]);
  455.         }
  456.         return $this->render('callcenter/cliente_v2.html.twig', [
  457.             'cliente' => $cabecera,
  458.             'form' => $form->createView(),
  459.             'sucursales' => $sucursales,
  460.         ]);
  461.     }
  462.     #[Route('/cabecera/{id}/favoritos'name'cc_favoritos')]
  463.     public function favoritos(int $id): Response {
  464.         // Redireccionar al nuevo método del OrderController
  465.         // que maneja el catálogo por sucursal
  466.         return $this->redirectToRoute('cc_pedido_v2', ['id' => $id]);
  467.     }
  468.     // #[Route('/cabecera/{id}/favoritos', name: 'cc_favoritos')]
  469.     // public function favoritos(
  470.     //     ArticulosRepository $articulosRepository,
  471.     //     EstadisticasArticulosService $estadisticasService,
  472.     //     FavoritoscabRepository $favoritoscab,
  473.     //     Request $request,
  474.     //     int $id
  475.     // ): Response {
  476.     //     $cabecera = $this->doctrine
  477.     //         ->getRepository(Cabecera::class)
  478.     //         ->find($id);
  479.     //     if (!$cabecera) {
  480.     //         throw $this->createNotFoundException(
  481.     //             'Pedido no encontrado'
  482.     //         );
  483.     //     }
  484.     //     if ($cabecera->getIsFinalizada()) {
  485.     //         throw $this->createNotFoundException(
  486.     //             'Pedido finalizado'
  487.     //         );
  488.     //     }
  489.     //     $status = array('INICIADO', 'PROGRAMADO', 'EDICION');
  490.     //     if (!in_array($cabecera->getEstado(), $status)) {
  491.     //         throw $this->createNotFoundException(
  492.     //             'Este pedido no se puede editar'
  493.     //         );
  494.     //     }
  495.     //     //log
  496.     //     if ($cabecera->getEstado() == 'PROGRAMADO') {
  497.     //         $entityManager = $this->doctrine->getManager();
  498.     //         $status = $this->createStatus($cabecera, 'EDICION', $this->getUser());
  499.     //         $entityManager->persist($status);
  500.     //         $entityManager->flush();
  501.     //     }
  502.     //     //log
  503.     //     $favoritos = $favoritoscab->findAllByTerminal(10);
  504.     //     $sucursal = $this->doctrine
  505.     //         ->getRepository(Sucursal::class)
  506.     //         ->findOneBy(array('nombre' => $cabecera->getSucursal()));
  507.     //     $sucursal = $sucursal->getCodalmvent() ?? '';
  508.     //     $top_ids_articulos = $estadisticasService->obtenerIdsTopArticulos(
  509.     //         $cabecera->getNifcliente(),
  510.     //         $cabecera->getTelefonocliente(),
  511.     //     );
  512.     //     if(!empty($top_ids_articulos)){
  513.     //         $top_articulos = $estadisticasService->obtenerTopArticulos(
  514.     //             $top_ids_articulos,
  515.     //             $sucursal,
  516.     //         );
  517.     //     } else {
  518.     //         $top_articulos = [];
  519.     //     }
  520.     //     return $this->render('callcenter/pedido_v2.html.twig', [
  521.     //         'favoritos' => $favoritos,
  522.     //         'cabecera' => $cabecera,
  523.     //         'top' => $top_articulos,
  524.     //     ]);
  525.     // }
  526.     #[Route('/load-modal'name'load_modal'methods: ['GET'])]
  527.     public function loadModal(ArticulosRepository $articulosRepositoryRequest $request): Response
  528.     {
  529.         // Obtenemos el tipo de modal desde el request (en lugar de pasar directamente la plantilla)
  530.         $modalType $request->query->get('modalType''default');
  531.         $data = [];
  532.         // Definimos diferentes plantillas según el tipo de modal
  533.         switch ($modalType) {
  534.             case 'search':
  535.                 $template 'callcenter/search_modal.html.twig';
  536.                 break;
  537.             case 'top':
  538.                 // $top_articulos = $articulosRepository->findArticulosByFavorito(80098823, 'POBLADO');
  539.                 $template 'callcenter/top_modal.html.twig';
  540.                 break;
  541.             default:
  542.                 $template 'callcenter/default_modal.html.twig';
  543.         }
  544.         return $this->render($template$data);
  545.     }
  546.     // #[Route('/buscar-productos-modal', name: 'buscar_productos_modal', methods: ['GET'])]
  547.     // public function loadModal(): Response
  548.     // {
  549.     //     return $this->render('callcenter/search_modal.html.twig');
  550.     // }
  551.     #[Route('/buscar-productos'name'buscar_productos'methods: ['GET'])]
  552.     public function buscarProductos(ArticulosRepository $articulosRepositoryRequest $request): Response
  553.     {
  554.         $query $request->query->get('query');
  555.         $sucursal $this->doctrine
  556.             ->getRepository(Sucursal::class)
  557.             ->findOneBy(array('nombre' => $request->query->get('sucursal')));
  558.         $sucursal $sucursal->getCodalmvent() ?? '';
  559.         $articulos $articulosRepository->findArticulosByName($query$sucursal);
  560.         return $this->render('callcenter/search_results.html.twig', [
  561.             'articulos' => $articulos,
  562.             'query' => strtoupper($request->query->get('query')),
  563.         ]);
  564.     }
  565.     #[Route('/articulos'name'cc_articulos')]
  566.     public function articulos(ArticulosRepository $articulosRepositoryRequest $request): Response
  567.     {
  568.         // $template = $request->query->get('ajax') ? '_articulos.html.twig' : 'fav.html.twig';
  569.         $favorito $request->query->get('fav');
  570.         $sucursal $this->doctrine
  571.             ->getRepository(Sucursal::class)
  572.             ->findOneBy(array('nombre' => $request->query->get('sucursal')));
  573.         // $sucursal = $sucursal ? $sucursal->getCodalmvent() : '';
  574.         $sucursal $sucursal->getCodalmvent() ?? '';
  575.         $articulos $articulosRepository->findArticulosByFavorito($favorito$sucursal);
  576.         return $this->render('callcenter/_articulos.html.twig', [
  577.             'articulos' => $articulos,
  578.         ]);
  579.     }
  580.     #[Route('/articulo'name'cc_articulo')]
  581.     public function articulo(ArticulosRepository $articulosRepositoryRequest $request): Response
  582.     {
  583.         $id $request->query->get('codarticulo');
  584.         $fav $request->query->get('fav');
  585.         $articulo $articulosRepository->findArticulo($id$fav);
  586.         if (!$articulo) {
  587.             throw $this->createNotFoundException(
  588.                 'Artículo no encontrado'
  589.             );
  590.         }
  591.         $modsbyarticulo $articulosRepository->findModificadoresByArticulo($id);
  592.         $mods = array();
  593.         foreach ($modsbyarticulo as $item) {
  594.             $mods[] = $articulosRepository->findModificadores($item['codmodificador']);
  595.         }
  596.         $inicialstate $articulosRepository->validadorArticulos($modsbyarticulo);
  597.         return $this->render('callcenter/_articulo.html.twig', [
  598.             'articulo' => $articulo,
  599.             'modsbyarticulo' => $modsbyarticulo,
  600.             'mods' => $mods,
  601.             'jsonmodsbyarticulo' => json_encode($modsbyarticulo),
  602.             'jsonmods' => json_encode($mods),
  603.             'inicialstate' => $inicialstate,
  604.         ]);
  605.     }
  606.     #[Route('/crearlistas'name'cc_crearlistas')]
  607.     public function crearlistas(ArticulosRepository $articulosRepositoryModificadoreslinRepository $mlinRepositoryRequest $requestEntityManagerInterface $entityManager): response
  608.     {
  609.         $cabeceraId $request->query->get('cabecera');
  610.         $parentId $request->query->get('parent');
  611.         $q intval($request->query->get('q'));
  612.         $fav $request->query->get('fav');
  613.         $childs explode(","$request->query->get('childs'));
  614.         $modcabs explode(","$request->query->get('modcabs'));
  615.         $cabecera $entityManager->getRepository(Cabecera::class)->find($cabeceraId);
  616.         $parent $articulosRepository->findArticulo($parentId$fav);
  617.         // Crear línea principal y líneas hijas
  618.         $parentLine $this->createParentLine($cabecera$parent$q$fav);
  619.         $entityManager->persist($parentLine);
  620.         $childTotalPrice 0;
  621.         if (!empty($childs[0])) {
  622.             $childTotalPrice $this->createChildLines($childs$modcabs$parent$q$parentLine$mlinRepository$entityManager);
  623.         }
  624.         // Actualizar totales en línea principal y Cabecera
  625.         $this->updateParentLineTotal($parentLine$childTotalPrice);
  626.         $this->updateCabeceraTotals($cabecera$parentLine$childTotalPrice);
  627.         $entityManager->flush();
  628.         return $this->render('callcenter/_lineas.html.twig', [
  629.             'cabecera' => $cabecera,
  630.         ]);
  631.     }
  632.     private function createParentLine($cabecera$parent$q$fav): Lineas
  633.     {
  634.         $linePrice $parent['pneto'] * $q;
  635.         $line = new Lineas();
  636.         $line->setCabecera($cabecera);
  637.         $line->setCodarticulo($parent['codarticulo']);
  638.         $line->setDescripcion($parent['descripcion']);
  639.         $line->setPrecio($linePrice);
  640.         $line->setPreciounidad($parent['pneto']);
  641.         $line->setPreciototal($parent['pneto']);
  642.         $line->setUnidades($q);
  643.         $line->setCodfavoritos($fav);
  644.         $line->setCodImpuesto($parent['tipoiva']);
  645.         $parentPriceWithoutTax $this->calcularPrecioSinImpuesto($linePrice$line->getCodImpuesto());
  646.         $line->setPreciosiniva($parentPriceWithoutTax);
  647.         return $line;
  648.     }
  649.     private function createChildLines($childs$modcabs$parent$q$parentLine$mlinRepositoryEntityManagerInterface $entityManager): float
  650.     {
  651.         $parentLine->setNumlineasmodif(count($childs));
  652.         $childTotalPrice 0;
  653.         $childData = [];
  654.         foreach ($childs as $key => $child) {
  655.             $childArticle $mlinRepository->findModificador($child$parent['codarticulo'], $modcabs[$key]);
  656.             $linePrice $childArticle['incprecio'] * $q;
  657.             // Almacena toda la información relevante
  658.             $childData[] = [
  659.                 'childArticle' => $childArticle,
  660.                 'linePrice' => $linePrice,
  661.                 'quantity' => $q,
  662.             ];
  663.         }
  664.         usort($childData, function ($a$b) {
  665.             return $a['childArticle']['posicion'] - $b['childArticle']['posicion'];
  666.         });
  667.         foreach ($childData as $data) {
  668.             $childArticle $data['childArticle'];
  669.             $linePrice $data['linePrice'];
  670.             $q $data['quantity'];
  671.             $line = new Lineas();
  672.             $line->setCabecera($parentLine->getCabecera());
  673.             $line->setParent($parentLine);
  674.             $line->setCodarticulo($childArticle['codarticulocom']);
  675.             $line->setDescripcion($childArticle['descripcion']);
  676.             $line->setPrecio($linePrice);
  677.             $line->setUnidades($q);
  678.             $line->setNumlineasmodif(null);
  679.             $line->setCodImpuesto($childArticle['tipoiva']);
  680.             $line->setPreciosiniva($this->calcularPrecioSinImpuesto($linePrice$childArticle['tipoiva']));
  681.             $line->setPosicion($childArticle['posicion']);
  682.             $childTotalPrice += $linePrice;
  683.             $entityManager->persist($line);
  684.         }
  685.         // $entityManager->flush();
  686.         return $childTotalPrice;
  687.     }
  688.     private function updateParentLineTotal($parentLinefloat $childTotalPrice): void
  689.     {
  690.         // $parentLine->setPreciototal($parentLine->getPrecio() + $childTotalPrice);
  691.         $totalPrice $parentLine->getPrecio() + $childTotalPrice;
  692.         $parentLine->setPreciototal($totalPrice);
  693.         $parentPriceWithoutTax $this->calcularPrecioSinImpuesto($totalPrice$parentLine->getCodImpuesto());
  694.         $parentLine->setPreciosiniva($parentPriceWithoutTax);
  695.     }
  696.     private function updateCabeceraTotals($cabecera$parentLinefloat $childTotalPrice): void
  697.     {
  698.         $cabecera->setTotal($cabecera->getTotal() + $parentLine->getPrecio() + $childTotalPrice);
  699.         $cabecera->setTotalsiniva($cabecera->getTotalsiniva() + $parentLine->getPreciosiniva());
  700.         // $cabecera->setTotalsiniva($cabecera->getTotalsiniva() + $parentLine->getPreciosiniva() + $this->calcularPrecioSinImpuesto($childTotalPrice, $parentLine->getCodImpuesto()));
  701.     }
  702.     private function calcularPrecioSinImpuesto($precioConImpuesto$porcentajeImpuesto)
  703.     {
  704.         return $precioConImpuesto / (+ ($porcentajeImpuesto 100));
  705.     }
  706.     #[Route('/agregarcomentario/{parent}'name'cc_agregarcomentario')]
  707.     public function addComent(EntityManagerInterface $emLineasRepository $lRequest $requestint $parent): response
  708.     {
  709.         $p $l->findOneBy(['id' => $parent]);
  710.         $linea = new Lineas;
  711.         $form $this->createForm(LineasType::class, $linea);
  712.         $form->handleRequest($request);
  713.         if ($form->isSubmitted() && $form->isValid()) {
  714.             $linea $form->getData();
  715.             $linea->setCodarticulo(0);
  716.             $linea->setPrecio(0);
  717.             $linea->setCodfavoritos(0);
  718.             // $linea->setParent($p);
  719.             $linea->setCabecera($p->getCabecera());
  720.             $root $p->getRoot();
  721.             $n $root->getNumlineasmodif() + 1;
  722.             $root->setNumlineasmodif($n);
  723.             // $l->persistAsFirstChildOf($linea, $p);
  724.             $l->persistAsLastChildOf($linea$p);
  725.             $em->persist($root);
  726.             $em->flush();
  727.             // if($countComment > 0){
  728.             //     $l->moveUp($linea, $countComment);
  729.             // }
  730.             return $this->redirectToRoute('cc_favoritos', [
  731.                 'id' => $p->getCabecera()->getId(),
  732.             ]);
  733.         }
  734.         return $this->render('callcenter/_comentarios.html.twig', [
  735.             'form' => $form->createView(),
  736.             'parent' => $p
  737.         ]);
  738.     }
  739.     #[Route('/borrarlista/{id}'name'cc_borrarlista')]
  740.     public function borrarlista(LineasRepository $lRequest $requestint $id): response
  741.     {
  742.         $entityManager $this->doctrine->getManager();
  743.         // Linea que se quiere borrar
  744.         $linea $l->find($id);
  745.         if (!$linea) {
  746.             throw $this->createNotFoundException('Linea no encontrada.');
  747.         }
  748.         $cabecera $linea->getCabecera();
  749.         $precioTotal $linea->getPrecio();
  750.         $precioSinIVA $linea->getPreciosiniva();
  751.         if ($linea->getParent() === null && $linea->getNumlineasmodif() > 0) {
  752.             list($childPriceTotal$childPriceWithoutTax) = $this->removeChildLines($linea$l$entityManager);
  753.             $precioTotal += $childPriceTotal;
  754.             $precioSinIVA += $childPriceWithoutTax;
  755.         } elseif ($linea->getParent() !== null) {
  756.             $parentLine $linea->getRoot();
  757.             $parentLine->setNumlineasmodif($parentLine->getNumlineasmodif() - 1);
  758.             $parentLine->setPreciototal($parentLine->getPreciototal() - ($precioTotal $linea->getUnidades()));
  759.             $parentLine->setPreciosiniva($parentLine->getPreciosiniva() - $precioSinIVA); // Añadido para actualizar el preciosiniva del parent
  760.             $entityManager->persist($parentLine);
  761.         }
  762.         $cabecera->setTotal($cabecera->getTotal() - $precioTotal);
  763.         $cabecera->setTotalsiniva($cabecera->getTotalsiniva() - $precioSinIVA);
  764.         $entityManager->remove($linea);
  765.         $entityManager->persist($cabecera);
  766.         $entityManager->flush();
  767.         return $this->redirectToRoute('cc_favoritos', ['id' => $cabecera->getId()]);
  768.     }
  769.     private function removeChildLines(Lineas $parentLineLineasRepository $lEntityManagerInterface $entityManager): array
  770.     {
  771.         $childLines $l->findBy(['parent' => $parentLine->getId()]);
  772.         $childPriceTotal 0;
  773.         $childPriceWithoutTax 0;
  774.         foreach ($childLines as $child) {
  775.             $childPriceTotal += $child->getPrecio();
  776.             $childPriceWithoutTax += $child->getPreciosiniva();
  777.             $entityManager->remove($child);
  778.         }
  779.         return [$childPriceTotal$childPriceWithoutTax];
  780.     }
  781.     // #[Route('/borrarlista/{id}', name: 'cc_borrarlista')]
  782.     // public function borrarlista(LineasRepository $l, Request $request, int $id): response
  783.     // {
  784.     //     // $favoritos = $favoritoscab->findAllByTerminal(2);
  785.     //     $entityManager = $this->doctrine->getManager();
  786.     //     //linea que se quiere borrar
  787.     //     $linea = $this->doctrine
  788.     //         ->getRepository(Lineas::class)
  789.     //         ->find($id);
  790.     //     $cabecera = $linea->getCabecera();
  791.     //     $total = $cabecera->getTotal();
  792.     //     if ($linea->getParent() === null) {
  793.     //         if ($linea->getNumlineasmodif() > 0) {
  794.     //             $childs = $l->findby(['parent' => $linea->getId()]);
  795.     //             foreach ($childs as $key => $child) {
  796.     //                 $total = $total - $child->getPrecio();
  797.     //                 $entityManager->remove($child);
  798.     //             }
  799.     //         }
  800.     //     } else {
  801.     //         $p = $linea->getRoot();
  802.     //         $countChild = $l->childCount($linea);
  803.     //         $count = $countChild + 1;
  804.     //         $n = $p->getNumlineasmodif() - $count;
  805.     //         $p->setNumlineasmodif($n);
  806.     //         //probando
  807.     //         $p->setPreciototal($p->getPreciototal() - ($linea->getPrecio() / $linea->getUnidades()));
  808.     //         $entityManager->persist($p);
  809.     //     }
  810.     //     $total = $total - $linea->getPrecio();
  811.     //     $cabecera->setTotal($total);
  812.     //     $entityManager->remove($linea);
  813.     //     $entityManager->persist($cabecera);
  814.     //     $entityManager->flush();
  815.     //     return $this->redirectToRoute('cc_favoritos', array('id' => $linea->getCabecera()->getId()));
  816.     // }
  817.     #[Route('/enespera/{id?}'name'cc_enespera')]
  818.     public function esperarpago(?int $id null): response
  819.     {
  820.         $cabecera null;
  821.         if ($id) {
  822.             $cabecera $this->doctrine->getRepository(Cabecera::class)->find($id);
  823.         }
  824.         return $this->render('callcenter/enespera.html.twig', [
  825.             'cabecera' => $cabecera,
  826.         ]);
  827.     }
  828.     #[Route('/hacerpedido/{id}'name'cc_hacerpedido')]
  829.     public function generarxml(int $idXmlGeneratorService $xml): response
  830.     {
  831.         $cab $this->doctrine
  832.             ->getRepository(Cabecera::class)
  833.             ->find($id);
  834.         if ($cab->getIsFinalizada()) {
  835.             $this->addFlash('notice''Este pedido ya fue procesado anteriormente.');
  836.             if ($cab->getEstado() == 'EDICION') {
  837.                 $url $this->adminUrlGenerator
  838.                     ->setController(CabeceraCrudController::class)
  839.                     ->setAction(Action::DETAIL)
  840.                     ->setEntityId($cab->getId())
  841.                     ->generateUrl();
  842.                 return $this->redirect($url);
  843.             } else {
  844.                 return $this->render('callcenter/finalizarpedido.html.twig', [
  845.                     'cabecera' => $cab
  846.                 ]);
  847.             }
  848.         }
  849.         $estadoinicial $cab->getEstado();
  850.         $entityManager $this->doctrine->getManager();
  851.         if ($this->isReservation($cab) === false) {
  852.             $filename $xml->generatorXML($cab);
  853.             $cab->setFilename($filename);
  854.             $cab->setIsFinalizada(true);
  855.             $status $this->createStatus($cab'PROCESANDO'$this->getUser());
  856.         } else {
  857.             $cab->setIsFinalizada(false);
  858.             $status $this->createStatus($cab'PROGRAMADO'$this->getUser());
  859.         }
  860.         $entityManager->persist($status);
  861.         $entityManager->persist($cab);
  862.         $entityManager->flush();
  863.         if ($estadoinicial == 'EDICION') {
  864.             $url $this->adminUrlGenerator
  865.                 ->setController(CabeceraCrudController::class)
  866.                 ->setAction(Action::DETAIL)
  867.                 ->setEntityId($cab->getId())
  868.                 ->generateUrl();
  869.             return $this->redirect($url);
  870.         } else {
  871.             return $this->render('callcenter/finalizarpedido.html.twig', [
  872.                 'cabecera' => $cab
  873.             ]);
  874.         }
  875.     }
  876.     // #[Route('/hacerpedido/{id}', name: 'cc_hacerpedido')]
  877.     // public function generarxml(int $id, Xml $xml): response
  878.     // {
  879.     //     $cab = $this->doctrine
  880.     //         ->getRepository(Cabecera::class)
  881.     //         ->find($id);
  882.     //     $estadoinicial = $cab->getEstado();
  883.     //     if ($this->isReservation($cab) === false) {
  884.     //         $datetime['fecha'] = $cab->getUpdatedAt()->format('dm');
  885.     //         $datetime['hora'] = $cab->getUpdatedAt()->format('His');
  886.     //         $filename = substr($cab->getSucursal(), 0, 3) . $datetime['fecha'] . $datetime['hora'] . '-' . $cab->getId();
  887.     //         $cab->setFilename($filename);
  888.     //         $cab->setIsFinalizada(true);
  889.     //         $entityManager = $this->doctrine->getManager();
  890.     //         //log
  891.     //         $status = $this->createStatus($cab, 'PROCESANDO', $this->getUser());
  892.     //         $entityManager->persist($status);
  893.     //         //log
  894.     //         $entityManager->persist($cab);
  895.     //         $numlineas = 2;
  896.     //         foreach ($cab->getLineas() as $key => $linea) {
  897.     //             if ($linea->getParent() == null) {
  898.     //                 $numlineas++;
  899.     //             }
  900.     //         }
  901.     //         $xmlText = $xml->generarXml($cab, $datetime, $numlineas, $filename);
  902.     //         // SIRVE PARA GUARDAR EL ARCHIVO EN PUBLIC/UPLOADS*****
  903.     //         $filenameext = $filename . '.xml';
  904.     //         $path1 = $this->getParameter('kernel.project_dir') . '/public/uploads/' . $filenameext;
  905.     //         $path2 = $this->getParameter('kernel.project_dir') . '/public/respaldoXML/' . $filenameext;
  906.     //         $fileSystem = new Filesystem();
  907.     //         $fileSystem->dumpFile($path1, $xmlText);
  908.     //         $fileSystem->dumpFile($path2, $xmlText);
  909.     //     } else {
  910.     //         $cab->setIsFinalizada(false);
  911.     //         $entityManager = $this->doctrine->getManager();
  912.     //         //log
  913.     //         $status = $this->createStatus($cab, 'PROGRAMADO', $this->getUser());
  914.     //         $entityManager->persist($status);
  915.     //         //log
  916.     //         $entityManager->persist($cab);
  917.     //     }
  918.     //     $entityManager->flush();
  919.     //     if ($estadoinicial == 'EDICION') {
  920.     //         $url = $this->adminUrlGenerator
  921.     //             ->setController(CabeceraCrudController::class)
  922.     //             ->setAction(Action::DETAIL)
  923.     //             ->setEntityId($cab->getId())
  924.     //             ->generateUrl();
  925.     //         return $this->redirect($url);
  926.     //     } else {
  927.     //         return $this->render('callcenter/finalizarpedido.html.twig', [
  928.     //             'cabecera' => $cab
  929.     //         ]);
  930.     //     }
  931.     // }
  932.     #[Route('/confirmarpedido/{id}'name'cc_confirmarpedido')]
  933.     public function confirmarpedido(int $idRequest $requestGlobalPayService $globalPayService): response
  934.     {
  935.         $cab $this->doctrine
  936.             ->getRepository(Cabecera::class)
  937.             ->find($id);
  938.         // Validar que el pedido tenga al menos un producto
  939.         // Solo contamos líneas principales (sin parent) que no sean domicilio (codarticulo != '0')
  940.         $lineasProducto $cab->getLineas()->filter(function($linea) {
  941.             return $linea->getParent() === null && $linea->getCodarticulo() !== '0';
  942.         });
  943.         if ($lineasProducto->count() === 0) {
  944.             $this->addFlash('error''No puede confirmar un pedido sin artículos. Por favor agregue al menos un producto.');
  945.             return $this->redirectToRoute('cc_pedido_v2', ['id' => $id]);
  946.         }
  947.         $form $this->createForm(Cabecera2Type::class, $cab);
  948.         $form->handleRequest($request);
  949.         if ($form->isSubmitted() && $form->isValid()) {
  950.             $cab $form->getData();
  951.             $propinatotal $cab->getPropinatotal();
  952.             if (is_numeric($propinatotal) && $propinatotal 0) {
  953.                 $cab->setPropinatotal(floor($propinatotal 100) * 100);
  954.             } else {
  955.                 $cab->setPropinatotal(0);
  956.                 $cab->setPropinaporcentaje(0);
  957.             }
  958.             if ((int) $cab->getMetododepago() === (int) Cabecera::PAY_METHOD['CALL CENTER PREPAGADA']) {
  959.                 $data $globalPayService->prepareGlobalpayData([
  960.                     'nifcliente' => $cab->getNifcliente(),
  961.                     'emailcliente' => $cab->getEmailLinkdepago(),
  962.                     'nombres' => $cab->getNombres(),
  963.                     'apellidos' => ($cab->getApellidos() === null or $cab->getApellidos() === '') ? '_' $cab->getApellidos(),
  964.                     'id' => $cab->getId(),
  965.                     'total' => $cab->getTotal() + $cab->getPropinatotal(),
  966.                     'totalsiniva' => $cab->getTotalsiniva(),
  967.                     'sucursal' => $cab->getSucursal(),
  968.                 ]);
  969.                 $response $globalPayService->enviarDatos($data);
  970.                 $content json_decode($response['content'], true);
  971.                 $cab->setLinkdepago($content['data']['payment']['payment_url']);
  972.                 $entityManager $this->doctrine->getManager();
  973.                 $entityManager->persist($cab);
  974.                 $entityManager->flush();
  975.                 return $this->redirectToRoute('cc_linkdepago', [
  976.                     'id' => $cab->getId()
  977.                 ]);
  978.             }
  979.             $entityManager $this->doctrine->getManager();
  980.             $entityManager->persist($cab);
  981.             $entityManager->flush();
  982.             // CAMBIO: Ahora usamos ConectorPlus en lugar del flujo XML antiguo
  983.             // Redirigir al nuevo flujo con ConectorPlus en OrderController
  984.             return $this->redirectToRoute('cc_procesar_pedido_confirmado', [
  985.                 'id' => $cab->getId()
  986.             ]);
  987.             // CÓDIGO ANTIGUO (mantener para rollback):
  988.             // return $this->redirectToRoute('cc_hacerpedido', [
  989.             //     'id' => $cab->getId()
  990.             // ]);
  991.         }
  992.         return $this->render('callcenter/confirmarpedido.html.twig', [
  993.             'cabecera' => $cab,
  994.             'form' => $form->createView(),
  995.         ]);
  996.     }
  997.     #[Route('/linkdepago/{id}'name'cc_linkdepago')]
  998.     public function linkdepago(int $idRequest $requestMailerService $mailerService): response
  999.     {
  1000.         $this->logger->info('=== INICIO linkdepago ===', [
  1001.             'id' => $id,
  1002.             'method' => $request->getMethod(),
  1003.             'is_submitted' => $request->isMethod('POST')
  1004.         ]);
  1005.         $entityManager $this->doctrine->getManager();
  1006.         $cabecera $entityManager->getRepository(Cabecera::class)->find($id);
  1007.         if (!$cabecera) {
  1008.             // Manejar el caso de que la cabecera no se encuentre
  1009.             $this->logger->error('Cabecera no encontrada', ['id' => $id]);
  1010.             $this->addFlash('error''No se encontró el pedido solicitado.');
  1011.             return $this->redirectToRoute('call_center');
  1012.         }
  1013.         if ($cabecera->getEmailLinkdepago() === null) {
  1014.             $cabecera->setEmailLinkdepago($cabecera->getEmailcliente() ?? '');
  1015.         }
  1016.         // $estado = $entityManager->getRepository(CabeceraLinkdepago::class)->findOneBy(
  1017.         //     ['Cabecera' => $cabecera->getId()],
  1018.         //     ['createdAt' => 'DESC']
  1019.         // );
  1020.         $form $this->createForm(CabeceraEmailLinkdepagoType::class, $cabecera);
  1021.         $form->handleRequest($request);
  1022.         if ($form->isSubmitted() && $form->isValid()) {
  1023.             $this->logger->info('Formulario enviado y válido', [
  1024.                 'cabecera_id' => $cabecera->getId(),
  1025.                 'email_destino' => $cabecera->getEmailLinkdepago()
  1026.             ]);
  1027.             $config $entityManager->getRepository(Configuracion::class)->findOneBy([]);
  1028.             if (!$config) {
  1029.                 $this->logger->error('No se encontró configuración de correo en la base de datos');
  1030.                 $this->addFlash('error''No se encontró la configuración de correo. Por favor contacte al administrador.');
  1031.                 // Redirigir para preservar el flash message
  1032.                 return $this->redirectToRoute('cc_linkdepago', ['id' => $id]);
  1033.                 // CÓDIGO ANTERIOR (comentado):
  1034.                 // return $this->render('callcenter/linkdepago.html.twig', [
  1035.                 //     'cabecera' => $cabecera,
  1036.                 //     'estado' => null,
  1037.                 //     'form' => $form->createView(),
  1038.                 // ]);
  1039.             }
  1040.             $this->logger->info('Configuración de correo encontrada', [
  1041.                 'mail_host' => $config->getMailHost(),
  1042.                 'mail_puerto' => $config->getMailPuerto(),
  1043.                 'mail_usuario' => $config->getMailUsuario(),
  1044.             ]);
  1045.             try {
  1046.                 $this->logger->info('Iniciando envío de correo...', [
  1047.                     'destinatario' => $cabecera->getEmailLinkdepago(),
  1048.                     'cabecera_id' => $cabecera->getId(),
  1049.                     'link_pago' => $cabecera->getLinkdepago()
  1050.                 ]);
  1051.                 $mailerService->sendEmail(
  1052.                     $cabecera->getEmailLinkdepago(),
  1053.                     "Crepes & Waffles - Tu link de pago seguro",
  1054.                     "emails/linkdepago.html.twig",
  1055.                     ['cabecera' => $cabecera'timeout' => $config->getLinkdepagoTimeout() ?? 5],
  1056.                 );
  1057.                 $this->logger->info('Correo enviado exitosamente', [
  1058.                     'destinatario' => $cabecera->getEmailLinkdepago(),
  1059.                     'cabecera_id' => $cabecera->getId()
  1060.                 ]);
  1061.             } catch (\Exception $e) {
  1062.                 $this->logger->error('Error al enviar correo', [
  1063.                     'error_message' => $e->getMessage(),
  1064.                     'error_code' => $e->getCode(),
  1065.                     'error_file' => $e->getFile(),
  1066.                     'error_line' => $e->getLine(),
  1067.                     'trace' => $e->getTraceAsString(),
  1068.                     'destinatario' => $cabecera->getEmailLinkdepago(),
  1069.                     'cabecera_id' => $cabecera->getId()
  1070.                 ]);
  1071.                 $this->addFlash('error''No se pudo enviar el correo: ' $e->getMessage());
  1072.                 // CAMBIO: Usar patrón Post-Redirect-Get en lugar de render directo
  1073.                 // Los flash messages se preservan automáticamente en redirecciones
  1074.                 // Esto evita que se pierdan los mensajes y previene reenvío del formulario
  1075.                 return $this->redirectToRoute('cc_linkdepago', ['id' => $id]);
  1076.                 // CÓDIGO ANTERIOR (comentado - causaba pérdida de flash messages):
  1077.                 // return $this->render('callcenter/linkdepago.html.twig', [
  1078.                 //     'cabecera' => $cabecera,
  1079.                 //     'estado' => null,
  1080.                 //     'form' => $form->createView(),
  1081.                 // ]);
  1082.             }
  1083.             $cabecera $form->getData();
  1084.             $entityManager->persist($cabecera);
  1085.             $entityManager->flush();
  1086.             $this->logger->info('Flush completado, redirigiendo a cc_enespera', [
  1087.                 'cabecera_id' => $cabecera->getId()
  1088.             ]);
  1089.             $this->addFlash('success''El correo se envió correctamente.');
  1090.             // Pasar el ID para mostrar el mensaje correcto en la página de confirmación
  1091.             return $this->redirectToRoute('cc_enespera', ['id' => $cabecera->getId()]);
  1092.         }
  1093.         $this->logger->info('Mostrando formulario (no enviado o inválido)', [
  1094.             'is_submitted' => $form->isSubmitted(),
  1095.             'is_valid' => $form->isSubmitted() ? $form->isValid() : 'N/A'
  1096.         ]);
  1097.         return $this->render('callcenter/linkdepago.html.twig', [
  1098.             'cabecera' => $cabecera,
  1099.             // 'estado' => $estado,
  1100.             'estado' => null,
  1101.             'form' => $form->createView(),
  1102.         ]);
  1103.     }
  1104.     private function isReservation(Cabecera $cabecera): bool
  1105.     {
  1106.         if ($cabecera->getFechareserva() != null) {
  1107.             //fecha actual mas el tiempo de preparacion
  1108.             if ($cabecera->getTipodeservicio() ==  16) {
  1109.                 $paramtimebc $this->getParameter('app.bc.horaclienterecoge');
  1110.             } else {
  1111.                 $paramtimebc $this->getParameter('app.bc.horareserva');
  1112.             }
  1113.             $time date("Y-m-d H:i:s"strtotime($paramtimebc ' minutes'));
  1114.             //Si la fecha de reserva es mayor que $time, Sí es reserva
  1115.             if ($cabecera->getFechareserva()->format('Y-m-d H:i:s') > $time) {
  1116.                 // Es reserva
  1117.                 return true;
  1118.             } else {
  1119.                 // No es reserva
  1120.                 return false;
  1121.             }
  1122.         } else {
  1123.             return false;
  1124.         }
  1125.     }
  1126.     #[Route('/cambiarestado/{id}/{action}'name'cambiar_estado')]
  1127.     public function cambiarEstado(int $id$action)
  1128.     {
  1129.         $cab $this->doctrine
  1130.             ->getRepository(Cabecera::class)
  1131.             ->find($id);
  1132.         if (!$cab) {
  1133.             throw $this->createNotFoundException(
  1134.                 'Pedido no encontrado'
  1135.             );
  1136.         }
  1137.         $entityManager $this->doctrine->getManager();
  1138.         switch ($action) {
  1139.             case 'cancelar':
  1140.                 $status $this->createStatus($cab'CANCELADO'$this->getUser());
  1141.                 $flash 'Pedido Cancelado';
  1142.                 $cab->setIsFinalizada(true);
  1143.                 $cab->setLinkdepago(null);
  1144.                 $entityManager->persist($cab);
  1145.                 break;
  1146.             case 'anular':
  1147.                 $status $this->createStatus($cab'ANULADO'$this->getUser());
  1148.                 $flash 'Pedido anulado';
  1149.                 $cab->setLinkdepago(null);
  1150.                 $entityManager->persist($cab);
  1151.                 break;
  1152.         }
  1153.         $entityManager->persist($status);
  1154.         $entityManager->flush();
  1155.         $url $this->adminUrlGenerator
  1156.             ->setController(CabeceraCrudController::class)
  1157.             ->setAction(Action::DETAIL)
  1158.             ->setEntityId($id)
  1159.             ->removeReferrer()
  1160.             ->generateUrl();
  1161.         $this->addFlash('success'$flash);
  1162.         return $this->redirect($url);
  1163.     }
  1164. }
  1165. // $ppk = $this->getParameter('kernel.project_dir') . '/public/uploads/idisftp.ppk';
  1166. // $key = PublicKeyLoader::load(file_get_contents($ppk), $password = false);
  1167. // $sftp = new SFTP('64.76.58.172', 222);
  1168. // $sftp_login = $sftp->login('idisftp', $key);
  1169. // if($sftp_login) {
  1170. //     // return $this->render('default/test.html.twig', array(
  1171. //     // 'path' => $sftp->exec('pwd'),
  1172. //     // ));
  1173. //     // $sftp->enablePTY();
  1174. //     dd($sftp->nlist());
  1175. //     dd($sftp->put('filename.remote', 'xxx'));
  1176. // }
  1177. // else throw new \Exception('Cannot login into your server !');