<?php
namespace App\Controller\Admin;
use App\Entity\Document;
use App\Entity\DocumentDeclinationProduit;
use App\Entity\DocumentProduit;
use App\Entity\Stock;
use App\Entity\Comment;
use App\Entity\CancelReason;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use App\Repository\CancelReasonRepository;
use App\Repository\RefundReasonRepository;
use App\Repository\CompanyRepository;
use App\Repository\SupplierRepository;
use App\Repository\SourceRepository;
use App\Repository\DeclinationRepository;
use App\Repository\DeliveryRepository;
use App\Repository\UserRepository;
use App\Repository\TvaRepository;
use App\Repository\ProduitDeclinationValueRepository;
use App\Repository\ProduitRepository;
use App\Repository\DocumentRepository;
use App\Form\FilterDocumentType;
use Dompdf\Dompdf;
use Dompdf\Options;
use Symfony\Component\HttpFoundation\RequestStack;
use App\Form\InfoLivraisonType;
use App\Service\ActivityService;
use App\Service\RightService;
use Symfony\Component\Routing\RouterInterface;
use App\Service\StockService;
use App\Service\PaymentUpdaterService;
use App\Repository\PromotionRepository;
/**
* @Route("/document")
*/
class DocumentController extends AbstractController {
use AccessTrait;
private $userRepository;
private $tvaRepository;
private $deliveryRepository;
private $produitRepository;
private $produitDeclinationValueRepository;
private $documentRepository;
private $supplierRepository;
private $sourceRepository;
protected $baseUrl;
private $activityService;
private $rightService;
private $declinationRepository;
private PromotionRepository $promotionRepository;
private StockService $stockService;
public function __construct(UserRepository $userRepository, TvaRepository $tvaRepository,
ProduitRepository $produitRepository, ProduitDeclinationValueRepository $produitDeclinationValueRepository,
DeliveryRepository $deliveryRepository, DocumentRepository $documentRepository, RequestStack $requestStack,
SupplierRepository $supplierRepository, SourceRepository $sourceRepository,
ActivityService $activityService, RightService $rightService, DeclinationRepository $declinationRepository,
PromotionRepository $promotionRepository
) {
$this->userRepository = $userRepository;
$this->tvaRepository = $tvaRepository;
$this->deliveryRepository = $deliveryRepository;
$this->produitRepository = $produitRepository;
$this->produitDeclinationValueRepository = $produitDeclinationValueRepository;
$this->documentRepository = $documentRepository;
$this->baseUrl = $requestStack->getCurrentRequest()->getSchemeAndHttpHost();
$this->supplierRepository = $supplierRepository;
$this->sourceRepository = $sourceRepository;
$this->activityService = $activityService;
$this->rightService = $rightService;
$this->declinationRepository = $declinationRepository;
$this->promotionRepository = $promotionRepository;
}
/**
* @Route("/index/{type}/{category}", name="document_index", options={"expose"=true})
*/
public function index($type, $category,Request $request): Response {
$this->hasRightByType( $request, $type, 'DOCUMENT_CLIENT', 'DOCUMENT_SUPPLIER');
$form = $this->createForm(FilterDocumentType::class, null, ['label' => $type,'context' => $category,]);
if ($category == 'client') {
return $this->render('@admin/document/list_documents_clients.html.twig', ['form' => $form->createView(),'type' => $type,'category' => $category ]);
} elseif ($category == 'fournisseur') {
return $this->render('@admin/document/list_documents_fournisseurs.html.twig', ['form' => $form->createView(),'type' => $type,'category' => $category]);
} else {
// Par défaut ou erreur
throw $this->createNotFoundException('Type de document inconnu.');
}
}
/**
* @Route("/show/{id}", name="document_show", options = { "expose" = true})
*/
public function show(Document $document,Request $request,CancelReasonRepository $cancelReasonRepository,RefundReasonRepository $refundReasonRepository): Response {
$rights=$this->hasRightByType( $request, $document->getCategory(), 'DOCUMENT_CLIENT', 'DOCUMENT_SUPPLIER');
$deliveryTypes=($document->getCategory() == 'client')?['client','client-fournisseur']:['fournisseur','client-fournisseur'];
$deliverys = $this->deliveryRepository->findAllByTypes($deliveryTypes);
$cancelReasons = $cancelReasonRepository->findBy(['isActive' => true],['displayOrder' => 'ASC', 'name' => 'ASC'] );
$refundReasons = $refundReasonRepository->findBy([], ['displayOrder' => 'ASC', 'name' => 'ASC']);
$suppliers = ($document->getCategory() == "fournisseur")?
$this->supplierRepository->findAll()
:[];
//$comments=$this->getAllDocumentComments($document);
$comments=$document->getComments();
//dd($comments);
$user =$document->getClient();
$cmdEnAttente=$cmdAccepte=$cmdAnnule=$cmdEnRetour=$echangeEnAttente=$nbCmdTotal=$nbBeTotal=0;
if($user != null) {
$cmdEnAttente = $user->getDocuments()->filter(function ($element) {
return in_array($element->getStatus(), ['en-attente']) and $element->getType() == 'commande';
})->count();
$cmdAccepte = $user->getDocuments()->filter(function ($element) {
return in_array($element->getStatus(), ['accepte']) and $element->getType() == 'commande';
})->count();
$cmdAnnule = $user->getDocuments()->filter(function ($element) {
return in_array($element->getStatus(), ['annule']) and $element->getType() == 'commande';
})->count();
$cmdEnRetour = $user->getDocuments()->filter(function ($element) {
return in_array($element->getStatus(), ['retourne', 'retour-en-cours']) and $element->getType() == 'commande';
})->count();
$echangeEnAttente = $user->getDocuments()->filter(function ($element) {
return $element->getStatus() == 'en-attente' and $element->getType() == 'echange';
})->count();
$nbCmdTotal = $user->getDocuments()->filter(function ($element) {
return $element->getType() == 'commande';
})->count();
$nbBeTotal = $user->getDocuments()->filter(function ($element) {
return $element->getType() == 'echange';
})->count();
}
if ($document->getCategory() === 'client') {
if ($document->getType() === 'echange') {
return $this->render('admin/document/detail_echange_client.html.twig', compact('document','comments','deliverys','suppliers','rights','cmdEnAttente','cmdAnnule','cmdEnRetour','echangeEnAttente','nbCmdTotal','nbBeTotal', 'cancelReasons', 'refundReasons'));
}else
// Chercher une facture liée à ce bon de commande
$factureExistante = null;
foreach ($document->getDocuments() as $doc) {
if ($doc->getType() === 'facture') {
$factureExistante = $doc;
break;
}
}
return $this->render('@admin/document/detail_document_client.html.twig', compact(
'document','comments','deliverys','suppliers','rights',
'cmdEnAttente','cmdAnnule','cmdEnRetour','echangeEnAttente','nbCmdTotal','nbBeTotal',
'cancelReasons', 'refundReasons', 'factureExistante'
));
} elseif ($document->getCategory() === 'fournisseur') {
return $this->render('@admin/document/detail_document_fournisseur.html.twig', compact('document','comments','deliverys','suppliers','rights','cmdEnAttente','cmdAnnule','cmdEnRetour','echangeEnAttente','nbCmdTotal','nbBeTotal', 'cancelReasons', 'refundReasons'));
} else {
// Par défaut ou erreur
throw $this->createNotFoundException('Type de document inconnu.');
}
}
private function getAllDocumentComments(Document $document):Collection {
$comments =$document->getComments();
if($document->getDocument()){
$childComments=$this->getAllDocumentComments( $document->getDocument());
if($childComments) foreach ($childComments as $childComment) $comments->add($childComment);
}
return $comments;
}
/**
* @Route("/listData", name="list_document", methods="GET|POST", options = { "expose" = true})
*/
public function listData(Request $request, DocumentRepository $documentRepository) {
$pagination = $request->get('pagination');
$page = $pagination['page'] - 1;
$limit = $pagination['perpage'];
$sortField=$request->get('sort')?$request->get('sort')["field"]:'createdAt';
$sortType=$request->get('sort')?$request->get('sort')["sort"]:'DESC';
//dd( $request->get('deliveryAt'));
$entities = $documentRepository->search(
$page,
$limit,
$request->get('status'),
$request->get('region'),
$request->get('internalNbr'),
$request->get('client'),
$request->get('type'),
$request->get('category'),
$request->get('supplier'),
$request->get('totalAmountTtcMin'),
$request->get('dateBefore'),
$request->get('dateAfter'),
$request->get('typeElement'),
$request->get('reference'),
$request->get('parcelTrackingNbr'),
$request->get('user'),
$request->get('source'),
$request->get('totalAmountTtcMax'),
$request->get('delivery'),
$request->get('deliveryAt'),
$request->get('deliveryAtAfter'),
$sortField,$sortType
);
$count = $documentRepository->countDocuments(
$request->get('status'),
$request->get('region'),
$request->get('internalNbr'),
$request->get('client'),
$request->get('type'),
$request->get('category'),
$request->get('supplier'),
$request->get('totalAmountTtcMin'),
$request->get('dateBefore'),
$request->get('dateAfter'),
$request->get('typeElement'),
$request->get('reference'),
$request->get('parcelTrackingNbr'),
$request->get('user'),
$request->get('source'),
$request->get('totalAmountTtcMax'),
$request->get('delivery'),
$request->get('deliveryAt'),
$request->get('deliveryAtAfter')
);
/*
$countCondition = $documentRepository->countCondition(
$request->get('status'),
$request->get('region'),
$request->get('internalNbr'),
$request->get('client'),
$request->get('type'),
$request->get('category'),
$request->get('supplier'),
$request->get('totalAmountTtcMin'),
$request->get('dateBefore'),
$request->get('dateAfter'),
$request->get('typeElement'),
$request->get('reference'),
$request->get('parcelTrackingNbr'),
$request->get('user'),
$request->get('source'),
$request->get('totalAmountTtcMax'),
$request->get('delivery'),
$request->get('deliveryAt'),
$request->get('deliveryAtAfter')
);
*/
$countStatut = $documentRepository->countStatut(
$request->get('status'),
$request->get('region'),
$request->get('internalNbr'),
$request->get('client'),
$request->get('type'),
$request->get('category'),
$request->get('supplier'),
$request->get('totalAmountTtcMin'),
$request->get('dateBefore'),
$request->get('dateAfter'),
$request->get('typeElement'),
$request->get('reference'),
$request->get('parcelTrackingNbr'),
$request->get('user'),
$request->get('source'),
$request->get('totalAmountTtcMax'),
$request->get('delivery'),
$request->get('deliveryAt'),
$request->get('deliveryAtAfter')
);
$moeynne =($count['count'] !== 0) ? round($count['totalAmountTtc'] / $count['count'], 3): 0;
//$totalAvecFrais = $count['totalAmountTtc'] ?? 0; // total global avec frais
$totalAvecFrais = (float)($count['totalAmountTtc'] ?? 0);
$deliveryTotal = (float)($count['deliveryTotal'] ?? 0);
$totalSansFrais = (float)($count['totalSansFrais'] ?? ($totalAvecFrais - $deliveryTotal));
$cogsTtc = (float)($count['cogsTtc'] ?? 0);
$profitNet = $totalSansFrais - $cogsTtc;
//$totalAvecFrais = (float)($count['totalAmountTtc'] ?? 0);
//$totalSansFrais = (float)($count['totalSansFrais'] ?? 0);
//$deliveryTotal = max(0.0, $totalAvecFrais - $totalSansFrais);
//$cogsTtc = (float)($count['cogsTtc'] ?? 0);
// Bénéfice net (optionnel) en déduisant la livraison
//$profitNet = $totalSansFrais - $cogsTtc;
$entities = $entities ?? [];
// Calculer total sans frais uniquement pour les entités chargées
/*
$totalSansFrais = 0;
foreach ($entities as $entity) {
$frais = 0;
if ($entity->getDelivery()) {
$frais = $entity->getDelivery()->getTotalPrice() ?? 0;
}
$totalSansFrais += $entity->getTotalAmountTtc() - $frais;
}
*/
$nbDocs = max(1, $count['count']); // utiliser le total global pour la moyenne
$moyenneAvecFrais = $totalAvecFrais / $nbDocs;
$moyenneSansFrais = $totalSansFrais / $nbDocs;
// ⚠ Si tu veux la moyenne sans frais sur l’ensemble des docs,
// il faut calculer sur toutes les entités, pas juste la page courante.
/*
$moyenneSansFrais = ($totalSansFrais > 0)
? $totalSansFrais / count($entities ?: [1])
: 0;
*/
$statistic = [
'total' => $count['count'],
'amountTotal' => number_format($totalAvecFrais, 3),
'amountTotalSansFrais' => number_format($totalSansFrais, 3),
'deliveryTotal' => number_format($deliveryTotal, 3),
'profitNet' => number_format($profitNet, 3),
'moyenne' => number_format($moyenneAvecFrais, 3),
'moyenneSansFrais' => number_format($moyenneSansFrais, 3),
'satatus' => $countStatut,
//'conditions' => $countCondition
];
$output = array(
'data' => array(),
'meta' => array(
'page' => $pagination['page'],
'perpage' => $limit,
"pages" => ceil($count['count'] / $limit),
"total" => $count['count'],
),
'statistic' => $statistic
);
$now = new \DateTime("now");
$after3Days=(new \DateTime("now"))->modify('+3 day');
foreach ($entities as $entity) {
$extra_info="";
if ($request->get('reference') && $entity->getType() =="echange") {
$reference = $request->get('reference');
if ($request->get('typeElement') && $request->get('typeElement') == 'produit'){
$count_ech_recieve = $entity->getDocumentDeclinationProduits()->filter(function ($prod) use ($reference) {
return $prod->getType() == "declinationEchange" && $prod->getProduitDeclinationValue()->getProduit()->getId() == $reference;
})->count();
$count_ech_send = $entity->getDocumentDeclinationProduits()->filter(function ($prod) use ($reference) {
return $prod->getType() != "declinationEchange" && $prod->getProduitDeclinationValue()->getProduit()->getId() == $reference;
})->count();
if ($count_ech_recieve > 0 && $count_ech_send > 0) {
$extra_info = "<br><small><span class='thirdlabel thirdlabel-supplier'>{$count_ech_recieve} prd <i class='flaticon-download'></i></span>
<span class='thirdlabel thirdlabel-client'>{$count_ech_send} prd <i class='flaticon-paper-plane'></i></span></small>";
} elseif ($count_ech_recieve > 0) {
$extra_info = "<br><small><span class='thirdlabel thirdlabel-supplier'>{$count_ech_recieve} prd <i class='flaticon-download'></i></span></small>";
} elseif ($count_ech_send > 0) {
$extra_info = "<br><small><span class='thirdlabel thirdlabel-client'>{$count_ech_send} prd <i class='flaticon-paper-plane'></i></span></small>";
}
}else{
$found = $entity->getDocumentDeclinationProduits()->exists(function ($key, $prod) use ($reference) {
return $prod->getType() == "declinationEchange" && $prod->getProduitDeclinationValue()->getId() == $reference;
});
$extra_info = $found ? "<br><small><span class='thirdlabel thirdlabel-supplier'>Article retourné</span></small>"
: "<br><small><span class='thirdlabel thirdlabel-client'>Article envoyé</span></small>";
}
}
$array1= [
'id' => $entity->getId(),
'status' => $entity->getStatus(),
'conditionDocument' => $entity->getConditionDocument(),
'internalNbr' => $entity->getInternalNbr().$extra_info,
'createdAt' => $entity->getCreatedAt()->format('d/m/Y H:i'),
'promisedAt' => ($entity->getPromisedAt()?
'<span class="m--font-'.(($entity->getPromisedAt()<$now && in_array($entity->getStatus(),['en-attente','accepte','expedie']) )?"danger":
(($entity->getPromisedAt()<$after3Days && in_array($entity->getStatus(),['en-attente','accepte','expedie']))?"warning":"success")).'">'.$entity->getPromisedAt()->format('d/m/Y').'</span>'
:"").($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().
'<br><i class="fa fa-chain"></i><code title="N° Suivie"><a href="'.$entity->getUrlTracking().'">'.$entity->getParcelTrackingNbr()."</a></code></small>":"")
,
'shippedAt' => $entity->getShippedAt() ? $entity->getShippedAt()->format('d/m/Y H:i') : '',
'bonrecuAt' => $entity->getBonrecuAt() ? $entity->getBonrecuAt()->format('d/m/Y H:i') : '',
'aPayerLe' => $entity->getAPayerLe() ? $entity->getAPayerLe()->format('d/m/Y H:i') : '',
'transporteur' => $entity->getDelivery() ? $entity->getDelivery()->getName() : '',
'tracking' => $entity->getParcelTrackingNbr(),
'urlTracking' => $entity->getUrlTracking(),
'totalAmountTtc' => number_format($entity->getTotalAmountTtc(), 3),
//'source' => ($entity->getSource())?$entity->getSource()->getName():"NULL",
'sourceId' => $entity->getSource() ? $entity->getSource()->getId() :"NULL",
'sourceName' => $entity->getSource() ? $entity->getSource()->getName() :"NULL",
'sourceIcon' => $entity->getSource() ? $entity->getSource()->getIcon() :"NULL",
'nbrProduits' => count($entity->getDocumentProduits())+count($entity->getDocumentDeclinationProduits()->filter(function ($prod) {
return $prod->getType() != "declinationEchange";
})),
'address' => '<small>'.$entity->getAdress() .'</small>',
'user' => '<small>'.$entity->getUser()->getFirstName() .'</small>',
'actions' => 'actions',
];
$array2= ($request->get('category') == 'client' || $request->get('client'))?[
'type' => 'client',
'phone' => $entity->getClient()->getPhone(),
'client' => $entity->getClient()->getCivility() . ' ' . $entity->getClient()->getFirstName() ,
'idClient' => $entity->getClient()->getId(),
'region' => $entity->getClient()->getRegion(),
'clientType' => $entity->getClient()->getClientType(),
]:[
'supplier' => $entity->getSupplier()->getName(),
'idSupplier' => $entity->getSupplier()->getId(),
'phone' => $entity->getSupplier()->getPhone(),
'type' => 'supplier',
'region' => $entity->getSupplier()->getRegion(),
];
$output['data'][] = array_merge($array1, $array2);
}
return new JsonResponse($output);
}
/**
* @Route("/create/{type}/{category}/{id}", name="new_document_commande", methods={"GET","POST"}, options={"expose"=true}, defaults={"type"="commande"})
*/
public function createCommande($type,$category, $id, Request $request,EntityManagerInterface $em): Response {
$rights=$this->hasRightByType( $request,$category,'DOCUMENT_CLIENT_CREATE','DOCUMENT_SUPPLIER_CREATE');
$document = new Document();
$date = new \DateTime('now');
$document->setType($type)
->setCategory($category)
->setCreatedAt(new \DateTime('now'))
//->setEndAt($date->add(new \DateInterval('P30D')))
->setUser($this->getUser())
->setStatus('en-attente')
->setConditionDocument('Creation')
->setDiscountType('amount')
->setPaymentMethod('especes')
->setTotalPaid(0);
if( $category == 'client') {
$client = $this->userRepository->find($id);
$deliverys = $this->deliveryRepository->findAllByTypes(['client','client-fournisseur']);
$document->setInternalNbr('BDC-' . date('dmY') . '-' . rand(10000, 99999))
->setClient($client);
} else {
$supplier = $this->supplierRepository->find($id);
$deliverys = $this->deliveryRepository->findAllByTypes(['fournisseur','client-fournisseur']);
if(in_array($type,['retour','reception']))$document->setStatus("brouillon");
$document->setInternalNbr((($type=="achat")?'DA-':((($type=="reception"))?"B-REC-":"BR-")) . date('dmY') . '-' . rand(10000, 99999))
->setSupplier($supplier);
}
if( $request->isMethod('POST')) {
if( $request->get('form_document')) {
$data = $request->get('form_document');
if (!empty($data['promotion_id'])) {
$promotion = $this->promotionRepository->find((int) $data['promotion_id']);
if ($promotion !== null) {
$document->setPromotion($promotion);
}
}
//check if this document has already created
if($documentChecked=$this->documentRepository->findOneBy(['internalNbr'=>$data['internalNbr']])){
$request->getSession()->getFlashBag()->add('danger', "Une réplication de création de bon de commande a été détectée !!! ");
return $this->redirectToRoute('document_show', ['id' => $documentChecked->getId()]);
}
//check if the qty of a product to return is avalaible
if($category == 'fournisseur' && $type=="retour"){
if( isset($data['content']) && $data['content']) {
foreach ($data['content'] as $item) {
$produitDecllination = $this->produitDeclinationValueRepository->find($item['id']);
$stock = $produitDecllination->getStocks()[0];
if($stock && (($stock->getQtStock() - $item['quantity'])<0)){
$request->getSession()->getFlashBag()->add('danger',
"vérifiez la quantité retournée, la Dec ".$produitDecllination->getName()." n'a pas de quantité retournée disponible !!!");
$route = $request->headers->get('referer');
return $this->redirect($route);
}
}
}
}
if( $data['discount'] == "") $data['discount'] = 0;
$source = null;
if ($category === 'client' && isset($data['source']['id']) && $data['source']['id']) {
$source = $this->sourceRepository->find($data['source']['id']);
}
$dateDelivery = (!empty($data['promisedAt'])) ? new \DateTime($data['promisedAt']) : null;
$datebonlivraison = (!empty($data['shippedAt'])) ? new \DateTime($data['shippedAt']) : null;
$datebonrecu = (!empty($data['bonrecuAt'])) ? new \DateTime($data['bonrecuAt']) : null;
$dateAPayerLe = (!empty($data['aPayerLe'])) ? new \DateTime($data['aPayerLe']) : null;
$delivery = $this->deliveryRepository->find($data['delivery']['id']);
$tvaDelivery = $this->tvaRepository->find($data['delivery']['tva']);
$document->setInternalNbr($data['internalNbr'])
->setExternalNbr(!empty($data['externalNbr']) ? $data['externalNbr'] : '')
->setSource($source)
->setObject($data['object'])
->setTotalAmountHt($data['totalAmountHt'])
->setTotalTva($data['totalTva'])
->setTotalAmountTtc($data['totalAmountTtc'])
->setAdress(!empty($data['adress']) ? $data['adress'] : null)
->setParcelTrackingNbr($data['parcelTrackingNbr'])
->setPaymentMethod($data['paymentMethod'])
->setPaymentDeadline($data['paymentDeadline'])
->setPaymentRef($data['paymentRef'])
->setDiscount($data['discount'])
->setDiscountType($data['discountType'])
->setAdvancePayment($data['advancePayment'])
->setAdvancePaymentType($data['advancePaymentType'])
->setPackagesNbr($data['packagesNbr'])
->setUrlTracking($data['urlTracking'])
->setPromisedAt($dateDelivery)
->setShippedAt($datebonlivraison)
->setBonrecuAt($datebonrecu)
->setBonrecuAt($dateAPayerLe)
->setNote($data['note'])
->setDelivery($delivery)
->setDeliveryDiscount($data['delivery']['discount'])
->setDeliveryDiscountType($data['delivery']['discount_type'])
->setDeliveryPrice($data['delivery']['price_ht'])
->setDeliveryTotal($data['delivery']['total_amount_ttc'])
->setIsFreeDelivery((isset($data['isFreedelivery']) && $data['isFreedelivery'] == "on"))
->setDeliveryTva($tvaDelivery);
if( isset($data['comment']) && $data['comment']) {
foreach ($data['comment'] as $item) {
$comment = new Comment();
$comment->setCreateAt(new \DateTime('now'))
->setDescription($item)
->setUser($this->getUser())
->setDocument($document);
$em->persist($comment);
$document->addDocumentComment($comment);
}
}
$em->persist($document);
if( isset($data['content']) && $data['content']) {
foreach ($data['content'] as $item) {
if( $item['type'] == 'produit') {
$entity = new DocumentProduit();
$entity->setType($item['type']);
if( isset($item['id']) && $item['id']) {
$produit = $this->produitRepository->find($item['id']);
$entity->setProduit($produit);
$entity->setUnite((isset($item['unit']) && $item['unit'])?$item['unit']
:$produit->getUnit());
}
} else {
$entity = new DocumentDeclinationProduit();
$entity->setType($item['type']);
if( isset($item['id']) && $item['id']) {
$produitDecllination = $this->produitDeclinationValueRepository->find($item['id']);
$entity->setProduitDeclinationValue($produitDecllination);
$stock = $produitDecllination->getStocks()[0];
if( $stock) {
if( $category == 'client') {
$stock->setQtReserved($stock->getQtReserved() + $item['quantity']);
}else{
if($type=="achat"){
//do nothing
}elseif($type=="reception"){
$stock->setQtStock($stock->getQtStock() + $item['quantity']);
}elseif($type=="retour"){
$newQty=$stock->getQtStock() - $item['quantity'];
if($newQty>=0){
$stock->setQtStock($newQty);
}
}
}
} else {
$stock = new Stock();
if( $category == 'client') {
$stock->setDeclinationProduit($produitDecllination)
->setQtReserved($item['quantity'])
->setQtStock(0)
->setStorehouse('Principal');
} else {
if($type=="achat" || $type=="retour"){
$stock->setDeclinationProduit($produitDecllination)
->setQtReserved(0)
->setQtStock(0)
->setStorehouse('Principal');
}elseif($type=="reception"){
$stock->setDeclinationProduit($produitDecllination)
->setQtReserved(0)
->setQtStock($item['quantity'])
->setStorehouse('Principal');
}
}
$em->persist($stock);
}
$entity->setUnite((isset($item['unit']) && $item['unit'])?
$item['unit']:$produitDecllination->getProduit()->getUnit());
}
}
// Calcul du total HT (avec remise éventuelle)
$priceHt = (float) ($item['price_ht'] ?? 0);
$qty = (float) ($item['quantity'] ?? 0);
$discount = (float) ($item['discount'] ?? 0);
$discountType = $item['discount_type'] ?? null;
$totalHt = $priceHt * $qty;
if ($discount > 0) {
if ($discountType === 'percent') {
$totalHt -= round($totalHt * $discount / 100, 3);
} else { // montant
$totalHt -= $discount;
}
}
$totalHt = max(0, round($totalHt, 3));
$tva =($item['tva'] != "0")? $this->tvaRepository->find($item['tva']): $this->tvaRepository->findOneBy(["number" => 0]);
$entity->setReference($item['reference'])
->setDiscount($item['discount'])
->setDiscountType($item['discount_type'])
->setPriceHt($item['price_ht'])
->setQuantity($item['quantity'])
->setCreatedAt(new \DateTime('now'))
->setTotalAmountHt($totalHt)
->setTotalAmountTtc($item['total_amount_ttc'])
->setTva($tva)
->setDocument($document);
if( isset($item['description']) && $item['description'])
$entity->setDescription($item['description']);
$em->persist($entity);
}
}
}
$message = '[' . $this->getUser()->getFullName() . '] a créé le bon de commande.';
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
$em->flush();
$request->getSession()->getFlashBag()->add('success',
(($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");
return (array_key_exists('save', $data) && $data['save']=="save")?
$this->redirectToRoute('edit_document_commande', ['type' =>$document->getType(),'document'=>$document->getId(),'category'=>$document->getCategory()]):
$this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
$tvas = $this->tvaRepository->findAll();
$sources = $this->sourceRepository->findAll();
$declinationCouleur = $this->declinationRepository->findOneBy(["name" => "Couleur"]);
//dump($document->getType()); die;
$template = ($category === 'fournisseur') ? '@admin/document/create_document_fournisseur.html.twig' : '@admin/document/create_document_client.html.twig';
return $this->render($template, [
'document' => $document,
'type' => $type,
'category' => $category,
'id' => $id,
'tvas' => $tvas,
'deliverys' => $deliverys,
'sources' => $sources,
'rights' => $rights,
'declinationCouleur' => $declinationCouleur
]);
}
/**
* @Route("/verify/client/{client}", name="verify_cond_document", methods="GET|POST", options = { "expose" = true})
*/
public function verifyConditionToCreateDocument(Request $request, $client, DocumentRepository $documentRepository, RouterInterface $router): JsonResponse
{
$statusesToCheck = ['en-attente', 'accepte'];
// Vérification 1 : statut
$documentsByStatus = $documentRepository->search( 0, 100, $statusesToCheck, null, null, $client, 'commande', 'client');
// Vérification 2 : date
$before3Days = (new \DateTime())->sub(new \DateInterval('P3D'));
$documentsByDate = $documentRepository->search( 0, 100, null, null, null,$client, 'commande', 'client', null, null, $before3Days );
//$router = $this->router;
$formatDocs = function ($docs) use ($router) {
return array_map(function ($doc) {
return [
'internalNbr' => $doc->getInternalNbr(),
'status' => $doc->getStatus(),
'createdAt' => $doc->getCreatedAt()?->format('d/m/Y'),
'link' => $this->generateUrl('document_show', ['id' => $doc->getId()])
];
}, $docs);
};
return new JsonResponse([
'statusCheck' => $formatDocs($documentsByStatus),
'dateCheck' => $formatDocs($documentsByDate),
]);
}
/**
* @Route("/accept/commande/{id}", name="accept_commande", methods={"GET","POST"}, options={"expose"=true})
*/
public function acceptCommande(Document $document,EntityManagerInterface $em,Request $request): Response {
if( $document->getStatus() == "en-attente") {
$document->setStatus("accepte");
$document->setConditionDocument($document->getConditionDocument()." -> Accepté");
}else{
$request->getSession()->getFlashBag()->add('danger', "Attention le bon de commande {$document->getInternalNbr()} a déjà été {$document->getStatus()}");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
$message = '[' . $this->getUser()->getFullName() . '] a accepté le bon de commande de Réf: ' . $document->getInternalNbr();
$this->activityService->addActivity('success', $message, $document, $this->getUser(), 'document');
$em->flush();
$request->getSession()->getFlashBag()->add('success', "Le bon de commande {$document->getInternalNbr()} a été accepté avec succès");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/validate/reception/{id}", name="accept_bon_reception", methods={"GET","POST"}, options={"expose"=true})
*/
public function acceptBonReception(Document $document,EntityManagerInterface $em,Request $request): Response {
if( $document->getStatus() == "brouillon") {
$document->setStatus("Validé");
$document->setConditionDocument($document->getConditionDocument()." -> Validé");
}else{
$request->getSession()->getFlashBag()->add('danger', "Attention le Bon de reception {$document->getInternalNbr()} a déjà été {$document->getStatus()}");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
$message = '[' . $this->getUser()->getFullName() . '] a validé le bon de réception de Réf: ' . $document->getInternalNbr();
$this->activityService->addActivity('success', $message, $document, $this->getUser(), 'document');
$em->flush();
$request->getSession()->getFlashBag()->add('success', "Le Bon de réception {$document->getInternalNbr()} a été validé avec succès");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/cancel-validation/recption/{id}", name="annul_validation_bon_reception", methods={"GET","POST"}, options={"expose"=true})
*/
public function cancelValidationOfBonReception(Document $document,EntityManagerInterface $em,Request $request): Response {
if( $document->getStatus() == "Validé") {
$document->setStatus("brouillon");
$document->setConditionDocument($document->getConditionDocument()." -> Brouillon");
$message = '[' . $this->getUser()->getFullName() . "] a annulé la validation de bon de réception de Réf: " . $document->getInternalNbr();
$this->activityService->addActivity('warning', $message, $document, $this->getUser(), 'document');
$request->getSession()->getFlashBag()->add('success', "Bon de réception devient brouillon");
} else
$request->getSession()->getFlashBag()->add('danger',
"Ce bon de réception de réf {$document->getInternalNbr()} ".($document->getStatus()=="brouillon")?
" a déjà été annulée ":" a déjà été Validé");
$em->flush();
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/cancel-acceptation/commande/{id}", name="annul_accept_commande", methods={"GET","POST"}, options={"expose"=true})
*/
public function cancelAcceptationOfCommande(Document $document,EntityManagerInterface $em,Request $request): Response {
if( ($document->getStatus() == "accepte" && !$document->getDocument())
|| ($document->getStatus() == "accepte" && $document->getType() == "echange")) {
$document->setStatus("en-attente");
$document->setConditionDocument($document->getConditionDocument()." -> En attente");
$message = '[' . $this->getUser()->getFullName() . "] a annulé l'acceptation de bon commande de Réf: " . $document->getInternalNbr();
$this->activityService->addActivity('warning', $message, $document, $this->getUser(), 'document');
$request->getSession()->getFlashBag()->add('success', "Bon commande est en attente");
} else
$request->getSession()->getFlashBag()->add('danger',
"Ce bon de commande de réf {$document->getInternalNbr()} ".($document->getStatus()=="en-attente")?
" a déjà été annulée ":" a déjà été Expédié");
$em->flush();
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/cancel-pending-shipment/commande/{id}", name="cancel_pending_shipment_commande", methods={"GET","POST"}, options={"expose"=true})
*/
public function cancelPendingShipmentOfCommande(Document $document, EntityManagerInterface $em, Request $request): Response
{
if ($document->getStatus() == "a-expedier") {
$document->setStatus("accepte");
$document->setConditionDocument($document->getConditionDocument()." -> Accepté");
$message ='[' . $this->getUser()->getFullName() . "] a remis le bon de commande de Réf: " . $document->getInternalNbr() . " au statut 'accepté'.";
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
$request->getSession()->getFlashBag()->add('success', "bon de commande remis au statut accepté.");
} else {
$request->getSession()->getFlashBag()->add('danger',
"Ce bon de commande ne peut pas être remis au statut accepté.");
}
$em->flush();
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/admin/document/{category}/{id}/pending-shipment/{idCommande}", name="pending_shipment_commande")
*/
public function pendingShipmentCommande($category, $id, $idCommande, Request $request, EntityManagerInterface $em): Response
{
$document = $this->documentRepository->find($idCommande);
if ($document && $document->getStatus() === "accepte") {
$this->hasRightByType($request, $category, 'DOCUMENT_CLIENT_CREATE', 'DOCUMENT_SUPPLIER_CREATE');
$auto = $request->get('auto_document') ?? [];
$suivi = $auto['parcelTrackingNbr'] ?? null;
$delivery_id = $auto['delivery_id'] ?? null;
$urlTracking = $auto['urlTracking'] ?? null;
$packagesNbr = $auto['packagesNbr'] ?? null;
$delivery = $delivery_id ? $this->deliveryRepository->find($delivery_id) : null;
$document->setParcelTrackingNbr($suivi)
->setUrlTracking($urlTracking)
->setPackagesNbr($packagesNbr);
if ($delivery) {
$companyTotal = (float) ($delivery->getTotalPrice() ?? 0);
$document->setDeliveryCompanyTotal(number_format($companyTotal, 3, '.', ''));
$document->setDelivery($delivery)
->setDeliveryDiscount($document->getDeliveryDiscount())
->setDeliveryDiscountType($document->getDeliveryDiscountType())
->setDeliveryPrice($document->getDeliveryPrice())
->setDeliveryTva($document->getDeliveryTva())
->setIsFreeDelivery($document->getIsFreeDelivery());
$tva = $document->getDeliveryTva() ? (float)$document->getDeliveryTva()->getNumber() : 0.0;
$price = (float)$document->getDeliveryPrice();
$disc = (float)$document->getDeliveryDiscount();
$isPct = $document->getDeliveryDiscountType() === 'percent';
$priceAfterDisc = $isPct ? ($price - ($price * $disc / 100)) : ($price - $disc);
$totalClientTtc = $priceAfterDisc + ($price * $tva / 100);
if ($document->getIsFreeDelivery()) {
$totalClientTtc = 0.0;
}
$document->setDeliveryTotal(number_format($totalClientTtc, 3, '.', ''));
}
// Ici, on ne met pas "expedie", mais "a-expedier"
$document->setStatus("a-expedier")
->setConditionDocument($document->getConditionDocument() . " -> En attente d'expédition");
$message ='[' . $this->getUser()->getFullName() . "] a mis le bon de commande en attente d'expédition.";
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
$em->persist($document);
$em->flush();
$request->getSession()->getFlashBag()->add(
'success',
(($document->getCategory() == 'client') ? "Le bon de commande" : "Le bon réception") .
" de réf {$document->getInternalNbr()} est désormais en attente d'expédition."
);
} else {
$request->getSession()->getFlashBag()->add(
'danger',
"Ce bon de commande de réf {$document->getInternalNbr()} doit être accepté avant de passer en attente d'expédition."
);
}
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* expedier BC avec la saisie des details de livraison
* @Route("/shipment/commande/{category}/{id}/{idCommande}", name="auto_document", methods={"GET","POST"}, options={"expose"=true})
*/
public function shipCommande($category, $id, $idCommande, Request $request, EntityManagerInterface $em): Response
{
$document = $this->documentRepository->find($idCommande);
// corrige la condition (parenthèses)
if ($document && (
$document->getStatus() === "accepte" ||
$document->getStatus() === "a-expedier" ||
($document->getStatus() === "brouillon" && $document->getType() === 'retour')
)) {
$this->hasRightByType($request, $category, 'DOCUMENT_CLIENT_CREATE', 'DOCUMENT_SUPPLIER_CREATE');
$auto = $request->get('auto_document') ?? [];
$suivi = $auto['parcelTrackingNbr'] ?? null;
$delivery_id = $auto['delivery_id'] ?? null;
$urlTracking = $auto['urlTracking'] ?? null;
$packagesNbr = $auto['packagesNbr'] ?? null;
$delivery = $delivery_id ? $this->deliveryRepository->find($delivery_id) : null;
$document->setShippedAt(new \DateTime('now'))
->setParcelTrackingNbr($suivi)
->setUrlTracking($urlTracking)
->setPackagesNbr($packagesNbr);
if ($delivery) {
// total transporteur TTC (coût réel société de livraison)
$companyTotal = (float) ($delivery->getTotalPrice() ?? 0); // delivery.total_price
$document->setDeliveryCompanyTotal(number_format($companyTotal, 3, '.', ''));
// total client TTC (ton calcul existant)
$document->setDelivery($delivery)
->setDeliveryDiscount($document->getDeliveryDiscount())
->setDeliveryDiscountType($document->getDeliveryDiscountType())
->setDeliveryPrice($document->getDeliveryPrice())
->setDeliveryTva($document->getDeliveryTva())
->setIsFreeDelivery($document->getIsFreeDelivery());
$tva = $document->getDeliveryTva() ? (float)$document->getDeliveryTva()->getNumber() : 0.0;
$price = (float)$document->getDeliveryPrice();
$disc = (float)$document->getDeliveryDiscount();
$isPct = $document->getDeliveryDiscountType() === 'percent';
$priceAfterDisc = $isPct ? ($price - ($price * $disc / 100)) : ($price - $disc);
$totalClientTtc = $priceAfterDisc + ($price * $tva / 100);
// si livraison gratuite côté client
if ($document->getIsFreeDelivery()) {
$totalClientTtc = 0.0;
}
$document->setDeliveryTotal(number_format($totalClientTtc, 3, '.', ''));
}
if ($category === "client") {
$document->setStatus("expedie")
->setConditionDocument($document->getConditionDocument() . " -> Expédié")
->setExternalNbr('BDL-' . date('dmY') . '-' . rand(10000, 99999));
} else {
$document->setStatus("expedie")
->setConditionDocument($document->getConditionDocument() . " -> Expédié")
->setInternalNbr('F_BR-' . date('dmY') . '-' . rand(10000, 99999));
}
if ($document->getCategory() === 'client') {
foreach ($document->getDocumentDeclinationProduits() as $dp) {
if ($dp->getType() !== 'declinationEchange') {
$stock = $dp->getProduitDeclinationValue()->getStocks()[0] ?? null;
if ($stock) {
if ($stock->getQtReserved() > 0) {
$stock->setQtReserved($stock->getQtReserved() - $dp->getQuantity());
}
$stock->setQtStock($stock->getQtStock() - $dp->getQuantity());
}
}
}
}
$message ='[' . $this->getUser()->getFullName() . "] a expédié le bon de commande.";
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
$em->persist($document);
$em->flush();
$request->getSession()->getFlashBag()->add(
'success',
(($document->getCategory() == 'client') ? "Le bon de commande" : "Le bon reception") .
" de réf {$document->getInternalNbr()} a été expédié avec succès"
);
} else {
$request->getSession()->getFlashBag()->add(
'danger',
"Ce bon de commande de réf {$document->getInternalNbr()} " .
(($document->getStatus() == "expedie") ? " a déjà été expédié " : " doit être accepté avant")
);
}
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/admin/document/{id}/payment-state/{state}", name="document_payment_state", methods={"GET","POST"}, options={"expose"=true})
*/
public function setPaymentState(Document $document, string $state, Request $request, PaymentUpdaterService $payment,EntityManagerInterface $em ): Response
{
$amount = $request->request->get('amount');
$amount = ($amount !== null && $amount !== '') ? (float)$amount : null;
$payment->setPaymentStatus($document, $state, $amount);
// ====== Historique + Flash comme les autres ======
$statusLabel = [
'paye' => 'Payé',
'partiellement-paye' => 'Partiellement payé',
'non-paye' => 'Non payé'
];
$message = '[' . $this->getUser()->getFullName() . '] a marqué le bon de commande comme ' . $statusLabel;
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
$request->getSession()->getFlashBag()->add('success', "Le statut de paiement du bon de commande de réf " . $document->getInternalNbr() . " a été mis à jour : " . $state . '.');
$em->flush();
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/admin/document/{id}/mark-paid", name="document_mark_paid", methods={"GET","POST"}, options={"expose"=true})
*/
public function markPaid(Document $document, Request $request, PaymentUpdaterService $payment,EntityManagerInterface $em): Response{
$amount = $request->request->get('amount'); // si null => payé à 100%
$datePaid = $request->request->get('date_paid');
$date = $datePaid ? \DateTime::createFromFormat('Y-m-d', $datePaid) : null;
/*
if ($datePaid) {
$date = \DateTime::createFromFormat('Y-m-d', $datePaid);
$document->setPaidAt($date);
} else {
$document->setPaidAt(new \DateTime()); // fallback : aujourd'hui
}
dump($datePaid, $date); die;
*/
$payment->setPaymentStatus($document, 'paye', $amount !== null ? (float)$amount : null, $date);
// flush ici ou dans le PaymentUpdaterService selon organisation
$this->getDoctrine()->getManager()->flush();
// ====== Historique + Flash comme les autres ======
$message = '[' . $this->getUser()->getFullName() . '] a marqué le bon de commande comme payé';
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
$request->getSession()->getFlashBag()->add('success', "Le statut de paiement du bon de commande de réf " . $document->getInternalNbr() . " a été mis à jour : Payé" . '.');
$em->flush();
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/admin/document/{id}/refund/{mode}", name="document_refund", methods={"GET","POST"}, options={"expose"=true})
*/
public function refund(
Document $doc,
string $mode,
Request $request,
PaymentUpdaterService $payment,
EntityManagerInterface $em,
RefundReasonRepository $refundReasonRepository
): Response
{
$mode = strtolower($mode);
// Modes : pending (marque à rembourser), finalize (finalise/remet le stock)
if (!in_array($mode, ['partial','full','pending','finalize'], true)) {
$this->addFlash('danger', "Mode de remboursement invalide.");
return $this->redirectToRoute('document_show', ['id' => $doc->getId()]);
}
if ($doc->getStatus() !== 'paye' && $doc->getStatus() !== 'a-rembourser') {
$this->addFlash('danger', "Seules les commandes payées ou à rembourser peuvent être traitées.");
return $this->redirectToRoute('document_show', ['id' => $doc->getId()]);
}
if ($mode === 'pending') {
// Marquer comme à rembourser (pas de remise en stock, pas de statut 'rembourse')
$refundReasonId = $request->request->get('refund_reason_id');
$refundReason = $refundReasonId ? $refundReasonRepository->find($refundReasonId) : null;
$refundNote = $request->request->get('refund_reason_note', '');
$doc->setStatus('a-rembourser');
$doc->setConditionDocument($doc->getConditionDocument()." -> À rembourser");
$doc->setRefundReason($refundReason);
$doc->setNote($refundNote);
$msg = '[' . $this->getUser()->getFullName() . "] a marqué le bon de commande de Réf: " . $doc->getInternalNbr() . " comme à rembourser.";
$this->activityService->addActivity('info', $msg, $doc, $this->getUser(), 'document');
$em->flush();
$this->addFlash('info', "Le bon de commande {$doc->getInternalNbr()} est maintenant en attente de remboursement.");
}
elseif ($mode === 'finalize') {
// Finalise le remboursement et remet le stock (stock remis, statut 'rembourse')
if ($doc->getCategory() == 'client') {
foreach ($doc->getDocumentDeclinationProduits() as $documentDeclination) {
if ($documentDeclination->getType() != 'declinationEchange') {
$stock = $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
if ($stock) {
$stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
}
}
}
}
$doc->setStatus('rembourse');
$doc->setConditionDocument($doc->getConditionDocument()." -> Remboursé");
$msg = '[' . $this->getUser()->getFullName() . "] a finalisé le remboursement du bon de commande de Réf: " . $doc->getInternalNbr() . " (retour stock).";
$this->activityService->addActivity('success', $msg, $doc, $this->getUser(), 'document');
$em->flush();
$this->addFlash('success', "Le bon de commande {$doc->getInternalNbr()} a été remboursé et les articles remis en stock.");
}
// ... (le reste de ta gestion, partial/full…)
return $this->redirectToRoute('document_show', ['id' => $doc->getId()]);
}
/**
* Bouton "Créer une facture" (pas de nouveaux champs — on utilise internal_nbr/created_at côté PDF).
* @Route("/admin/document/{id}/create-invoice", name="document_create_invoice", methods={"GET","POST"}, options={"expose"=true})
*/
public function createInvoice(Document $doc, EntityManagerInterface $em)
{
// Ici, pas d’écriture DB (tu as choisi d’utiliser internal_nbr + created_at).
// Tu peux lancer une génération PDF/HTML selon ton système existant.
// Exemple : return $this->redirectToRoute('document_invoice_pdf', ['id' => $doc->getId()]);
return $this->redirectToRoute('document_show', ['id' => $doc->getId()]);
}
/**
* @Route("/cancel-shipment/commande/{id}", name="annul_expedition_commande", methods={"GET","POST"}, options={"expose"=true})
*/
/*-- Annuler l'expidition --*/
public function cancelShipmentOfCommande(Document $document,EntityManagerInterface $em,Request $request): Response {
/*Si l'utilsiateur n'a pas le droit d'accès*/
if (!$this->isGranted('ROLE_SUPER_ADMIN')) {
$this->addFlash('danger', 'Vous n’avez pas le droit d’effectuer cette action.');
// Revenir à la page d’origine (ex. : page détail du document)
return $this->redirectToRoute('document_show', [
'id' => $document->getId(),
]);
}
if( ($document->getStatus() == "expedie" && !$document->getDocument())|| ($document->getStatus() == "expedie" && $document->getType() == "echange")) {
$document->setStatus("a-expedier")
->setConditionDocument($document->getConditionDocument()." -> A Expedier");
foreach ($document->getDocumentDeclinationProduits() as $documentDeclination) {
if( $documentDeclination->getType() != 'declinationEchange') {
$stock = $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
if( $stock) {
if( $document->getCategory() == 'client') {
$stock->setQtReserved($stock->getQtReserved() + $documentDeclination->getQuantity());
$stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
} else {
$stock->setQtStock($stock->getQtStock() - $documentDeclination->getQuantity());
}
}
}
}
$message = '[' . $this->getUser()->getFullName() . "] a annulé l'expédition du bon de commande.";
$this->activityService->addActivity('warning', $message, $document, $this->getUser(), 'document');
$request->getSession()->getFlashBag()->add('success', "Bon commande est en attente");
} else
$request->getSession()->getFlashBag()->add('danger',
"Ce bon de commande de réf {$document->getInternalNbr()} ".($document->getStatus()=="a-expedier")?
" a déjà été annulée l'expédition ":" a déjà été Livré");
$em->flush();
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/return-shipment/commande/{id}", name="return_expedition_commande", methods={"GET","POST"}, options={"expose"=true})
*/
public function returnAfterShipmentOfCommande(Document $document,EntityManagerInterface $em,Request $request): Response {
if( ($document->getStatus() == "retour-en-cours" && !$document->getDocument())|| ($document->getStatus() == "retour-en-cours" && $document->getType() == "echange")) {
$document->setStatus("retourne")
->setConditionDocument($document->getConditionDocument()." -> Retourné");
$document->setReturnedAt(new \DateTime());
foreach ($document->getDocumentDeclinationProduits() as $documentDeclination) {
if( $documentDeclination->getType() != 'declinationEchange') {
$stock = $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
if( $stock) {
if( $document->getCategory() == 'client') {
$stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
} else {
$stock->setQtStock($stock->getQtStock() - $documentDeclination->getQuantity());
}
}
}
}
$message ='[' . $this->getUser()->getFullName() . '] a retourné le bon de commande.';
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
$request->getSession()->getFlashBag()->add('success', "La Commande de réf ".$document->getInternalNbr()." a été retourné");
} else
$request->getSession()->getFlashBag()->add('danger',
"Ce bon de commande de réf {$document->getInternalNbr()} ".($document->getStatus()=="accepte")?
" a déjà été annulée l'expédition ":(($document->getStatus()=="retourne")?" a déjà été retourné":" a été Livré !!!"));
$em->flush();
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/success-shipment/commande/{id}", name="success_expedition_commande", methods={"GET","POST"}, options={"expose"=true})
*/
public function shipmentSuccessOfCommande(Document $document,EntityManagerInterface $em,Request $request): Response {
if( ($document->getStatus() == "expedie" && !$document->getDocument())|| ($document->getStatus() == "expedie" && $document->getType() == "echange")) {
$dateStr = $request->request->get('delivered_at');
if ($dateStr) {
$date = \DateTime::createFromFormat('Y-m-d', $dateStr);
if ($date !== false) {
$document->setDeliveredAt($date);
}
}
$document->setStatus("livre")
->setConditionDocument($document->getConditionDocument()." -> Livré");
$message ='[' . $this->getUser()->getFullName() . '] a livré le bon de commande.';
$this->activityService->addActivity('success', $message, $document, $this->getUser(), 'document');
$request->getSession()->getFlashBag()->add('success', "Bon commande est en attente");
} else
$request->getSession()->getFlashBag()->add('danger',
"Ce bon de commande de réf {$document->getInternalNbr()} ".($document->getStatus()=="accepte")?
" a déjà été annulée l'expédition ":(($document->getStatus()=="retourne")?" a déjà été retourné":" a déjà été Livré !!"));
$em->flush();
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/invoice/commande/{id}", name="create_facture_document", methods={"GET","POST"}, options={"expose"=true})
*/
public function createFactureCommande(Document $document, Request $request,EntityManagerInterface $em): Response {
// 1. Vérifier s'il existe déjà une facture liée à ce bon de commande
$factureExistante = null;
foreach ($document->getDocuments() as $docFils) {
if ($docFils->getType() === 'facture') {
$factureExistante = $docFils;
break;
}
}
if ($factureExistante) {
$this->addFlash('danger',
"Ce bon de commande de réf {$document->getInternalNbr()} a déjà été facturé (Facture n° {$factureExistante->getInternalNbr()}).");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
// 2. Conditions classiques :
if( (in_array($document->getStatus(), ['livre', 'partiellement-paye', 'paye']) && $document->getType() === 'commande') || ($document->getStatus() == "Validé" && $document->getType() === 'reception')) {
$newDocument = new Document();
$date = new \DateTime('now');
$type = 'facture';
$newDocument = $this->createCopyDocument($newDocument, $document);
$newDocument->setDocument($document);
$newDocument->setType($type);
$newDocument->setCategory($document->getCategory());
$newDocument->setCreatedAt(new \DateTime('now'));
//$newDocument->setEndAt($date->add(new \DateInterval('P30D')));
$newDocument->setUser($this->getUser());
$newDocument->setStatus("facture");
$newDocument->setConditionDocument("Facturé");
/*
foreach ($document->getDocumentComments() as $item) {
$comment = new Comment();
$comment->setCreateAt(new \DateTime('now'));
$comment->setDescription($item->getDescription())
->setUser($item->getUser());
$em->persist($comment);
$newDocument->addDocumentComment($comment);
}
*/
$em->persist($newDocument);
if( $document->getCategory() == "client") {
$newDocument->setInternalNbr('FAC-' . date('dmY') . '-' . rand(10000, 99999));
$client = $document->getClient();
$newDocument->setClient($client);
} else {
$newDocument->setInternalNbr('F_FAC-' . date('dmY') . '-' . rand(10000, 99999));
$supplier = $document->getSupplier();
$newDocument->setSupplier($supplier);
}
foreach ($document->getDocumentDeclinationProduits() as $documentDeclinationProduit) {
$new = new DocumentDeclinationProduit();
$copy = $this->createCopyDocumentProduit($new, $documentDeclinationProduit);
$copy->setProduitDeclinationValue($documentDeclinationProduit->getProduitDeclinationValue());
$newDocument->addDocumentDeclinationProduit($copy);
$em->persist($copy);
}
foreach ($document->getDocumentProduits() as $documentProduit) {
$new = new DocumentProduit();
$copy = $this->createCopyDocumentProduit($new, $documentProduit);
$copy->setProduit($documentProduit->getProduit());
$newDocument->addDocumentProduit($copy);
$em->persist($copy);
}
//$document->setStatus("paye");
$document->setConditionDocument($document->getConditionDocument()." -> Facturé");
$message = '[' . $this->getUser()->getFullName() . '] a facturé le bon de commande.';
$this->activityService->addActivity('success', $message, $document, $this->getUser(), 'document');
$em->flush();
if( $newDocument->getCategory() == 'client')
$request->getSession()->getFlashBag()->add('success', "bon de commande de réf {$document->getInternalNbr()} a été facturé avec succès");
else
$request->getSession()->getFlashBag()->add('success', "Bon reception de réf {$document->getInternalNbr()} a été facturé avec succès");
return $this->redirectToRoute('document_show', ['id' => $newDocument->getId()]);
} else
$request->getSession()->getFlashBag()->add('danger',
"Ce bon de commande de réf {$document->getInternalNbr()} doit être payé pour que la facture puisse être crée !!!");
}
/**
* @Route("/admin/avoir/{id}", name="create_avoir_document", methods={"POST"}, options={"expose"=true})
*/
public function createAvoirFacture(Document $document, Request $request, EntityManagerInterface $em, RefundReasonRepository $refundReasonRepository ): Response
{
// 1. Vérifier s'il existe déjà un avoir lié à cette facture
$avoirExistante = null;
foreach ($document->getDocuments() as $docFils) {
if ($docFils->getType() === 'avoir') {
$avoirExistante = $docFils;
break;
}
}
if ($avoirExistante) {
$this->addFlash('danger',
"Cette facture de réf {$document->getInternalNbr()} a déjà été remboursée (Avoir n° {$avoirExistante->getInternalNbr()}).");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
// 2. Conditions classiques
if ($document->getType() !== 'facture' || $document->getStatus() !== 'facture') {
$this->addFlash('danger', "Seules les factures non remboursées peuvent donner lieu à un avoir.");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
// 3. Récupérer le motif et la note
$formData = $request->get('avoir_document');
$refundReason = null;
if (!empty($formData['reason_id'])) {
$refundReason = $refundReasonRepository->find($formData['reason_id']);
}
$note = $formData['note'] ?? null;
// 4. Création du document d’avoir
$avoir = new Document();
$avoir = $this->createCopyDocument($avoir, $document);
$avoir->setType('avoir');
$avoir->setStatus('rembourse');
$avoir->setCreatedAt(new \DateTime());
$avoir->setUser($this->getUser());
$avoir->setConditionDocument("Avoir sur facture {$document->getInternalNbr()}");
$avoir->setDocument($document);
$avoir->setInternalNbr('AVOIR-' . date('dmY') . '-' . rand(10000, 99999));
if ($document->getCategory() == "client") {
$avoir->setClient($document->getClient());
} else {
$avoir->setSupplier($document->getSupplier());
}
if ($refundReason) {
$avoir->setRefundReason($refundReason);
}
if ($note) {
$avoir->setNote($note);
}
// *** Copier les lignes produits ***
foreach ($document->getDocumentDeclinationProduits() as $documentDeclinationProduit) {
$new = new DocumentDeclinationProduit();
$copy = $this->createCopyDocumentProduit($new, $documentDeclinationProduit);
$copy->setProduitDeclinationValue($documentDeclinationProduit->getProduitDeclinationValue());
$avoir->addDocumentDeclinationProduit($copy);
$em->persist($copy);
}
foreach ($document->getDocumentProduits() as $documentProduit) {
$new = new DocumentProduit();
$copy = $this->createCopyDocumentProduit($new, $documentProduit);
$copy->setProduit($documentProduit->getProduit());
$avoir->addDocumentProduit($copy);
$em->persist($copy);
}
$em->persist($avoir);
// Mettre à jour la facture mère
$document->setStatus('rembourse');
$document->setConditionDocument($document->getConditionDocument() . " -> Remboursé via l'avoir " . $avoir->getInternalNbr());
$em->persist($document);
// Historique
$msg = '[' . $this->getUser()->getFullName() . "] a généré un avoir (remboursement) pour la facture de Réf: " . $document->getInternalNbr();
$this->activityService->addActivity('info', $msg, $document, $this->getUser(), 'document');
$em->flush();
$this->addFlash('success', "Avoir {$avoir->getInternalNbr()} généré avec succès pour la facture de réf {$document->getInternalNbr()}.");
return $this->redirectToRoute('document_show', ['id' => $avoir->getId()]);
}
/**
* @Route("/retour/{id}", name="retour_document", methods={"GET","POST"}, options={"expose"=true})
*/
public function retourDocument(Document $document, Request $request, EntityManagerInterface $em): Response
{
if ($document->getType() !== 'commande' || !in_array($document->getStatus(), ['expedie', 'livre'])) {
$this->addFlash('danger', "Seuls les bons de commande expédiés ou livrés peuvent faire l'objet d'un retour de colis.");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
$note = $request->get('retour_document')['note'] ?? null;
if ($note) {
$document->setNote($note);
}
$document->setStatus("retour-en-cours");
$document->setConditionDocument($document->getConditionDocument() . " -> Retour en cours");
$em->persist($document);
$message = '[' . $this->getUser()->getFullName() . '] a initié un retour de colis sur le bon de commande.';
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
$em->flush();
$this->addFlash('success', "Retour de colis lancé pour la commande de réf {$document->getInternalNbr()}.");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/*
public function retourDocument(Document $document, Request $request,EntityManagerInterface $em): Response {
if( ($document->getStatus() == "expedie" && !$document->getDocument()) || $document->getType() === 'facture' && $document->getStatus() == "paye" || ($document->getStatus() == "expedie" && $document->getType() == "echange")) {
$note = $request->get('retour_document')['note'];
$document->setStatus("retour-en-cours");
$document->setConditionDocument($document->getConditionDocument() . " -> Retour en cours");
$document->setNote($note);
if( $document->getType() === 'facture') {
$document->getDocument()->setConditionDocument($document->getDocument()->getConditionDocument() . " -> Retour en cours");
$document->getDocument()->setNote($note);
}
$message = '[' . $this->getUser()->getFullName() . '] a retourné le bon de commande.';
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
$em->flush();
$request->getSession()->getFlashBag()->add('success', "Facture de réf {$document->getInternalNbr()} est en cours de remboursement avec succès");
}else{
if( $document->getType() === 'facture' && $document->getStatus() == "retour-en-cours" )
$request->getSession()->getFlashBag()->add('danger',
"Cette facture de réf {$document->getInternalNbr()} est en cours de remboursement !!!");
else {
$request->getSession()->getFlashBag()->add('danger',
"Ce bon de commande de réf {$document->getInternalNbr()} " .( ($document->getStatus() == "retour-en-cours") ?
" a déjà en cours de retour " : (($document->getStatus() == "retourne") ? " a déjà été retourné" : " a été annulé l'expédition !!!")));
}
}
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
*/
/**
* @Route("/retour/final/document/{id}", name="retour_final_document", methods={"GET","POST"}, options={"expose"=true})
*/
public function retourFinalDocument(Document $document, Request $request,EntityManagerInterface $em): Response {
if( $document->getType() === 'facture' && $document->getStatus() == "retour-en-cours"){
$document->setStatus("rembourse");
$document->setConditionDocument($document->getConditionDocument()." -> Remboursé");
$document->getDocument()->setConditionDocument($document->getDocument()->getConditionDocument()." -> Remboursé");
//todo: change the stock for a document product also.
foreach ($document->getDocument()->getDocumentDeclinationProduits() as $documentDeclination) {
$stock = $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
if( $stock) {
if( $document->getCategory() == 'client') {
$stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
} else {
$stock->setQtStock($stock->getQtStock() - $documentDeclination->getQuantity());
}
}
}
$message = '[' . $this->getUser()->getFullName() . '] a validé le retour du bon de commande de la facture.';
$this->activityService->addActivity('success', $message, $document, $this->getUser(), 'document');
$em->flush();
$request->getSession()->getFlashBag()->add('success', "Facture de réf {$document->getInternalNbr()} est en cours de remboursement avec succès");
}else
$request->getSession()->getFlashBag()->add('danger',
($document->getStatus() == "rembourse")? "Cette Facture de réf {$document->getInternalNbr()} a dejà été remboursé!!!":" Une erreur a été rencontrée, contactez l'administrateur ");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("updateRaison/commande/{id}", name="update_raison", methods={"GET","POST"}, options={"expose"=true})
*/
public function updateRaisonCommande(Document $document, Request $request,EntityManagerInterface $em): Response {
if( in_array($document->getStatus(),["annule",'retour-en-cours','retourne'])) {
$note = $request->get('raison_document')['note'];
$document->setNote($note);
$em->flush();
$request->getSession()->getFlashBag()->add('success', "La raison de ce bon de commande a été modifiée avec succès");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
$request->getSession()->getFlashBag()->add('danger',"le bon de commande doit être en état de retour ou annulé pour faire changer son motif( raison)");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/annulled/commande/{id}", name="annulled_commande", methods={"GET","POST"}, options={"expose"=true})
*/
public function annulledCommande(Document $document, Request $request, EntityManagerInterface $em): Response
{
$note = $request->get('annuled_document')['note'] ?? null;
$reasonId = $request->get('annuled_document')['cancelReason'] ?? null;
$reason = $reasonId ? $em->getRepository(CancelReason::class)->find($reasonId) : null;
if ($document->getStatus() == "en-attente") {
$document->setStatus("annule")
->setConditionDocument($document->getConditionDocument() . " -> Annulé")
->setNote($note)
->setCancelReason($reason);
if ($document->getType() != 'echange' && $document->getDocument()) {
$document->getDocument()->setStatus("annule");
$document->getDocument()->setConditionDocument($document->getConditionDocument() . " -> Annulé");
$document->getDocument()->setNote($note);
$document->getDocument()->setCancelReason($reason);
}
foreach ($document->getDocumentDeclinationProduits() as $documentDeclination) {
if ($documentDeclination->getType() != 'declinationEchange') {
$stock = $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
if ($stock && $document->getCategory() == 'client') {
if ($stock->getQtReserved() > 0) {
$stock->setQtReserved($stock->getQtReserved() - $documentDeclination->getQuantity());
}
}
} else {
$stock = $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
if ($stock && $document->getCategory() == 'client') {
if ($stock->getQtReserved() > 0) {
$stock->setQtReserved($stock->getQtReserved() - $documentDeclination->getQuantity());
}
}
if ($document->getType() != 'echange' && $document->getDocument()) {
if ($document->getDocument()->getDocument()) {
$document->getDocument()->getDocument()->setStatus("annule");
$document->getDocument()->getDocument()->setConditionDocument("Annulé");
$document->getDocument()->getDocument()->setNote($note);
$document->getDocument()->getDocument()->setCancelReason($reason);
}
}
}
}
} else if (in_array($document->getStatus(), ["expedie", "brouillon"])) {
$document->setStatus("annule")
->setConditionDocument($document->getConditionDocument() . " -> Annulé")
->setNote($note)
->setCancelReason($reason);
foreach ($document->getDocumentProduits() as $documentProduit) {
$stockPrd = $documentProduit->getProduit()->getStocks()[0];
if ($stockPrd) {
if ($document->getCategory() == 'client') {
$stockPrd->setQtStock($stockPrd->getQtStock() + $documentProduit->getQuantity());
} else {
if ($document->getType() == 'reception') {
$stockPrd->setQtStock($stockPrd->getQtStock() - $documentProduit->getQuantity());
} elseif ($document->getType() == 'retour') {
$stockPrd->setQtStock($stockPrd->getQtStock() + $documentProduit->getQuantity());
}
}
}
}
foreach ($document->getDocumentDeclinationProduits() as $documentDeclination) {
if ($documentDeclination->getType() != 'declinationEchange') {
$stock = $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
if ($stock) {
if ($document->getCategory() == 'client') {
$stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
} else {
if ($document->getType() == "reception") {
$stock->setQtStock($stock->getQtStock() - $documentDeclination->getQuantity());
} elseif ($document->getType() == 'retour') {
$stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
}
}
}
}
}
}
$message ='[' . $this->getUser()->getFullName() . '] a annulé le bon de commande.';
$this->activityService->addActivity('warning', $message, $document, $this->getUser(), 'document');
$em->flush();
$request->getSession()->getFlashBag()->add('success', "Le bon de commande a été annulé avec succès");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/*
public function annulledCommande(Document $document, Request $request,EntityManagerInterface $em): Response {
//todo : add a condition when the document is already canceled (annuled) and verify if impacted the stock or not
if( $document->getStatus() == "en-attente") {
$note = $request->get('annuled_document')['note'];
$document->setStatus("annule")
->setConditionDocument($document->getConditionDocument()." -> Annulé")
->setNote($note);
if( $document->getType() != 'echange' && $document->getDocument()) {
$document->getDocument()->setStatus("annule");
$document->getDocument()->setConditionDocument($document->getConditionDocument()." -> Annulé");
$document->getDocument()->setNote($note);
}
//todo: verify the producte also
foreach ($document->getDocumentDeclinationProduits() as $documentDeclination) {
if( $documentDeclination->getType() != 'declinationEchange') {
$stock = $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
if( $stock) {
if( $document->getCategory() == 'client') {
if( $stock->getQtReserved() > 0) {
$stock->setQtReserved($stock->getQtReserved() - $documentDeclination->getQuantity());
}
}
}
} else {
$stock = $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
if( $stock) {
if( $document->getCategory() == 'client') {
if( $stock->getQtReserved() > 0) {
$stock->setQtReserved($stock->getQtReserved() - $documentDeclination->getQuantity());
}
}
}
if( $document->getType() != 'echange' && $document->getDocument()) {
if( $document->getDocument()->getDocument()) {
$document->getDocument()->getDocument()->setStatus("annule");
$document->getDocument()->getDocument()->setConditionDocument("Annulé");
$document->getDocument()->getDocument()->setNote($note);
}
}
}
}
} else if( in_array( $document->getStatus(),["expedie","brouillon"])) {
$note = $request->get('annuled_document')['note'];
$document->setStatus("annule")
->setConditionDocument($document->getConditionDocument()." -> Annulé")
->setNote($note);
foreach ($document->getDocumentProduits() as $documentProduit) {
$stockPrd = $documentProduit->getProduit()->getStocks()[0];
if( $stockPrd) {
if($document->getCategory() == 'client') {
$stockPrd->setQtStock($stockPrd->getQtStock()+$documentProduit->getQuantity());
}else{
if($document->getType() == 'reception'){
$newQte =$stockPrd->getQtStock() - $documentProduit->getQuantity();
$stockPrd->setQtStock($newQte);
}elseif($document->getType() == 'retour'){
$newQte =$stockPrd->getQtStock() + $documentProduit->getQuantity();
$stockPrd->setQtStock($newQte);
}
}
}
}
foreach ($document->getDocumentDeclinationProduits() as $documentDeclination) {
if( $documentDeclination->getType() != 'declinationEchange') {
$stock = $documentDeclination->getProduitDeclinationValue()->getStocks()[0];
if( $stock)
if( $document->getCategory() == 'client') {
$stock->setQtStock($stock->getQtStock() + $documentDeclination->getQuantity());
}else{
if( $document->getType() == "reception") {
$newQte = $stock->getQtStock() - $documentDeclination->getQuantity();
$stock->setQtStock($newQte);
} elseif( $document->getType() == 'retour') {
$newQte = $stock->getQtStock() + $documentDeclination->getQuantity();
$stock->setQtStock($newQte);
}
}
}
}
}
$message = '[' . $this->getUser()->getFullName() . '] annuler le bon de commande ' . $document->getInternalNbr();
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
$em->flush();
$request->getSession()->getFlashBag()->add('success', "Le bon de commande a été annulé avec succès");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
*/
/**
* @Route("/edit/{type}/{document}/{category}", name="edit_document_commande", methods={"GET","POST"}, options={"expose"=true},defaults={"type"="commande"})
*/
public function editCommande(Document $document,$type,$category, Request $request,EntityManagerInterface $em): Response {
$rights =$this->hasRightByType( $request,$category,'DOCUMENT_CLIENT_UPDATE','DOCUMENT_SUPPLIER_UPDATE');
if( in_array($document->getStatus(),["en-attente","brouillon"]) ) {
if( $request->isMethod('POST')) {
$message = '[' . $this->getUser()->getFullName() . "] a mis à jour le bon de commande ($type) " . $document->getInternalNbr();
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
foreach ($document->getDocumentDeclinationProduits() as $docDec) {
$prodDecVa = $docDec->getProduitDeclinationValue();
if(!$prodDecVa->__isInitialized()) $prodDecVa->__load();
$stock = $prodDecVa->getStocks()[0];
if($stock) {
if( $category == 'client') {
if( !$stock->getQtReserved() <= 0) {
$stock->setQtReserved($stock->getQtReserved() - $docDec->getQuantity());
}
} else {
if( $document->getType() == "reception") {
$newQte = $stock->getQtStock() - $docDec->getQuantity();
$stock->setQtStock($newQte);
} elseif( $document->getType() == 'retour') {
$newQte = $stock->getQtStock() + $docDec->getQuantity();
$stock->setQtStock($newQte);
}
}
}
$document->removeDocumentDeclinationProduit($docDec);
}
foreach ($document->getDocumentProduits() as $docProd) {
$prod = $docProd->getProduit();
$stock = $prod->getStocks()[0];
if( $stock) {
if($category == 'client') {
if( !$stock->getQtReserved() <= 0) {
$newQte = $stock->getQtReserved() - $docProd->getQuantity();
$stock->setQtReserved($newQte);
}
}else{
if($document->getType() == 'reception'){
$newQte =$stock->getQtStock() - $docProd->getQuantity();
$stock->setQtStock($newQte);
}elseif($document->getType() == 'retour'){
$newQte =$stock->getQtStock() + $docProd->getQuantity();
$stock->setQtStock($newQte);
}
}
}
$document->removeDocumentProduit($docProd);
}
foreach ($document->getDocumentComments() as $comm) {
$document->removeDocumentComment($comm);
}
if( $request->get('form_document')) {
$data = $request->get('form_document');
//dump($data);die;
if (!empty($data['promotion_id'])) {
$promotion = $this->promotionRepository->find((int) $data['promotion_id']);
if ($promotion !== null) {
$document->setPromotion($promotion);
} else {
$document->setPromotion(null);
}
} else {
$document->setPromotion(null);
}
if( $data['discount'] == "") $data['discount'] = 0;
$dateDelivery = (!empty($data['promisedAt'])) ? new \DateTime($data['promisedAt']) : null;
$datebonlivraison = (!empty($data['shippedAt'])) ? new \DateTime($data['shippedAt']) : null;
$datebonrecu = (!empty($data['bonrecuAt'])) ? new \DateTime($data['bonrecuAt']) : null;
$dateAPayerLe = (!empty($data['aPayerLe'])) ? new \DateTime($data['aPayerLe']) : null;
$delivery = $this->deliveryRepository->find($data['delivery']['id']);
$source = null;
if ($category === 'client' && isset($data['source']['id']) && $data['source']['id']) {
$source = $this->sourceRepository->find($data['source']['id']);
}
$tvaDelivery = $this->tvaRepository->find($data['delivery']['tva']);
$document->setInternalNbr($data['internalNbr'])
->setExternalNbr(!empty($data['externalNbr']) ? $data['externalNbr'] : '')
->setObject(!empty($data['object']) ? $data['object'] : '')
->setTotalAmountHt($data['totalAmountHt'])
->setTotalTva($data['totalTva'])
->setTotalAmountTtc($data['totalAmountTtc'])
->setAdress(!empty($data['adress']) ? $data['adress'] : null)
->setParcelTrackingNbr($data['parcelTrackingNbr'])
->setPaymentMethod($data['paymentMethod'])
->setPaymentDeadline($data['paymentDeadline'])
->setDiscount($data['discount'])
->setDiscountType($data['discountType'])
->setAdvancePayment($data['advancePayment'])
->setAdvancePaymentType($data['advancePaymentType'])
->setPackagesNbr($data['packagesNbr'])
->setUrlTracking($data['urlTracking'])
->setPromisedAt($dateDelivery)
->setShippedAt($datebonlivraison)
->setBonrecuAt($datebonrecu)
->setAPayerLe($dateAPayerLe)
->setNote($data['note'])
->setSource($source)
->setDelivery($delivery)
->setDeliveryDiscount($data['delivery']['discount'])
->setDeliveryDiscountType($data['delivery']['discount_type'])
->setDeliveryPrice($data['delivery']['price_ht'])
->setDeliveryTotal((float) $data['delivery']['total_amount_ttc'])
->setIsFreeDelivery((isset($data['isFreedelivery']) && $data['isFreedelivery'] == "on"))
->setDeliveryTva($tvaDelivery);
if( isset($data['comment']) && $data['comment']) {
foreach ($data['comment'] as $item) {
$comment = new Comment();
$comment->setCreateAt(new \DateTime('now'));
$comment->setDocumentComment($document)
->setDescription($item)
->setUser($this->getUser());
$em->persist($comment);
}
}
if( isset($data['content']) && $data['content']) {
foreach ($data['content'] as $item) {
if( $item['type'] == 'produit') {
$entity = new DocumentProduit();
$entity->setType($item['type']);
if( isset($item['id']) && $item['id']) {
$produit = $this->produitRepository->find($item['id']);
$entity->setProduit($produit);
$entity->setUnite((isset($item['unit']) && $item['unit'])?$item['unit']:$produit->getUnit());
}
} else {
$entity = new DocumentDeclinationProduit();
$entity->setType($item['type']);
if( isset($item['id']) && $item['id']) {
$produitDecllination = $this->produitDeclinationValueRepository->find($item['id']);
$entity->setProduitDeclinationValue($produitDecllination);
$stock = $produitDecllination->getStocks()[0];
if( $stock) {
if( $category == 'client') {
$stock->setQtReserved($stock->getQtReserved() + $item['quantity']);
}else{
if($type=="achat"){
//do nothing
}elseif($type=="reception"){
$stock->setQtStock($stock->getQtStock() + $item['quantity']);
}elseif($type=="retour"){
$newQty=$stock->getQtStock() - $item['quantity'];
if($newQty>=0){
$stock->setQtStock($newQty);
}
}
}
} else {
$stock = new Stock();
if( $category == 'client') {
$stock->setDeclinationProduit($produitDecllination)
->setQtReserved($item['quantity'])
->setQtStock(0)
->setStorehouse('Principal');
} else {
if($type=="achat" || $type=="retour"){
$stock->setDeclinationProduit($produitDecllination)
->setQtReserved(0)
->setQtStock(0)
->setStorehouse('Principal');
}elseif($type=="reception"){
$stock->setDeclinationProduit($produitDecllination)
->setQtReserved(0)
->setQtStock($item['quantity'])
->setStorehouse('Principal');
}
}
$em->persist($stock);
}
$entity->setUnite((isset($item['unit']) && $item['unit'])?
$item['unit']:$produitDecllination->getProduit()->getUnit());
}
}
// Calcul du total HT (avec remise éventuelle)
$priceHt = (float) ($item['price_ht'] ?? 0);
$qty = (float) ($item['quantity'] ?? 0);
$discount = (float) ($item['discount'] ?? 0);
$discountType = $item['discount_type'] ?? null;
$totalHt = $priceHt * $qty;
if ($discount > 0) {
if ($discountType === 'percent') {
$totalHt -= round($totalHt * $discount / 100, 3);
} else { // montant
$totalHt -= $discount;
}
}
$totalHt = max(0, round($totalHt, 3));
$entity->setReference($item['reference'])
->setDiscount((float)$item['discount'])
->setDiscountType($item['discount_type'])
->setPriceHt((float)$item['price_ht'])
->setQuantity((int)$item['quantity'])
->setCreatedAt(new \DateTime('now'))
->setTotalAmountHt($totalHt)
->setTotalAmountTtc((float)$item['total_amount_ttc']);
if( isset($item['description']) && $item['description'])
$entity->setDescription($item['description']);
$tva =($item['tva'] != "0") ?
$this->tvaRepository->find($item['tva'])
:$this->tvaRepository->findOneBy(["number" => 0]);
$entity->setTva($tva);
$entity->setDocument($document);
$em->persist($entity);
}
}
}
$document->setUpdatedBy($this->getUser());
$document->setUpdatedAt(new \DateTime('now'));
$em->beginTransaction();
try {
$em->flush();
$em->commit();
} catch (\Throwable $e) {
$em->rollback();
throw $e;
}
$request->getSession()->getFlashBag()->add('success', "Document modifié avec succès");
return (array_key_exists('save', $data) && $data['save']=="save-and-exit")?
$this->redirectToRoute('document_show', ['id' => $document->getId()]):
$this->redirectToRoute('edit_document_commande', ['type' =>$document->getType(),'document'=>$document->getId(),'category'=>$document->getCategory()]);
}
} else {
$request->getSession()->getFlashBag()->add('danger', "Le bon de commande $type " . $document->getStatus() . ", on ne peut pas modifier , vérifiez son état avant de continuer !!");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
$tvas = $this->tvaRepository->findAll();
$deliveryTypes=($category == 'client')?['client','client-fournisseur']:['fournisseur','client-fournisseur'];
$deliverys = $this->deliveryRepository->findAllByTypes($deliveryTypes);
$sources = $this->sourceRepository->findAll();
$declinationCouleur = $this->declinationRepository->findOneBy(["name" => "Couleur"]);
$id = ($category == 'client')?$document->getClient()->getId():$document->getSupplier()->getId();
$template = ($category === 'fournisseur') ? '@admin/document/edit_document_fournisseur.html.twig' : '@admin/document/edit_document_client.html.twig';
return $this->render($template, [
'document' => $document,
'type' => $type,
'category' => $category,
'id' => $id,
'tvas' => $tvas,
'deliverys' => $deliverys,
'sources' => $sources,
'declinationCouleur' => $declinationCouleur,
'rights' => $rights
]);
}
/**
* @Route("/print/{id}", name="print_document", methods={"GET","POST"}, options={"expose"=true})
*/
public function printDocument(Document $document,EntityManagerInterface $em, CompanyRepository $companyRepository): Response {
$publicPath = $this->getParameter('kernel.project_dir') . '/public';
$company = $companyRepository->getCompanyInfo();
$twig = '@admin/document/pdf.html.twig';
$urlPdf = $this->createPdf($twig, ['document' => $document,'company'=>$company,'publicPath' => $publicPath], $document->getInternalNbr());
$document->setUrlPdf($urlPdf);
$em->flush();
return $this->render('@admin/document/print.html.twig', [
'document' => $document
]);
}
/**
* @Route("/printdoc/{id}", name="print_doc", methods={"GET","POST"}, options={"expose"=true})
*/
public function printDoc(Document $document,EntityManagerInterface $em, CompanyRepository $companyRepository) {
$publicPath = $this->getParameter('kernel.project_dir') . '/public';
$company = $companyRepository->getCompanyInfo();
$twig = '@admin/document/pdf.html.twig';
$urlPdf = $this->createPdf($twig, ['document' => $document,'company'=>$company,'publicPath' => $publicPath], $document->getInternalNbr());
$document->setUrlPdf($urlPdf);
$em->flush();
return new JsonResponse(["url" => $document->getUrlPdf()]);
}
/**
* @Route("/download/{id}", name="download_doc", methods={"GET","POST"}, options={"expose"=true})
*/
public function downloadDoc(Document $document,EntityManagerInterface $em, CompanyRepository $companyRepository) {
if( !$document->getUrlPdf()) {
$company = $companyRepository->getCompanyInfo();
$twig = '@admin/document/pdf.html.twig';
$urlPdf = $this->createPdf($twig, ['document' => $document,'company'=>$company], $document->getInternalNbr());
$document->setUrlPdf($urlPdf);
$em->flush();
}
return new JsonResponse(["url" => $document->getUrlPdf(), "filename" => $document->getInternalNbr() . '.pdf']);
}
/**
* @Route("/edit/info-livraison/{document}", name="edit_info_livarison", methods={"GET","POST"}, options={"expose"=true})
*/
public function editInfo(Request $request, Document $document,EntityManagerInterface $em): Response {
$rights =$this->hasRightByType( $request,$document->getCategory(),'DOCUMENT_CLIENT_UPDATE','DOCUMENT_SUPPLIER_UPDATE');
$form = $this->createForm(InfoLivraisonType::class, $document);
$form->handleRequest($request);
if( $form->isSubmitted() && $form->isValid()) {
$message = '[' . $this->getUser()->getFullName() . "] a modifié l'info du bon de commande de Réf: " . $document->getInternalNbr();
$this->activityService->addActivity('warning', $message, $document, $this->getUser(), 'document');
$em->persist($document);
$em->flush();
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
return $this->render('@admin/document/_formEditInfo.html.twig', [
'form' => $form->createView(),
'document' => $document
]);
}
/**
* @Route("/echange/commande/{id}/{category}", name="echange_document_commande", methods={"GET","POST"}, options={"expose"=true})
*/
public function create_echange(Document $commande, $category, Request $request,EntityManagerInterface $em): Response {
$rights =$this->hasRightByType( $request,$category,'DOCUMENT_CLIENT_UPDATE',null);
if( ($commande->getType() === 'commande' && ($commande->getstatus() === 'livre' || $commande->getstatus() === 'paye'))
||($commande->getType() === 'echange' && $commande->getstatus() === 'echange-recu') ){
//$commande->setUser($this->getUser());
if( $request->isMethod('POST')) {
if( $request->get('form_document')) {
$data = $request->get('form_document');
$existChange = false;
if( isset($data['content']) && $data['content'])
foreach ($data['content'] as $item) {
if( isset($item['change']) && $item['change'])
if( $item['change'] == "true") {
$existChange = true;
break;
}
}
if( $existChange) {
$document = new Document();
$date = new \DateTime('now');
$document = $this->createCopyDocument($document, $commande);
if( $data['discount'] == "")$data['discount'] = 0;
$dateDelivery =($data['promisedAt'] && $data['promisedAt'] != '' && $data['promisedAt'] != null)?
new \DateTime($data['promisedAt']): null;
$delivery = $this->deliveryRepository->find($data['delivery']['id']);
$source = $this->sourceRepository->find($data['source']['id']);
$tvaDelivery = $this->tvaRepository->find($data['delivery']['tva']);
$document->setDocument($commande)
->setType('echange')
->setCategory($category)
->setCreatedAt(new \DateTime('now'))
//->setEndAt($date->add(new \DateInterval('P30D')))
->setUser($this->getUser())
->setInternalNbr($data['internalNbr'])
//->setObject($data['object'])
->setTotalAmountHt($data['totalAmountHt'])
->setTotalTva($data['totalTva'])
->setTotalAmountTtc($data['totalAmountTtc'])
->setAdress(!empty($data['adress']) ? $data['adress'] : null)
->setParcelTrackingNbr(null)
->setUrlTracking(null)
->setPaymentMethod($data['paymentMethod'])
->setPaymentRef(null)
//->setPaymentDeadline($data['paymentDeadline'])
->setDiscount($data['discount'])
->setDiscountType($data['discountType'])
//->setAdvancePayment($data['advancePayment'])
//->setAdvancePaymentType($data['advancePaymentType'])
->setPackagesNbr($data['packagesNbr'])
->setPromisedAt($dateDelivery)
->setNote($data['note'])
->setSource($source)
->setDelivery($delivery)
->setDeliveryDiscount($data['delivery']['discount'])
->setDeliveryDiscountType($data['delivery']['discount_type'])
->setDeliveryPrice($data['delivery']['price_ht'])
->setDeliveryTotal((float) $data['delivery']['total_amount_ttc'])
->setIsFreeDelivery((isset($data['isFreedelivery']) && $data['isFreedelivery'] == "on"))
->setDeliveryTva($tvaDelivery);
if( isset($data['comment']) && $data['comment']) {
foreach ($data['comment'] as $item) {
$comment = new Comment();
$comment->setCreateAt(new \DateTime('now'))
->setDescription($item)
->setUser($this->getUser());
$em->persist($comment);
$document->addDocumentComment($comment);
}
}
$em->persist($document);
if( isset($data['content']) && $data['content']) {
foreach ($data['content'] as $item) {
if( $item['type'] == 'produit') {
$entity = new DocumentProduit();
$entity->setType($item['type']);
if( isset($item['id']) && $item['id']) {
$produit = $this->produitRepository->find($item['id']);
$entity->setProduit($produit)
->setUnite((isset($item['unit']) && $item['unit'])?
$item['unit']:$produit->getUnit());
}
} else {
if( isset($item['change']) && $item['change']) {
if( $item['change'] == "true") {
$entity = new DocumentDeclinationProduit();
$entity->setType('declinationEchange');
if( isset($item['id']) && $item['id']) {
$produitDecllination = $this->produitDeclinationValueRepository->find($item['id']);
$entity->setProduitDeclinationValue($produitDecllination)
->setUnite((isset($item['unit']) && $item['unit'])?
$item['unit']:$produitDecllination->getProduit()->getUnit());
}
if( isset($entity)) {
// Calcul du total HT (avec remise éventuelle)
$priceHt = (float) ($item['price_ht'] ?? 0);
$qty = (float) ($item['quantity'] ?? 0);
$discount = (float) ($item['discount'] ?? 0);
$discountType = $item['discount_type'] ?? null;
$totalHt = $priceHt * $qty;
if ($discount > 0) {
if ($discountType === 'percent') {
$totalHt -= round($totalHt * $discount / 100, 3);
} else { // montant
$totalHt -= $discount;
}
}
$totalHt = max(0, round($totalHt, 3));
$tva = ($item['tva'] != "0")?$this->tvaRepository->find($item['tva']):$this->tvaRepository->findOneBy(["number" => 0]);
$entity->setReference($item['reference'])
->setDiscount($item['discount'])
->setDiscountType($item['discount_type'])
->setPriceHt($item['price_ht'])
->setQuantity($item['quantity'])
->setCreatedAt(new \DateTime('now'))
->setTotalAmountHt($totalHt)
->setTotalAmountTtc($item['total_amount_ttc'])
->setTva($tva)
->setDocument($document);
if( isset($item['description']) && $item['description'])
$entity->setDescription($item['description']);
$em->persist($entity);
}
}
} else {
$entity = new DocumentDeclinationProduit();
$entity->setType($item['type']);
if( isset($item['id']) && $item['id']) {
$produitDecllination = $this->produitDeclinationValueRepository->find($item['id']);
$entity->setProduitDeclinationValue($produitDecllination);
$stock = $produitDecllination->getStocks()[0];
if( $stock) {
if( $category == 'client') {
$stock->setQtReserved($stock->getQtReserved() + $item['quantity']);
}
} else {
$stock = new Stock();
if( $category == 'client') {
$stock->setDeclinationProduit($produitDecllination)
->setQtReserved($item['quantity'])
->setQtStock(0)
->setStorehouse('Principal');
} else {
$stock->setDeclinationProduit($produitDecllination)
->setQtReserved(0)
->setQtStock(0)
->setStorehouse('Principal');
}
$em->persist($stock);
}
$entity->setUnite((isset($item['unit']) && $item['unit'])?
$item['unit']:$produitDecllination->getProduit()->getUnit());
}
if( isset($entity)) {
// Calcul du total HT (avec remise éventuelle)
$priceHt = (float) ($item['price_ht'] ?? 0);
$qty = (float) ($item['quantity'] ?? 0);
$discount = (float) ($item['discount'] ?? 0);
$discountType = $item['discount_type'] ?? null;
$totalHt = $priceHt * $qty;
if ($discount > 0) {
if ($discountType === 'percent') {
$totalHt -= round($totalHt * $discount / 100, 3);
} else { // montant
$totalHt -= $discount;
}
}
$totalHt = max(0, round($totalHt, 3));
$tva = ($item['tva'] != "0")?
$this->tvaRepository->find($item['tva'])
:$this->tvaRepository->findOneBy(["number" => 0]);
$entity->setReference($item['reference'])
->setDiscount($item['discount'])
->setDiscountType($item['discount_type'])
->setPriceHt($item['price_ht'])
->setQuantity($item['quantity'])
->setCreatedAt(new \DateTime('now'))
->setTotalAmountHt($totalHt)
->setTotalAmountTtc($item['total_amount_ttc'])
->setTva($tva)
->setDocument($document);
if( isset($item['description']) && $item['description'])
$entity->setDescription($item['description']);
$em->persist($entity);
}
}
}
}
}
if( $category == "client") {
$document->setStatus('en-attente')
->setConditionDocument('Create BEC from BC#'.$commande->getId())
->setInternalNbr('BEC-' . date('dmY') . '-' . rand(10000, 99999))
->setClient($commande->getClient());
}
$em->persist($document);
$message = '[' . $this->getUser()->getFullName() . "] a crée le bon d'échange.";
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
$em->flush();
$request->getSession()->getFlashBag()->add('success', "Bon echange créé avec succès");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
$request->getSession()->getFlashBag()->add('danger',
"Vous devez choisir certains articles pour effectuer l'échange !");
}
}
$tvas = $this->tvaRepository->findAll();
$deliveryTypes=($category == 'client')?['client','client-fournisseur']:['fournisseur','client-fournisseur'];
$deliverys = $this->deliveryRepository->findAllByTypes($deliveryTypes);
$sources = $this->sourceRepository->findAll();
$id = ($category == 'client')?$commande->getClient()->getId():$commande->getSupplier()->getId();
$declinationCouleur = $this->declinationRepository->findOneBy(["name" => "Couleur"]);
return $this->render('@admin/document/echange_document_client.html.twig', [
'document' => $commande,
'commande' => null,
'type' => 'commande',
'declinationCouleur'=>$declinationCouleur,
'category' => $category,
'id' => $id,
'tvas' => $tvas,
'deliverys' => $deliverys,
'sources' => $sources,
'rights' => $rights
]);
}else
$request->getSession()->getFlashBag()->add('danger',
"Ce document doit être une livré pour être effectué une echange!!!");
return $this->redirectToRoute('document_show', ['id' => $commande->getId()]);
}
/**
* @Route("/exchange/received/{id}", name="exchange_received", methods={"GET","POST"}, options={"expose"=true})
*/
public function exchangeReceived(Document $document, EntityManagerInterface $em, Request $request): Response
{
// Vérifier que c’est un échange et qu’il est bien expédié
if ($document->getType() === "echange" && $document->getStatus() === "expedie") {
/** -----------------------------
* 1) Récupérer la date reçue du form
* ----------------------------- */
$dateStr = $request->request->get('received_at');
if ($dateStr) {
$date = \DateTime::createFromFormat('Y-m-d', $dateStr);
if ($date !== false) {
$document->setBonrecuAt($date); // <-- enregistrement date réception
}
}
/** -----------------------------
* 2) Mise à jour statut & condition
* ----------------------------- */
$document
->setStatus("echange-recu")
->setConditionDocument(
$document->getConditionDocument() . " -> Échange reçu"
);
/** -----------------------------
* 3) Mise à jour des stocks pour les articles échangés
* ----------------------------- */
foreach ($document->getDocumentDeclinationProduits() as $docDecl) {
if ($docDecl->getType() === 'declinationEchange') {
$produitDecl = $docDecl->getProduitDeclinationValue();
$stocks = $produitDecl->getStocks();
if ($stocks && isset($stocks[0])) {
$stock = $stocks[0];
if ($document->getCategory() === 'client') {
// Ajouter au stock la quantité reçue
$stock->setQtStock(
$stock->getQtStock() + $docDecl->getQuantity()
);
}
}
}
}
/** -----------------------------
* 4) Activité
* ----------------------------- */
$message = '[' . $this->getUser()->getFullName() . '] a confirmé la réception de l’échange.';
$this->activityService->addActivity('success', $message, $document, $this->getUser(), 'document');
/** -----------------------------
* 5) Flash + Redirect
* ----------------------------- */
$em->flush();
$request->getSession()->getFlashBag()->add('success', "Échange reçu avec succès.");
} else {
/** -----------------------------
* 6) Cas d’erreur
* ----------------------------- */
$request->getSession()->getFlashBag()->add(
'danger',
"Impossible de confirmer : le document {$document->getInternalNbr()} n'est pas dans un état expédié."
);
}
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/echangeedit/commande/{id}/{category}/{document}", name="echange_document_commande_edit", methods={"GET","POST"}, options={"expose"=true})
*/
public function editEchange(Document $commande, $category, Document $document, Request $request,EntityManagerInterface $em): Response {
$rights=$this->hasRightByType( $request,$category,'DOCUMENT_CLIENT_UPDATE','DOCUMENT_SUPPLIER_UPDATE');
$type = 'commande';
//$commande->setUser($this->getUser());
if( $request->isMethod('POST')) {
//Supprimer les anciennes lignes du bon d'échange intial
foreach ($document->getDocumentDeclinationProduits() as $docDec) {
$prodDecVa = $docDec->getProduitDeclinationValue();
if( $docDec->getType() != 'declinationEchange') {
$stock = $prodDecVa->getStocks()[0];
if( $stock && $category == 'client') {
if( !$stock->getQtReserved() <= 0) {
$stock->setQtReserved($stock->getQtReserved() - $docDec->getQuantity());
}
}
}
$document->removeDocumentDeclinationProduit($docDec);
}
//Ajouter les nouvelles lignes du bon d'échange
foreach ($document->getDocumentProduits() as $docProd) {
$prod = $docProd->getProduit();
if( $docProd->getType() != 'declinationEchange') {
$stock = $prod->getStocks()[0];
if( $stock && $category == 'client') {
if( !$stock->getQtReserved() <= 0) {
$stock->setQtReserved($stock->getQtReserved() - $docProd->getQuantity());
}
}
}
$document->removeDocumentProduit($docProd);
}
foreach ($document->getDocumentComments() as $comm) {
$document->removeDocumentComment($comm);
}
if( $request->get('form_document')) {
$data = $request->get('form_document');
//dd($data);
$existChange = false;
if( isset($data['content']) && $data['content']) {
foreach ($data['content'] as $item) {
if( isset($item['change']) && $item['change']) {
if( $item['change'] == "true") {
$existChange = true;
break;
}
}
}
}
if( $existChange) {
$date = new \DateTime('now');
$type = 'echange';
$document = $this->createCopyDocument($document, $commande);
$document->setDocument($commande);
$document->setType($type);
$document->setCategory($category);
//$document->setCreatedAt(new \DateTime('now'));
//$document->setEndAt($date->add(new \DateInterval('P30D')));
//$document->setUser($this->getUser());
$document->setUpdatedBy($this->getUser());
$document->setUpdatedAt($date);
if( $data['discount'] == "") $data['discount'] = 0;
$dateDelivery =($data['promisedAt'] && $data['promisedAt'] != '' && $data['promisedAt'] != null)?
new \DateTime($data['promisedAt']):null;
$document
//->setObject($data['object'])
->setTotalAmountHt((float) ($data['totalAmountHt'] ?? 0))
->setTotalTva($data['totalTva'])
->setTotalAmountTtc($data['totalAmountTtc'])
->setAdress(!empty($data['adress']) ? $data['adress'] : null)
//->setParcelTrackingNbr($data['parcelTrackingNbr'])
->setPaymentMethod($data['paymentMethod'])
//->setPaymentDeadline($data['paymentDeadline'])
->setDiscount($data['discount'])
->setDiscountType($data['discountType'])
//->setAdvancePayment($data['advancePayment'])
//->setAdvancePaymentType($data['advancePaymentType'])
->setPackagesNbr($data['packagesNbr'])
//->setUrlTracking($data['urlTracking'])
->setPromisedAt($dateDelivery)
->setNote($data['note']);
$delivery = $this->deliveryRepository->find($data['delivery']['id']);
$source = $this->sourceRepository->find($data['source']['id']);
$document->setSource($source);
$document->setDelivery($delivery)
->setDeliveryDiscount($data['delivery']['discount'])
->setDeliveryDiscountType($data['delivery']['discount_type'])
->setDeliveryPrice($data['delivery']['price_ht'])
->setDeliveryTotal((float) $data['delivery']['total_amount_ttc']);
$document->setIsFreeDelivery((isset($data['isFreedelivery']) && $data['isFreedelivery'] == "on"));
$tvaDelivery = $this->tvaRepository->find($data['delivery']['tva']);
$document->setDeliveryTva($tvaDelivery);
if( isset($data['comment']) && $data['comment']) {
foreach ($data['comment'] as $item) {
$comment = new Comment();
$comment->setCreateAt(new \DateTime('now'))
->setDescription($item)
->setUser($this->getUser());
$em->persist($comment);
$document->addDocumentComment($comment);
}
}
if( isset($data['content']) && $data['content']) {
$totalHt = (float)$item['price_ht'] * (int)$item['quantity'];
foreach ($data['content'] as $item) {
if( $item['type'] == 'produit') {
$entity = new DocumentProduit();
$entity->setType($item['type']);
if( isset($item['id']) && $item['id']) {
$produit = $this->produitRepository->find($item['id']);
$entity->setProduit($produit);
if( isset($item['unit']) && $item['unit'])
$entity->setUnite($item['unit']);
else
$entity->setUnite($produit->getUnit());
}
} else {
if( isset($item['change']) && $item['change']) {
if( $item['change'] == "true") {
$entity = new DocumentDeclinationProduit();
$entity->setType('declinationEchange');
if( isset($item['id']) && $item['id']) {
$produitDecllination = $this->produitDeclinationValueRepository->find($item['id']);
$entity->setProduitDeclinationValue($produitDecllination);
if( isset($item['unit']) && $item['unit'])
$entity->setUnite($item['unit']);
else
$entity->setUnite($produitDecllination->getProduit()->getUnit());
}
if( isset($entity)) {
$entity->setReference($item['reference'])
->setDiscount($item['discount'])
//->setDiscountType($item['discount_type'])
->setPriceHt($item['price_ht'])
->setQuantity($item['quantity'])
->setCreatedAt(new \DateTime('now'))
->setTotalAmountHt($totalHt)
->setTotalAmountTtc($item['total_amount_ttc']);
if( isset($item['description']) && $item['description'])
$entity->setDescription($item['description']);
if( $item['tva'] != "0") {
$tva = $this->tvaRepository->find($item['tva']);
} else {
$tva = $this->tvaRepository->findOneBy(["number" => 0]);
}
$entity->setTva($tva);
$entity->setDocument($document);
$em->persist($entity);
}
}
} else {
$entity = new DocumentDeclinationProduit();
$entity->setType($item['type']);
if( isset($item['id']) && $item['id']) {
$produitDecllination = $this->produitDeclinationValueRepository->find($item['id']);
$entity->setProduitDeclinationValue($produitDecllination);
$stock = $produitDecllination->getStocks()[0];
if( $stock) {
if( $category == 'client') {
$stock->setQtReserved($stock->getQtReserved() + $item['quantity']);
}
} else {
$stock = new Stock();
if( $category == 'client') {
$stock->setDeclinationProduit($produitDecllination)
->setQtReserved($item['quantity'])
->setQtStock(0)
->setStorehouse('Principal');
} else {
$stock->setDeclinationProduit($produitDecllination)
->setQtReserved(0)
->setQtStock(0)
->setStorehouse('Principal');
}
$em->persist($stock);
}
$entity->setUnite((isset($item['unit']) && $item['unit'])?$item['unit']:$produitDecllination->getProduit()->getUnit());
}
if( isset($entity)) {
$entity->setReference($item['reference'])
->setDiscount($item['discount'])
->setDiscountType($item['discount_type'])
->setPriceHt($item['price_ht'])
->setQuantity($item['quantity'])
->setCreatedAt(new \DateTime('now'))
->setTotalAmountHt($totalHt)
->setTotalAmountTtc($item['total_amount_ttc']);
if( isset($item['description']) && $item['description'])
$entity->setDescription($item['description']);
$tva =($item['tva'] != "0")? $this->tvaRepository->find($item['tva'])
:$this->tvaRepository->findOneBy(["number" => 0]);
$entity->setTva($tva);
$entity->setDocument($document);
$em->persist($entity);
}
}
}
}
}
if( $category == "client") {
$document->setStatus('en-attente');
$document->setConditionDocument('Aucun');
$document->setClient($commande->getClient());
} else {
}
$message = '[' . $this->getUser()->getFullName() . "] a modifié le bon d'échange.";
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
$em->flush();
$request->getSession()->getFlashBag()->add('success', "Bon echange créé avec succès");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
}
}
$tvas = $this->tvaRepository->findAll();
$deliveryTypes=($category == 'client')?['client','client-fournisseur']:['fournisseur','client-fournisseur'];
$deliverys = $this->deliveryRepository->findAllByTypes($deliveryTypes);
$sources = $this->sourceRepository->findAll();
$id = ($category == 'client')?$commande->getClient()->getId():$commande->getSupplier()->getId();
$declinationCouleur = $this->declinationRepository->findOneBy(["name" => "Couleur"]);
return $this->render('@admin/document/edit_echange_document_client.html.twig', [
'document' => $commande,
'commande' => $document,
'declinationCouleur'=>$declinationCouleur,
'type' => $type,
'category' => $category,
'id' => $id,
'tvas' => $tvas,
'deliverys' => $deliverys,
'sources' => $sources,
'rights' => $rights
]);
}
/**
* @Route("/change/supplier/{id}", name="change_supplier", methods={"GET","POST"}, options={"expose"=true})
*/
public function changeSupplier(Document $document, Request $request,EntityManagerInterface $em): Response {
if( $request->isMethod('POST')) {
$supplier = $this->supplierRepository->find($request->get('change_supplier')["id"]);
$document->setSupplier($supplier);
$message = '[' . $this->getUser()->getFullName() . '] a changé le fournisseur du bon de commande.';
$this->activityService->addActivity('info', $message, $document, $this->getUser(), 'document');
$em->flush();
$request->getSession()->getFlashBag()->add('success', "Fournisseur modifiée avec succès");
}
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
/**
* @Route("/search", name="search_document", methods="GET|POST", options = { "expose" = true})
*/
public function searchItem2(Request $request, DocumentRepository $document) {
$query = $request->get('query');
$deleteEspace = str_replace(' ', '', $query);
if( is_numeric($deleteEspace)) $query = $deleteEspace;
$entities = $document->search2( $query);
$output='<div class="m-list-search__results">';
foreach ($entities as $entity) {
$className='';
switch ($entity->getStatus()) {
case 'en-attente':
$className="alert-en-attente";
break;
case 'accepte':
$className='alert-accepte';
break;
case 'expedie':
case 'livre':
$className='alert-expedie';
break;
case 'retour-en-cours':
$className='alert-retour';
break;
case 'retourne':
$className='alert-retourne';
break;
case 'annule':
$className='alert-annule';
break;
case 'echange-recu':
$className='alert-echange-recu';
break;
case 'paye':
$className='alert-paye';
break;
default:
$className='m-badge--metal';
}
$statusHtml= ' <span class="m-badge '.$className.' m-badge--wide">' .$entity->getStatus().'</span>';
$output .= '<a href="/admin/document/show/'.$entity->getId().'" class="m-list-search__result-item">
<span class="m-list-search__result-item-pic">'.$entity->getInternalNbr().'
<br><small> Créé le '.$entity->getCreatedAt()->format('d/m/y H:i').'</small>
<br><small><i class="fa fa-chain"></i><code title="'.(($entity->getDelivery())?$entity->getDelivery()->getName():"N suivie").'">'.$entity->getParcelTrackingNbr().'</code></small>
</span>
<span class="m-list-search__result-item-text">
'.(($entity->getClient())?'<small><i class="fa fa-user"></i> '.$entity->getClient()->getCivility() . ' ' . $entity->getClient()->getFirstName() .'</small>':'').'
<span class="float-right">'.$statusHtml.'</span>
<br>
'.(($entity->getClient())?'<small><i class="fa fa fa-phone"></i> '. $entity->getClient()->getPhone().'</small>':'').'
<br>
<small><i class="fa fa fa-map-signs"></i> '. $entity->getAdress().'</small>
<span class="float-right"><small>PAR '.$entity->getUser()->getFirstName().'</small></span>
</span>
</a>';
}
$output .='</div>';
if( !$entities) $output ="";
return new Response($output);
}
/**
* @Route("/delete/{document}", name="document_delete", methods="DELETE", options = { "expose" = true})
*/
public function delete(Request $request, Document $document,EntityManagerInterface $em): Response {
$rights =$this->hasRightByType( $request,$document->getCategory(),'DOCUMENT_CLIENT_DELETE','DOCUMENT_SUPPLIER_DELETE');
if( $document->getstatus() === 'annule' ) {
if( $this->isCsrfTokenValid($this->getUser()->getId(), $request->server->get("HTTP_X_CSRF_TOKEN"))) {
//dump($request);die;
$message = '[' . $this->getUser()->getFullName() . '] a supprimé le bon de commande.';
$this->activityService->addActivity('danger', $message, NULL, $this->getUser(), 'document');
$this->documentRemove($document, $em);
$em->flush();
if( $request->isXmlHttpRequest())
return new JsonResponse(['status' => 'success', 'message' => 'Document supprimé avec succés'], Response::HTTP_OK);
else return $this->redirectToRoute('document_index');
}
}
return new JsonResponse('Something went wrong!', Response::HTTP_OK);
}
private function documentRemove(Document $document, EntityManagerInterface $em) {
foreach($document->getDocumentDeclinationProduits() as $documentDeclination)
$em->remove($documentDeclination);
foreach($document->getDocumentProduits() as $documentProduit)
$em->remove($documentProduit);
foreach($document->getComments() as $comment)
$em->remove($comment);
foreach($document->getDocumentComments() as $commentDoc)
$em->remove($commentDoc);
foreach($document->getActivities() as $activitie)
$em->remove($activitie);
foreach($document->getDocuments() as $doc)
$document->removeDocument($doc);
$em->remove($document);
}
private function createPdf($twig, $param, $name) {
$pdfOptions = new Options();
$pdfOptions->set('defaultFont', 'DejaVu')
->set('isHtml5ParserEnabled', true)
->set('isRemoteEnabled', true);
$dompdf = new Dompdf($pdfOptions);
$html = $this->renderView($twig, $param);
$contxt = stream_context_create([
'ssl' => [
'verify_peer' => FALSE,
'verify_peer_name' => FALSE,
'allow_self_signed' => TRUE
]
]);
$dompdf->setHttpContext($contxt);
$dompdf->loadHtml($html);
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();
// Store PDF Binary Data
$output = $dompdf->output();
// In this case, we want to write the file in the public directory
$publicDirectory = $this->getParameter('kernel.project_dir') . '/public/pdf';
$pdfFilepath = $publicDirectory . '/' . $name . '.pdf';
file_put_contents($pdfFilepath, $output);// Write file to the desired path
$url = $this->baseUrl . '/pdf/' . $name . '.pdf';
return $url;
}
private function createCopyDocumentProduit($new, $old) {
$new->setReference($old->getReference())
->setDiscount($old->getDiscount())
->setDescription($old->getDescription())
->setDiscountType($old->getDiscountType())
->setPriceHt($old->getPriceHt())
->setPriceTtc($old->getPriceTtc())
->setQuantity($old->getQuantity())
->setCreatedAt(new \DateTime('now'))
->setUnite($old->getUnite())
->setTva($old->getTva())
->setType($old->getType())
->setName($old->getName())
->setTotalAmountHt($old->getTotalAmountHt() ?? 0)
->setTva($old->getTva() ?? 0)
->setTotalAmountTtc($old->getTotalAmountTtc());
return $new;
}
private function createCopyDocument($new, $old) {
$new->setObject($old->getObject())
->setNote($old->getNote())
->setPaymentMethod($old->getPaymentMethod())
->setPaymentDeadline($old->getPaymentDeadline())
->setDiscount($old->getDiscount())
->setDiscountType($old->getDiscountType())
->setAdvancePayment($old->getAdvancePayment())
->setAdvancePaymentType($old->getAdvancePaymentType())
->setParcelTrackingNbr($old->getParcelTrackingNbr())
->setCategory($old->getCategory())
->setDelivery($old->getDelivery())
->setIsFreeDelivery($old->getIsFreeDelivery())
->setDeliveryDiscount($old->getDeliveryDiscount())
->setDeliveryDiscountType($old->getDeliveryDiscountType())
->setDeliveryPrice($old->getDeliveryPrice())
->setDeliveryTva($old->getDeliveryTva())
->setDeliveryTotal($old->getDeliveryTotal())
->setPackagesNbr($old->getPackagesNbr())
->setUrlTracking($old->getUrlTracking())
->setPromisedAt($old->getPromisedAt())
->setAdress($old->getAdress())
->setSource($old->getSource())
->setTotalAmountHt((float)$old->getTotalAmountHt() ?? 0)
->setTotalAmountTtc($old->getTotalAmountTtc() ?? 0)
->setTotalTva($old->getTotalTva() ?? 0)
->setTotalPaid($old->getTotalPaid() ?? 0)
->setExternalNbr($old->getExternalNbr());
return $new;
}
/**
* convertir directement un DA en Brecp
* @Route("/convert-DA/{document}", name="convert_da_to_bon_reception", methods={"GET","POST"}, options={"expose"=true})
*/
public function convetDaToBonReception(Document $document, Request $request,EntityManagerInterface $em): Response
{
$rights = $this->hasRightByType($request, $document->getCategory(), 'DOCUMENT_CLIENT_CREATE', 'DOCUMENT_SUPPLIER_CREATE');
if( $document->getStatus() == "en-attente" and $document->getType() == "achat") {
$newDocument = new Document();
$date = new \DateTime('now');
$newDocument = $this->createCopyDocument($newDocument, $document);
$newDocument->setInternalNbr("B-REC-" . date('dmY') . '-' . rand(10000, 99999))
->setType("reception")
->setCategory("fournisseur")
->setUser($this->getUser())
->setSupplier($document->getSupplier())
->setStatus('brouillon');
if( $request->isMethod('POST')) {
if( $request->get('form_document')) {
$data = $request->get('form_document');
if( $data['discount'] == "") $data['discount'] = 0;
$dateDelivery = (!empty($data['promisedAt'])) ? new \DateTime($data['promisedAt']) : null;
$datebonlivraison = (!empty($data['shippedAt'])) ? new \DateTime($data['shippedAt']) : null;
$datebonrecu = (!empty($data['bonrecuAt'])) ? new \DateTime($data['bonrecuAt']) : null;
$dateAPayerLe = (!empty($data['aPayerLe'])) ? new \DateTime($data['aPayerLe']) : null;
$delivery = $this->deliveryRepository->find($data['delivery']['id']);
$source = null;
if (isset($data['source']['id']) && $data['source']['id']) {
$source = $this->sourceRepository->find($data['source']['id']);
}
$tvaDelivery = $this->tvaRepository->find($data['delivery']['tva']);
$newDocument->setDocument($document)
->setConditionDocument("transformé")
->setInternalNbr($data['internalNbr'])
->setExternalNbr(!empty($data['externalNbr']) ? $data['externalNbr'] : '')
->setCreatedAt(new \DateTime('now'))
//->setEndAt($date->add(new \DateInterval('P30D')))
->setObject($data['object'])
->setTotalAmountHt($data['totalAmountHt'])
->setTotalTva($data['totalTva'])
->setTotalAmountTtc($data['totalAmountTtc'])
->setAdress(!empty($data['adress']) ? $data['adress'] : null)
->setParcelTrackingNbr($data['parcelTrackingNbr'])
->setPaymentMethod($data['paymentMethod'])
->setPaymentDeadline($data['paymentDeadline'])
->setDiscount($data['discount'])
->setDiscountType($data['discountType'])
->setAdvancePayment($data['advancePayment'])
->setAdvancePaymentType($data['advancePaymentType'])
->setPackagesNbr($data['packagesNbr'])
->setUrlTracking($data['urlTracking'])
->setPromisedAt($dateDelivery)
->setShippedAt($datebonlivraison)
->setBonrecuAt($datebonrecu)
->setAPayerLe($dateAPayerLe)
->setNote($data['note'])
->setSource($source)
->setDelivery($delivery)
->setDeliveryDiscount($data['delivery']['discount'])
->setDeliveryDiscountType($data['delivery']['discount_type'])
->setDeliveryPrice($data['delivery']['price_ht'])
->setDeliveryTotal((float) $data['delivery']['total_amount_ttc'])
->setIsFreeDelivery((isset($data['isFreedelivery']) && $data['isFreedelivery'] == "on"))
->setDeliveryTva($tvaDelivery);
if( isset($data['comment']) && $data['comment']) {
foreach ($data['comment'] as $item) {
$comment = new Comment();
$comment->setCreateAt(new \DateTime('now'));
$comment->setDocumentComment($newDocument)
->setDescription($item)
->setUser($this->getUser());
$em->persist($comment);
}
}
if( isset($data['content']) && $data['content']) {
foreach ($data['content'] as $item) {
if( $item['type'] == 'produit') {
$entity = new DocumentProduit();
$entity->setType($item['type']);
if( isset($item['id']) && $item['id']) {
$produit = $this->produitRepository->find($item['id']);
$entity->setProduit($produit);
$entity->setUnite((isset($item['unit']) && $item['unit'])?$item['unit']:$produit->getUnit());
}
} else {
$entity = new DocumentDeclinationProduit();
$entity->setType($item['type']);
if( isset($item['id']) && $item['id']) {
$produitDecllination = $this->produitDeclinationValueRepository->find($item['id']);
$entity->setProduitDeclinationValue($produitDecllination);
$stock = $produitDecllination->getStocks()[0];
if( $stock) {
$stock->setQtStock($stock->getQtStock() + $item['quantity']);
} else {
$stock = new Stock();
$stock->setDeclinationProduit($produitDecllination)
->setQtReserved(0)
->setQtStock($item['quantity'])
->setStorehouse('Principal');
}
$em->persist($stock);
$entity->setUnite((isset($item['unit']) && $item['unit'])?
$item['unit']:$produitDecllination->getProduit()->getUnit());
}
}
// Calcul du total HT (avec remise éventuelle)
$priceHt = (float) ($item['price_ht'] ?? 0);
$qty = (float) ($item['quantity'] ?? 0);
$discount = (float) ($item['discount'] ?? 0);
$discountType = $item['discount_type'] ?? null;
$totalHt = $priceHt * $qty;
if ($discount > 0) {
if ($discountType === 'percent') {
$totalHt -= round($totalHt * $discount / 100, 3);
} else { // montant
$totalHt -= $discount;
}
}
$totalHt = max(0, round($totalHt, 3));
$entity->setReference($item['reference'])
->setDiscount($item['discount'])
->setDiscountType($item['discount_type'])
->setPriceHt($item['price_ht'])
->setQuantity($item['quantity'])
->setCreatedAt(new \DateTime('now'))
->setTotalAmountHt($totalHt)
->setTotalAmountTtc($item['total_amount_ttc']);
if( isset($item['description']) && $item['description'])
$entity->setDescription($item['description']);
$tva =($item['tva'] != "0") ?
$this->tvaRepository->find($item['tva'])
:$this->tvaRepository->findOneBy(["number" => 0]);
$entity->setTva($tva);
$entity->setDocument($newDocument);
$em->persist($newDocument);
$em->persist($entity);
}
}
$document
->setUpdatedBy($this->getUser())
->setUpdatedAt(new \DateTime('now'))
->setStatus('transforme')
->setConditionDocument($document->getConditionDocument()." -> Transformé");
}
$message = '[' . $this->getUser()->getFullName() . '] a transformé le bon de commande en Bon de réception de Réf: ' . $newDocument->getInternalNbr();
$this->activityService->addActivity('success', $message, $document, $this->getUser(), 'document');
$em->flush();
$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");
return (array_key_exists('save', $data) && $data['save']=="save-and-exit")?
$this->redirectToRoute('document_show', ['id' => $newDocument->getId()]):
$this->redirectToRoute('edit_document_commande', ['type' =>$newDocument->getType(),'document'=>$newDocument->getId(),'category'=>$newDocument->getCategory()]);
}
$tvas = $this->tvaRepository->findAll();
$deliverys = $this->deliveryRepository->findAllByTypes(['fournisseur','client-fournisseur']);
$sources = $this->sourceRepository->findAll();
$declinationCouleur = $this->declinationRepository->findOneBy(["name" => "Couleur"]);
return $this->render('@admin/document/edit_document_fournisseur.html.twig', [
'newDocument' => $newDocument,
'document'=> $document,
'type' => 'reception',
'category' => 'fournisseur',
'id' => $document->getSupplier()->getId(),
'tvas' => $tvas,
'deliverys' => $deliverys,
'sources' => $sources,
'declinationCouleur'=>$declinationCouleur,
'rights' => $rights
]);
}else {
$request->getSession()->getFlashBag()->add('danger', "Le DA de réf {$document->getInternalNbr()} ".($document->getStatus()=="annule")?
" a déjà été annulée":" a déjà été transformé");
return $this->redirectToRoute('document_show', ['id' => $document->getId()]);
}
}
}