src/Controller/Admin/DocumentController.php line 1984

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Admin;
  3. use App\Entity\Document;
  4. use App\Entity\DocumentDeclinationProduit;
  5. use App\Entity\DocumentProduit;
  6. use App\Entity\Stock;
  7. use App\Entity\Comment;
  8. use App\Entity\CancelReason;
  9. use Doctrine\Common\Collections\Collection;
  10. use Doctrine\ORM\EntityManagerInterface;
  11. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\HttpFoundation\JsonResponse;
  15. use Symfony\Component\Routing\Annotation\Route;
  16. use App\Repository\CancelReasonRepository;
  17. use App\Repository\RefundReasonRepository;
  18. use App\Repository\CompanyRepository;
  19. use App\Repository\SupplierRepository;
  20. use App\Repository\SourceRepository;
  21. use App\Repository\DeclinationRepository;
  22. use App\Repository\DeliveryRepository;
  23. use App\Repository\UserRepository;
  24. use App\Repository\TvaRepository;
  25. use App\Repository\ProduitDeclinationValueRepository;
  26. use App\Repository\ProduitRepository;
  27. use App\Repository\DocumentRepository;
  28. use App\Form\FilterDocumentType;
  29. use Dompdf\Dompdf;
  30. use Dompdf\Options;
  31. use Symfony\Component\HttpFoundation\RequestStack;
  32. use App\Form\InfoLivraisonType;
  33. use App\Service\ActivityService;
  34. use App\Service\RightService;
  35. use Symfony\Component\Routing\RouterInterface;
  36. use App\Service\StockService;
  37. use App\Service\PaymentUpdaterService
  38. use App\Repository\PromotionRepository;
  39. /**
  40.  * @Route("/document")
  41.  */
  42. class DocumentController extends AbstractController {
  43.     use AccessTrait;
  44.     private $userRepository;
  45.     private $tvaRepository;
  46.     private $deliveryRepository;
  47.     private $produitRepository;
  48.     private $produitDeclinationValueRepository;
  49.     private $documentRepository;
  50.     private $supplierRepository;
  51.     private $sourceRepository;
  52.     protected $baseUrl;
  53.     private $activityService;
  54.     private $rightService;
  55.     private $declinationRepository;
  56.     private PromotionRepository $promotionRepository;
  57.     private StockService $stockService;
  58.     public function __construct(UserRepository $userRepositoryTvaRepository $tvaRepository,
  59.             ProduitRepository $produitRepositoryProduitDeclinationValueRepository $produitDeclinationValueRepository,
  60.             DeliveryRepository $deliveryRepositoryDocumentRepository $documentRepositoryRequestStack $requestStack,
  61.             SupplierRepository $supplierRepositorySourceRepository $sourceRepository,
  62.             ActivityService $activityServiceRightService $rightServiceDeclinationRepository $declinationRepository,
  63.             PromotionRepository $promotionRepository
  64.             
  65.     ) {
  66.         $this->userRepository $userRepository;
  67.         $this->tvaRepository $tvaRepository;
  68.         $this->deliveryRepository $deliveryRepository;
  69.         $this->produitRepository $produitRepository;
  70.         $this->produitDeclinationValueRepository $produitDeclinationValueRepository;
  71.         $this->documentRepository $documentRepository;
  72.         $this->baseUrl $requestStack->getCurrentRequest()->getSchemeAndHttpHost();
  73.         $this->supplierRepository $supplierRepository;
  74.         $this->sourceRepository $sourceRepository;
  75.         $this->activityService $activityService;
  76.         $this->rightService $rightService;
  77.         $this->declinationRepository $declinationRepository;
  78.         $this->promotionRepository $promotionRepository;
  79.     }
  80.     /**
  81.      * @Route("/index/{type}/{category}", name="document_index", options={"expose"=true})
  82.      */
  83.     public function index($type$category,Request $request): Response {
  84.         $this->hasRightByType$request$type'DOCUMENT_CLIENT''DOCUMENT_SUPPLIER');
  85.         $form $this->createForm(FilterDocumentType::class, null, ['label' => $type,'context' => $category,]);
  86.         
  87.         if ($category == 'client') {
  88.             return $this->render('@admin/document/list_documents_clients.html.twig', ['form' => $form->createView(),'type' => $type,'category' => $category ]);
  89.         } elseif ($category == 'fournisseur') {
  90.             return $this->render('@admin/document/list_documents_fournisseurs.html.twig', ['form' => $form->createView(),'type' => $type,'category' => $category]);
  91.         } else {
  92.             // Par défaut ou erreur
  93.             throw $this->createNotFoundException('Type de document inconnu.');
  94.         }
  95.     }
  96.     /**
  97.      * @Route("/show/{id}", name="document_show", options = { "expose" =  true})
  98.      */
  99.     public function show(Document $document,Request $request,CancelReasonRepository $cancelReasonRepository,RefundReasonRepository $refundReasonRepository): Response {
  100.         $rights=$this->hasRightByType$request$document->getCategory(), 'DOCUMENT_CLIENT''DOCUMENT_SUPPLIER');
  101.         $deliveryTypes=($document->getCategory() == 'client')?['client','client-fournisseur']:['fournisseur','client-fournisseur'];
  102.         $deliverys $this->deliveryRepository->findAllByTypes($deliveryTypes);
  103.         $cancelReasons $cancelReasonRepository->findBy(['isActive' => true],['displayOrder' => 'ASC''name' => 'ASC'] );
  104.         $refundReasons $refundReasonRepository->findBy([], ['displayOrder' => 'ASC''name' => 'ASC']);
  105.         $suppliers = ($document->getCategory() == "fournisseur")?
  106.             $this->supplierRepository->findAll()
  107.             :[];
  108.         //$comments=$this->getAllDocumentComments($document);
  109.         $comments=$document->getComments();
  110.         //dd($comments);
  111.         $user =$document->getClient();
  112.         $cmdEnAttente=$cmdAccepte=$cmdAnnule=$cmdEnRetour=$echangeEnAttente=$nbCmdTotal=$nbBeTotal=0;
  113.         if($user != null) {
  114.             $cmdEnAttente $user->getDocuments()->filter(function ($element) {
  115.                 return in_array($element->getStatus(), ['en-attente']) and $element->getType() == 'commande';
  116.             })->count();
  117.             $cmdAccepte $user->getDocuments()->filter(function ($element) {
  118.                 return in_array($element->getStatus(), ['accepte']) and $element->getType() == 'commande';
  119.             })->count();
  120.             $cmdAnnule $user->getDocuments()->filter(function ($element) {
  121.                 return in_array($element->getStatus(), ['annule']) and $element->getType() == 'commande';
  122.             })->count();
  123.             $cmdEnRetour $user->getDocuments()->filter(function ($element) {
  124.                 return in_array($element->getStatus(), ['retourne''retour-en-cours']) and $element->getType() == 'commande';
  125.             })->count();
  126.             $echangeEnAttente $user->getDocuments()->filter(function ($element) {
  127.                 return $element->getStatus() == 'en-attente' and $element->getType() == 'echange';
  128.             })->count();
  129.             $nbCmdTotal $user->getDocuments()->filter(function ($element) {
  130.                 return $element->getType() == 'commande';
  131.             })->count();
  132.             $nbBeTotal $user->getDocuments()->filter(function ($element) {
  133.                 return $element->getType() == 'echange';
  134.             })->count();
  135.         }
  136.         if ($document->getCategory() === 'client') {
  137.             if ($document->getType() === 'echange') {
  138.                 return $this->render('admin/document/detail_echange_client.html.twig'compact('document','comments','deliverys','suppliers','rights','cmdEnAttente','cmdAnnule','cmdEnRetour','echangeEnAttente','nbCmdTotal','nbBeTotal''cancelReasons''refundReasons'));
  139.             }else
  140.                 // Chercher une facture liée à ce bon de commande
  141.                 $factureExistante null;
  142.                 foreach ($document->getDocuments() as $doc) {
  143.                     if ($doc->getType() === 'facture') {
  144.                         $factureExistante $doc;
  145.                         break;
  146.                     }
  147.                 }
  148.                 return $this->render('@admin/document/detail_document_client.html.twig'compact(
  149.                                     'document','comments','deliverys','suppliers','rights',
  150.                                     'cmdEnAttente','cmdAnnule','cmdEnRetour','echangeEnAttente','nbCmdTotal','nbBeTotal',
  151.                                     'cancelReasons''refundReasons''factureExistante' 
  152.                                 ));
  153.            
  154.            
  155.         } elseif ($document->getCategory() === 'fournisseur') {
  156.             return $this->render('@admin/document/detail_document_fournisseur.html.twig'compact('document','comments','deliverys','suppliers','rights','cmdEnAttente','cmdAnnule','cmdEnRetour','echangeEnAttente','nbCmdTotal','nbBeTotal''cancelReasons''refundReasons'));
  157.            
  158.         } else {
  159.             // Par défaut ou erreur
  160.             throw $this->createNotFoundException('Type de document inconnu.');
  161.         }
  162.         
  163.     }
  164.     private function getAllDocumentComments(Document $document):Collection {
  165.         $comments =$document->getComments();
  166.         if($document->getDocument()){
  167.            $childComments=$this->getAllDocumentComments$document->getDocument());
  168.            if($childComments) foreach ($childComments as $childComment$comments->add($childComment);
  169.         }
  170.        return $comments;
  171.     }
  172.     /**
  173.      * @Route("/listData", name="list_document", methods="GET|POST", options = { "expose" =  true})
  174.      */
  175.     public function listData(Request $requestDocumentRepository $documentRepository) {
  176.         $pagination $request->get('pagination');
  177.         $page $pagination['page'] - 1;
  178.         $limit $pagination['perpage'];
  179.         $sortField=$request->get('sort')?$request->get('sort')["field"]:'createdAt';
  180.         $sortType=$request->get('sort')?$request->get('sort')["sort"]:'DESC';
  181.         //dd( $request->get('deliveryAt'));
  182.         
  183.         $entities $documentRepository->search(
  184.                 $page,
  185.                 $limit,
  186.                 $request->get('status'),
  187.                 $request->get('region'),
  188.                 $request->get('internalNbr'),
  189.                 $request->get('client'),
  190.                 $request->get('type'),
  191.                 $request->get('category'),
  192.                 $request->get('supplier'),
  193.                 $request->get('totalAmountTtcMin'),
  194.                 $request->get('dateBefore'),
  195.                 $request->get('dateAfter'),
  196.                 $request->get('typeElement'),
  197.                 $request->get('reference'),
  198.                 $request->get('parcelTrackingNbr'),
  199.                 $request->get('user'),
  200.                 $request->get('source'),
  201.                 $request->get('totalAmountTtcMax'),
  202.                 $request->get('delivery'),
  203.                 $request->get('deliveryAt'),
  204.                 $request->get('deliveryAtAfter'),
  205.                 $sortField,$sortType
  206.         );
  207.         $count $documentRepository->countDocuments(
  208.                 $request->get('status'),
  209.                 $request->get('region'),
  210.                 $request->get('internalNbr'),
  211.                 $request->get('client'),
  212.                 $request->get('type'),
  213.                 $request->get('category'),
  214.                 $request->get('supplier'),
  215.                 $request->get('totalAmountTtcMin'),
  216.                 $request->get('dateBefore'),
  217.                 $request->get('dateAfter'),
  218.                 $request->get('typeElement'),
  219.                 $request->get('reference'),
  220.                 $request->get('parcelTrackingNbr'),
  221.                 $request->get('user'),
  222.                 $request->get('source'),
  223.                 $request->get('totalAmountTtcMax'),
  224.                 $request->get('delivery'),
  225.                 $request->get('deliveryAt'),
  226.                 $request->get('deliveryAtAfter')
  227.         );
  228.         /*
  229.         $countCondition = $documentRepository->countCondition(
  230.                 $request->get('status'),
  231.                 $request->get('region'),
  232.                 $request->get('internalNbr'),
  233.                 $request->get('client'),
  234.                 $request->get('type'),
  235.                 $request->get('category'),
  236.                 $request->get('supplier'),
  237.                 $request->get('totalAmountTtcMin'),
  238.                 $request->get('dateBefore'),
  239.                 $request->get('dateAfter'),
  240.                 $request->get('typeElement'),
  241.                 $request->get('reference'),
  242.                 $request->get('parcelTrackingNbr'),
  243.                 $request->get('user'),
  244.                 $request->get('source'),
  245.                 $request->get('totalAmountTtcMax'),
  246.                 $request->get('delivery'),
  247.                 $request->get('deliveryAt'),
  248.                 $request->get('deliveryAtAfter')
  249.         );
  250.         */
  251.         $countStatut $documentRepository->countStatut(
  252.                 $request->get('status'),
  253.                 $request->get('region'),
  254.                 $request->get('internalNbr'),
  255.                 $request->get('client'),
  256.                 $request->get('type'),
  257.                 $request->get('category'),
  258.                 $request->get('supplier'),
  259.                 $request->get('totalAmountTtcMin'),
  260.                 $request->get('dateBefore'),
  261.                 $request->get('dateAfter'),
  262.                 $request->get('typeElement'),
  263.                 $request->get('reference'),
  264.                 $request->get('parcelTrackingNbr'),
  265.                 $request->get('user'),
  266.                 $request->get('source'),
  267.                 $request->get('totalAmountTtcMax'),
  268.                 $request->get('delivery'),
  269.                 $request->get('deliveryAt'),
  270.                 $request->get('deliveryAtAfter')
  271.         );
  272.         $moeynne =($count['count'] !== 0) ? round($count['totalAmountTtc'] / $count['count'], 3): 0;
  273.         //$totalAvecFrais = $count['totalAmountTtc'] ?? 0; // total global avec frais
  274.        
  275.         $totalAvecFrais  = (float)($count['totalAmountTtc'] ?? 0);
  276.         $deliveryTotal   = (float)($count['deliveryTotal']   ?? 0);
  277.         $totalSansFrais  = (float)($count['totalSansFrais']  ?? ($totalAvecFrais $deliveryTotal));
  278.         $cogsTtc         = (float)($count['cogsTtc']         ?? 0);
  279.         $profitNet       $totalSansFrais $cogsTtc;
  280.         //$totalAvecFrais       = (float)($count['totalAmountTtc'] ?? 0);
  281.         //$totalSansFrais = (float)($count['totalSansFrais'] ?? 0);
  282.         //$deliveryTotal        = max(0.0, $totalAvecFrais - $totalSansFrais);
  283.         //$cogsTtc              = (float)($count['cogsTtc'] ?? 0);
  284.        // Bénéfice net (optionnel) en déduisant la livraison
  285.         //$profitNet = $totalSansFrais - $cogsTtc;
  286.        
  287.         $entities $entities ?? [];
  288.         // Calculer total sans frais uniquement pour les entités chargées
  289.         /*
  290.         $totalSansFrais = 0;
  291.         foreach ($entities as $entity) {
  292.             $frais = 0;
  293.             if ($entity->getDelivery()) {
  294.                 $frais = $entity->getDelivery()->getTotalPrice() ?? 0;
  295.             }
  296.             $totalSansFrais += $entity->getTotalAmountTtc() - $frais;
  297.         }
  298.             */
  299.         
  300.         $nbDocs max(1$count['count']); // utiliser le total global pour la moyenne
  301.         $moyenneAvecFrais $totalAvecFrais $nbDocs;
  302.         $moyenneSansFrais $totalSansFrais $nbDocs;
  303.         // ⚠ Si tu veux la moyenne sans frais sur l’ensemble des docs,
  304.         // il faut calculer sur toutes les entités, pas juste la page courante.
  305.         /*
  306.         $moyenneSansFrais = ($totalSansFrais > 0)
  307.             ? $totalSansFrais / count($entities ?: [1])
  308.             : 0;
  309.         */
  310.         $statistic = [
  311.             'total' => $count['count'],
  312.             'amountTotal' => number_format($totalAvecFrais3),
  313.             'amountTotalSansFrais' => number_format($totalSansFrais3),
  314.             'deliveryTotal'         => number_format($deliveryTotal3),
  315.             'profitNet'             => number_format($profitNet3),
  316.             'moyenne' => number_format($moyenneAvecFrais3),
  317.             'moyenneSansFrais' => number_format($moyenneSansFrais3),
  318.             'satatus' => $countStatut,
  319.             //'conditions' => $countCondition
  320.         ];
  321.         $output = array(
  322.             'data' => array(),
  323.             'meta' => array(
  324.                 'page' => $pagination['page'],
  325.                 'perpage' => $limit,
  326.                 "pages" => ceil($count['count'] / $limit),
  327.                 "total" => $count['count'],
  328.             ),
  329.             'statistic' => $statistic
  330.         );
  331.         $now = new \DateTime("now");
  332.         $after3Days=(new \DateTime("now"))->modify('+3 day');
  333.             foreach ($entities as $entity) {
  334.                 $extra_info="";
  335.                 if ($request->get('reference') && $entity->getType() =="echange") {
  336.                     $reference $request->get('reference');
  337.                     if ($request->get('typeElement') && $request->get('typeElement') == 'produit'){
  338.                             $count_ech_recieve $entity->getDocumentDeclinationProduits()->filter(function ($prod) use ($reference) {
  339.                                 return $prod->getType() == "declinationEchange" &&  $prod->getProduitDeclinationValue()->getProduit()->getId() == $reference;
  340.                             })->count();
  341.                             $count_ech_send $entity->getDocumentDeclinationProduits()->filter(function ($prod) use ($reference) {
  342.                                 return $prod->getType() != "declinationEchange" &&  $prod->getProduitDeclinationValue()->getProduit()->getId() == $reference;
  343.                             })->count();
  344.                         if ($count_ech_recieve && $count_ech_send 0) {
  345.                             $extra_info "<br><small><span class='thirdlabel thirdlabel-supplier'>{$count_ech_recieve} prd <i class='flaticon-download'></i></span> 
  346.                                            <span class='thirdlabel thirdlabel-client'>{$count_ech_send} prd <i class='flaticon-paper-plane'></i></span></small>";
  347.                         } elseif ($count_ech_recieve 0) {
  348.                             $extra_info "<br><small><span class='thirdlabel thirdlabel-supplier'>{$count_ech_recieve} prd <i class='flaticon-download'></i></span></small>";
  349.                         } elseif ($count_ech_send 0) {
  350.                             $extra_info "<br><small><span class='thirdlabel thirdlabel-client'>{$count_ech_send} prd <i class='flaticon-paper-plane'></i></span></small>";
  351.                         }
  352.                     }else{
  353.                         $found $entity->getDocumentDeclinationProduits()->exists(function ($key$prod) use ($reference) {
  354.                             return $prod->getType() == "declinationEchange" && $prod->getProduitDeclinationValue()->getId() == $reference;
  355.                         });
  356.                         $extra_info $found "<br><small><span class='thirdlabel thirdlabel-supplier'>Article retourné</span></small>"
  357.                             "<br><small><span class='thirdlabel thirdlabel-client'>Article envoyé</span></small>";
  358.                     }
  359.                 }
  360.                 $array1= [
  361.                     'id' => $entity->getId(),
  362.                     'status' => $entity->getStatus(),
  363.                     'conditionDocument' => $entity->getConditionDocument(),
  364.                     'internalNbr' => $entity->getInternalNbr().$extra_info,
  365.                     'createdAt' => $entity->getCreatedAt()->format('d/m/Y H:i'),
  366.                     'promisedAt' => ($entity->getPromisedAt()?
  367.                         '<span class="m--font-'.(($entity->getPromisedAt()<$now && in_array($entity->getStatus(),['en-attente','accepte','expedie']) )?"danger":
  368.                             (($entity->getPromisedAt()<$after3Days &&  in_array($entity->getStatus(),['en-attente','accepte','expedie']))?"warning":"success")).'">'.$entity->getPromisedAt()->format('d/m/Y').'</span>'
  369.                         :"").($entity->getShippedAt() && in_array($entity->getStatus(),['expedie','livre','paye','retour-en-cours','retourne'])?"<small> <span class='m--font-info'>Exp le:".$entity->getShippedAt()->format('d/m/Y')."</span><br><i class='fa fa-truck'></i> ".$entity->getDelivery()->getName().
  370.                             '<br><i class="fa fa-chain"></i><code title="N° Suivie"><a href="'.$entity->getUrlTracking().'">'.$entity->getParcelTrackingNbr()."</a></code></small>":"")
  371.                     ,
  372.                     
  373.                     'shippedAt' => $entity->getShippedAt() ? $entity->getShippedAt()->format('d/m/Y H:i') : '',
  374.                     'bonrecuAt' => $entity->getBonrecuAt() ? $entity->getBonrecuAt()->format('d/m/Y H:i') : '',
  375.                     'aPayerLe' => $entity->getAPayerLe() ? $entity->getAPayerLe()->format('d/m/Y H:i') : '',
  376.                     'transporteur' => $entity->getDelivery() ? $entity->getDelivery()->getName() : '',
  377.                     'tracking' => $entity->getParcelTrackingNbr(),
  378.                     'urlTracking' => $entity->getUrlTracking(),
  379.                     
  380.                     'totalAmountTtc' => number_format($entity->getTotalAmountTtc(), 3),
  381.                     //'source' => ($entity->getSource())?$entity->getSource()->getName():"NULL",
  382.                     'sourceId'   => $entity->getSource() ? $entity->getSource()->getId()   :"NULL",
  383.                     'sourceName' => $entity->getSource() ? $entity->getSource()->getName() :"NULL",
  384.                     'sourceIcon' => $entity->getSource() ? $entity->getSource()->getIcon() :"NULL",
  385.                     'nbrProduits' => count($entity->getDocumentProduits())+count($entity->getDocumentDeclinationProduits()->filter(function ($prod) {
  386.                             return $prod->getType() != "declinationEchange";
  387.                         })),
  388.                     'address' => '<small>'.$entity->getAdress() .'</small>',
  389.                     'user' => '<small>'.$entity->getUser()->getFirstName() .'</small>',
  390.                     
  391.                      
  392.                     'actions' => 'actions',
  393.                 ];
  394.                 $array2= ($request->get('category') == 'client' || $request->get('client'))?[
  395.                     'type' => 'client',
  396.                     'phone' => $entity->getClient()->getPhone(),
  397.                     'client' => $entity->getClient()->getCivility() . ' ' $entity->getClient()->getFirstName() ,
  398.                     'idClient' => $entity->getClient()->getId(),
  399.                     'region' =>   $entity->getClient()->getRegion(),
  400.                     'clientType' => $entity->getClient()->getClientType(),
  401.                 ]:[
  402.                     'supplier' => $entity->getSupplier()->getName(),
  403.                     'idSupplier' => $entity->getSupplier()->getId(),
  404.                     'phone' => $entity->getSupplier()->getPhone(),
  405.                     'type' => 'supplier',
  406.                     'region' =>   $entity->getSupplier()->getRegion(),
  407.                 ];
  408.                 $output['data'][] = array_merge($array1$array2);
  409.             }
  410.         return new JsonResponse($output);
  411.     }
  412.     /**
  413.      * @Route("/create/{type}/{category}/{id}", name="new_document_commande", methods={"GET","POST"}, options={"expose"=true}, defaults={"type"="commande"})
  414.      */
  415.     public function createCommande($type,$category$idRequest $request,EntityManagerInterface $em): Response {
  416.         $rights=$this->hasRightByType$request,$category,'DOCUMENT_CLIENT_CREATE','DOCUMENT_SUPPLIER_CREATE');
  417.         $document = new Document();
  418.         $date = new \DateTime('now');
  419.         $document->setType($type)
  420.             ->setCategory($category)
  421.             ->setCreatedAt(new \DateTime('now'))
  422.             //->setEndAt($date->add(new \DateInterval('P30D')))
  423.             ->setUser($this->getUser())
  424.             ->setStatus('en-attente')
  425.             ->setConditionDocument('Creation')
  426.             ->setDiscountType('amount')
  427.             ->setPaymentMethod('especes')
  428.             ->setTotalPaid(0); 
  429.         if( $category == 'client') {
  430.             $client $this->userRepository->find($id);
  431.             $deliverys $this->deliveryRepository->findAllByTypes(['client','client-fournisseur']);
  432.             
  433.             $document->setInternalNbr('BDC-' date('dmY') . '-' rand(1000099999))
  434.                 ->setClient($client);  
  435.         } else {
  436.             $supplier $this->supplierRepository->find($id);
  437.             $deliverys $this->deliveryRepository->findAllByTypes(['fournisseur','client-fournisseur']);
  438.             if(in_array($type,['retour','reception']))$document->setStatus("brouillon");
  439.             $document->setInternalNbr((($type=="achat")?'DA-':((($type=="reception"))?"B-REC-":"BR-")) . date('dmY') . '-' rand(1000099999))
  440.                 ->setSupplier($supplier);
  441.                
  442.         }
  443.         if( $request->isMethod('POST')) {
  444.             if( $request->get('form_document')) {
  445.                 $data $request->get('form_document');
  446.                 
  447.                
  448.                 if (!empty($data['promotion_id'])) {
  449.                     $promotion $this->promotionRepository->find((int) $data['promotion_id']);
  450.                     if ($promotion !== null) {
  451.                         $document->setPromotion($promotion);
  452.                     }
  453.                 }
  454.                 //check if this document has already created
  455.                 if($documentChecked=$this->documentRepository->findOneBy(['internalNbr'=>$data['internalNbr']])){
  456.                     $request->getSession()->getFlashBag()->add('danger'"Une  réplication de création de bon de commande a été détectée !!! ");
  457.                      return $this->redirectToRoute('document_show', ['id' => $documentChecked->getId()]);
  458.                 }
  459.                 //check if the qty of a product to return is avalaible
  460.                 if($category == 'fournisseur' && $type=="retour"){
  461.                     if( isset($data['content']) && $data['content']) {
  462.                         foreach ($data['content'] as $item) {
  463.                             $produitDecllination $this->produitDeclinationValueRepository->find($item['id']);
  464.                             $stock $produitDecllination->getStocks()[0];
  465.                             if($stock && (($stock->getQtStock() - $item['quantity'])<0)){
  466.                                 $request->getSession()->getFlashBag()->add('danger',
  467.                                     "vérifiez la quantité retournée, la Dec ".$produitDecllination->getName()." n'a pas de quantité retournée disponible !!!");
  468.                                 $route $request->headers->get('referer');
  469.                                 return $this->redirect($route);
  470.                             }
  471.                         }
  472.                     }
  473.                 }
  474.                 
  475.                 if( $data['discount'] == ""$data['discount'] = 0;
  476.                 $source null;
  477.                 if ($category === 'client' && isset($data['source']['id']) && $data['source']['id']) {
  478.                     $source $this->sourceRepository->find($data['source']['id']);
  479.                     
  480.                 }
  481.                
  482.                 $dateDelivery = (!empty($data['promisedAt'])) ? new \DateTime($data['promisedAt']) : null;
  483.                
  484.                 $datebonlivraison = (!empty($data['shippedAt'])) ? new \DateTime($data['shippedAt']) : null;
  485.                 $datebonrecu = (!empty($data['bonrecuAt'])) ? new \DateTime($data['bonrecuAt']) : null;
  486.                 $dateAPayerLe = (!empty($data['aPayerLe'])) ? new \DateTime($data['aPayerLe']) : null;
  487.                 
  488.                 
  489.                 $delivery $this->deliveryRepository->find($data['delivery']['id']);
  490.                 
  491.                 
  492.                 $tvaDelivery $this->tvaRepository->find($data['delivery']['tva']);
  493.                 $document->setInternalNbr($data['internalNbr'])
  494.                         ->setExternalNbr(!empty($data['externalNbr']) ? $data['externalNbr'] : '')
  495.                         ->setSource($source)
  496.                         ->setObject($data['object'])
  497.                         ->setTotalAmountHt($data['totalAmountHt'])
  498.                         ->setTotalTva($data['totalTva'])
  499.                         ->setTotalAmountTtc($data['totalAmountTtc'])
  500.                         ->setAdress(!empty($data['adress']) ? $data['adress'] : null)
  501.                         ->setParcelTrackingNbr($data['parcelTrackingNbr'])
  502.                         ->setPaymentMethod($data['paymentMethod'])
  503.                         ->setPaymentDeadline($data['paymentDeadline'])
  504.                         ->setPaymentRef($data['paymentRef'])
  505.                         ->setDiscount($data['discount'])
  506.                         ->setDiscountType($data['discountType'])
  507.                         ->setAdvancePayment($data['advancePayment'])
  508.                         ->setAdvancePaymentType($data['advancePaymentType'])
  509.                         ->setPackagesNbr($data['packagesNbr'])
  510.                         ->setUrlTracking($data['urlTracking'])
  511.                         ->setPromisedAt($dateDelivery)
  512.                         ->setShippedAt($datebonlivraison)
  513.                         ->setBonrecuAt($datebonrecu)
  514.                         ->setBonrecuAt($dateAPayerLe)
  515.                         ->setNote($data['note'])
  516.                         
  517.                         ->setDelivery($delivery)
  518.                         ->setDeliveryDiscount($data['delivery']['discount'])
  519.                         ->setDeliveryDiscountType($data['delivery']['discount_type'])
  520.                         ->setDeliveryPrice($data['delivery']['price_ht'])
  521.                         ->setDeliveryTotal($data['delivery']['total_amount_ttc'])
  522.                         ->setIsFreeDelivery((isset($data['isFreedelivery']) && $data['isFreedelivery'] == "on"))
  523.                         ->setDeliveryTva($tvaDelivery);
  524.                 if( isset($data['comment']) && $data['comment']) {
  525.                     foreach ($data['comment'] as $item) {
  526.                         $comment = new Comment();
  527.                         $comment->setCreateAt(new \DateTime('now'))
  528.                                 ->setDescription($item)
  529.                                 ->setUser($this->getUser())
  530.                                 ->setDocument($document);
  531.                         $em->persist($comment);
  532.                         $document->addDocumentComment($comment);
  533.                     }
  534.                 }
  535.                 $em->persist($document);
  536.                 if( isset($data['content']) && $data['content']) {
  537.                     foreach ($data['content'] as $item) {
  538.                         if( $item['type'] == 'produit') {
  539.                             $entity = new DocumentProduit();
  540.                             $entity->setType($item['type']);
  541.                             if( isset($item['id']) && $item['id']) {
  542.                                 $produit $this->produitRepository->find($item['id']);
  543.                                 $entity->setProduit($produit);
  544.                                 $entity->setUnite((isset($item['unit']) && $item['unit'])?$item['unit']
  545.                                     :$produit->getUnit());
  546.                             }
  547.                         } else {
  548.                             $entity = new DocumentDeclinationProduit();
  549.                             $entity->setType($item['type']);
  550.                             if( isset($item['id']) && $item['id']) {
  551.                                 $produitDecllination $this->produitDeclinationValueRepository->find($item['id']);
  552.                                 $entity->setProduitDeclinationValue($produitDecllination);
  553.                                 $stock $produitDecllination->getStocks()[0];
  554.                                 if( $stock) {
  555.                                     if( $category == 'client') {
  556.                                         $stock->setQtReserved($stock->getQtReserved() + $item['quantity']);
  557.                                     }else{
  558.                                         if($type=="achat"){
  559.                                             //do nothing
  560.                                         }elseif($type=="reception"){
  561.                                             $stock->setQtStock($stock->getQtStock() + $item['quantity']);
  562.                                         }elseif($type=="retour"){
  563.                                             $newQty=$stock->getQtStock() - $item['quantity'];
  564.                                             if($newQty>=0){
  565.                                                 $stock->setQtStock($newQty);
  566.                                             }
  567.                                         }
  568.                                     }
  569.                                 } else {
  570.                                     $stock = new Stock();
  571.                                     if( $category == 'client') {
  572.                                         $stock->setDeclinationProduit($produitDecllination)
  573.                                                 ->setQtReserved($item['quantity'])
  574.                                                 ->setQtStock(0)
  575.                                                 ->setStorehouse('Principal');
  576.                                     } else {
  577.                                         if($type=="achat" || $type=="retour"){
  578.                                             $stock->setDeclinationProduit($produitDecllination)
  579.                                                 ->setQtReserved(0)
  580.                                                 ->setQtStock(0)
  581.                                                 ->setStorehouse('Principal');
  582.                                         }elseif($type=="reception"){
  583.                                             $stock->setDeclinationProduit($produitDecllination)
  584.                                                 ->setQtReserved(0)
  585.                                                 ->setQtStock($item['quantity'])
  586.                                                 ->setStorehouse('Principal');
  587.                                         }
  588.                                     }
  589.                                     $em->persist($stock);
  590.                                 }
  591.                                     $entity->setUnite((isset($item['unit']) && $item['unit'])?
  592.                                         $item['unit']:$produitDecllination->getProduit()->getUnit());
  593.                             }
  594.                         }
  595.                         // Calcul du total HT (avec remise éventuelle)
  596.                         $priceHt      = (float) ($item['price_ht'] ?? 0);
  597.                         $qty          = (float) ($item['quantity'] ?? 0);
  598.                         $discount     = (float) ($item['discount'] ?? 0);
  599.                         $discountType $item['discount_type'] ?? null;
  600.                         $totalHt $priceHt $qty;
  601.                         if ($discount 0) {
  602.                             if ($discountType === 'percent') {
  603.                                 $totalHt -= round($totalHt $discount 1003);
  604.                             } else { // montant
  605.                                 $totalHt -= $discount;
  606.                             }
  607.                         }
  608.                         $totalHt max(0round($totalHt3));
  609.                         $tva =($item['tva'] != "0")? $this->tvaRepository->find($item['tva']): $this->tvaRepository->findOneBy(["number" => 0]);
  610.                         $entity->setReference($item['reference'])
  611.                                 ->setDiscount($item['discount'])
  612.                                 ->setDiscountType($item['discount_type'])
  613.                                 ->setPriceHt($item['price_ht'])
  614.                                 ->setQuantity($item['quantity'])
  615.                                 ->setCreatedAt(new \DateTime('now'))
  616.                                 ->setTotalAmountHt($totalHt)
  617.                                 ->setTotalAmountTtc($item['total_amount_ttc'])
  618.                                 ->setTva($tva)
  619.                                 ->setDocument($document);
  620.                         if( isset($item['description']) && $item['description'])
  621.                             $entity->setDescription($item['description']);
  622.                         $em->persist($entity);
  623.                     }
  624.                 }
  625.             }
  626.             $message '[' $this->getUser()->getFullName() . '] a créé le bon de commande.';
  627.             $this->activityService->addActivity('info'$message$document$this->getUser(), 'document');
  628.             $em->flush();
  629.             $request->getSession()->getFlashBag()->add('success',
  630.                 (($type=="commande")?"Le bon de commande":(($type=="achat")?"La demande d'achat":((($type=="reception"))?"Le Bon de réception":"Le Bon de retour"))).{$document->getInternalNbr()} a été créé avec succès");
  631.             return (array_key_exists('save'$data) && $data['save']=="save")?
  632.             $this->redirectToRoute('edit_document_commande', ['type' =>$document->getType(),'document'=>$document->getId(),'category'=>$document->getCategory()]):
  633.             $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  634.         }
  635.         $tvas $this->tvaRepository->findAll();
  636.         $sources $this->sourceRepository->findAll();
  637.         $declinationCouleur $this->declinationRepository->findOneBy(["name" => "Couleur"]);
  638.          //dump($document->getType()); die;
  639.         $template = ($category === 'fournisseur')  ? '@admin/document/create_document_fournisseur.html.twig'  '@admin/document/create_document_client.html.twig';
  640.         return $this->render($template, [
  641.             'document' => $document,
  642.             'type' => $type,
  643.             'category' => $category,
  644.             'id' => $id,
  645.             'tvas' => $tvas,
  646.             'deliverys' => $deliverys,
  647.             'sources' => $sources,
  648.             'rights' => $rights,
  649.             'declinationCouleur' => $declinationCouleur
  650.         ]);
  651.        
  652.     }
  653.     /**
  654.      * @Route("/verify/client/{client}", name="verify_cond_document", methods="GET|POST", options = { "expose" =  true})
  655.      */ 
  656.     public function verifyConditionToCreateDocument(Request $request$clientDocumentRepository $documentRepositoryRouterInterface $router): JsonResponse
  657.     {
  658.         $statusesToCheck = ['en-attente''accepte'];
  659.         // Vérification 1 : statut
  660.         $documentsByStatus $documentRepository->search0100$statusesToChecknullnull$client'commande''client');
  661.         // Vérification 2 : date
  662.         $before3Days = (new \DateTime())->sub(new \DateInterval('P3D'));
  663.         $documentsByDate $documentRepository->search0100nullnullnull,$client'commande''client'nullnull$before3Days );
  664.         //$router = $this->router;
  665.         $formatDocs = function ($docs) use ($router) {
  666.             return array_map(function ($doc) {
  667.                 return [
  668.                     'internalNbr' => $doc->getInternalNbr(),
  669.                     'status' => $doc->getStatus(),
  670.                     'createdAt' => $doc->getCreatedAt()?->format('d/m/Y'),
  671.                     'link' => $this->generateUrl('document_show', ['id' => $doc->getId()])
  672.                 ];
  673.             }, $docs);
  674.         };
  675.         return new JsonResponse([
  676.             'statusCheck' => $formatDocs($documentsByStatus),
  677.             'dateCheck' => $formatDocs($documentsByDate),
  678.         ]);
  679.     }
  680.     
  681.     /**
  682.      * @Route("/accept/commande/{id}", name="accept_commande", methods={"GET","POST"}, options={"expose"=true})
  683.      */
  684.     public function acceptCommande(Document $document,EntityManagerInterface $em,Request $request): Response {
  685.         if( $document->getStatus() == "en-attente") {
  686.             $document->setStatus("accepte");
  687.             $document->setConditionDocument($document->getConditionDocument()." -> Accepté");
  688.         }else{
  689.             $request->getSession()->getFlashBag()->add('danger'"Attention le bon de commande {$document->getInternalNbr()} a déjà été {$document->getStatus()}");
  690.             return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  691.         }
  692.         $message '[' $this->getUser()->getFullName() . '] a accepté le bon de commande de Réf: ' $document->getInternalNbr();
  693.         $this->activityService->addActivity('success'$message$document$this->getUser(), 'document');
  694.         $em->flush();
  695.         $request->getSession()->getFlashBag()->add('success'"Le bon de commande {$document->getInternalNbr()} a été accepté avec succès");
  696.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  697.     }
  698.     /**
  699.      * @Route("/validate/reception/{id}", name="accept_bon_reception", methods={"GET","POST"}, options={"expose"=true})
  700.      */
  701.     public function acceptBonReception(Document $document,EntityManagerInterface $em,Request $request): Response {
  702.         if( $document->getStatus() == "brouillon") {
  703.             $document->setStatus("Validé");
  704.             $document->setConditionDocument($document->getConditionDocument()." -> Validé");
  705.         }else{
  706.             $request->getSession()->getFlashBag()->add('danger'"Attention le Bon de reception {$document->getInternalNbr()} a déjà été {$document->getStatus()}");
  707.             return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  708.         }
  709.         $message '[' $this->getUser()->getFullName() . '] a validé le bon de réception de Réf: ' $document->getInternalNbr();
  710.         $this->activityService->addActivity('success'$message$document$this->getUser(), 'document');
  711.         $em->flush();
  712.         $request->getSession()->getFlashBag()->add('success'"Le Bon de réception {$document->getInternalNbr()} a été validé avec succès");
  713.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  714.     }
  715.     /**
  716.      * @Route("/cancel-validation/recption/{id}", name="annul_validation_bon_reception", methods={"GET","POST"}, options={"expose"=true})
  717.      */
  718.     public function cancelValidationOfBonReception(Document $document,EntityManagerInterface $em,Request $request): Response {
  719.         if( $document->getStatus() == "Validé") {
  720.             $document->setStatus("brouillon");
  721.             $document->setConditionDocument($document->getConditionDocument()." -> Brouillon");
  722.             $message '[' $this->getUser()->getFullName() . "] a annulé la validation de bon de réception de Réf: " $document->getInternalNbr();
  723.             $this->activityService->addActivity('warning'$message$document$this->getUser(), 'document');
  724.             $request->getSession()->getFlashBag()->add('success'"Bon de réception devient brouillon");
  725.         } else
  726.             $request->getSession()->getFlashBag()->add('danger',
  727.                 "Ce bon de réception de réf {$document->getInternalNbr()} ".($document->getStatus()=="brouillon")?
  728.                     " a déjà été annulée ":" a déjà été Validé");
  729.         $em->flush();
  730.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  731.     }
  732.     /**
  733.      * @Route("/cancel-acceptation/commande/{id}", name="annul_accept_commande", methods={"GET","POST"}, options={"expose"=true})
  734.      */
  735.     public function cancelAcceptationOfCommande(Document $document,EntityManagerInterface $em,Request $request): Response {
  736.         if( ($document->getStatus() == "accepte" && !$document->getDocument())
  737.             || ($document->getStatus() == "accepte" && $document->getType() == "echange")) {
  738.             $document->setStatus("en-attente");
  739.             $document->setConditionDocument($document->getConditionDocument()." -> En attente");
  740.             $message '[' $this->getUser()->getFullName() . "] a annulé l'acceptation de bon commande de Réf: " $document->getInternalNbr();
  741.             $this->activityService->addActivity('warning'$message$document$this->getUser(), 'document');
  742.             $request->getSession()->getFlashBag()->add('success'"Bon commande est en attente");
  743.         } else
  744.             $request->getSession()->getFlashBag()->add('danger',
  745.                 "Ce bon de commande de réf {$document->getInternalNbr()} ".($document->getStatus()=="en-attente")?
  746.                 " a déjà été annulée ":" a déjà été Expédié");
  747.         $em->flush();
  748.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  749.     }
  750.     /**
  751.      * @Route("/cancel-pending-shipment/commande/{id}", name="cancel_pending_shipment_commande", methods={"GET","POST"}, options={"expose"=true})
  752.      */
  753.     public function cancelPendingShipmentOfCommande(Document $documentEntityManagerInterface $emRequest $request): Response
  754.     {
  755.         if ($document->getStatus() == "a-expedier") {
  756.             $document->setStatus("accepte");
  757.             $document->setConditionDocument($document->getConditionDocument()." -> Accepté");
  758.             $message ='[' $this->getUser()->getFullName() . "] a remis le bon de commande de Réf: " $document->getInternalNbr() . " au statut 'accepté'.";
  759.             $this->activityService->addActivity('info'$message$document$this->getUser(), 'document');
  760.             $request->getSession()->getFlashBag()->add('success'"bon de commande remis au statut accepté.");
  761.         } else {
  762.             $request->getSession()->getFlashBag()->add('danger',
  763.                 "Ce bon de commande ne peut pas être remis au statut accepté.");
  764.         }
  765.         $em->flush();
  766.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  767.     }
  768.     /**
  769.      * @Route("/admin/document/{category}/{id}/pending-shipment/{idCommande}", name="pending_shipment_commande")
  770.      */
  771.     public function pendingShipmentCommande($category$id$idCommandeRequest $requestEntityManagerInterface $em): Response
  772.     {
  773.         $document $this->documentRepository->find($idCommande);
  774.         if ($document && $document->getStatus() === "accepte") {
  775.             $this->hasRightByType($request$category'DOCUMENT_CLIENT_CREATE''DOCUMENT_SUPPLIER_CREATE');
  776.             $auto        $request->get('auto_document') ?? [];
  777.             $suivi       $auto['parcelTrackingNbr'] ?? null;
  778.             $delivery_id $auto['delivery_id'] ?? null;
  779.             $urlTracking $auto['urlTracking'] ?? null;
  780.             $packagesNbr $auto['packagesNbr'] ?? null;
  781.             $delivery $delivery_id $this->deliveryRepository->find($delivery_id) : null;
  782.             $document->setParcelTrackingNbr($suivi)
  783.                     ->setUrlTracking($urlTracking)
  784.                     ->setPackagesNbr($packagesNbr);
  785.             if ($delivery) {
  786.                 $companyTotal = (float) ($delivery->getTotalPrice() ?? 0);
  787.                 $document->setDeliveryCompanyTotal(number_format($companyTotal3'.'''));
  788.                 $document->setDelivery($delivery)
  789.                         ->setDeliveryDiscount($document->getDeliveryDiscount())
  790.                         ->setDeliveryDiscountType($document->getDeliveryDiscountType())
  791.                         ->setDeliveryPrice($document->getDeliveryPrice())
  792.                         ->setDeliveryTva($document->getDeliveryTva())
  793.                         ->setIsFreeDelivery($document->getIsFreeDelivery());
  794.                 $tva    $document->getDeliveryTva() ? (float)$document->getDeliveryTva()->getNumber() : 0.0;
  795.                 $price  = (float)$document->getDeliveryPrice();
  796.                 $disc   = (float)$document->getDeliveryDiscount();
  797.                 $isPct  $document->getDeliveryDiscountType() === 'percent';
  798.                 $priceAfterDisc $isPct ? ($price - ($price $disc 100)) : ($price $disc);
  799.                 $totalClientTtc $priceAfterDisc + ($price $tva 100);
  800.                 if ($document->getIsFreeDelivery()) {
  801.                     $totalClientTtc 0.0;
  802.                 }
  803.                 $document->setDeliveryTotal(number_format($totalClientTtc3'.'''));
  804.             }
  805.             // Ici, on ne met pas "expedie", mais "a-expedier"
  806.             $document->setStatus("a-expedier")
  807.                     ->setConditionDocument($document->getConditionDocument() . " -> En attente d'expédition");
  808.             $message ='[' $this->getUser()->getFullName() . "] a mis le bon de commande en attente d'expédition.";
  809.             $this->activityService->addActivity('info'$message$document$this->getUser(), 'document');
  810.             $em->persist($document);
  811.             $em->flush();
  812.             $request->getSession()->getFlashBag()->add(
  813.                 'success',
  814.                 (($document->getCategory() == 'client') ? "Le bon de commande" "Le bon réception") .
  815.                 " de réf {$document->getInternalNbr()} est désormais en attente d'expédition."
  816.             );
  817.         } else {
  818.             $request->getSession()->getFlashBag()->add(
  819.                 'danger',
  820.                 "Ce bon de commande de réf {$document->getInternalNbr()} doit être accepté avant de passer en attente d'expédition."
  821.             );
  822.         }
  823.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  824.     }
  825.     /**
  826.      * expedier BC  avec la saisie des details de livraison
  827.      * @Route("/shipment/commande/{category}/{id}/{idCommande}", name="auto_document", methods={"GET","POST"}, options={"expose"=true})
  828.      */
  829.     public function shipCommande($category$id$idCommandeRequest $requestEntityManagerInterface $em): Response
  830.     {
  831.         $document $this->documentRepository->find($idCommande);
  832.         // corrige la condition (parenthèses)
  833.         if ($document && (
  834.                 $document->getStatus() === "accepte" ||
  835.                 $document->getStatus() === "a-expedier" ||
  836.                 ($document->getStatus() === "brouillon" && $document->getType() === 'retour')
  837.             )) {
  838.             $this->hasRightByType($request$category'DOCUMENT_CLIENT_CREATE''DOCUMENT_SUPPLIER_CREATE');
  839.             $auto        $request->get('auto_document') ?? [];
  840.             $suivi       $auto['parcelTrackingNbr'] ?? null;
  841.             $delivery_id $auto['delivery_id'] ?? null;
  842.             $urlTracking $auto['urlTracking'] ?? null;
  843.             $packagesNbr $auto['packagesNbr'] ?? null;
  844.             $delivery $delivery_id $this->deliveryRepository->find($delivery_id) : null;
  845.             $document->setShippedAt(new \DateTime('now'))
  846.                     ->setParcelTrackingNbr($suivi)
  847.                     ->setUrlTracking($urlTracking)
  848.                     ->setPackagesNbr($packagesNbr);
  849.             if ($delivery) {
  850.                 // total transporteur TTC (coût réel société de livraison)
  851.                 $companyTotal = (float) ($delivery->getTotalPrice() ?? 0); // delivery.total_price
  852.                 $document->setDeliveryCompanyTotal(number_format($companyTotal3'.'''));
  853.                 // total client TTC (ton calcul existant)
  854.                 $document->setDelivery($delivery)
  855.                         ->setDeliveryDiscount($document->getDeliveryDiscount())
  856.                         ->setDeliveryDiscountType($document->getDeliveryDiscountType())
  857.                         ->setDeliveryPrice($document->getDeliveryPrice())
  858.                         ->setDeliveryTva($document->getDeliveryTva())
  859.                         ->setIsFreeDelivery($document->getIsFreeDelivery());
  860.                 $tva    $document->getDeliveryTva() ? (float)$document->getDeliveryTva()->getNumber() : 0.0;
  861.                 $price  = (float)$document->getDeliveryPrice();
  862.                 $disc   = (float)$document->getDeliveryDiscount();
  863.                 $isPct  $document->getDeliveryDiscountType() === 'percent';
  864.                 $priceAfterDisc $isPct ? ($price - ($price $disc 100)) : ($price $disc);
  865.                 $totalClientTtc $priceAfterDisc + ($price $tva 100);
  866.                 // si livraison gratuite côté client
  867.                 if ($document->getIsFreeDelivery()) {
  868.                     $totalClientTtc 0.0;
  869.                 }
  870.                 $document->setDeliveryTotal(number_format($totalClientTtc3'.'''));
  871.             }
  872.             if ($category === "client") {
  873.                 $document->setStatus("expedie")
  874.                         ->setConditionDocument($document->getConditionDocument() . " -> Expédié")
  875.                         ->setExternalNbr('BDL-' date('dmY') . '-' rand(1000099999));
  876.             } else {
  877.                 $document->setStatus("expedie")
  878.                         ->setConditionDocument($document->getConditionDocument() . " -> Expédié")
  879.                         ->setInternalNbr('F_BR-' date('dmY') . '-' rand(1000099999));
  880.             }
  881.             if ($document->getCategory() === 'client') {
  882.                 foreach ($document->getDocumentDeclinationProduits() as $dp) {
  883.                     if ($dp->getType() !== 'declinationEchange') {
  884.                         $stock $dp->getProduitDeclinationValue()->getStocks()[0] ?? null;
  885.                         if ($stock) {
  886.                             if ($stock->getQtReserved() > 0) {
  887.                                 $stock->setQtReserved($stock->getQtReserved() - $dp->getQuantity());
  888.                             }
  889.                             $stock->setQtStock($stock->getQtStock() - $dp->getQuantity());
  890.                         }
  891.                     }
  892.                 }
  893.             }
  894.             $message ='[' $this->getUser()->getFullName() . "] a expédié le bon de commande.";
  895.             $this->activityService->addActivity('info'$message$document$this->getUser(), 'document');
  896.             $em->persist($document);
  897.             $em->flush();
  898.             $request->getSession()->getFlashBag()->add(
  899.                 'success',
  900.                 (($document->getCategory() == 'client') ? "Le bon de commande" "Le bon reception") .
  901.                 " de réf {$document->getInternalNbr()} a été expédié avec succès"
  902.             );
  903.         } else {
  904.             $request->getSession()->getFlashBag()->add(
  905.                 'danger',
  906.                 "Ce bon de commande de réf {$document->getInternalNbr()} " .
  907.                 (($document->getStatus() == "expedie") ? " a déjà été expédié " " doit être accepté avant")
  908.             );
  909.         }
  910.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  911.     }
  912.     /**
  913.      * @Route("/admin/document/{id}/payment-state/{state}", name="document_payment_state",  methods={"GET","POST"}, options={"expose"=true})
  914.      */
  915.     public function setPaymentState(Document $documentstring $stateRequest $requestPaymentUpdaterService $payment,EntityManagerInterface $em ): Response
  916.     {
  917.         $amount $request->request->get('amount');
  918.         $amount = ($amount !== null && $amount !== '') ? (float)$amount null;
  919.         $payment->setPaymentStatus($document$state$amount);
  920.         // ====== Historique + Flash comme les autres ======
  921.         $statusLabel = [
  922.             'paye' => 'Payé',
  923.             'partiellement-paye' => 'Partiellement payé',
  924.             'non-paye' => 'Non payé'
  925.         ];
  926.         $message =  '[' $this->getUser()->getFullName() . '] a marqué le bon de commande comme ' $statusLabel;
  927.         $this->activityService->addActivity('info'$message$document$this->getUser(), 'document');
  928.         $request->getSession()->getFlashBag()->add('success'"Le statut de paiement du bon de commande de réf " $document->getInternalNbr() . " a été mis à jour : " $state '.');
  929.         $em->flush();
  930.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  931.     }
  932.     /**
  933.      * @Route("/admin/document/{id}/mark-paid", name="document_mark_paid", methods={"GET","POST"}, options={"expose"=true})
  934.      */    
  935.     public function markPaid(Document $documentRequest $requestPaymentUpdaterService $payment,EntityManagerInterface $em): Response{
  936.         $amount $request->request->get('amount'); // si null => payé à 100%
  937.         $datePaid $request->request->get('date_paid');
  938.         $date $datePaid \DateTime::createFromFormat('Y-m-d'$datePaid) : null;
  939.         /*
  940.         if ($datePaid) {
  941.             $date = \DateTime::createFromFormat('Y-m-d', $datePaid);
  942.             $document->setPaidAt($date);
  943.         } else {
  944.             $document->setPaidAt(new \DateTime()); // fallback : aujourd'hui
  945.         }
  946.         dump($datePaid, $date); die;
  947.         */
  948.         $payment->setPaymentStatus($document'paye'$amount !== null ? (float)$amount null$date);
  949.         
  950.         // flush ici ou dans le PaymentUpdaterService selon organisation
  951.         $this->getDoctrine()->getManager()->flush();
  952.         
  953.         // ====== Historique + Flash comme les autres ======
  954.         $message =  '[' $this->getUser()->getFullName() . '] a marqué le bon de commande comme payé';
  955.         $this->activityService->addActivity('info'$message$document$this->getUser(), 'document');
  956.         $request->getSession()->getFlashBag()->add('success'"Le statut de paiement du bon de commande de réf " $document->getInternalNbr() . " a été mis à jour : Payé" '.');
  957.         $em->flush();
  958.         
  959.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  960.     }
  961.     /**
  962.      * @Route("/admin/document/{id}/refund/{mode}", name="document_refund", methods={"GET","POST"}, options={"expose"=true})
  963.      */
  964.     public function refund(
  965.         Document $doc,
  966.         string $mode,
  967.         Request $request,
  968.         PaymentUpdaterService $payment,
  969.         EntityManagerInterface $em,
  970.         RefundReasonRepository $refundReasonRepository
  971.     ): Response
  972.     {
  973.         $mode strtolower($mode);
  974.         // Modes : pending (marque à rembourser), finalize (finalise/remet le stock)
  975.         if (!in_array($mode, ['partial','full','pending','finalize'], true)) {
  976.             $this->addFlash('danger'"Mode de remboursement invalide.");
  977.             return $this->redirectToRoute('document_show', ['id' => $doc->getId()]);
  978.         }
  979.         if ($doc->getStatus() !== 'paye' && $doc->getStatus() !== 'a-rembourser') {
  980.             $this->addFlash('danger'"Seules les commandes payées ou à rembourser peuvent être traitées.");
  981.             return $this->redirectToRoute('document_show', ['id' => $doc->getId()]);
  982.         }
  983.         if ($mode === 'pending') {
  984.             // Marquer comme à rembourser (pas de remise en stock, pas de statut 'rembourse')
  985.             $refundReasonId $request->request->get('refund_reason_id');
  986.             $refundReason $refundReasonId $refundReasonRepository->find($refundReasonId) : null;
  987.             $refundNote $request->request->get('refund_reason_note''');
  988.             $doc->setStatus('a-rembourser');
  989.             $doc->setConditionDocument($doc->getConditionDocument()." -> À rembourser");
  990.             $doc->setRefundReason($refundReason);
  991.             $doc->setNote($refundNote);
  992.             $msg '[' $this->getUser()->getFullName() . "] a marqué le bon de commande de Réf: " $doc->getInternalNbr() . " comme à rembourser.";
  993.             $this->activityService->addActivity('info'$msg$doc$this->getUser(), 'document');
  994.             $em->flush();
  995.             $this->addFlash('info'"Le bon de commande {$doc->getInternalNbr()} est maintenant en attente de remboursement.");
  996.         }
  997.         elseif ($mode === 'finalize') {
  998.             // Finalise le remboursement et remet le stock (stock remis, statut 'rembourse')
  999.             if ($doc->getCategory() == 'client') {
  1000.                 foreach ($doc->getDocumentDeclinationProduits() as $documentDeclination) {
  1001.                     if ($documentDeclination->getType() != 'declinationEchange') {
  1002.                         $stock $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
  1003.                         if ($stock) {
  1004.                             $stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
  1005.                         }
  1006.                     }
  1007.                 }
  1008.             }
  1009.             $doc->setStatus('rembourse');
  1010.             $doc->setConditionDocument($doc->getConditionDocument()." -> Remboursé");
  1011.             $msg '[' $this->getUser()->getFullName() . "] a finalisé le remboursement du bon de commande de Réf: " $doc->getInternalNbr() . " (retour stock).";
  1012.             $this->activityService->addActivity('success'$msg$doc$this->getUser(), 'document');
  1013.             $em->flush();
  1014.             $this->addFlash('success'"Le bon de commande {$doc->getInternalNbr()} a été remboursé et les articles remis en stock.");
  1015.         }
  1016.         // ... (le reste de ta gestion, partial/full…)
  1017.         return $this->redirectToRoute('document_show', ['id' => $doc->getId()]);
  1018.     }
  1019.     /**
  1020.      * Bouton "Créer une facture" (pas de nouveaux champs — on utilise internal_nbr/created_at côté PDF).
  1021.      * @Route("/admin/document/{id}/create-invoice", name="document_create_invoice", methods={"GET","POST"}, options={"expose"=true})
  1022.      */
  1023.     public function createInvoice(Document $docEntityManagerInterface $em)
  1024.     {
  1025.         // Ici, pas d’écriture DB (tu as choisi d’utiliser internal_nbr + created_at).
  1026.         // Tu peux lancer une génération PDF/HTML selon ton système existant.
  1027.         // Exemple : return $this->redirectToRoute('document_invoice_pdf', ['id' => $doc->getId()]);
  1028.         return $this->redirectToRoute('document_show', ['id' => $doc->getId()]);
  1029.     }
  1030.     /**
  1031.      * @Route("/cancel-shipment/commande/{id}", name="annul_expedition_commande", methods={"GET","POST"}, options={"expose"=true})
  1032.      */
  1033.      /*-- Annuler l'expidition --*/
  1034.     public function cancelShipmentOfCommande(Document $document,EntityManagerInterface $em,Request $request): Response {
  1035.         
  1036.         /*Si l'utilsiateur n'a pas le droit d'accès*/ 
  1037.         if (!$this->isGranted('ROLE_SUPER_ADMIN')) {
  1038.             $this->addFlash('danger''Vous n’avez pas le droit d’effectuer cette action.');
  1039.             // Revenir à la page d’origine (ex. : page détail du document)
  1040.             return $this->redirectToRoute('document_show', [
  1041.                 'id' => $document->getId(),
  1042.             ]);
  1043.         }
  1044.         if( ($document->getStatus() == "expedie" && !$document->getDocument())|| ($document->getStatus() == "expedie" && $document->getType() == "echange")) {
  1045.             $document->setStatus("a-expedier")
  1046.                 ->setConditionDocument($document->getConditionDocument()." -> A Expedier");
  1047.             foreach ($document->getDocumentDeclinationProduits() as $documentDeclination) {
  1048.                 if( $documentDeclination->getType() != 'declinationEchange') {
  1049.                     $stock $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
  1050.                     if( $stock) {
  1051.                         if( $document->getCategory() == 'client') {
  1052.                             $stock->setQtReserved($stock->getQtReserved() + $documentDeclination->getQuantity());
  1053.                             $stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
  1054.                         } else {
  1055.                             $stock->setQtStock($stock->getQtStock() - $documentDeclination->getQuantity());
  1056.                         }
  1057.                     }
  1058.                 }
  1059.             }
  1060.             $message =  '[' $this->getUser()->getFullName() . "] a annulé l'expédition du bon de commande.";
  1061.             $this->activityService->addActivity('warning'$message$document$this->getUser(), 'document');
  1062.             $request->getSession()->getFlashBag()->add('success'"Bon commande est en attente");
  1063.         } else
  1064.             $request->getSession()->getFlashBag()->add('danger',
  1065.                 "Ce bon de commande de réf {$document->getInternalNbr()} ".($document->getStatus()=="a-expedier")?
  1066.                     " a déjà été annulée l'expédition ":" a déjà été Livré");
  1067.         $em->flush();
  1068.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1069.     }
  1070.     /**
  1071.      * @Route("/return-shipment/commande/{id}", name="return_expedition_commande", methods={"GET","POST"}, options={"expose"=true})
  1072.      */
  1073.     public function returnAfterShipmentOfCommande(Document $document,EntityManagerInterface $em,Request $request): Response {
  1074.         if( ($document->getStatus() == "retour-en-cours" && !$document->getDocument())|| ($document->getStatus() == "retour-en-cours" && $document->getType() == "echange")) {
  1075.             $document->setStatus("retourne")
  1076.                 ->setConditionDocument($document->getConditionDocument()." -> Retourné");
  1077.             $document->setReturnedAt(new \DateTime());
  1078.             foreach ($document->getDocumentDeclinationProduits() as $documentDeclination) {
  1079.                 if( $documentDeclination->getType() != 'declinationEchange') {
  1080.                     $stock $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
  1081.                     if( $stock) {
  1082.                         if( $document->getCategory() == 'client') {
  1083.                             $stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
  1084.                         } else {
  1085.                             $stock->setQtStock($stock->getQtStock() - $documentDeclination->getQuantity());
  1086.                         }
  1087.                     }
  1088.                 }
  1089.             }
  1090.             $message ='[' $this->getUser()->getFullName() . '] a retourné le bon de commande.';
  1091.             $this->activityService->addActivity('info'$message$document$this->getUser(), 'document');
  1092.             $request->getSession()->getFlashBag()->add('success'"La Commande de réf ".$document->getInternalNbr()." a  été retourné");
  1093.         } else
  1094.             $request->getSession()->getFlashBag()->add('danger',
  1095.                 "Ce bon de commande de réf {$document->getInternalNbr()} ".($document->getStatus()=="accepte")?
  1096.                     " a déjà été annulée l'expédition ":(($document->getStatus()=="retourne")?" a déjà été retourné":" a été Livré !!!"));
  1097.         $em->flush();
  1098.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1099.     }
  1100.     /**
  1101.      * @Route("/success-shipment/commande/{id}", name="success_expedition_commande", methods={"GET","POST"}, options={"expose"=true})
  1102.      */
  1103.     public function shipmentSuccessOfCommande(Document $document,EntityManagerInterface $em,Request $request): Response {
  1104.         if( ($document->getStatus() == "expedie" && !$document->getDocument())|| ($document->getStatus() == "expedie" && $document->getType() == "echange")) {
  1105.             $dateStr $request->request->get('delivered_at');
  1106.             if ($dateStr) {
  1107.                 $date \DateTime::createFromFormat('Y-m-d'$dateStr);
  1108.                 if ($date !== false) {
  1109.                     $document->setDeliveredAt($date);
  1110.                 }
  1111.             }
  1112.             $document->setStatus("livre")
  1113.                 ->setConditionDocument($document->getConditionDocument()." -> Livré");
  1114.            
  1115.             $message ='[' $this->getUser()->getFullName() . '] a livré le bon de commande.';
  1116.             $this->activityService->addActivity('success'$message$document$this->getUser(), 'document');
  1117.             $request->getSession()->getFlashBag()->add('success'"Bon commande est en attente");
  1118.         } else
  1119.             $request->getSession()->getFlashBag()->add('danger',
  1120.                 "Ce bon de commande de réf {$document->getInternalNbr()} ".($document->getStatus()=="accepte")?
  1121.                     " a déjà été annulée l'expédition ":(($document->getStatus()=="retourne")?" a déjà été retourné":" a déjà été Livré !!"));
  1122.         $em->flush();
  1123.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1124.     }
  1125.     
  1126.     /**
  1127.      * @Route("/invoice/commande/{id}", name="create_facture_document", methods={"GET","POST"}, options={"expose"=true})
  1128.      */
  1129.     public function createFactureCommande(Document $documentRequest $request,EntityManagerInterface $em): Response {
  1130.         // 1. Vérifier s'il existe déjà une facture liée à ce bon de commande
  1131.         $factureExistante null;
  1132.         foreach ($document->getDocuments() as $docFils) {
  1133.             if ($docFils->getType() === 'facture') {
  1134.                 $factureExistante $docFils;
  1135.                 break;
  1136.             }
  1137.         }
  1138.         if ($factureExistante) {
  1139.             $this->addFlash('danger',
  1140.                 "Ce bon de commande de réf {$document->getInternalNbr()} a déjà été facturé (Facture n° {$factureExistante->getInternalNbr()}).");
  1141.             return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1142.         }
  1143.         // 2. Conditions classiques :
  1144.         if( (in_array($document->getStatus(), ['livre''partiellement-paye''paye']) && $document->getType() === 'commande') || ($document->getStatus() == "Validé" && $document->getType() === 'reception')) {
  1145.             $newDocument = new Document();
  1146.             $date = new \DateTime('now');
  1147.             $type 'facture';
  1148.             $newDocument $this->createCopyDocument($newDocument$document);
  1149.             
  1150.             $newDocument->setDocument($document);
  1151.             
  1152.             $newDocument->setType($type);
  1153.             $newDocument->setCategory($document->getCategory());
  1154.             $newDocument->setCreatedAt(new \DateTime('now'));
  1155.             //$newDocument->setEndAt($date->add(new \DateInterval('P30D')));
  1156.             $newDocument->setUser($this->getUser());
  1157.             $newDocument->setStatus("facture");
  1158.             $newDocument->setConditionDocument("Facturé");
  1159.             
  1160.             /*
  1161.             foreach ($document->getDocumentComments() as $item) {
  1162.                 $comment = new Comment();
  1163.                 $comment->setCreateAt(new \DateTime('now'));
  1164.                 $comment->setDescription($item->getDescription())
  1165.                         ->setUser($item->getUser());
  1166.                 $em->persist($comment);
  1167.                 $newDocument->addDocumentComment($comment);
  1168.             }
  1169.             */
  1170.             
  1171.             $em->persist($newDocument);
  1172.             
  1173.             
  1174.             if( $document->getCategory() == "client") {
  1175.                 $newDocument->setInternalNbr('FAC-' date('dmY') . '-' rand(1000099999));
  1176.                 $client $document->getClient();
  1177.                 $newDocument->setClient($client);
  1178.             } else {
  1179.                 $newDocument->setInternalNbr('F_FAC-' date('dmY') . '-' rand(1000099999));
  1180.                 $supplier $document->getSupplier();
  1181.                 $newDocument->setSupplier($supplier);
  1182.             }
  1183.             foreach ($document->getDocumentDeclinationProduits() as $documentDeclinationProduit) {
  1184.                 $new = new DocumentDeclinationProduit();
  1185.                 $copy $this->createCopyDocumentProduit($new$documentDeclinationProduit);
  1186.                 $copy->setProduitDeclinationValue($documentDeclinationProduit->getProduitDeclinationValue());
  1187.                 $newDocument->addDocumentDeclinationProduit($copy);
  1188.                 $em->persist($copy);
  1189.             }
  1190.             
  1191.             foreach ($document->getDocumentProduits() as $documentProduit) {
  1192.                 $new = new DocumentProduit();
  1193.                 $copy $this->createCopyDocumentProduit($new$documentProduit);
  1194.                 $copy->setProduit($documentProduit->getProduit());
  1195.                 $newDocument->addDocumentProduit($copy);
  1196.                 $em->persist($copy);
  1197.             }
  1198.             
  1199.             //$document->setStatus("paye");
  1200.             $document->setConditionDocument($document->getConditionDocument()." -> Facturé");
  1201.             $message '[' $this->getUser()->getFullName() . ']  a facturé le bon de commande.';
  1202.             $this->activityService->addActivity('success'$message$document$this->getUser(), 'document');
  1203.          
  1204.             $em->flush();
  1205.             
  1206.             if( $newDocument->getCategory() == 'client')
  1207.                 $request->getSession()->getFlashBag()->add('success'"bon de commande de réf {$document->getInternalNbr()} a été facturé avec succès");
  1208.             else
  1209.                 $request->getSession()->getFlashBag()->add('success'"Bon reception de réf {$document->getInternalNbr()} a été facturé avec succès");
  1210.             return $this->redirectToRoute('document_show', ['id' => $newDocument->getId()]);
  1211.         } else
  1212.             $request->getSession()->getFlashBag()->add('danger',
  1213.                 "Ce bon de commande de réf {$document->getInternalNbr()} doit être payé pour que la facture puisse être crée !!!");
  1214.         
  1215.     }
  1216.     /**
  1217.      * @Route("/admin/avoir/{id}", name="create_avoir_document", methods={"POST"}, options={"expose"=true})
  1218.      */
  1219.     public function createAvoirFacture(Document $documentRequest $request,  EntityManagerInterface $em,   RefundReasonRepository $refundReasonRepository ): Response
  1220.     {
  1221.         // 1. Vérifier s'il existe déjà un avoir lié à cette facture
  1222.         $avoirExistante null;
  1223.         foreach ($document->getDocuments() as $docFils) {
  1224.             if ($docFils->getType() === 'avoir') {
  1225.                 $avoirExistante $docFils;
  1226.                 break;
  1227.             }
  1228.         }
  1229.         if ($avoirExistante) {
  1230.             $this->addFlash('danger',
  1231.                 "Cette facture de réf {$document->getInternalNbr()} a déjà été remboursée (Avoir n° {$avoirExistante->getInternalNbr()}).");
  1232.             return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1233.         }
  1234.         // 2. Conditions classiques
  1235.         if ($document->getType() !== 'facture' || $document->getStatus() !== 'facture') {
  1236.             $this->addFlash('danger'"Seules les factures non remboursées peuvent donner lieu à un avoir.");
  1237.             return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1238.         }
  1239.         // 3. Récupérer le motif et la note
  1240.         $formData $request->get('avoir_document');
  1241.         $refundReason null;
  1242.         if (!empty($formData['reason_id'])) {
  1243.             $refundReason $refundReasonRepository->find($formData['reason_id']);
  1244.         }
  1245.         $note $formData['note'] ?? null;
  1246.         // 4. Création du document d’avoir
  1247.         $avoir = new Document();
  1248.         $avoir $this->createCopyDocument($avoir$document);
  1249.         $avoir->setType('avoir');
  1250.         $avoir->setStatus('rembourse');
  1251.         $avoir->setCreatedAt(new \DateTime());
  1252.         $avoir->setUser($this->getUser());
  1253.         $avoir->setConditionDocument("Avoir sur facture {$document->getInternalNbr()}");
  1254.         $avoir->setDocument($document);
  1255.         $avoir->setInternalNbr('AVOIR-' date('dmY') . '-' rand(1000099999));
  1256.         if ($document->getCategory() == "client") {
  1257.             $avoir->setClient($document->getClient());
  1258.         } else {
  1259.             $avoir->setSupplier($document->getSupplier());
  1260.         }
  1261.         if ($refundReason) {
  1262.             $avoir->setRefundReason($refundReason);
  1263.         }
  1264.         if ($note) {
  1265.             $avoir->setNote($note);
  1266.         }
  1267.         // *** Copier les lignes produits ***
  1268.         foreach ($document->getDocumentDeclinationProduits() as $documentDeclinationProduit) {
  1269.             $new = new DocumentDeclinationProduit();
  1270.             $copy $this->createCopyDocumentProduit($new$documentDeclinationProduit);
  1271.             $copy->setProduitDeclinationValue($documentDeclinationProduit->getProduitDeclinationValue());
  1272.             $avoir->addDocumentDeclinationProduit($copy);
  1273.             $em->persist($copy);
  1274.         }
  1275.         foreach ($document->getDocumentProduits() as $documentProduit) {
  1276.             $new = new DocumentProduit();
  1277.             $copy $this->createCopyDocumentProduit($new$documentProduit);
  1278.             $copy->setProduit($documentProduit->getProduit());
  1279.             $avoir->addDocumentProduit($copy);
  1280.             $em->persist($copy);
  1281.         }
  1282.         $em->persist($avoir);
  1283.         // Mettre à jour la facture mère
  1284.         $document->setStatus('rembourse');
  1285.         $document->setConditionDocument($document->getConditionDocument() . " -> Remboursé via l'avoir " $avoir->getInternalNbr());
  1286.         $em->persist($document);
  1287.         // Historique
  1288.         $msg '[' $this->getUser()->getFullName() . "] a généré un avoir (remboursement) pour la facture de Réf: " $document->getInternalNbr();
  1289.         $this->activityService->addActivity('info'$msg$document$this->getUser(), 'document');
  1290.         $em->flush();
  1291.         $this->addFlash('success'"Avoir {$avoir->getInternalNbr()} généré avec succès pour la facture de réf {$document->getInternalNbr()}.");
  1292.         return $this->redirectToRoute('document_show', ['id' => $avoir->getId()]);
  1293.     }
  1294.     /**
  1295.      * @Route("/retour/{id}", name="retour_document", methods={"GET","POST"}, options={"expose"=true})
  1296.      */
  1297.     public function retourDocument(Document $documentRequest $requestEntityManagerInterface $em): Response
  1298.     {
  1299.         if ($document->getType() !== 'commande' || !in_array($document->getStatus(), ['expedie''livre'])) {
  1300.             $this->addFlash('danger'"Seuls les bons de commande expédiés ou livrés peuvent faire l'objet d'un retour de colis.");
  1301.             return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1302.         }
  1303.         $note $request->get('retour_document')['note'] ?? null;
  1304.         if ($note) {
  1305.             $document->setNote($note);
  1306.         }
  1307.         $document->setStatus("retour-en-cours");
  1308.         $document->setConditionDocument($document->getConditionDocument() . " -> Retour en cours");
  1309.         $em->persist($document);
  1310.         $message '[' $this->getUser()->getFullName() . '] a initié un retour de colis sur le bon de commande.';
  1311.         $this->activityService->addActivity('info'$message$document$this->getUser(), 'document');
  1312.         $em->flush();
  1313.         $this->addFlash('success'"Retour de colis lancé pour la commande de réf {$document->getInternalNbr()}.");
  1314.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1315.     }
  1316.     /*
  1317.     public function retourDocument(Document $document, Request $request,EntityManagerInterface $em): Response {
  1318.         if( ($document->getStatus() == "expedie" && !$document->getDocument()) || $document->getType() === 'facture' && $document->getStatus() == "paye" || ($document->getStatus() == "expedie" && $document->getType() == "echange")) {
  1319.             $note = $request->get('retour_document')['note'];
  1320.             $document->setStatus("retour-en-cours");
  1321.             $document->setConditionDocument($document->getConditionDocument() . " -> Retour en cours");
  1322.             $document->setNote($note);
  1323.             if( $document->getType() === 'facture') {
  1324.                     $document->getDocument()->setConditionDocument($document->getDocument()->getConditionDocument() . " -> Retour en cours");
  1325.                     $document->getDocument()->setNote($note);
  1326.             }
  1327.             $message = '[' . $this->getUser()->getFullName() . '] a retourné le bon de commande.';
  1328.             $this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
  1329.             $em->flush();
  1330.             $request->getSession()->getFlashBag()->add('success', "Facture de réf {$document->getInternalNbr()} est en cours de remboursement avec succès");
  1331.         }else{
  1332.             if( $document->getType() === 'facture' && $document->getStatus() == "retour-en-cours" )
  1333.                 $request->getSession()->getFlashBag()->add('danger',
  1334.                     "Cette facture de réf {$document->getInternalNbr()} est en cours de remboursement !!!");
  1335.             else {
  1336.                 $request->getSession()->getFlashBag()->add('danger',
  1337.                     "Ce bon de commande de réf {$document->getInternalNbr()} " .( ($document->getStatus() == "retour-en-cours") ?
  1338.                         " a déjà en cours de retour " : (($document->getStatus() == "retourne") ? " a déjà été retourné" : " a été annulé l'expédition !!!")));
  1339.             }
  1340.         }
  1341.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1342.     }
  1343.         */
  1344.     /**
  1345.      * @Route("/retour/final/document/{id}", name="retour_final_document", methods={"GET","POST"}, options={"expose"=true})
  1346.      */
  1347.     public function retourFinalDocument(Document $documentRequest $request,EntityManagerInterface $em): Response {
  1348.           if( $document->getType() === 'facture' && $document->getStatus() == "retour-en-cours"){
  1349.                 $document->setStatus("rembourse");
  1350.                 $document->setConditionDocument($document->getConditionDocument()." -> Remboursé");
  1351.                 $document->getDocument()->setConditionDocument($document->getDocument()->getConditionDocument()." -> Remboursé");
  1352.                 //todo: change the stock for a document product also.
  1353.                 foreach ($document->getDocument()->getDocumentDeclinationProduits() as $documentDeclination) {
  1354.                     $stock $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
  1355.                     if( $stock) {
  1356.                         if( $document->getCategory() == 'client') {
  1357.                             $stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
  1358.                         } else {
  1359.                             $stock->setQtStock($stock->getQtStock() - $documentDeclination->getQuantity());
  1360.                         }
  1361.                     }
  1362.                 }
  1363.                 $message '[' $this->getUser()->getFullName() . '] a validé le retour du bon de commande de la facture.';
  1364.                 $this->activityService->addActivity('success'$message$document$this->getUser(), 'document');
  1365.                 $em->flush();
  1366.                 $request->getSession()->getFlashBag()->add('success'"Facture de réf {$document->getInternalNbr()} est en cours de remboursement avec succès");
  1367.             }else
  1368.                 $request->getSession()->getFlashBag()->add('danger',
  1369.                     ($document->getStatus() == "rembourse")? "Cette Facture de réf {$document->getInternalNbr()} a dejà été remboursé!!!":" Une erreur a été rencontrée, contactez l'administrateur  ");
  1370.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1371.     }
  1372.     /**
  1373.      * @Route("updateRaison/commande/{id}", name="update_raison", methods={"GET","POST"}, options={"expose"=true})
  1374.      */
  1375.     public function updateRaisonCommande(Document $documentRequest $request,EntityManagerInterface $em): Response {
  1376.         if( in_array($document->getStatus(),["annule",'retour-en-cours','retourne'])) {
  1377.             $note $request->get('raison_document')['note'];
  1378.             $document->setNote($note);
  1379.             $em->flush();
  1380.             $request->getSession()->getFlashBag()->add('success'"La raison de ce bon de commande a été modifiée avec succès");
  1381.             return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1382.         }
  1383.         $request->getSession()->getFlashBag()->add('danger',"le bon de commande doit être en état de retour ou annulé pour faire changer son motif( raison)");
  1384.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1385.     }
  1386.     /**
  1387.      * @Route("/annulled/commande/{id}", name="annulled_commande", methods={"GET","POST"}, options={"expose"=true})
  1388.      */
  1389.     public function annulledCommande(Document $documentRequest $requestEntityManagerInterface $em): Response
  1390.     {
  1391.         $note $request->get('annuled_document')['note'] ?? null;
  1392.         $reasonId $request->get('annuled_document')['cancelReason'] ?? null;
  1393.         $reason $reasonId $em->getRepository(CancelReason::class)->find($reasonId) : null;
  1394.         if ($document->getStatus() == "en-attente") {
  1395.             $document->setStatus("annule")
  1396.                 ->setConditionDocument($document->getConditionDocument() . " -> Annulé")
  1397.                 ->setNote($note)
  1398.                 ->setCancelReason($reason);
  1399.             if ($document->getType() != 'echange' && $document->getDocument()) {
  1400.                 $document->getDocument()->setStatus("annule");
  1401.                 $document->getDocument()->setConditionDocument($document->getConditionDocument() . " -> Annulé");
  1402.                 $document->getDocument()->setNote($note);
  1403.                 $document->getDocument()->setCancelReason($reason);
  1404.             }
  1405.             foreach ($document->getDocumentDeclinationProduits() as $documentDeclination) {
  1406.                 if ($documentDeclination->getType() != 'declinationEchange') {
  1407.                     $stock $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
  1408.                     if ($stock && $document->getCategory() == 'client') {
  1409.                         if ($stock->getQtReserved() > 0) {
  1410.                             $stock->setQtReserved($stock->getQtReserved() - $documentDeclination->getQuantity());
  1411.                         }
  1412.                     }
  1413.                 } else {
  1414.                     $stock $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
  1415.                     if ($stock && $document->getCategory() == 'client') {
  1416.                         if ($stock->getQtReserved() > 0) {
  1417.                             $stock->setQtReserved($stock->getQtReserved() - $documentDeclination->getQuantity());
  1418.                         }
  1419.                     }
  1420.                     if ($document->getType() != 'echange' && $document->getDocument()) {
  1421.                         if ($document->getDocument()->getDocument()) {
  1422.                             $document->getDocument()->getDocument()->setStatus("annule");
  1423.                             $document->getDocument()->getDocument()->setConditionDocument("Annulé");
  1424.                             $document->getDocument()->getDocument()->setNote($note);
  1425.                             $document->getDocument()->getDocument()->setCancelReason($reason);
  1426.                         }
  1427.                     }
  1428.                 }
  1429.             }
  1430.         } else if (in_array($document->getStatus(), ["expedie""brouillon"])) {
  1431.             $document->setStatus("annule")
  1432.                 ->setConditionDocument($document->getConditionDocument() . " -> Annulé")
  1433.                 ->setNote($note)
  1434.                 ->setCancelReason($reason);
  1435.             foreach ($document->getDocumentProduits() as $documentProduit) {
  1436.                 $stockPrd $documentProduit->getProduit()->getStocks()[0];
  1437.                 if ($stockPrd) {
  1438.                     if ($document->getCategory() == 'client') {
  1439.                         $stockPrd->setQtStock($stockPrd->getQtStock() + $documentProduit->getQuantity());
  1440.                     } else {
  1441.                         if ($document->getType() == 'reception') {
  1442.                             $stockPrd->setQtStock($stockPrd->getQtStock() - $documentProduit->getQuantity());
  1443.                         } elseif ($document->getType() == 'retour') {
  1444.                             $stockPrd->setQtStock($stockPrd->getQtStock() + $documentProduit->getQuantity());
  1445.                         }
  1446.                     }
  1447.                 }
  1448.             }
  1449.             foreach ($document->getDocumentDeclinationProduits() as $documentDeclination) {
  1450.                 if ($documentDeclination->getType() != 'declinationEchange') {
  1451.                     $stock $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
  1452.                     if ($stock) {
  1453.                         if ($document->getCategory() == 'client') {
  1454.                             $stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
  1455.                         } else {
  1456.                             if ($document->getType() == "reception") {
  1457.                                 $stock->setQtStock($stock->getQtStock() - $documentDeclination->getQuantity());
  1458.                             } elseif ($document->getType() == 'retour') {
  1459.                                 $stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
  1460.                             }
  1461.                         }
  1462.                     }
  1463.                 }
  1464.             }
  1465.         }
  1466.         $message ='[' $this->getUser()->getFullName() . '] a annulé le bon de commande.';
  1467.         $this->activityService->addActivity('warning'$message$document$this->getUser(), 'document');
  1468.         $em->flush();
  1469.         $request->getSession()->getFlashBag()->add('success'"Le bon de commande a été annulé avec succès");
  1470.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1471.     }
  1472.     /*
  1473.     public function annulledCommande(Document $document, Request $request,EntityManagerInterface $em): Response {
  1474.         //todo : add a condition when the document is already canceled (annuled) and verify if impacted the stock or not
  1475.         if( $document->getStatus() == "en-attente") {
  1476.             $note = $request->get('annuled_document')['note'];
  1477.             $document->setStatus("annule")
  1478.                 ->setConditionDocument($document->getConditionDocument()." -> Annulé")
  1479.                 ->setNote($note);
  1480.             if( $document->getType() != 'echange' && $document->getDocument()) {
  1481.                 $document->getDocument()->setStatus("annule");
  1482.                 $document->getDocument()->setConditionDocument($document->getConditionDocument()." -> Annulé");
  1483.                 $document->getDocument()->setNote($note);
  1484.             }
  1485.             //todo: verify the producte also
  1486.             foreach ($document->getDocumentDeclinationProduits() as $documentDeclination) {
  1487.                 if( $documentDeclination->getType() != 'declinationEchange') {
  1488.                     $stock = $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
  1489.                     if( $stock) {
  1490.                         if( $document->getCategory() == 'client') {
  1491.                             if( $stock->getQtReserved() > 0) {
  1492.                                 $stock->setQtReserved($stock->getQtReserved() - $documentDeclination->getQuantity());
  1493.                             }
  1494.                         }
  1495.                     }
  1496.                 } else {
  1497.                     $stock = $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
  1498.                     if( $stock) {
  1499.                         if( $document->getCategory() == 'client') {
  1500.                             if( $stock->getQtReserved() > 0) {
  1501.                                 $stock->setQtReserved($stock->getQtReserved() - $documentDeclination->getQuantity());
  1502.                             }
  1503.                         }
  1504.                     }
  1505.                     if( $document->getType() != 'echange' && $document->getDocument()) {
  1506.                         if( $document->getDocument()->getDocument()) {
  1507.                             $document->getDocument()->getDocument()->setStatus("annule");
  1508.                             $document->getDocument()->getDocument()->setConditionDocument("Annulé");
  1509.                             $document->getDocument()->getDocument()->setNote($note);
  1510.                         }
  1511.                     }
  1512.                 }
  1513.             }
  1514.         } else if( in_array( $document->getStatus(),["expedie","brouillon"])) {
  1515.             $note = $request->get('annuled_document')['note'];
  1516.             $document->setStatus("annule")
  1517.                 ->setConditionDocument($document->getConditionDocument()." -> Annulé")
  1518.                 ->setNote($note);
  1519.             foreach ($document->getDocumentProduits() as $documentProduit) {
  1520.                 $stockPrd = $documentProduit->getProduit()->getStocks()[0];
  1521.                 if( $stockPrd) {
  1522.                     if($document->getCategory() == 'client') {
  1523.                             $stockPrd->setQtStock($stockPrd->getQtStock()+$documentProduit->getQuantity());
  1524.                     }else{
  1525.                         if($document->getType() == 'reception'){
  1526.                             $newQte =$stockPrd->getQtStock() - $documentProduit->getQuantity();
  1527.                             $stockPrd->setQtStock($newQte);
  1528.                         }elseif($document->getType() == 'retour'){
  1529.                             $newQte =$stockPrd->getQtStock() + $documentProduit->getQuantity();
  1530.                             $stockPrd->setQtStock($newQte);
  1531.                         }
  1532.                     }
  1533.                 }
  1534.             }
  1535.             foreach ($document->getDocumentDeclinationProduits() as $documentDeclination) {
  1536.                 if( $documentDeclination->getType() != 'declinationEchange') {
  1537.                     $stock = $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
  1538.                     if( $stock)
  1539.                         if( $document->getCategory() == 'client') {
  1540.                             $stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
  1541.                         }else{
  1542.                             if( $document->getType() == "reception") {
  1543.                                 $newQte = $stock->getQtStock() - $documentDeclination->getQuantity();
  1544.                                 $stock->setQtStock($newQte);
  1545.                             } elseif( $document->getType() == 'retour') {
  1546.                                 $newQte = $stock->getQtStock() + $documentDeclination->getQuantity();
  1547.                                 $stock->setQtStock($newQte);
  1548.                             }
  1549.                         }
  1550.                 }
  1551.             }
  1552.         }
  1553.         $message = '[' . $this->getUser()->getFullName() . '] annuler le bon de commande ' . $document->getInternalNbr();
  1554.         $this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
  1555.         $em->flush();
  1556.         $request->getSession()->getFlashBag()->add('success', "Le bon de commande a été annulé avec succès");
  1557.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1558.     }
  1559.         */
  1560.     /**
  1561.      * @Route("/edit/{type}/{document}/{category}", name="edit_document_commande", methods={"GET","POST"}, options={"expose"=true},defaults={"type"="commande"})
  1562.      */
  1563.     public function editCommande(Document $document,$type,$categoryRequest $request,EntityManagerInterface $em): Response {
  1564.         $rights =$this->hasRightByType$request,$category,'DOCUMENT_CLIENT_UPDATE','DOCUMENT_SUPPLIER_UPDATE');
  1565.         if( in_array($document->getStatus(),["en-attente","brouillon"]) ) {
  1566.             if( $request->isMethod('POST')) {
  1567.                 $message '[' $this->getUser()->getFullName() . "] a mis à jour le bon de commande ($type) " $document->getInternalNbr();
  1568.                 $this->activityService->addActivity('info'$message$document$this->getUser(), 'document');
  1569.                 foreach ($document->getDocumentDeclinationProduits() as $docDec) {
  1570.                     $prodDecVa $docDec->getProduitDeclinationValue();
  1571.                     if(!$prodDecVa->__isInitialized()) $prodDecVa->__load();
  1572.                     $stock $prodDecVa->getStocks()[0];
  1573.                     if($stock) {
  1574.                         if( $category == 'client') {
  1575.                             if( !$stock->getQtReserved() <= 0) {
  1576.                                 $stock->setQtReserved($stock->getQtReserved() - $docDec->getQuantity());
  1577.                             }
  1578.                         } else {
  1579.                             if( $document->getType() == "reception") {
  1580.                                 $newQte $stock->getQtStock() - $docDec->getQuantity();
  1581.                                 $stock->setQtStock($newQte);
  1582.                             } elseif( $document->getType() == 'retour') {
  1583.                                 $newQte $stock->getQtStock() + $docDec->getQuantity();
  1584.                                 $stock->setQtStock($newQte);
  1585.                             }
  1586.                         }
  1587.                     }
  1588.                     $document->removeDocumentDeclinationProduit($docDec);
  1589.                 }
  1590.                 foreach ($document->getDocumentProduits() as $docProd) {
  1591.                     $prod $docProd->getProduit();
  1592.                     $stock $prod->getStocks()[0];
  1593.                     if( $stock) {
  1594.                         if($category == 'client') {
  1595.                             if( !$stock->getQtReserved() <= 0) {
  1596.                                 $newQte $stock->getQtReserved() - $docProd->getQuantity();
  1597.                                 $stock->setQtReserved($newQte);
  1598.                             }
  1599.                         }else{
  1600.                             if($document->getType() == 'reception'){
  1601.                                 $newQte =$stock->getQtStock() - $docProd->getQuantity();
  1602.                                 $stock->setQtStock($newQte);
  1603.                             }elseif($document->getType() == 'retour'){
  1604.                                 $newQte =$stock->getQtStock() + $docProd->getQuantity();
  1605.                                 $stock->setQtStock($newQte);
  1606.                             }
  1607.                         }
  1608.                     }
  1609.                     $document->removeDocumentProduit($docProd);
  1610.                 }
  1611.                 foreach ($document->getDocumentComments() as $comm) {
  1612.                     $document->removeDocumentComment($comm);
  1613.                 }
  1614.                 if( $request->get('form_document')) {
  1615.                     $data $request->get('form_document');
  1616.                      //dump($data);die;
  1617.                       if (!empty($data['promotion_id'])) {
  1618.                             $promotion $this->promotionRepository->find((int) $data['promotion_id']);
  1619.                             if ($promotion !== null) {
  1620.                                 $document->setPromotion($promotion);
  1621.                             } else {
  1622.                                 $document->setPromotion(null);
  1623.                             }
  1624.                         } else {
  1625.                             $document->setPromotion(null);
  1626.                         }
  1627.                     if( $data['discount'] == ""$data['discount'] = 0;
  1628.                    
  1629.                     $dateDelivery = (!empty($data['promisedAt'])) ? new \DateTime($data['promisedAt']) : null;
  1630.                
  1631.                     $datebonlivraison = (!empty($data['shippedAt'])) ? new \DateTime($data['shippedAt']) : null;
  1632.                     $datebonrecu = (!empty($data['bonrecuAt'])) ? new \DateTime($data['bonrecuAt']) : null;
  1633.                   
  1634.                     $dateAPayerLe = (!empty($data['aPayerLe'])) ? new \DateTime($data['aPayerLe']) : null;
  1635.                     $delivery $this->deliveryRepository->find($data['delivery']['id']);
  1636.                     
  1637.                     $source null;
  1638.                     if ($category === 'client' && isset($data['source']['id']) && $data['source']['id']) {
  1639.                         $source $this->sourceRepository->find($data['source']['id']);
  1640.                         
  1641.                     }
  1642.                     $tvaDelivery $this->tvaRepository->find($data['delivery']['tva']);
  1643.                     $document->setInternalNbr($data['internalNbr'])
  1644.                         ->setExternalNbr(!empty($data['externalNbr']) ? $data['externalNbr'] : '')
  1645.                         ->setObject(!empty($data['object']) ? $data['object'] : '')
  1646.                         ->setTotalAmountHt($data['totalAmountHt'])
  1647.                         ->setTotalTva($data['totalTva'])
  1648.                         ->setTotalAmountTtc($data['totalAmountTtc'])
  1649.                         ->setAdress(!empty($data['adress']) ? $data['adress'] : null)
  1650.                         ->setParcelTrackingNbr($data['parcelTrackingNbr'])
  1651.                         ->setPaymentMethod($data['paymentMethod'])
  1652.                         ->setPaymentDeadline($data['paymentDeadline'])
  1653.                         ->setDiscount($data['discount'])
  1654.                         ->setDiscountType($data['discountType'])
  1655.                         ->setAdvancePayment($data['advancePayment'])
  1656.                         ->setAdvancePaymentType($data['advancePaymentType'])
  1657.                         ->setPackagesNbr($data['packagesNbr'])
  1658.                         ->setUrlTracking($data['urlTracking'])
  1659.                         ->setPromisedAt($dateDelivery)
  1660.                         ->setShippedAt($datebonlivraison)
  1661.                         ->setBonrecuAt($datebonrecu)
  1662.                         ->setAPayerLe($dateAPayerLe)
  1663.                         ->setNote($data['note'])
  1664.                         ->setSource($source)
  1665.                         ->setDelivery($delivery)
  1666.                         ->setDeliveryDiscount($data['delivery']['discount'])
  1667.                         ->setDeliveryDiscountType($data['delivery']['discount_type'])
  1668.                         ->setDeliveryPrice($data['delivery']['price_ht'])
  1669.                         ->setDeliveryTotal((float) $data['delivery']['total_amount_ttc'])
  1670.                         ->setIsFreeDelivery((isset($data['isFreedelivery']) && $data['isFreedelivery'] == "on"))
  1671.                         ->setDeliveryTva($tvaDelivery);
  1672.                     if( isset($data['comment']) && $data['comment']) {
  1673.                         foreach ($data['comment'] as $item) {
  1674.                             $comment = new Comment();
  1675.                             $comment->setCreateAt(new \DateTime('now'));
  1676.                             $comment->setDocumentComment($document)
  1677.                                 ->setDescription($item)
  1678.                                 ->setUser($this->getUser());
  1679.                             $em->persist($comment);
  1680.                         }
  1681.                     }
  1682.                     if( isset($data['content']) && $data['content']) {
  1683.                         foreach ($data['content'] as $item) {
  1684.                             if( $item['type'] == 'produit') {
  1685.                                 $entity = new DocumentProduit();
  1686.                                 $entity->setType($item['type']);
  1687.                                 if( isset($item['id']) && $item['id']) {
  1688.                                     $produit $this->produitRepository->find($item['id']);
  1689.                                     $entity->setProduit($produit);
  1690.                                     $entity->setUnite((isset($item['unit']) && $item['unit'])?$item['unit']:$produit->getUnit());
  1691.                                 }
  1692.                             } else {
  1693.                                 $entity = new DocumentDeclinationProduit();
  1694.                                 $entity->setType($item['type']);
  1695.                                 if( isset($item['id']) && $item['id']) {
  1696.                                     $produitDecllination $this->produitDeclinationValueRepository->find($item['id']);
  1697.                                     $entity->setProduitDeclinationValue($produitDecllination);
  1698.                                     $stock $produitDecllination->getStocks()[0];
  1699.                                     if( $stock) {
  1700.                                         if( $category == 'client') {
  1701.                                             $stock->setQtReserved($stock->getQtReserved() + $item['quantity']);
  1702.                                         }else{
  1703.                                             if($type=="achat"){
  1704.                                                 //do nothing
  1705.                                             }elseif($type=="reception"){
  1706.                                                 $stock->setQtStock($stock->getQtStock() + $item['quantity']);
  1707.                                             }elseif($type=="retour"){
  1708.                                                 $newQty=$stock->getQtStock() - $item['quantity'];
  1709.                                                 if($newQty>=0){
  1710.                                                     $stock->setQtStock($newQty);
  1711.                                                 }
  1712.                                             }
  1713.                                         }
  1714.                                     } else {
  1715.                                         $stock = new Stock();
  1716.                                         if( $category == 'client') {
  1717.                                             $stock->setDeclinationProduit($produitDecllination)
  1718.                                                 ->setQtReserved($item['quantity'])
  1719.                                                 ->setQtStock(0)
  1720.                                                 ->setStorehouse('Principal');
  1721.                                         } else {
  1722.                                             if($type=="achat" || $type=="retour"){
  1723.                                                 $stock->setDeclinationProduit($produitDecllination)
  1724.                                                     ->setQtReserved(0)
  1725.                                                     ->setQtStock(0)
  1726.                                                     ->setStorehouse('Principal');
  1727.                                             }elseif($type=="reception"){
  1728.                                                 $stock->setDeclinationProduit($produitDecllination)
  1729.                                                     ->setQtReserved(0)
  1730.                                                     ->setQtStock($item['quantity'])
  1731.                                                     ->setStorehouse('Principal');
  1732.                                             }
  1733.                                         }
  1734.                                         $em->persist($stock);
  1735.                                     }
  1736.                                     $entity->setUnite((isset($item['unit']) && $item['unit'])?
  1737.                                         $item['unit']:$produitDecllination->getProduit()->getUnit());
  1738.                                 }
  1739.                             }
  1740.                              // Calcul du total HT (avec remise éventuelle)
  1741.                             $priceHt      = (float) ($item['price_ht'] ?? 0);
  1742.                             $qty          = (float) ($item['quantity'] ?? 0);
  1743.                             $discount     = (float) ($item['discount'] ?? 0);
  1744.                             $discountType $item['discount_type'] ?? null;
  1745.                             $totalHt $priceHt $qty;
  1746.                             if ($discount 0) {
  1747.                                 if ($discountType === 'percent') {
  1748.                                     $totalHt -= round($totalHt $discount 1003);
  1749.                                 } else { // montant
  1750.                                     $totalHt -= $discount;
  1751.                                 }
  1752.                             }
  1753.                             $totalHt max(0round($totalHt3));
  1754.                             $entity->setReference($item['reference'])
  1755.                                 ->setDiscount((float)$item['discount'])
  1756.                                 ->setDiscountType($item['discount_type'])
  1757.                                 ->setPriceHt((float)$item['price_ht'])
  1758.                                 ->setQuantity((int)$item['quantity'])
  1759.                                 ->setCreatedAt(new \DateTime('now'))
  1760.                                 ->setTotalAmountHt($totalHt)
  1761.                                 ->setTotalAmountTtc((float)$item['total_amount_ttc']);
  1762.                             if( isset($item['description']) && $item['description'])
  1763.                                 $entity->setDescription($item['description']);
  1764.                             $tva =($item['tva'] != "0") ?
  1765.                                 $this->tvaRepository->find($item['tva'])
  1766.                                 :$this->tvaRepository->findOneBy(["number" => 0]);
  1767.                             $entity->setTva($tva);
  1768.                             $entity->setDocument($document);
  1769.                             $em->persist($entity);
  1770.                         }
  1771.                     }
  1772.                 }
  1773.                 $document->setUpdatedBy($this->getUser());
  1774.                 $document->setUpdatedAt(new \DateTime('now'));
  1775.                 $em->beginTransaction();
  1776.                 try {
  1777.                     
  1778.                     $em->flush();
  1779.                     $em->commit();
  1780.                 } catch (\Throwable $e) {
  1781.                     $em->rollback();
  1782.                     throw $e;
  1783.                 }
  1784.                 $request->getSession()->getFlashBag()->add('success'"Document modifié avec succès");
  1785.                 return (array_key_exists('save'$data) && $data['save']=="save-and-exit")?
  1786.                 $this->redirectToRoute('document_show', ['id' => $document->getId()]):
  1787.             $this->redirectToRoute('edit_document_commande', ['type' =>$document->getType(),'document'=>$document->getId(),'category'=>$document->getCategory()]);
  1788.             }
  1789.         } else {
  1790.             $request->getSession()->getFlashBag()->add('danger'"Le bon de commande $type " $document->getStatus() . ", on ne peut pas modifier , vérifiez son état avant de continuer !!");
  1791.             return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1792.         }
  1793.         $tvas $this->tvaRepository->findAll();
  1794.         $deliveryTypes=($category == 'client')?['client','client-fournisseur']:['fournisseur','client-fournisseur'];
  1795.         $deliverys $this->deliveryRepository->findAllByTypes($deliveryTypes);
  1796.         $sources $this->sourceRepository->findAll();
  1797.         $declinationCouleur $this->declinationRepository->findOneBy(["name" => "Couleur"]);
  1798.         $id = ($category == 'client')?$document->getClient()->getId():$document->getSupplier()->getId();
  1799.        
  1800.         $template = ($category === 'fournisseur') ? '@admin/document/edit_document_fournisseur.html.twig' '@admin/document/edit_document_client.html.twig';
  1801.         return $this->render($template, [
  1802.             'document' => $document,
  1803.             'type' => $type,
  1804.             'category' => $category,
  1805.             'id' => $id,
  1806.             'tvas' => $tvas,
  1807.             'deliverys' => $deliverys,
  1808.             'sources' => $sources,
  1809.             'declinationCouleur' => $declinationCouleur,
  1810.             'rights' => $rights
  1811.         ]);
  1812.     }
  1813.     /**
  1814.      * @Route("/print/{id}", name="print_document", methods={"GET","POST"}, options={"expose"=true})
  1815.      */
  1816.     public function printDocument(Document $document,EntityManagerInterface $emCompanyRepository $companyRepository): Response {
  1817.         $publicPath $this->getParameter('kernel.project_dir') . '/public';
  1818.         $company $companyRepository->getCompanyInfo();
  1819.         $twig '@admin/document/pdf.html.twig';
  1820.         $urlPdf $this->createPdf($twig, ['document' => $document,'company'=>$company,'publicPath'  => $publicPath], $document->getInternalNbr());
  1821.         $document->setUrlPdf($urlPdf);
  1822.         $em->flush();
  1823.         return $this->render('@admin/document/print.html.twig', [
  1824.             'document' => $document
  1825.         ]);
  1826.     }
  1827.     /**
  1828.      * @Route("/printdoc/{id}", name="print_doc", methods={"GET","POST"}, options={"expose"=true})
  1829.      */
  1830.     public function printDoc(Document $document,EntityManagerInterface $emCompanyRepository $companyRepository) {
  1831.         $publicPath $this->getParameter('kernel.project_dir') . '/public';
  1832.         $company $companyRepository->getCompanyInfo();
  1833.         $twig '@admin/document/pdf.html.twig';
  1834.         $urlPdf $this->createPdf($twig, ['document' => $document,'company'=>$company,'publicPath'  => $publicPath], $document->getInternalNbr());
  1835.         $document->setUrlPdf($urlPdf);
  1836.         $em->flush();
  1837.         return new JsonResponse(["url" => $document->getUrlPdf()]);
  1838.     }
  1839.     /**
  1840.      * @Route("/download/{id}", name="download_doc", methods={"GET","POST"}, options={"expose"=true})
  1841.      */
  1842.     public function downloadDoc(Document $document,EntityManagerInterface $emCompanyRepository $companyRepository) {
  1843.         if( !$document->getUrlPdf()) {
  1844.             $company $companyRepository->getCompanyInfo();
  1845.             $twig '@admin/document/pdf.html.twig';
  1846.             $urlPdf $this->createPdf($twig, ['document' => $document,'company'=>$company], $document->getInternalNbr());
  1847.             $document->setUrlPdf($urlPdf);
  1848.             $em->flush();
  1849.         }
  1850.         return new JsonResponse(["url" => $document->getUrlPdf(), "filename" => $document->getInternalNbr() . '.pdf']);
  1851.     }
  1852.     /**
  1853.      * @Route("/edit/info-livraison/{document}", name="edit_info_livarison", methods={"GET","POST"}, options={"expose"=true})
  1854.      */
  1855.     public function editInfo(Request $requestDocument $document,EntityManagerInterface $em): Response {
  1856.         $rights =$this->hasRightByType$request,$document->getCategory(),'DOCUMENT_CLIENT_UPDATE','DOCUMENT_SUPPLIER_UPDATE');
  1857.         $form $this->createForm(InfoLivraisonType::class, $document);
  1858.         $form->handleRequest($request);
  1859.         if( $form->isSubmitted() && $form->isValid()) {
  1860.             $message '[' $this->getUser()->getFullName() . "] a modifié l'info du bon de commande de Réf: " $document->getInternalNbr();
  1861.             $this->activityService->addActivity('warning'$message$document$this->getUser(), 'document');
  1862.             $em->persist($document);
  1863.             $em->flush();
  1864.             return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  1865.         }
  1866.         return $this->render('@admin/document/_formEditInfo.html.twig', [
  1867.                     'form' => $form->createView(),
  1868.                     'document' => $document
  1869.         ]);
  1870.     }
  1871.     /**
  1872.      * @Route("/echange/commande/{id}/{category}", name="echange_document_commande", methods={"GET","POST"}, options={"expose"=true})
  1873.      */
  1874.     public function create_echange(Document $commande$categoryRequest $request,EntityManagerInterface $em): Response {
  1875.         $rights =$this->hasRightByType$request,$category,'DOCUMENT_CLIENT_UPDATE',null);
  1876.         if(   ($commande->getType() === 'commande' && ($commande->getstatus() === 'livre' || $commande->getstatus() === 'paye'))
  1877.         ||($commande->getType() === 'echange' && $commande->getstatus() === 'echange-recu') ){
  1878.             //$commande->setUser($this->getUser());
  1879.             if( $request->isMethod('POST')) {
  1880.                 if( $request->get('form_document')) {
  1881.                     $data $request->get('form_document');
  1882.                     $existChange false;
  1883.                     if( isset($data['content']) && $data['content'])
  1884.                         foreach ($data['content'] as $item) {
  1885.                             if( isset($item['change']) && $item['change'])
  1886.                                 if( $item['change'] == "true") {
  1887.                                     $existChange true;
  1888.                                     break;
  1889.                                 }
  1890.                         }
  1891.                     if( $existChange) {
  1892.                         $document = new Document();
  1893.                         $date = new \DateTime('now');
  1894.                         $document $this->createCopyDocument($document$commande);
  1895.                         if( $data['discount'] == "")$data['discount'] = 0;
  1896.                         $dateDelivery =($data['promisedAt'] && $data['promisedAt'] != '' && $data['promisedAt'] != null)?
  1897.                             new \DateTime($data['promisedAt']): null;
  1898.                         $delivery $this->deliveryRepository->find($data['delivery']['id']);
  1899.                         $source $this->sourceRepository->find($data['source']['id']);
  1900.                         $tvaDelivery $this->tvaRepository->find($data['delivery']['tva']);
  1901.                         $document->setDocument($commande)
  1902.                                 ->setType('echange')
  1903.                                 ->setCategory($category)
  1904.                                 ->setCreatedAt(new \DateTime('now'))
  1905.                                 //->setEndAt($date->add(new \DateInterval('P30D')))
  1906.                                 ->setUser($this->getUser())
  1907.                                 ->setInternalNbr($data['internalNbr'])
  1908.                                 //->setObject($data['object'])
  1909.                                 ->setTotalAmountHt($data['totalAmountHt'])
  1910.                                 ->setTotalTva($data['totalTva'])
  1911.                                 ->setTotalAmountTtc($data['totalAmountTtc'])
  1912.                                 ->setAdress(!empty($data['adress']) ? $data['adress'] : null)
  1913.                                 ->setParcelTrackingNbr(null)
  1914.                                 ->setUrlTracking(null)
  1915.                                 ->setPaymentMethod($data['paymentMethod'])
  1916.                                 ->setPaymentRef(null)
  1917.                                 //->setPaymentDeadline($data['paymentDeadline'])
  1918.                                 ->setDiscount($data['discount'])
  1919.                                 ->setDiscountType($data['discountType'])
  1920.                                 //->setAdvancePayment($data['advancePayment'])
  1921.                                 //->setAdvancePaymentType($data['advancePaymentType'])
  1922.                                 ->setPackagesNbr($data['packagesNbr'])
  1923.                                 
  1924.                                 ->setPromisedAt($dateDelivery)
  1925.                                 ->setNote($data['note'])
  1926.                                 ->setSource($source)
  1927.                                 ->setDelivery($delivery)
  1928.                                 ->setDeliveryDiscount($data['delivery']['discount'])
  1929.                                 ->setDeliveryDiscountType($data['delivery']['discount_type'])
  1930.                                 ->setDeliveryPrice($data['delivery']['price_ht'])
  1931.                                 ->setDeliveryTotal((float) $data['delivery']['total_amount_ttc'])
  1932.                                 ->setIsFreeDelivery((isset($data['isFreedelivery']) && $data['isFreedelivery'] == "on"))
  1933.                                 ->setDeliveryTva($tvaDelivery);
  1934.                         if( isset($data['comment']) && $data['comment']) {
  1935.                             foreach ($data['comment'] as $item) {
  1936.                                 $comment = new Comment();
  1937.                                 $comment->setCreateAt(new \DateTime('now'))
  1938.                                         ->setDescription($item)
  1939.                                         ->setUser($this->getUser());
  1940.                                 $em->persist($comment);
  1941.                                 $document->addDocumentComment($comment);
  1942.                             }
  1943.                         }
  1944.                         $em->persist($document);
  1945.                         if( isset($data['content']) && $data['content']) {
  1946.                             foreach ($data['content'] as $item) {
  1947.                                 if( $item['type'] == 'produit') {
  1948.                                     $entity = new DocumentProduit();
  1949.                                     $entity->setType($item['type']);
  1950.                                     if( isset($item['id']) && $item['id']) {
  1951.                                         $produit $this->produitRepository->find($item['id']);
  1952.                                         $entity->setProduit($produit)
  1953.                                             ->setUnite((isset($item['unit']) && $item['unit'])?
  1954.                                                 $item['unit']:$produit->getUnit());
  1955.                                     }
  1956.                                 } else {
  1957.                                     if( isset($item['change']) && $item['change']) {
  1958.                                         if( $item['change'] == "true") {
  1959.                                             $entity = new DocumentDeclinationProduit();
  1960.                                             $entity->setType('declinationEchange');
  1961.                                             if( isset($item['id']) && $item['id']) {
  1962.                                                 $produitDecllination $this->produitDeclinationValueRepository->find($item['id']);
  1963.                                                 $entity->setProduitDeclinationValue($produitDecllination)
  1964.                                                     ->setUnite((isset($item['unit']) && $item['unit'])?
  1965.                                                             $item['unit']:$produitDecllination->getProduit()->getUnit());
  1966.                                             }
  1967.                                             if( isset($entity)) {
  1968.                                                   // Calcul du total HT (avec remise éventuelle)
  1969.                                                 $priceHt      = (float) ($item['price_ht'] ?? 0);
  1970.                                                 $qty          = (float) ($item['quantity'] ?? 0);
  1971.                                                 $discount     = (float) ($item['discount'] ?? 0);
  1972.                                                 $discountType $item['discount_type'] ?? null;
  1973.                                                 $totalHt $priceHt $qty;
  1974.                                                 if ($discount 0) {
  1975.                                                     if ($discountType === 'percent') {
  1976.                                                         $totalHt -= round($totalHt $discount 1003);
  1977.                                                     } else { // montant
  1978.                                                         $totalHt -= $discount;
  1979.                                                     }
  1980.                                                 }
  1981.                                                 $totalHt max(0round($totalHt3));
  1982.                                                 $tva = ($item['tva'] != "0")?$this->tvaRepository->find($item['tva']):$this->tvaRepository->findOneBy(["number" => 0]);
  1983.                                                 $entity->setReference($item['reference'])
  1984.                                                         ->setDiscount($item['discount'])
  1985.                                                         ->setDiscountType($item['discount_type'])
  1986.                                                         ->setPriceHt($item['price_ht'])
  1987.                                                         ->setQuantity($item['quantity'])
  1988.                                                         ->setCreatedAt(new \DateTime('now'))
  1989.                                                          ->setTotalAmountHt($totalHt)
  1990.                                                         ->setTotalAmountTtc($item['total_amount_ttc'])
  1991.                                                         ->setTva($tva)
  1992.                                                         ->setDocument($document);
  1993.                                                 if( isset($item['description']) && $item['description'])
  1994.                                                     $entity->setDescription($item['description']);
  1995.                                                 $em->persist($entity);
  1996.                                             }
  1997.                                         }
  1998.                                     } else {
  1999.                                         $entity = new DocumentDeclinationProduit();
  2000.                                         $entity->setType($item['type']);
  2001.                                         if( isset($item['id']) && $item['id']) {
  2002.                                             $produitDecllination $this->produitDeclinationValueRepository->find($item['id']);
  2003.                                             $entity->setProduitDeclinationValue($produitDecllination);
  2004.                                             $stock $produitDecllination->getStocks()[0];
  2005.                                             if( $stock) {
  2006.                                                 if( $category == 'client') {
  2007.                                                     $stock->setQtReserved($stock->getQtReserved() + $item['quantity']);
  2008.                                                 }
  2009.                                             } else {
  2010.                                                 $stock = new Stock();
  2011.                                                 if( $category == 'client') {
  2012.                                                     $stock->setDeclinationProduit($produitDecllination)
  2013.                                                             ->setQtReserved($item['quantity'])
  2014.                                                             ->setQtStock(0)
  2015.                                                             ->setStorehouse('Principal');
  2016.                                                 } else {
  2017.                                                     $stock->setDeclinationProduit($produitDecllination)
  2018.                                                             ->setQtReserved(0)
  2019.                                                             ->setQtStock(0)
  2020.                                                             ->setStorehouse('Principal');
  2021.                                                 }
  2022.                                                 $em->persist($stock);
  2023.                                             }
  2024.                                                 $entity->setUnite((isset($item['unit']) && $item['unit'])?
  2025.                                                     $item['unit']:$produitDecllination->getProduit()->getUnit());
  2026.                                         }
  2027.                                         if( isset($entity)) {
  2028.                                             // Calcul du total HT (avec remise éventuelle)
  2029.                                             $priceHt      = (float) ($item['price_ht'] ?? 0);
  2030.                                             $qty          = (float) ($item['quantity'] ?? 0);
  2031.                                             $discount     = (float) ($item['discount'] ?? 0);
  2032.                                             $discountType $item['discount_type'] ?? null;
  2033.                                             $totalHt $priceHt $qty;
  2034.                                             if ($discount 0) {
  2035.                                                 if ($discountType === 'percent') {
  2036.                                                     $totalHt -= round($totalHt $discount 1003);
  2037.                                                 } else { // montant
  2038.                                                     $totalHt -= $discount;
  2039.                                                 }
  2040.                                             }
  2041.                                             $totalHt max(0round($totalHt3));
  2042.                                             $tva = ($item['tva'] != "0")?
  2043.                                                 $this->tvaRepository->find($item['tva'])
  2044.                                                 :$this->tvaRepository->findOneBy(["number" => 0]);
  2045.                                             $entity->setReference($item['reference'])
  2046.                                                     ->setDiscount($item['discount'])
  2047.                                                     ->setDiscountType($item['discount_type'])
  2048.                                                     ->setPriceHt($item['price_ht'])
  2049.                                                     ->setQuantity($item['quantity'])
  2050.                                                     ->setCreatedAt(new \DateTime('now'))
  2051.                                                     ->setTotalAmountHt($totalHt)
  2052.                                                     ->setTotalAmountTtc($item['total_amount_ttc'])
  2053.                                                     ->setTva($tva)
  2054.                                                     ->setDocument($document);
  2055.                                             if( isset($item['description']) && $item['description'])
  2056.                                                 $entity->setDescription($item['description']);
  2057.                                             $em->persist($entity);
  2058.                                         }
  2059.                                     }
  2060.                                 }
  2061.                             }
  2062.                         }
  2063.                         if( $category == "client") {
  2064.                             $document->setStatus('en-attente')
  2065.                                 ->setConditionDocument('Create BEC from BC#'.$commande->getId())
  2066.                                 ->setInternalNbr('BEC-' date('dmY') . '-' rand(1000099999))
  2067.                                 ->setClient($commande->getClient());
  2068.                         }
  2069.                         $em->persist($document);
  2070.                         $message '[' $this->getUser()->getFullName() . "] a crée le bon d'échange.";
  2071.                         $this->activityService->addActivity('info'$message$document$this->getUser(), 'document');
  2072.                         $em->flush();
  2073.                         $request->getSession()->getFlashBag()->add('success'"Bon echange créé avec succès");
  2074.                         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  2075.                     }
  2076.                     $request->getSession()->getFlashBag()->add('danger',
  2077.                         "Vous devez choisir certains articles pour effectuer l'échange !");
  2078.                 }
  2079.             }
  2080.             $tvas $this->tvaRepository->findAll();
  2081.             $deliveryTypes=($category == 'client')?['client','client-fournisseur']:['fournisseur','client-fournisseur'];
  2082.             $deliverys $this->deliveryRepository->findAllByTypes($deliveryTypes);
  2083.             $sources $this->sourceRepository->findAll();
  2084.             $id = ($category == 'client')?$commande->getClient()->getId():$commande->getSupplier()->getId();
  2085.             $declinationCouleur $this->declinationRepository->findOneBy(["name" => "Couleur"]);
  2086.             return $this->render('@admin/document/echange_document_client.html.twig', [
  2087.                         'document' => $commande,
  2088.                         'commande' => null,
  2089.                         'type' => 'commande',
  2090.                         'declinationCouleur'=>$declinationCouleur,
  2091.                         'category' => $category,
  2092.                         'id' => $id,
  2093.                         'tvas' => $tvas,
  2094.                         'deliverys' => $deliverys,
  2095.                         'sources' => $sources,
  2096.                         'rights' => $rights
  2097.             ]);
  2098.         }else
  2099.             $request->getSession()->getFlashBag()->add('danger',
  2100.                 "Ce document doit être une livré pour être effectué une echange!!!");
  2101.         return $this->redirectToRoute('document_show', ['id' => $commande->getId()]);
  2102.     }
  2103.     /**
  2104.      * @Route("/exchange/received/{id}", name="exchange_received", methods={"GET","POST"}, options={"expose"=true})
  2105.      */
  2106.     public function exchangeReceived(Document $documentEntityManagerInterface $emRequest $request): Response
  2107.     {
  2108.         // Vérifier que c’est un échange et qu’il est bien expédié
  2109.         if ($document->getType() === "echange" && $document->getStatus() === "expedie") {
  2110.             /** -----------------------------
  2111.              *  1) Récupérer la date reçue du form
  2112.              * ----------------------------- */
  2113.             $dateStr $request->request->get('received_at');
  2114.             if ($dateStr) {
  2115.                 $date \DateTime::createFromFormat('Y-m-d'$dateStr);
  2116.                 if ($date !== false) {
  2117.                     $document->setBonrecuAt($date);      // <-- enregistrement date réception
  2118.                 }
  2119.             }
  2120.             /** -----------------------------
  2121.              *  2) Mise à jour statut & condition
  2122.              * ----------------------------- */
  2123.             $document
  2124.                 ->setStatus("echange-recu")
  2125.                 ->setConditionDocument(
  2126.                     $document->getConditionDocument() . " -> Échange reçu"
  2127.                 );
  2128.             /** -----------------------------
  2129.              *  3) Mise à jour des stocks pour les articles échangés
  2130.              * ----------------------------- */
  2131.             foreach ($document->getDocumentDeclinationProduits() as $docDecl) {
  2132.                 if ($docDecl->getType() === 'declinationEchange') {
  2133.                     $produitDecl $docDecl->getProduitDeclinationValue();
  2134.                     $stocks $produitDecl->getStocks();
  2135.                     if ($stocks && isset($stocks[0])) {
  2136.                         $stock $stocks[0];
  2137.                         if ($document->getCategory() === 'client') {
  2138.                             // Ajouter au stock la quantité reçue
  2139.                             $stock->setQtStock(
  2140.                                 $stock->getQtStock() + $docDecl->getQuantity()
  2141.                             );
  2142.                         }
  2143.                     }
  2144.                 }
  2145.             }
  2146.             /** -----------------------------
  2147.              *  4) Activité
  2148.              * ----------------------------- */
  2149.             $message '[' $this->getUser()->getFullName() . '] a confirmé la réception de l’échange.';
  2150.             $this->activityService->addActivity('success'$message$document$this->getUser(), 'document');
  2151.             /** -----------------------------
  2152.              *  5) Flash + Redirect
  2153.              * ----------------------------- */
  2154.             $em->flush();
  2155.             $request->getSession()->getFlashBag()->add('success'"Échange reçu avec succès.");
  2156.         } else {
  2157.             /** -----------------------------
  2158.              *  6) Cas d’erreur
  2159.              * ----------------------------- */
  2160.             $request->getSession()->getFlashBag()->add(
  2161.                 'danger',
  2162.                 "Impossible de confirmer : le document {$document->getInternalNbr()} n'est pas dans un état expédié."
  2163.             );
  2164.         }
  2165.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  2166.     }
  2167.     /**
  2168.      * @Route("/echangeedit/commande/{id}/{category}/{document}", name="echange_document_commande_edit", methods={"GET","POST"}, options={"expose"=true})
  2169.      */
  2170.     public function editEchange(Document $commande$categoryDocument $documentRequest $request,EntityManagerInterface $em): Response {
  2171.         $rights=$this->hasRightByType$request,$category,'DOCUMENT_CLIENT_UPDATE','DOCUMENT_SUPPLIER_UPDATE');
  2172.         $type 'commande';
  2173.         //$commande->setUser($this->getUser());
  2174.         if( $request->isMethod('POST')) {
  2175.             //Supprimer les anciennes lignes du bon d'échange intial
  2176.             foreach ($document->getDocumentDeclinationProduits() as $docDec) {
  2177.                 $prodDecVa $docDec->getProduitDeclinationValue();
  2178.                 if( $docDec->getType() != 'declinationEchange') {
  2179.                     $stock $prodDecVa->getStocks()[0];
  2180.                     if( $stock && $category == 'client') {
  2181.                         if( !$stock->getQtReserved() <= 0) {
  2182.                             $stock->setQtReserved($stock->getQtReserved() - $docDec->getQuantity());
  2183.                         }
  2184.                     }
  2185.                 }
  2186.                 $document->removeDocumentDeclinationProduit($docDec);
  2187.             }
  2188.             //Ajouter les nouvelles lignes du bon d'échange
  2189.             foreach ($document->getDocumentProduits() as $docProd) {
  2190.                 $prod $docProd->getProduit();
  2191.                 if( $docProd->getType() != 'declinationEchange') {
  2192.                     $stock $prod->getStocks()[0];
  2193.                     if( $stock && $category == 'client') {
  2194.                         if( !$stock->getQtReserved() <= 0) {
  2195.                             $stock->setQtReserved($stock->getQtReserved() - $docProd->getQuantity());
  2196.                         }
  2197.                     }
  2198.                 }
  2199.                 $document->removeDocumentProduit($docProd);
  2200.             }
  2201.             foreach ($document->getDocumentComments() as $comm) {
  2202.                 $document->removeDocumentComment($comm);
  2203.             }
  2204.             if( $request->get('form_document')) {
  2205.                 $data $request->get('form_document');
  2206.                 //dd($data);
  2207.                 $existChange false;
  2208.                 if( isset($data['content']) && $data['content']) {
  2209.                     foreach ($data['content'] as $item) {
  2210.                         if( isset($item['change']) && $item['change']) {
  2211.                             if( $item['change'] == "true") {
  2212.                                 $existChange true;
  2213.                                 break;
  2214.                             }
  2215.                         }
  2216.                     }
  2217.                 }
  2218.                 if( $existChange) {
  2219.                     $date = new \DateTime('now');
  2220.                     $type 'echange';
  2221.                     $document $this->createCopyDocument($document$commande);
  2222.                     $document->setDocument($commande);
  2223.                     $document->setType($type);
  2224.                     $document->setCategory($category);
  2225.                     //$document->setCreatedAt(new \DateTime('now'));
  2226.                     //$document->setEndAt($date->add(new \DateInterval('P30D')));
  2227.                     //$document->setUser($this->getUser());
  2228.                     $document->setUpdatedBy($this->getUser());
  2229.                     $document->setUpdatedAt($date);
  2230.                     if( $data['discount'] == ""$data['discount'] = 0;
  2231.                     $dateDelivery =($data['promisedAt'] && $data['promisedAt'] != '' && $data['promisedAt'] != null)?
  2232.                         new \DateTime($data['promisedAt']):null;
  2233.                     
  2234.                     $document
  2235.                             //->setObject($data['object'])
  2236.                             ->setTotalAmountHt((float) ($data['totalAmountHt'] ?? 0))
  2237.                             ->setTotalTva($data['totalTva'])
  2238.                             ->setTotalAmountTtc($data['totalAmountTtc'])
  2239.                             ->setAdress(!empty($data['adress']) ? $data['adress'] : null)
  2240.                             //->setParcelTrackingNbr($data['parcelTrackingNbr'])
  2241.                             ->setPaymentMethod($data['paymentMethod'])
  2242.                             //->setPaymentDeadline($data['paymentDeadline'])
  2243.                             ->setDiscount($data['discount'])
  2244.                             ->setDiscountType($data['discountType'])
  2245.                             //->setAdvancePayment($data['advancePayment'])
  2246.                             //->setAdvancePaymentType($data['advancePaymentType'])
  2247.                             ->setPackagesNbr($data['packagesNbr'])
  2248.                             //->setUrlTracking($data['urlTracking'])
  2249.                             ->setPromisedAt($dateDelivery)
  2250.                             ->setNote($data['note']);
  2251.                     $delivery $this->deliveryRepository->find($data['delivery']['id']);
  2252.                     $source $this->sourceRepository->find($data['source']['id']);
  2253.                     $document->setSource($source);
  2254.                     $document->setDelivery($delivery)
  2255.                             ->setDeliveryDiscount($data['delivery']['discount'])
  2256.                             ->setDeliveryDiscountType($data['delivery']['discount_type'])
  2257.                             ->setDeliveryPrice($data['delivery']['price_ht'])
  2258.                             ->setDeliveryTotal((float) $data['delivery']['total_amount_ttc']);
  2259.                     $document->setIsFreeDelivery((isset($data['isFreedelivery']) && $data['isFreedelivery'] == "on"));
  2260.                     $tvaDelivery $this->tvaRepository->find($data['delivery']['tva']);
  2261.                     $document->setDeliveryTva($tvaDelivery);
  2262.                     if( isset($data['comment']) && $data['comment']) {
  2263.                         foreach ($data['comment'] as $item) {
  2264.                             $comment = new Comment();
  2265.                             $comment->setCreateAt(new \DateTime('now'))
  2266.                                     ->setDescription($item)
  2267.                                     ->setUser($this->getUser());
  2268.                             $em->persist($comment);
  2269.                             $document->addDocumentComment($comment);
  2270.                         }
  2271.                     }
  2272.                     if( isset($data['content']) && $data['content']) {
  2273.                         $totalHt = (float)$item['price_ht'] * (int)$item['quantity'];
  2274.                         foreach ($data['content'] as $item) {
  2275.                             if( $item['type'] == 'produit') {
  2276.                                 $entity = new DocumentProduit();
  2277.                                 $entity->setType($item['type']);
  2278.                                 if( isset($item['id']) && $item['id']) {
  2279.                                     $produit $this->produitRepository->find($item['id']);
  2280.                                     $entity->setProduit($produit);
  2281.                                     if( isset($item['unit']) && $item['unit'])
  2282.                                         $entity->setUnite($item['unit']);
  2283.                                     else
  2284.                                         $entity->setUnite($produit->getUnit());
  2285.                                 }
  2286.                             } else {
  2287.                                 if( isset($item['change']) && $item['change']) {
  2288.                                     if( $item['change'] == "true") {
  2289.                                         $entity = new DocumentDeclinationProduit();
  2290.                                         $entity->setType('declinationEchange');
  2291.                                         if( isset($item['id']) && $item['id']) {
  2292.                                             $produitDecllination $this->produitDeclinationValueRepository->find($item['id']);
  2293.                                             $entity->setProduitDeclinationValue($produitDecllination);
  2294.                                             if( isset($item['unit']) && $item['unit'])
  2295.                                                 $entity->setUnite($item['unit']);
  2296.                                             else
  2297.                                                 $entity->setUnite($produitDecllination->getProduit()->getUnit());
  2298.                                         }
  2299.                                         if( isset($entity)) {
  2300.                                             $entity->setReference($item['reference'])
  2301.                                                     ->setDiscount($item['discount'])
  2302.                                                     //->setDiscountType($item['discount_type'])
  2303.                                                     ->setPriceHt($item['price_ht'])
  2304.                                                     ->setQuantity($item['quantity'])
  2305.                                                     ->setCreatedAt(new \DateTime('now'))
  2306.                                                     ->setTotalAmountHt($totalHt)
  2307.                                                     ->setTotalAmountTtc($item['total_amount_ttc']);
  2308.                                             if( isset($item['description']) && $item['description'])
  2309.                                                 $entity->setDescription($item['description']);
  2310.                                             if( $item['tva'] != "0") {
  2311.                                                 $tva $this->tvaRepository->find($item['tva']);
  2312.                                             } else {
  2313.                                                 $tva $this->tvaRepository->findOneBy(["number" => 0]);
  2314.                                             }
  2315.                                             $entity->setTva($tva);
  2316.                                             $entity->setDocument($document);
  2317.                                             $em->persist($entity);
  2318.                                         }
  2319.                                     }
  2320.                                 } else {
  2321.                                     $entity = new DocumentDeclinationProduit();
  2322.                                     $entity->setType($item['type']);
  2323.                                     if( isset($item['id']) && $item['id']) {
  2324.                                         $produitDecllination $this->produitDeclinationValueRepository->find($item['id']);
  2325.                                         $entity->setProduitDeclinationValue($produitDecllination);
  2326.                                         $stock $produitDecllination->getStocks()[0];
  2327.                                         if( $stock) {
  2328.                                             if( $category == 'client') {
  2329.                                                 $stock->setQtReserved($stock->getQtReserved() + $item['quantity']);
  2330.                                             }
  2331.                                         } else {
  2332.                                             $stock = new Stock();
  2333.                                             if( $category == 'client') {
  2334.                                                 $stock->setDeclinationProduit($produitDecllination)
  2335.                                                         ->setQtReserved($item['quantity'])
  2336.                                                         ->setQtStock(0)
  2337.                                                         ->setStorehouse('Principal');
  2338.                                             } else {
  2339.                                                 $stock->setDeclinationProduit($produitDecllination)
  2340.                                                         ->setQtReserved(0)
  2341.                                                         ->setQtStock(0)
  2342.                                                         ->setStorehouse('Principal');
  2343.                                             }
  2344.                                             $em->persist($stock);
  2345.                                         }
  2346.                                         $entity->setUnite((isset($item['unit']) && $item['unit'])?$item['unit']:$produitDecllination->getProduit()->getUnit());
  2347.                                     }
  2348.                                     if( isset($entity)) {
  2349.                                         $entity->setReference($item['reference'])
  2350.                                                 ->setDiscount($item['discount'])
  2351.                                                 ->setDiscountType($item['discount_type'])
  2352.                                                 ->setPriceHt($item['price_ht'])
  2353.                                                 ->setQuantity($item['quantity'])
  2354.                                                 ->setCreatedAt(new \DateTime('now'))
  2355.                                                 ->setTotalAmountHt($totalHt)
  2356.                                                 ->setTotalAmountTtc($item['total_amount_ttc']);
  2357.                                         if( isset($item['description']) && $item['description'])
  2358.                                             $entity->setDescription($item['description']);
  2359.                                         $tva =($item['tva'] != "0")? $this->tvaRepository->find($item['tva'])
  2360.                                                 :$this->tvaRepository->findOneBy(["number" => 0]);
  2361.                                         $entity->setTva($tva);
  2362.                                         $entity->setDocument($document);
  2363.                                         $em->persist($entity);
  2364.                                     }
  2365.                                 }
  2366.                             }
  2367.                         }
  2368.                     }
  2369.                     if( $category == "client") {
  2370.                         $document->setStatus('en-attente');
  2371.                         $document->setConditionDocument('Aucun');
  2372.                         $document->setClient($commande->getClient());
  2373.                     } else {
  2374.                         
  2375.                     }
  2376.                     $message '[' $this->getUser()->getFullName() . "] a modifié le bon d'échange.";
  2377.                     $this->activityService->addActivity('info'$message$document$this->getUser(), 'document');
  2378.                     $em->flush();
  2379.                     $request->getSession()->getFlashBag()->add('success'"Bon echange créé avec succès");
  2380.                     return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  2381.                 }
  2382.             }
  2383.         }
  2384.         $tvas $this->tvaRepository->findAll();
  2385.         $deliveryTypes=($category == 'client')?['client','client-fournisseur']:['fournisseur','client-fournisseur'];
  2386.         $deliverys $this->deliveryRepository->findAllByTypes($deliveryTypes);
  2387.         $sources $this->sourceRepository->findAll();
  2388.         $id = ($category == 'client')?$commande->getClient()->getId():$commande->getSupplier()->getId();
  2389.         $declinationCouleur $this->declinationRepository->findOneBy(["name" => "Couleur"]);
  2390.         return $this->render('@admin/document/edit_echange_document_client.html.twig', [
  2391.                     'document' => $commande,
  2392.                     'commande' => $document,
  2393.                     'declinationCouleur'=>$declinationCouleur,
  2394.                     'type' => $type,
  2395.                     'category' => $category,
  2396.                     'id' => $id,
  2397.                     'tvas' => $tvas,
  2398.                     'deliverys' => $deliverys,
  2399.                     'sources' => $sources,
  2400.                     'rights' => $rights
  2401.         ]);
  2402.     }
  2403.     /**
  2404.      * @Route("/change/supplier/{id}", name="change_supplier", methods={"GET","POST"}, options={"expose"=true})
  2405.      */
  2406.     public function changeSupplier(Document $documentRequest $request,EntityManagerInterface $em): Response {
  2407.         if( $request->isMethod('POST')) {
  2408.             $supplier $this->supplierRepository->find($request->get('change_supplier')["id"]);
  2409.             $document->setSupplier($supplier);
  2410.             $message '[' $this->getUser()->getFullName() . '] a changé le fournisseur du bon de commande.';
  2411.             $this->activityService->addActivity('info'$message$document$this->getUser(), 'document');
  2412.             $em->flush();
  2413.             $request->getSession()->getFlashBag()->add('success'"Fournisseur modifiée avec succès");
  2414.         }
  2415.         return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  2416.     }
  2417.     /**
  2418.      * @Route("/search", name="search_document", methods="GET|POST", options = { "expose" =  true})
  2419.      */
  2420.     public function searchItem2(Request $requestDocumentRepository $document) {
  2421.         $query $request->get('query');
  2422.         $deleteEspace str_replace(' '''$query);
  2423.         if( is_numeric($deleteEspace)) $query $deleteEspace;
  2424.         $entities $document->search2$query);
  2425.         $output='<div class="m-list-search__results">';
  2426.         foreach ($entities as $entity) {
  2427.              $className='';
  2428.                         switch ($entity->getStatus()) {
  2429.                             case 'en-attente':
  2430.                                 $className="alert-en-attente";
  2431.                                 break;
  2432.                             case 'accepte':
  2433.                                 $className='alert-accepte';
  2434.                                 break;
  2435.                             case 'expedie':
  2436.                             case 'livre':
  2437.                                 $className='alert-expedie';
  2438.                                 break;
  2439.                             case 'retour-en-cours':
  2440.                                 $className='alert-retour';
  2441.                                 break;
  2442.                             case 'retourne':
  2443.                                 $className='alert-retourne';
  2444.                                 break;
  2445.                             case 'annule':
  2446.                                 $className='alert-annule';
  2447.                                 break;
  2448.                             case 'echange-recu':
  2449.                                 $className='alert-echange-recu';
  2450.                                 break;
  2451.                             case 'paye':
  2452.                                 $className='alert-paye';
  2453.                                 break;
  2454.                             default:
  2455.                                 $className='m-badge--metal';
  2456.                         }
  2457.                        $statusHtml' <span class="m-badge '.$className.' m-badge--wide">' .$entity->getStatus().'</span>';
  2458.             $output .= '<a href="/admin/document/show/'.$entity->getId().'" class="m-list-search__result-item">
  2459.                             <span class="m-list-search__result-item-pic">'.$entity->getInternalNbr().'
  2460.                                 <br><small> Créé le '.$entity->getCreatedAt()->format('d/m/y H:i').'</small>
  2461.                                 <br><small><i class="fa fa-chain"></i><code title="'.(($entity->getDelivery())?$entity->getDelivery()->getName():"N suivie").'">'.$entity->getParcelTrackingNbr().'</code></small>
  2462.                             </span>
  2463.                             <span class="m-list-search__result-item-text">
  2464.                                 '.(($entity->getClient())?'<small><i class="fa fa-user"></i> '.$entity->getClient()->getCivility() . ' ' $entity->getClient()->getFirstName() .'</small>':'').'
  2465.                                 <span class="float-right">'.$statusHtml.'</span>
  2466.                                 <br>
  2467.                                  '.(($entity->getClient())?'<small><i class="fa fa fa-phone"></i> '$entity->getClient()->getPhone().'</small>':'').'
  2468.                                 <br>
  2469.                                 <small><i class="fa fa fa-map-signs"></i> '$entity->getAdress().'</small>
  2470.                                 <span class="float-right"><small>PAR '.$entity->getUser()->getFirstName().'</small></span>
  2471.                             </span>
  2472.                         </a>';
  2473.         }
  2474.         $output .='</div>';
  2475.         if( !$entities$output ="";
  2476.         return new Response($output);
  2477.     }
  2478.     /**
  2479.      * @Route("/delete/{document}", name="document_delete", methods="DELETE", options = { "expose" =  true})
  2480.      */
  2481.     public function delete(Request $requestDocument $document,EntityManagerInterface $em): Response {
  2482.         $rights =$this->hasRightByType$request,$document->getCategory(),'DOCUMENT_CLIENT_DELETE','DOCUMENT_SUPPLIER_DELETE');
  2483.         if( $document->getstatus() === 'annule' ) {
  2484.             if( $this->isCsrfTokenValid($this->getUser()->getId(), $request->server->get("HTTP_X_CSRF_TOKEN"))) {
  2485.                 //dump($request);die;
  2486.                 $message '[' $this->getUser()->getFullName() . '] a supprimé le bon de commande.';
  2487.                 $this->activityService->addActivity('danger'$messageNULL$this->getUser(), 'document');
  2488.                 $this->documentRemove($document$em);
  2489.                 $em->flush();
  2490.                 if( $request->isXmlHttpRequest())
  2491.                     return new JsonResponse(['status' => 'success''message' => 'Document supprimé avec succés'], Response::HTTP_OK);
  2492.                 else return $this->redirectToRoute('document_index');
  2493.             }
  2494.         }
  2495.         return new JsonResponse('Something went wrong!'Response::HTTP_OK);
  2496.     }
  2497.     private function documentRemove(Document $documentEntityManagerInterface $em) {
  2498.         foreach($document->getDocumentDeclinationProduits() as $documentDeclination)
  2499.             $em->remove($documentDeclination);
  2500.         foreach($document->getDocumentProduits() as $documentProduit)
  2501.             $em->remove($documentProduit);
  2502.         foreach($document->getComments() as $comment)
  2503.             $em->remove($comment);
  2504.         foreach($document->getDocumentComments() as $commentDoc)
  2505.             $em->remove($commentDoc);
  2506.         foreach($document->getActivities() as $activitie)
  2507.             $em->remove($activitie);
  2508.         foreach($document->getDocuments() as $doc)
  2509.             $document->removeDocument($doc);
  2510.         $em->remove($document);
  2511.     }
  2512.     private function createPdf(string $twig, array $paramsstring $name): string
  2513.     {
  2514.         /* =====================================================
  2515.         CONFIGURATION DOMPDF — SÉCURISÉE & STABLE
  2516.         ===================================================== */
  2517.         $options = new Options();
  2518.         $options->setDefaultFont('DejaVu Sans');
  2519.         $options->setIsHtml5ParserEnabled(true);
  2520.         // IMPORTANT : PAS de chargement HTTP
  2521.         $options->setIsRemoteEnabled(false);
  2522.         // CHROOT STRICT : autorise uniquement /public
  2523.         $options->setChroot(
  2524.             $this->getParameter('kernel.project_dir') . '/public'
  2525.         );
  2526.         $dompdf = new Dompdf($options);
  2527.         /* =====================================================
  2528.         RENDU HTML
  2529.         ===================================================== */
  2530.         $html $this->renderView($twig$params);
  2531.         $dompdf->loadHtml($html'UTF-8');
  2532.         $dompdf->setPaper('A4''portrait');
  2533.         /* =====================================================
  2534.         GÉNÉRATION PDF
  2535.         ===================================================== */
  2536.         $dompdf->render();
  2537.         $output $dompdf->output();
  2538.         /* =====================================================
  2539.         STOCKAGE TEMPORAIRE (OPTIONNEL)
  2540.         ===================================================== */
  2541.         $pdfDir $this->getParameter('kernel.project_dir') . '/public/pdf';
  2542.         if (!is_dir($pdfDir)) {
  2543.             mkdir($pdfDir0755true);
  2544.         }
  2545.         $filePath $pdfDir '/' $name '.pdf';
  2546.         file_put_contents($filePath$output);
  2547.         return '/pdf/' $name '.pdf';
  2548.     }
  2549.     private function createCopyDocumentProduit($new$old) {
  2550.         $new->setReference($old->getReference())
  2551.             ->setDiscount($old->getDiscount())
  2552.             ->setDescription($old->getDescription())
  2553.             ->setDiscountType($old->getDiscountType())
  2554.             ->setPriceHt($old->getPriceHt())
  2555.             ->setPriceTtc($old->getPriceTtc())
  2556.             ->setQuantity($old->getQuantity())
  2557.             ->setCreatedAt(new \DateTime('now'))
  2558.             ->setUnite($old->getUnite())
  2559.             ->setTva($old->getTva())
  2560.             ->setType($old->getType())
  2561.             ->setName($old->getName())
  2562.             ->setTotalAmountHt($old->getTotalAmountHt() ?? 0)
  2563.             ->setTva($old->getTva() ?? 0)
  2564.             ->setTotalAmountTtc($old->getTotalAmountTtc());
  2565.         return $new;
  2566.     }
  2567.     private function createCopyDocument($new$old) {
  2568.     
  2569.         $new->setObject($old->getObject())
  2570.             ->setNote($old->getNote())
  2571.             ->setPaymentMethod($old->getPaymentMethod())
  2572.             ->setPaymentDeadline($old->getPaymentDeadline())
  2573.             ->setDiscount($old->getDiscount())
  2574.             ->setDiscountType($old->getDiscountType())
  2575.             ->setAdvancePayment($old->getAdvancePayment())
  2576.             ->setAdvancePaymentType($old->getAdvancePaymentType())
  2577.             ->setParcelTrackingNbr($old->getParcelTrackingNbr())
  2578.             ->setCategory($old->getCategory())
  2579.             ->setDelivery($old->getDelivery())
  2580.             ->setIsFreeDelivery($old->getIsFreeDelivery())
  2581.             ->setDeliveryDiscount($old->getDeliveryDiscount())
  2582.             ->setDeliveryDiscountType($old->getDeliveryDiscountType())
  2583.             ->setDeliveryPrice($old->getDeliveryPrice())
  2584.             ->setDeliveryTva($old->getDeliveryTva())
  2585.             ->setDeliveryTotal($old->getDeliveryTotal())
  2586.             ->setPackagesNbr($old->getPackagesNbr())
  2587.             ->setUrlTracking($old->getUrlTracking())
  2588.             ->setPromisedAt($old->getPromisedAt())
  2589.             ->setAdress($old->getAdress())
  2590.             ->setSource($old->getSource())            
  2591.             ->setTotalAmountHt((float)$old->getTotalAmountHt() ?? 0)
  2592.             ->setTotalAmountTtc($old->getTotalAmountTtc() ?? 0)
  2593.             ->setTotalTva($old->getTotalTva() ?? 0)
  2594.             ->setTotalPaid($old->getTotalPaid() ?? 0)
  2595.             ->setExternalNbr($old->getExternalNbr());
  2596.         
  2597.        
  2598.         return $new;
  2599.     }
  2600.     /**
  2601.      * convertir directement un DA en Brecp
  2602.      * @Route("/convert-DA/{document}", name="convert_da_to_bon_reception", methods={"GET","POST"}, options={"expose"=true})
  2603.      */
  2604.     public function convetDaToBonReception(Document $documentRequest $request,EntityManagerInterface $em): Response
  2605.     {
  2606.         $rights $this->hasRightByType($request$document->getCategory(), 'DOCUMENT_CLIENT_CREATE''DOCUMENT_SUPPLIER_CREATE');
  2607.         if( $document->getStatus() == "en-attente" and $document->getType() == "achat") {
  2608.             $newDocument = new Document();
  2609.             $date = new \DateTime('now');
  2610.             $newDocument $this->createCopyDocument($newDocument$document);
  2611.             $newDocument->setInternalNbr("B-REC-" date('dmY') . '-' rand(1000099999))
  2612.                 ->setType("reception")
  2613.                 ->setCategory("fournisseur")
  2614.                 ->setUser($this->getUser())
  2615.                 ->setSupplier($document->getSupplier())
  2616.                 ->setStatus('brouillon');
  2617.             if( $request->isMethod('POST')) {
  2618.                 if( $request->get('form_document')) {
  2619.                     $data $request->get('form_document');
  2620.                     if( $data['discount'] == ""$data['discount'] = 0;
  2621.                    
  2622.                     $dateDelivery = (!empty($data['promisedAt'])) ? new \DateTime($data['promisedAt']) : null;
  2623.                
  2624.                     $datebonlivraison = (!empty($data['shippedAt'])) ? new \DateTime($data['shippedAt']) : null;
  2625.                     $datebonrecu = (!empty($data['bonrecuAt'])) ? new \DateTime($data['bonrecuAt']) : null;
  2626.                     $dateAPayerLe = (!empty($data['aPayerLe'])) ? new \DateTime($data['aPayerLe']) : null;
  2627.                     $delivery $this->deliveryRepository->find($data['delivery']['id']);
  2628.                      $source null;
  2629.                     if (isset($data['source']['id']) && $data['source']['id']) {
  2630.                         $source $this->sourceRepository->find($data['source']['id']);
  2631.                         
  2632.                     }
  2633.                     $tvaDelivery $this->tvaRepository->find($data['delivery']['tva']);
  2634.                     $newDocument->setDocument($document)
  2635.                         ->setConditionDocument("transformé")
  2636.                         ->setInternalNbr($data['internalNbr'])
  2637.                         ->setExternalNbr(!empty($data['externalNbr']) ? $data['externalNbr'] : '')
  2638.                         ->setCreatedAt(new \DateTime('now'))
  2639.                         //->setEndAt($date->add(new \DateInterval('P30D')))
  2640.                         ->setObject($data['object'])
  2641.                         ->setTotalAmountHt($data['totalAmountHt'])
  2642.                         ->setTotalTva($data['totalTva'])
  2643.                         ->setTotalAmountTtc($data['totalAmountTtc'])
  2644.                         ->setAdress(!empty($data['adress']) ? $data['adress'] : null)
  2645.                         ->setParcelTrackingNbr($data['parcelTrackingNbr'])
  2646.                         ->setPaymentMethod($data['paymentMethod'])
  2647.                         ->setPaymentDeadline($data['paymentDeadline'])
  2648.                         ->setDiscount($data['discount'])
  2649.                         ->setDiscountType($data['discountType'])
  2650.                         ->setAdvancePayment($data['advancePayment'])
  2651.                         ->setAdvancePaymentType($data['advancePaymentType'])
  2652.                         ->setPackagesNbr($data['packagesNbr'])
  2653.                         ->setUrlTracking($data['urlTracking'])
  2654.                        
  2655.                         ->setPromisedAt($dateDelivery)
  2656.                         ->setShippedAt($datebonlivraison)
  2657.                         ->setBonrecuAt($datebonrecu)
  2658.                         ->setAPayerLe($dateAPayerLe)                       
  2659.                         ->setNote($data['note'])
  2660.                         ->setSource($source)
  2661.                         ->setDelivery($delivery)
  2662.                         ->setDeliveryDiscount($data['delivery']['discount'])
  2663.                         ->setDeliveryDiscountType($data['delivery']['discount_type'])
  2664.                         ->setDeliveryPrice($data['delivery']['price_ht'])
  2665.                         ->setDeliveryTotal((float) $data['delivery']['total_amount_ttc'])
  2666.                         ->setIsFreeDelivery((isset($data['isFreedelivery']) && $data['isFreedelivery'] == "on"))
  2667.                         ->setDeliveryTva($tvaDelivery);
  2668.                     if( isset($data['comment']) && $data['comment']) {
  2669.                         foreach ($data['comment'] as $item) {
  2670.                             $comment = new Comment();
  2671.                             $comment->setCreateAt(new \DateTime('now'));
  2672.                             $comment->setDocumentComment($newDocument)
  2673.                                 ->setDescription($item)
  2674.                                 ->setUser($this->getUser());
  2675.                             $em->persist($comment);
  2676.                         }
  2677.                     }
  2678.                     if( isset($data['content']) && $data['content']) {
  2679.                         foreach ($data['content'] as $item) {
  2680.                             if( $item['type'] == 'produit') {
  2681.                                 $entity = new DocumentProduit();
  2682.                                 $entity->setType($item['type']);
  2683.                                 if( isset($item['id']) && $item['id']) {
  2684.                                     $produit $this->produitRepository->find($item['id']);
  2685.                                     $entity->setProduit($produit);
  2686.                                     $entity->setUnite((isset($item['unit']) && $item['unit'])?$item['unit']:$produit->getUnit());
  2687.                                 }
  2688.                             } else {
  2689.                                 $entity = new DocumentDeclinationProduit();
  2690.                                 $entity->setType($item['type']);
  2691.                                 if( isset($item['id']) && $item['id']) {
  2692.                                     $produitDecllination $this->produitDeclinationValueRepository->find($item['id']);
  2693.                                     $entity->setProduitDeclinationValue($produitDecllination);
  2694.                                     $stock $produitDecllination->getStocks()[0];
  2695.                                     if( $stock) {
  2696.                                         $stock->setQtStock($stock->getQtStock() + $item['quantity']);
  2697.                                     } else {
  2698.                                         $stock = new Stock();
  2699.                                         $stock->setDeclinationProduit($produitDecllination)
  2700.                                             ->setQtReserved(0)
  2701.                                             ->setQtStock($item['quantity'])
  2702.                                             ->setStorehouse('Principal');
  2703.                                     }
  2704.                                     $em->persist($stock);
  2705.                                     $entity->setUnite((isset($item['unit']) && $item['unit'])?
  2706.                                         $item['unit']:$produitDecllination->getProduit()->getUnit());
  2707.                                 }
  2708.                             }
  2709.                             // Calcul du total HT (avec remise éventuelle)
  2710.                             $priceHt      = (float) ($item['price_ht'] ?? 0);
  2711.                             $qty          = (float) ($item['quantity'] ?? 0);
  2712.                             $discount     = (float) ($item['discount'] ?? 0);
  2713.                             $discountType $item['discount_type'] ?? null;
  2714.                             $totalHt $priceHt $qty;
  2715.                             if ($discount 0) {
  2716.                                 if ($discountType === 'percent') {
  2717.                                     $totalHt -= round($totalHt $discount 1003);
  2718.                                 } else { // montant
  2719.                                     $totalHt -= $discount;
  2720.                                 }
  2721.                             }
  2722.                             $totalHt max(0round($totalHt3));
  2723.                             
  2724.                             $entity->setReference($item['reference'])
  2725.                                 ->setDiscount($item['discount'])
  2726.                                 ->setDiscountType($item['discount_type'])
  2727.                                 ->setPriceHt($item['price_ht'])
  2728.                                 ->setQuantity($item['quantity'])
  2729.                                 ->setCreatedAt(new \DateTime('now'))
  2730.                                 ->setTotalAmountHt($totalHt)
  2731.                                 ->setTotalAmountTtc($item['total_amount_ttc']);
  2732.                             if( isset($item['description']) && $item['description'])
  2733.                                 $entity->setDescription($item['description']);
  2734.                             $tva =($item['tva'] != "0") ?
  2735.                                 $this->tvaRepository->find($item['tva'])
  2736.                                 :$this->tvaRepository->findOneBy(["number" => 0]);
  2737.                             $entity->setTva($tva);
  2738.                             $entity->setDocument($newDocument);
  2739.                             $em->persist($newDocument);
  2740.                             $em->persist($entity);
  2741.                         }
  2742.                     }
  2743.                     $document
  2744.                         ->setUpdatedBy($this->getUser())
  2745.                         ->setUpdatedAt(new \DateTime('now'))
  2746.                         ->setStatus('transforme')
  2747.                         ->setConditionDocument($document->getConditionDocument()." -> Transformé");
  2748.                 }
  2749.                 $message '[' $this->getUser()->getFullName() . '] a transformé le bon de commande en Bon de réception de Réf: ' $newDocument->getInternalNbr();
  2750.                 $this->activityService->addActivity('success'$message$document$this->getUser(), 'document');
  2751.                 $em->flush();
  2752.                 $request->getSession()->getFlashBag()->add('success'"Le Demande d'achat de réf  {$document->getInternalNbr()} a été transformé en Bon de réception de réf {$newDocument->getInternalNbr()} avec succès");
  2753.                 return (array_key_exists('save'$data) && $data['save']=="save-and-exit")?
  2754.                     $this->redirectToRoute('document_show', ['id' => $newDocument->getId()]):
  2755.                     $this->redirectToRoute('edit_document_commande', ['type' =>$newDocument->getType(),'document'=>$newDocument->getId(),'category'=>$newDocument->getCategory()]);
  2756.             }
  2757.             $tvas $this->tvaRepository->findAll();
  2758.             $deliverys $this->deliveryRepository->findAllByTypes(['fournisseur','client-fournisseur']);
  2759.             $sources $this->sourceRepository->findAll();
  2760.             $declinationCouleur $this->declinationRepository->findOneBy(["name" => "Couleur"]);
  2761.             return $this->render('@admin/document/edit_document_fournisseur.html.twig', [
  2762.                 'newDocument' => $newDocument,
  2763.                 'document'=> $document,
  2764.                 'type' => 'reception',
  2765.                 'category' => 'fournisseur',
  2766.                 'id' => $document->getSupplier()->getId(),
  2767.                 'tvas' => $tvas,
  2768.                 'deliverys' => $deliverys,
  2769.                 'sources' => $sources,
  2770.                 'declinationCouleur'=>$declinationCouleur,
  2771.                 'rights' => $rights
  2772.             ]);
  2773.         }else {
  2774.             $request->getSession()->getFlashBag()->add('danger'"Le DA de réf {$document->getInternalNbr()} ".($document->getStatus()=="annule")?
  2775.                 " a déjà été annulée":" a déjà été transformé");
  2776.             return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
  2777.         }
  2778.     }
  2779.     
  2780. }