src/Controller/Front/ClientOrderController.php line 265

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Front;
  3. use App\Entity\Cadre;
  4. use App\Entity\CaisseAmericaine;
  5. use App\Entity\ClientOrder;
  6. use App\Entity\Internaute;
  7. use App\Entity\PassePartout;
  8. use App\Entity\Sujet;
  9. use App\Manager\SettingManager;
  10. use App\Repository\ClientOrderRepository;
  11. use App\Repository\ImageRepository;
  12. use App\Repository\ProjectRepository;
  13. use App\Repository\TinyUrlRepository;
  14. use App\Service\ClientOrderManager;
  15. use App\Service\Mailer;
  16. use App\Service\OrderProductService;
  17. use Doctrine\Persistence\ManagerRegistry;
  18. use Psr\Log\LoggerInterface;
  19. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  20. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  21. use Symfony\Component\HttpFoundation\JsonResponse;
  22. use Symfony\Component\HttpFoundation\RedirectResponse;
  23. use Symfony\Component\HttpFoundation\Request;
  24. use Symfony\Component\HttpFoundation\Response;
  25. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  26. use Symfony\Component\Routing\Annotation\Route;
  27. #[Route('/client-order'name'client_order.')]
  28. class ClientOrderController extends AbstractController
  29. {
  30.     public function __construct(
  31.         private ImageRepository $imageRepository,
  32.         private ProjectRepository $projectRepository,
  33.         private ClientOrderManager $clientOrderManager,
  34.         private TinyUrlRepository $tinyUrlRepository,
  35.         private ClientOrderRepository $clientOrderRepository,
  36.         private SettingManager $settingManager,
  37.         private ManagerRegistry $doctrine,
  38.         private OrderProductService $orderProductService,
  39.     ) {}
  40.     #[Route('/generate-devis'name'generate_devis'methods: ['POST'])]
  41.     public function generateDevis(Request $request): BinaryFileResponse|JsonResponse
  42.     {
  43.         $data json_decode($request->getContent(), true);
  44.         if (!$data) {
  45.             return new JsonResponse(['error' => 'Invalid JSON'], Response::HTTP_BAD_REQUEST);
  46.         }
  47.         $project $this->projectRepository->findOneBy(['token' => $data['project_token'] ?? '']);
  48.         if (!$project) {
  49.             return new JsonResponse(['error' => 'No project found'], Response::HTTP_BAD_REQUEST);
  50.         }
  51.         $clientOrder = new ClientOrder();
  52.         $clientOrder->setProject($project);
  53.         $clientOrder->setReference('DEVIS-' date('YmdHis') . '-' substr(uniqid(), -4));
  54.         $totalPrice 0;
  55.         if (!empty($data['client'])) {
  56.             $internaute $this->clientOrderManager->makeInternauteFromData($data['client']);
  57.             $clientOrder->setInternaute($internaute);
  58.         }
  59.         foreach ($data['groups'] ?? [] as $group) {
  60.             if (!empty($group['cadre'])) {
  61.                 $cadre $this->clientOrderManager->makeCadreFromData($group['cadre']);
  62.                 $cadre->setPrice((float) ($group['cadre']['price'] ?? 0));
  63.                 $cadre->setQuantity((int) ($group['cadre']['quantity'] ?? 1));
  64.                 $clientOrder->addOrderProduct($cadre);
  65.                 $totalPrice += (float) ($group['cadre']['price'] ?? 0);
  66.             }
  67.             if (!empty($group['passepartout'])) {
  68.                 $pp $group['passepartout'];
  69.                 if (($pp['marge_haut'] ?? 0) != || ($pp['marge_bas'] ?? 0) != || ($pp['marge_gauche'] ?? 0) != || ($pp['marge_droit'] ?? 0) != 0) {
  70.                     $passepartout $this->clientOrderManager->makePassePartoutFromData($pp);
  71.                     $passepartout->setPrice((float) ($pp['price'] ?? 0));
  72.                     $passepartout->setQuantity((int) ($pp['quantity'] ?? 1));
  73.                     $clientOrder->addOrderProduct($passepartout);
  74.                     $totalPrice += (float) ($pp['price'] ?? 0);
  75.                 }
  76.             }
  77.             if (!empty($group['caisseamericaine'])) {
  78.                 $ca $this->clientOrderManager->makeCaisseAmericaineFromData($group['caisseamericaine']);
  79.                 $ca->setPrice((float) ($group['caisseamericaine']['price'] ?? 0));
  80.                 $ca->setQuantity((int) ($group['caisseamericaine']['quantity'] ?? 1));
  81.                 $clientOrder->addOrderProduct($ca);
  82.                 $totalPrice += (float) ($group['caisseamericaine']['price'] ?? 0);
  83.             }
  84.             if (!empty($group['sujet']) && ($group['sujet']['price'] ?? $group['sujet']['largeur'] ?? null)) {
  85.                 $sujet $this->clientOrderManager->makeSujetFromData($group['sujet']);
  86.                 $sujet->setPrice((float) ($group['sujet']['price'] ?? 0));
  87.                 $clientOrder->addOrderProduct($sujet);
  88.                 $totalPrice += (float) ($group['sujet']['price'] ?? 0);
  89.             }
  90.             if (!empty($group['partial'])) {
  91.                 $partial $this->clientOrderManager->makePartialFromApiData($group['partial']);
  92.                 if ($partial) {
  93.                     $clientOrder->addOrderProduct($partial);
  94.                     $totalPrice += (float) ($group['partial']['price'] ?? 0);
  95.                 }
  96.             }
  97.             if (!empty($group['save_code'])) {
  98.                 $clientOrder->setSaveLink($group['save_code']);
  99.             }
  100.         }
  101.         $clientOrder->setPrice(round($totalPrice2));
  102.         $project->settings $this->settingManager->getProjectSettings($project);
  103.         $clientOrder->setProject($project);
  104.         $filePath sprintf("%s/var/cache/pdf/client-order/%s.pdf",
  105.             $this->getParameter('kernel.project_dir'),
  106.             uniqid('devis_')
  107.         );
  108.         $this->clientOrderManager->streamPdf($clientOrder$filePath);
  109.         if (!file_exists($filePath)) {
  110.             return new JsonResponse(['error' => 'PDF generation failed'], Response::HTTP_INTERNAL_SERVER_ERROR);
  111.         }
  112.         $response $this->file($filePath'devis_' $clientOrder->getReference() . '.pdf'ResponseHeaderBag::DISPOSITION_INLINE);
  113.         $response->deleteFileAfterSend(true);
  114.         return $response;
  115.     }
  116.     // Used for wordpress plugin call
  117.     #[Route('/create'name'create')]
  118.     public function create(Request $requestManagerRegistry $emMailer $mailerLoggerInterface $logger): JsonResponse
  119.     {
  120.         $r_cadre        $request->get('cadre');
  121.         $r_passepartout $request->get('passepartout');
  122.         $r_caisseamericaine $request->get('caisseamericaine');
  123.         $r_sujet        $request->get('sujet');
  124.         $r_intenaute    $request->get('client');
  125.         $r_partial      $request->get('partial');
  126.         if (!$r_cadre && !$r_passepartout && !$r_sujet && !$r_caisseamericaine) return new JsonResponse(['error' => 'No data provided'], Response::HTTP_BAD_REQUEST);
  127.         $clientOrder    = new ClientOrder();
  128.         $price          0;
  129.         if ( $r_cadre )
  130.         {
  131.             $cadre $this->clientOrderManager->makeCadreFromData($r_cadre);
  132.             array_key_exists('price'$r_cadre) ? $price += (float) $r_cadre['price'] : $price += 0;
  133.             $clientOrder->setCadre($cadre);
  134.             $em->getManager()->persist($cadre);
  135.         }
  136.         if ( $r_passepartout )
  137.         {
  138.             if ( ($r_passepartout['marge_haut'] ?? 0) != || ($r_passepartout['marge_bas'] ?? 0) != || ($r_passepartout['marge_gauche'] ?? 0) != || ($r_passepartout['marge_droit'] ?? 0) != )
  139.             {
  140.                 $passepartout $this->clientOrderManager->makePassePartoutFromData($r_passepartout);
  141.                 array_key_exists('price'$r_passepartout) ? $price += (float) $r_passepartout['price'] : $price += 0;
  142.                 $clientOrder->setPassePartout($passepartout);
  143.                 $em->getManager()->persist($passepartout);
  144.             }
  145.         }
  146.         if ( $r_caisseamericaine )
  147.         {
  148.             $caisseAmericaine $this->clientOrderManager->makeCaisseAmericaineFromData($r_caisseamericaine);
  149.             array_key_exists('price'$r_caisseamericaine) ? $price += (float) $r_caisseamericaine['price'] : $price += 0;
  150.             $clientOrder->setCaisseAmericaine($caisseAmericaine);
  151.             $em->getManager()->persist($caisseAmericaine);
  152.         }
  153.         if ( $r_sujet && ($r_sujet['price'] ?? $r_sujet['largeur'] ?? null) )
  154.         {
  155.             $sujet $this->clientOrderManager->makeSujetFromData($r_sujet);
  156.             array_key_exists('price'$r_sujet) ? $price += (float) $r_sujet['price'] : $price += 0;
  157.             $clientOrder->setSujet($sujet);
  158.             $em->getManager()->persist($sujet);
  159.         }
  160.         if ( $r_partial )
  161.         {
  162.             $partial $this->clientOrderManager->makePartialFromApiData($r_partial);
  163.             if ($partial) {
  164.                 array_key_exists('price'$r_partial) ? $price += (float) $r_partial['price'] : $price += 0;
  165.                 $clientOrder->setPartial($partial);
  166.                 $em->getManager()->persist($partial);
  167.             }
  168.         }
  169.         if ( $r_intenaute )
  170.         {
  171.             $internaute $this->clientOrderManager->makeInternauteFromData($r_intenaute);
  172.             $clientOrder->setInternaute($internaute);
  173.             $em->getManager()->persist($internaute);
  174.         }
  175.         $this->clientOrderManager->setReference($clientOrder);
  176.         $project $this->projectRepository->findOneBy(['id' => $request->get('project_id')]);
  177.         if (!$project) {
  178.             $project $this->projectRepository->findOneBy(['token' => $request->get('project_token')]);
  179.         }
  180.         if (!$project) {
  181.             return new JsonResponse(['error' => 'No project found'], Response::HTTP_BAD_REQUEST);
  182.         }
  183.         $clientOrder->setSellerName($request->get('seller_name'));
  184.         $clientOrder->setComment($request->get('comment'));
  185.         $clientOrder->setSaveLink($request->get('save_code'));
  186.         $clientOrder->setPrice(round($price2));
  187.         $clientOrder->setProject($project);
  188.         $clientOrder->setStatus(ClientOrder::STATUS_TOSEND);
  189.         foreach (($request->get('tiny_urls') ?? []) as $url) {
  190.             $urlParts explode('/'$url);
  191.             $slug end($urlParts);
  192.             if ($tinyUrl $this->tinyUrlRepository->findOneBy(['project' => $project'slug' => $slug])) {
  193.                 $tinyUrl->setClientOrder($clientOrder);
  194.             }
  195.         }
  196.         $em->getManager()->persist($clientOrder);
  197.         $em->getManager()->flush();
  198.         if ($clientOrder->getStatus() != ClientOrder::STATUS_DRAFT) {
  199.             $mailer->sendCreated($clientOrder);
  200.         }
  201.         if ($project->getProjectSettings()->isHasAutomaticSendToNielsen() && $clientOrder->getStatus() === ClientOrder::STATUS_TOSEND)
  202.         {
  203.             $this->clientOrderManager->sendToNielsen($clientOrder);
  204.         }
  205.         return new JsonResponse("ok"Response::HTTP_OK);
  206.     }
  207.     #[Route('/{reference}/print-by-reference'name'print_by_reference')]
  208.     public function printByReference(ClientOrder $clientOrder): RedirectResponse
  209.     {
  210.         return $this->redirectToRoute('client_order.print', ['id' => $clientOrder->getId()]);
  211.     }
  212.     #[Route('/{id}/print'name'print')]
  213.     #[Route('/print'name'print_data')]
  214. //    public function print(Request $request, ?ClientOrder $clientOrder = null): BinaryFileResponse
  215.     public function print(Request $request, ?ClientOrder $clientOrder null)
  216.     {
  217.         $clientOrder $clientOrder
  218.             ?? $this->makeClientOrderFromData($request->query->all());
  219.         $project $clientOrder->getProject();
  220.         $project->settings $this->settingManager->getProjectSettings($clientOrder->getProject());
  221.         $clientOrder->setProject($project);
  222.     //    return $this->render('client_order/ticket/ticket.pdf.twig', [
  223.     //        'clientOrder' => $clientOrder,
  224.     //    ]);
  225.         $filePath sprintf("%s/var/cache/pdf/client-order/%s.pdf",
  226.             $this->getParameter('kernel.project_dir'),
  227.             uniqid()
  228.         );
  229.         $this->clientOrderManager->streamPdf($clientOrder$filePath);
  230.         return $this->file($filePath'composition_' $clientOrder->getReference() ?? "XXXXXX" '.pdf'ResponseHeaderBag::DISPOSITION_INLINE);
  231.     }
  232.     private function makeClientOrderFromData(array $data): ClientOrder
  233.     {
  234.         $r_cadre        $data['cadre'] ?? [];
  235.         $r_passepartout $data['passepartout'] ?? [];
  236.         $r_caisseamericaine $data['caisseamericaine'] ?? [];
  237.         $r_sujet        $data['sujet'] ?? [];
  238.         $r_intenaute    $data['client'] ?? [];
  239.         if ( isset($data['reference']) && $clientOrder $this->clientOrderRepository->findOneBy(['reference' => $data['reference']])) {
  240.             $save_link $data['save_link'] ?? null;
  241.             // if save_link is 6 characters or less, find the url from the tiny_url table
  242.             if (strlen($save_link) <= 6)
  243.             {
  244.                 $tinyUrl $this->tinyUrlRepository->findOneBy(['slug' => $save_link]);
  245.                 if ($tinyUrl)
  246.                 {
  247.                     $url $tinyUrl->getUrl();
  248.                     if ( !$url )
  249.                     {
  250.                         $save_link $this->generateUrl('project.app.new', ['token' => $clientOrder->getProject()->getToken()], 0) . '?save_code=' $save_link;
  251.                     }
  252.                 }
  253.             }
  254.             $clientOrder->setSaveLink($save_link);
  255.             return $clientOrder;
  256.         }
  257.         $clientOrder    = new ClientOrder();
  258.         $price          0;
  259.         if ( !empty($r_cadre) ) {
  260.             $cadre $this->clientOrderManager->makeCadreFromData($r_cadre);
  261.             $clientOrder->setCadre($cadre);
  262.             $price += (float) ($r_cadre['price'] ?? 0);
  263.         }
  264.         if ( !empty($r_passepartout) && $r_passepartout['marge_haut'] !== "0" ) {
  265.             $passepartout $this->clientOrderManager->makePassePartoutFromData($r_passepartout);
  266.             $clientOrder->setPassePartout($passepartout);
  267.             $price += (float) ($r_passepartout['price'] ?? 0);
  268.         }
  269.         if ( !empty($r_caisseamericaine) ) {
  270.             $caisseAmericaine $this->clientOrderManager->makeCaisseAmericaineFromData($r_caisseamericaine);
  271.             $clientOrder->setCaisseAmericaine($caisseAmericaine);
  272.             $price += (float) ($r_caisseamericaine['price'] ?? 0);
  273.         }
  274.         if ( !empty($r_sujet) ) {
  275.             $sujet $this->clientOrderManager->makeSujetFromData($r_sujet);
  276.             $clientOrder->setSujet($sujet);
  277.             $price += (float) ($r_sujet['price'] ?? 0);
  278.         }
  279.         if ( !empty($r_intenaute) ) {
  280.             $internaute $this->clientOrderManager->makeInternauteFromData($r_intenaute);
  281.             $clientOrder->setInternaute($internaute);
  282.         }
  283.         $project null;
  284.         if (key_exists('project_id'$data))
  285.         {
  286.             $project $this->projectRepository->findOneBy(['id' => $data['project_id']]);
  287.         }
  288.         if (key_exists('project_token'$data))
  289.         {
  290.             $project $this->projectRepository->findOneBy(['token' => $data['project_token']]);
  291.         }
  292.         $save_link $data['save_link'] ?? null;
  293.         // if save_link is 6 characters or less, find the url from the tiny_url table
  294.         if (strlen($save_link) <= 6)
  295.         {
  296.             $tinyUrl $this->tinyUrlRepository->findOneBy(['slug' => $save_link]);
  297.             if ($tinyUrl)
  298.             {
  299.                 $url $tinyUrl->getUrl();
  300.                 if ( !$url )
  301.                 {
  302.                     $save_link $this->generateUrl('project.app.new', ['token' => $project->getToken()], 0) . '?save_code=' $save_link;
  303.                 }
  304.             }
  305.         }
  306.         $clientOrder
  307.             ->setReference($data['reference'] ?? null)
  308.             ->setSellerName($data['seller_name'])
  309.             ->setComment($data['comment'])
  310.             ->setPrice($price)
  311.             ->setProject($project)
  312.             ->setSaveLink($save_link)
  313.         ;
  314.         return $clientOrder;
  315.     }
  316.     #[Route('/{reference}/update'name'update'methods: ['PUT''PATCH'])]
  317.     public function update(Request $requestClientOrder $clientOrder): JsonResponse
  318.     {
  319.         $data json_decode($request->getContent(), true);
  320.         if (!$data) {
  321.             return new JsonResponse(['error' => 'Invalid JSON data'], Response::HTTP_BAD_REQUEST);
  322.         }
  323.         try {
  324.             // Handle cart items update - support both new cart structure and legacy cartItems
  325.             $cartItems $this->getCartItemsFromConfig($data);
  326.             if (!empty($cartItems)) {
  327.                 $this->updateClientOrderFromCartItems($clientOrder$cartItems);
  328.             } else {
  329.                 // Legacy system fallback using ClientOrderManager
  330.                 $this->clientOrderManager->updateFromConfig($clientOrder$data);
  331.             }
  332.             // Update additional fields - support both new cart structure and legacy
  333.             $cartTotal $this->getCartTotalFromConfig($data);
  334.             if ($cartTotal !== null) {
  335.                 $clientOrder->setPrice(round($cartTotal2));
  336.             }
  337.             if (isset($data['comment'])) {
  338.                 $clientOrder->setComment($data['comment']);
  339.             }
  340.             if (isset($data['sellerName'])) {
  341.                 $clientOrder->setSellerName($data['sellerName']);
  342.             }
  343.             $em $this->doctrine->getManager();
  344.             // Update the associated TinyUrl's config with the full configuration state
  345.             $tinyUrl $this->tinyUrlRepository->findOneBy(['clientOrder' => $clientOrder]);
  346.             if ($tinyUrl) {
  347.                 // Remove backend-specific fields that shouldn't be stored in the config
  348.                 $configToStore $data;
  349.                 unset($configToStore['projectToken']); // This is project-specific, not config-specific
  350.                 $tinyUrl->setAppConfig($configToStore);
  351.                 $em->persist($tinyUrl);
  352.             }
  353.             $clientOrder->setPriceNetRefToSend($this->clientOrderManager->getTotalNet($clientOrder));
  354.             $em->persist($clientOrder);
  355.             $em->flush();
  356.             return new JsonResponse([
  357.                 'success' => true,
  358.                 'reference' => $clientOrder->getReference(),
  359.                 'price' => $clientOrder->getPrice(),
  360.                 'message' => 'ClientOrder updated successfully'
  361.             ], Response::HTTP_OK);
  362.         } catch (\Exception $e) {
  363.             return new JsonResponse([
  364.                 'error' => 'Failed to update ClientOrder',
  365.                 'message' => $e->getMessage()
  366.             ], Response::HTTP_INTERNAL_SERVER_ERROR);
  367.         }
  368.     }
  369.     private function updateClientOrderFromCartItems(ClientOrder $clientOrder, array $cartItems): void
  370.     {
  371.         $em $this->doctrine->getManager();
  372.         
  373.         // Clear existing order products
  374.         foreach ($clientOrder->getOrderProducts() as $orderProduct) {
  375.             $clientOrder->removeOrderProduct($orderProduct);
  376.             $em->remove($orderProduct);
  377.         }
  378.         
  379.         // Clear legacy products for backward compatibility
  380.         foreach (['cadre''passePartout''caisseAmericaine''sujet'] as $property) {
  381.             $getter 'get' ucfirst($property);
  382.             $setter 'set' ucfirst($property);
  383.             
  384.             if (method_exists($clientOrder$getter) && $entity $clientOrder->$getter()) {
  385.                 $clientOrder->$setter(null);
  386.                 $em->remove($entity);
  387.             }
  388.         }
  389.         
  390.         // Create new order products from cart items
  391.         $this->createOrderProductsFromCartItems($clientOrder$cartItems);
  392.     }
  393.     
  394.     private function createOrderProductsFromCartItems(ClientOrder $clientOrder, array $cartItems): void
  395.     {
  396.         $em $this->doctrine->getManager();
  397.         
  398.         foreach ($cartItems as $cartItem) {
  399.             $orderProduct $this->orderProductService->createOrderProductFromCartItem($cartItem);
  400.             if ($orderProduct) {
  401.                 $clientOrder->addOrderProduct($orderProduct);
  402.                 $em->persist($orderProduct);
  403.             }
  404.         }
  405.     }
  406.     
  407.     /**
  408.      * Helper method to get cart items from config
  409.      */
  410.     private function getCartItemsFromConfig(array $config): array
  411.     {
  412.         // Use new cart structure: config.cart.items
  413.         if (isset($config['cart']['items']) && is_array($config['cart']['items'])) {
  414.             return $config['cart']['items'];
  415.         }
  416.         
  417.         return [];
  418.     }
  419.     /**
  420.      * Helper method to get cart total from config
  421.      */
  422.     private function getCartTotalFromConfig(array $config): ?float
  423.     {
  424.         // Use new cart structure: config.cart.total
  425.         if (isset($config['cart']['total']) && is_numeric($config['cart']['total'])) {
  426.             return (float) $config['cart']['total'];
  427.         }
  428.         
  429.         return null;
  430.     }
  431. }