<?php
namespace App\Controller;
use DateTime;
use App\Entity\Depense;
use App\Entity\Produit;
use App\Entity\Recette;
use App\Entity\Boutique;
use App\Entity\Livraison;
use App\Entity\Vente;
use App\Entity\EntreeStock;
use App\Entity\SortieStock;
use App\Repository\VenteRepository;
use App\Repository\FactureRepository;
use App\Repository\ProduitRepository;
use Doctrine\ORM\EntityManagerInterface;
use App\Repository\EntreeStockRepository;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use App\Service\PaiementService;
use App\Service\CalculFinancierService;
class DashboardController extends AbstractController
{
private $entityManager;
private $venteRepository;
private $paiementService;
private $calculFinancierService;
public function __construct(EntityManagerInterface $entityManager, VenteRepository $venteRepository, PaiementService $paiementService, CalculFinancierService $calculFinancierService)
{
$this->entityManager = $entityManager;
$this->venteRepository = $venteRepository;
$this->paiementService = $paiementService;
$this->calculFinancierService = $calculFinancierService;
}
#[Route('/dashboard', name: 'app_dashboard')]
public function index(Request $request, ProduitRepository $menuRepository, FactureRepository $factureRepository): Response
{
// Récupérer l'utilisateur connecté et son rôle
$user = $this->getUser();
$isSuperAdmin = $this->isGranted('ROLE_SUPER_ADMIN');
$isAdmin = $this->isGranted('ROLE_ADMIN');
// Si l'utilisateur n'est pas super admin, afficher un message simple
if (!$isSuperAdmin) {
return $this->render('dashboard/index.html.twig', [
'isSuperAdmin' => false,
'isAdmin' => $isAdmin,
'userBoutique' => $user ? $user->getBoutique() : null,
'showData' => false, // Indicateur pour le template
]);
}
// Récupérer la période sélectionnée (journalier, hebdomadaire, mensuel, trimestriel, semestriel, annuel)
$period = $request->query->get('period', 'daily');
// Initialiser les variables de date selon la période
$startDate = new \DateTime('today');
$endDate = clone $startDate;
$endDate->modify('+1 day');
$periodLabel = 'Journalier';
// Définir les dates selon la période sélectionnée
switch ($period) {
case 'weekly':
$startDate = new \DateTime('monday this week');
$endDate = clone $startDate;
$endDate->modify('+1 week');
$periodLabel = 'Hebdomadaire';
break;
case 'monthly':
$startDate = new \DateTime('first day of this month');
$endDate = clone $startDate;
$endDate->modify('+1 month');
$periodLabel = 'Mensuel';
break;
case 'quarterly':
$startDate = new \DateTime('first day of this month');
$quarter = ceil($startDate->format('n') / 3);
$startDate->setDate($startDate->format('Y'), ($quarter - 1) * 3 + 1, 1);
$endDate = clone $startDate;
$endDate->modify('+3 months');
$periodLabel = 'Trimestriel';
break;
case 'biannual':
$startDate = new \DateTime('first day of january this year');
if ((int)$startDate->format('n') > 6) {
$startDate->setDate($startDate->format('Y'), 7, 1);
}
$endDate = clone $startDate;
$endDate->modify('+6 months');
$periodLabel = 'Semestriel';
break;
case 'annual':
$startDate = new \DateTime('first day of january this year');
$endDate = clone $startDate;
$endDate->modify('+1 year');
$periodLabel = 'Annuel';
break;
}
// Récupérer toutes les boutiques pour admin/superadmin ou seulement la boutique associée pour magasinier
$boutiqueRepository = $this->entityManager->getRepository(Boutique::class);
if ($isSuperAdmin || $isAdmin) {
// Admin ou SuperAdmin voit toutes les boutiques
$boutiques = $boutiqueRepository->findAll();
} else {
// Magasinier ne voit que sa boutique assignée
$boutiques = [];
if ($user && $user->getBoutique()) {
$boutiques = [$user->getBoutique()];
}
}
// Récupérer les encaissements réels par boutique pour la période sélectionnée
$encaissementsByBoutique = $this->venteRepository->getEncaissementsByBoutique($startDate, $endDate);
$totalEncaissements = $this->venteRepository->getTotalEncaissements($startDate, $endDate);
// Calculer les totaux globaux directs et dettes
$totalDirects = 0;
$totalDettes = 0;
foreach ($encaissementsByBoutique as $encaissement) {
$totalDirects += $encaissement['encaissements_directs'];
$totalDettes += $encaissement['encaissements_dettes'];
}
// Formater les données pour l'affichage
$recettesByBoutique = [];
foreach ($boutiques as $boutique) {
$encaissement = $encaissementsByBoutique[$boutique->getId()] ?? null;
$montantTotal = $encaissement ? $encaissement['total_encaissements'] : 0;
$recettesByBoutique[$boutique->getId()] = [
'boutique' => $boutique,
'montant' => $montantTotal,
'encaissements_directs' => $encaissement ? $encaissement['encaissements_directs'] : 0,
'encaissements_dettes' => $encaissement ? $encaissement['encaissements_dettes'] : 0
];
}
// Récupérer les autres données existantes
$numberOfMenus = $menuRepository->createQueryBuilder('m')
->select('COUNT(m.id)')
->getQuery()
->getSingleScalarResult();
$topMenus = $this->entityManager->getRepository(Produit::class)->findTopMenus(5);
$bottomProducts = $this->entityManager->getRepository(Produit::class)->findBottomProducts(5);
$today = new DateTime('today');
$recette = $this->entityManager->getRepository(Recette::class)->findOneBy(['dateRecette' => $today]);
$depenses = $this->entityManager->getRepository(Depense::class)->createQueryBuilder('d')
->where('d.dateDepense >= :start')
->andWhere('d.dateDepense < :end')
->setParameter('start', $startDate->format('Y-m-d H:i:s'))
->setParameter('end', $endDate->format('Y-m-d H:i:s'))
->getQuery()
->getResult();
$livraisonsEnAttente = $this->entityManager->getRepository(Livraison::class)->findBy(['statut' => 'en attente']);
$livraisonsEnCours = $this->entityManager->getRepository(Livraison::class)->findBy(['statut' => 'en cours']);
$dailyRevenue = $factureRepository->getRevenueByPeriod($today, new \DateTime('tomorrow'));
$monthlyRevenue = $factureRepository->getRevenueByPeriod(new \DateTime('first day of this month'), new \DateTime('last day of this month'));
$trimesterRevenue = $factureRepository->getRevenueByPeriod(new \DateTime(date('Y-m-d', strtotime('-2 months', strtotime('first day of this month')))), new \DateTime('last day of this month'));
// Récupérer les ventes journalières (exclure les ventes virtuelles)
$ventesJournalieres = $this->entityManager->getRepository(Vente::class)->createQueryBuilder('v')
->where('v.dateVente >= :start')
->andWhere('v.dateVente < :end')
->andWhere('(v.type IS NULL OR v.type != :typeVirtuelle)')
->setParameter('start', $today->format('Y-m-d H:i:s'))
->setParameter('end', (clone $today)->modify('+1 day')->format('Y-m-d H:i:s'))
->setParameter('typeVirtuelle', 'virtuelle')
->orderBy('v.dateVente', 'DESC')
->getQuery()
->getResult();
// Calculer le total des ventes journalières avec frais de transport
$totalVentesJournalieres = 0;
foreach ($ventesJournalieres as $vente) {
// Calculer le montant des produits
$montantProduits = 0;
foreach ($vente->getDetailsVentes() as $detail) {
$montantProduits += $detail->getQuantiteVendu() * $detail->getPrixUnitaire();
}
// Ajouter les frais de transport
$fraisTransport = 0;
foreach ($vente->getFactures() as $facture) {
$fraisTransport += $facture->getFraisTransport() ?? 0;
}
$totalVentesJournalieres += $montantProduits + $fraisTransport;
}
// Calculer les encaissements directs pour les ventes d'aujourd'hui (harmonisé)
$encaissementsDirectsAujourdhui = $this->calculFinancierService->getEncaissementsDirectsByVenteDate($today, (clone $today)->modify('+1 day'));
// Calculer les paiements de dettes effectués aujourd'hui (basé sur la date de paiement)
$paiementsDettesAujourdhui = $this->calculFinancierService->getPaiementsDettesByPaiementDate($today, (clone $today)->modify('+1 day'));
// Vérifier la cohérence des calculs
$coherenceEncaissements = $this->calculFinancierService->verifierCohérenceEncaissements($today, (clone $today)->modify('+1 day'));
return $this->render('dashboard/index.html.twig', [
'numberOfMenus' => $numberOfMenus,
'topMenus' => $topMenus,
'btP' => $bottomProducts,
'montantRecette' => $recette ? $recette->getMontant() : 0,
'depenses' => $depenses,
'livraisonsEnAttente' => $livraisonsEnAttente,
'livraisonsEnCours' => $livraisonsEnCours,
'dailyRevenue' => $dailyRevenue,
'monthlyRevenue' => $monthlyRevenue,
'trimesterRevenue' => $trimesterRevenue,
'recettesByBoutique' => $recettesByBoutique,
'totalRecette' => $totalEncaissements,
'totalDirects' => $totalDirects,
'totalDettes' => $totalDettes,
'ventesJournalieres' => $ventesJournalieres,
'totalVentesJournalieres' => $totalVentesJournalieres,
'encaissementsDirectsAujourdhui' => $encaissementsDirectsAujourdhui,
'paiementsDettesAujourdhui' => $paiementsDettesAujourdhui,
'coherenceEncaissements' => $coherenceEncaissements,
'period' => $period,
'periodLabel' => $periodLabel,
'startDate' => $startDate,
'endDate' => $endDate,
'isSuperAdmin' => $isSuperAdmin,
'isAdmin' => $isAdmin,
'userBoutique' => $user ? $user->getBoutique() : null,
'showData' => true, // Indicateur pour le template
]);
}
#[Route('/dashboard/boutique/{id}/recettes', name: 'app_dashboard_boutique_recettes')]
public function boutiqueRecettes(Request $request, Boutique $boutique): Response
{
// Vérifier les permissions
$user = $this->getUser();
if (!$this->isGranted('ROLE_ADMIN') && !$this->isGranted('ROLE_SUPER_ADMIN')) {
if (!$user->getBoutique() || $user->getBoutique()->getId() !== $boutique->getId()) {
throw $this->createAccessDeniedException('Vous n\'avez pas accès à cette boutique');
}
}
// Récupérer la période et les dates
$period = $request->query->get('period', 'daily');
$startDate = new \DateTime('today');
$endDate = clone $startDate;
$endDate->modify('+1 day');
// Définir les dates selon la période sélectionnée (même logique que dans index)
switch ($period) {
case 'weekly':
$startDate = new \DateTime('monday this week');
$endDate = clone $startDate;
$endDate->modify('+1 week');
break;
case 'monthly':
$startDate = new \DateTime('first day of this month');
$endDate = clone $startDate;
$endDate->modify('+1 month');
break;
case 'quarterly':
$startDate = new \DateTime('first day of this month');
$quarter = ceil($startDate->format('n') / 3);
$startDate->setDate($startDate->format('Y'), ($quarter - 1) * 3 + 1, 1);
$endDate = clone $startDate;
$endDate->modify('+3 months');
break;
case 'biannual':
$startDate = new \DateTime('first day of january this year');
if ((int)$startDate->format('n') > 6) {
$startDate->setDate($startDate->format('Y'), 7, 1);
}
$endDate = clone $startDate;
$endDate->modify('+6 months');
break;
case 'annual':
$startDate = new \DateTime('first day of january this year');
$endDate = clone $startDate;
$endDate->modify('+1 year');
break;
}
// Récupérer les encaissements réels pour cette boutique dans la période
$encaissementsByBoutique = $this->venteRepository->getEncaissementsByBoutique($startDate, $endDate);
$encaissementBoutique = $encaissementsByBoutique[$boutique->getId()] ?? null;
// Récupérer les factures payées pour cette boutique dans la période
$factures = $this->entityManager->getRepository(\App\Entity\Facture::class)->createQueryBuilder('f')
->leftJoin('f.vente', 'v')
->where('v.boutique = :boutique')
->andWhere('f.createdAt >= :start')
->andWhere('f.createdAt < :end')
->andWhere('f.statutPaiement = :statut')
->setParameter('boutique', $boutique)
->setParameter('start', $startDate->format('Y-m-d H:i:s'))
->setParameter('end', $endDate->format('Y-m-d H:i:s'))
->setParameter('statut', 'Payé')
->orderBy('f.createdAt', 'DESC')
->getQuery()
->getResult();
return $this->render('dashboard/boutique_recettes.html.twig', [
'boutique' => $boutique,
'factures' => $factures,
'encaissement' => $encaissementBoutique,
'period' => $period,
'startDate' => $startDate,
'endDate' => $endDate,
]);
}
#[Route('/ventes-journalieres', name: 'app_ventes_journalieres')]
public function ventesJournalieres(): Response
{
$user = $this->getUser();
$isSuperAdmin = $this->isGranted('ROLE_SUPER_ADMIN');
$isAdmin = $this->isGranted('ROLE_ADMIN');
// Date d'aujourd'hui
$today = new \DateTime('today');
$tomorrow = clone $today;
$tomorrow->modify('+1 day');
// Récupérer les ventes journalières (exclure les ventes virtuelles pour les crédits)
$queryBuilder = $this->entityManager->getRepository(Vente::class)->createQueryBuilder('v')
->leftJoin('v.client', 'c')
->leftJoin('v.boutique', 'b')
->leftJoin('v.detailsVentes', 'dv')
->leftJoin('v.echeances', 'e')
->where('v.dateVente >= :start')
->andWhere('v.dateVente < :end')
->andWhere('(v.type IS NULL OR v.type != :typeVirtuelle)')
->setParameter('start', $today->format('Y-m-d H:i:s'))
->setParameter('end', $tomorrow->format('Y-m-d H:i:s'))
->setParameter('typeVirtuelle', 'virtuelle')
->orderBy('v.dateVente', 'DESC');
// Filtrer par boutique si l'utilisateur n'est pas admin
if (!$isSuperAdmin && !$isAdmin) {
if ($user && $user->getBoutique()) {
$queryBuilder->andWhere('v.boutique = :boutique')
->setParameter('boutique', $user->getBoutique());
} else {
// Si l'utilisateur n'a pas de boutique, retourner un tableau vide
return $this->render('dashboard/ventes_journalieres.html.twig', [
'ventes' => [],
'totalVentes' => 0,
'totalEncaisse' => 0,
'totalReste' => 0,
'date' => $today,
]);
}
}
$ventes = $queryBuilder->getQuery()->getResult();
// Calculer les totaux avec frais de transport
$totalVentes = 0;
$totalProduits = 0;
$totalFraisTransport = 0;
$totalEncaisse = 0;
$totalReste = 0;
foreach ($ventes as $vente) {
$montantProduits = $this->paiementService->calculerMontantProduitsVente($vente);
$fraisTransport = $this->paiementService->calculerFraisTransportVente($vente);
$montantTotal = $this->paiementService->calculerMontantTotalVente($vente);
$montantPaye = $this->paiementService->calculerMontantPayeVente($vente);
$reste = $this->paiementService->calculerResteAPayerVente($vente);
$totalProduits += $montantProduits;
$totalFraisTransport += $fraisTransport;
$totalVentes += $montantTotal;
$totalEncaisse += $montantPaye;
$totalReste += $reste;
}
// Calculer les encaissements directs harmonisés pour les ventes d'aujourd'hui
$encaissementsDirectsAujourdhui = $this->calculFinancierService->getEncaissementsDirectsByVenteDate($today, $tomorrow);
// Calculer les paiements de dettes effectués aujourd'hui (basé sur la date de paiement)
$paiementsDettesAujourdhui = $this->calculFinancierService->getPaiementsDettesByPaiementDate($today, $tomorrow);
// Vérifier la cohérence des calculs
$coherenceEncaissements = $this->calculFinancierService->verifierCohérenceEncaissements($today, $tomorrow);
return $this->render('dashboard/ventes_journalieres.html.twig', [
'ventes' => $ventes,
'totalProduits' => $totalProduits,
'totalFraisTransport' => $totalFraisTransport,
'totalVentes' => $totalVentes,
'totalEncaisse' => $totalEncaisse,
'totalReste' => $totalReste,
'encaissementsDirectsAujourdhui' => $encaissementsDirectsAujourdhui,
'paiementsDettesAujourdhui' => $paiementsDettesAujourdhui,
'coherenceEncaissements' => $coherenceEncaissements,
'date' => $today,
]);
}
// Les autres méthodes existantes (dashboardData, dashboardData2, dashboardReportsData)
#[Route('/dashboard/data', name: 'app_dashboard_data')]
public function dashboardData(Request $request): Response
{
$filter = $request->query->get('filter', 'today');
if (!in_array($filter, ['today', 'month', 'year'])) {
return $this->json(['error' => 'Invalid filter'], Response::HTTP_BAD_REQUEST);
}
switch ($filter) {
case 'today':
$salesCount = $this->venteRepository->getSalesCountByPeriod('today');
break;
case 'month':
$salesCount = $this->venteRepository->getSalesCountByPeriod('month');
break;
case 'year':
$salesCount = $this->venteRepository->getSalesCountByPeriod('year');
break;
default:
$salesCount = 0;
break;
}
// Construire les données au format JSON
$data = [
'nombreVentes' => $salesCount
// Ajoutez ici d'autres données si nécessaire
];
// Renvoyer les données au format JSON
return $this->json($data);
}
#[Route('/dashboard/data2', name: 'app_dashboard_data2')]
public function dashboardData2(Request $request): Response
{
$filter = $request->query->get('filter', 'today');
$forceRefresh = $request->query->get('refresh', false);
if (!in_array($filter, ['today', 'month', 'year'])) {
return $this->json(['error' => 'Invalid filter'], Response::HTTP_BAD_REQUEST);
}
// Forcer le rafraîchissement si demandé
if ($forceRefresh) {
$this->entityManager->clear();
}
// Utiliser les nouvelles méthodes qui prennent en compte les paiements réels
$totalRevenue = $this->venteRepository->getTotalPaymentsByPeriod($filter);
$directRevenue = $this->venteRepository->getDirectRevenueByPeriod($filter);
$echeanceRevenue = $this->venteRepository->getRealRevenueByPeriod($filter);
$data = [
'totalRevenue' => $totalRevenue,
'directRevenue' => $directRevenue,
'echeanceRevenue' => $echeanceRevenue,
'breakdown' => [
'direct' => $directRevenue,
'echeances' => $echeanceRevenue
],
'lastUpdate' => (new \DateTime())->format('Y-m-d H:i:s')
];
return $this->json($data);
}
#[Route('/dashboard/reports/data', name: 'app_dashboard_reports_data')]
public function dashboardReportsData(Request $request): Response
{
$filter = $request->query->get('filter', 'today');
if (!in_array($filter, ['today', 'month', 'year'])) {
return $this->json(['error' => 'Invalid filter'], Response::HTTP_BAD_REQUEST);
}
// Initialiser les variables pour les données de ventes et de revenus
$salesData = [];
$revenueData = [];
$directRevenueData = [];
$echeanceRevenueData = [];
$categories = [];
switch ($filter) {
case 'today':
// Générer les catégories pour aujourd'hui (par exemple, chaque heure)
for ($i = 0; $i < 24; $i++) {
$categories[] = (new \DateTime())->setTime($i, 0)->format('Y-m-d\TH:i:s.v\Z');
$salesData[] = $this->venteRepository->getSalesCountByPeriod('today');
$revenueData[] = $this->venteRepository->getTotalPaymentsByPeriod('today');
$directRevenueData[] = $this->venteRepository->getDirectRevenueByPeriod('today');
$echeanceRevenueData[] = $this->venteRepository->getRealRevenueByPeriod('today');
}
break;
case 'month':
// Générer les catégories pour ce mois (par exemple, chaque jour)
$daysInMonth = (int) date('t');
$currentDate = new \DateTime('first day of this month');
for ($i = 0; $i < $daysInMonth; $i++) {
$categories[] = $currentDate->format('Y-m-d\TH:i:s.v\Z');
$salesData[] = $this->venteRepository->getSalesCountByPeriod('month');
$revenueData[] = $this->venteRepository->getTotalPaymentsByPeriod('month');
$directRevenueData[] = $this->venteRepository->getDirectRevenueByPeriod('month');
$echeanceRevenueData[] = $this->venteRepository->getRealRevenueByPeriod('month');
}
break;
case 'year':
// Générer les catégories pour cette année (par exemple, chaque mois)
for ($i = 1; $i <= 12; $i++) {
$categories[] = (new \DateTime())->setDate(date('Y'), $i, 1)->format('Y-m-d\TH:i:s.v\Z');
$salesData[] = $this->venteRepository->getSalesCountByPeriod('year');
$revenueData[] = $this->venteRepository->getTotalPaymentsByPeriod('year');
$directRevenueData[] = $this->venteRepository->getDirectRevenueByPeriod('year');
$echeanceRevenueData[] = $this->venteRepository->getRealRevenueByPeriod('year');
}
break;
}
$data = [
'categories' => $categories,
'salesData' => $salesData,
'revenueData' => $revenueData,
'directRevenueData' => $directRevenueData,
'echeanceRevenueData' => $echeanceRevenueData
];
return $this->json($data);
}
#[Route('/dashboard/credits-paid-details/{date}', name: 'app_dashboard_credits_paid_details')]
public function creditsPaidDetails(string $date): Response
{
try {
$user = $this->getUser();
$isSuperAdmin = $this->isGranted('ROLE_SUPER_ADMIN');
$isAdmin = $this->isGranted('ROLE_ADMIN');
// Valider le format de date
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
return $this->json(['error' => 'Format de date invalide'], 400);
}
// Convertir la date en DateTime avec gestion d'erreur
try {
$targetDate = new \DateTime($date);
$nextDay = clone $targetDate;
$nextDay->modify('+1 day');
} catch (\Exception $e) {
return $this->json(['error' => 'Date invalide'], 400);
}
// Récupérer les paiements de dettes effectués à cette date
$queryBuilder = $this->entityManager->getRepository(\App\Entity\PaiementDette::class)->createQueryBuilder('pd')
->leftJoin('pd.detteClient', 'dc')
->leftJoin('dc.client', 'c')
->leftJoin('dc.vente', 'v')
->leftJoin('v.boutique', 'b')
->where('pd.datePaiement >= :start')
->andWhere('pd.datePaiement < :end')
->setParameter('start', $targetDate->format('Y-m-d H:i:s'))
->setParameter('end', $nextDay->format('Y-m-d H:i:s'))
->orderBy('pd.datePaiement', 'DESC');
// Filtrer par boutique si l'utilisateur n'est pas admin
if (!$isSuperAdmin && !$isAdmin) {
if ($user && method_exists($user, 'getBoutique') && $user->getBoutique()) {
$queryBuilder->andWhere('v.boutique = :boutique')
->setParameter('boutique', $user->getBoutique());
} else {
return $this->json([]);
}
}
$paiements = $queryBuilder->getQuery()->getResult();
$data = [];
foreach ($paiements as $paiement) {
try {
$detteClient = $paiement->getDetteClient();
if (!$detteClient) {
continue; // Ignorer les paiements sans dette associée
}
$vente = $detteClient->getVente();
$client = $detteClient->getClient();
$boutique = $vente ? $vente->getBoutique() : null;
$data[] = [
'client' => $client ? $client->getNom() : 'Client non spécifié',
'phone' => $client ? $client->getPhone() : null,
'boutique' => $boutique ? $boutique->getNom() : null,
'montant' => $paiement->getMontant() ?? 0,
'date' => $paiement->getDatePaiement() ? $paiement->getDatePaiement()->format('d/m/Y H:i') : 'Date inconnue',
'statut' => 'Payé'
];
} catch (\Exception $e) {
// Ignorer les paiements problématiques et continuer
continue;
}
}
return $this->json($data);
} catch (\Exception $e) {
// Log l'erreur pour le débogage
error_log('Erreur dans creditsPaidDetails: ' . $e->getMessage());
return $this->json([
'error' => 'Erreur lors du chargement des données',
'message' => 'Une erreur est survenue lors de la récupération des crédits payés'
], 500);
}
}
#[Route('/dashboard/credits-given-details/{date}', name: 'app_dashboard_credits_given_details')]
public function creditsGivenDetails(string $date): Response
{
try {
$user = $this->getUser();
$isSuperAdmin = $this->isGranted('ROLE_SUPER_ADMIN');
$isAdmin = $this->isGranted('ROLE_ADMIN');
// Valider le format de date
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
return $this->json(['error' => 'Format de date invalide'], 400);
}
// Convertir la date en DateTime avec gestion d'erreur
try {
$targetDate = new \DateTime($date);
$nextDay = clone $targetDate;
$nextDay->modify('+1 day');
} catch (\Exception $e) {
return $this->json(['error' => 'Date invalide'], 400);
}
// Récupérer les ventes avec crédit (reste à payer > 0) créées à cette date
$queryBuilder = $this->entityManager->getRepository(Vente::class)->createQueryBuilder('v')
->leftJoin('v.client', 'c')
->leftJoin('v.boutique', 'b')
->leftJoin('v.factures', 'f')
->where('v.dateVente >= :start')
->andWhere('v.dateVente < :end')
->andWhere('(v.type IS NULL OR v.type != :typeVirtuelle)')
->setParameter('start', $targetDate->format('Y-m-d H:i:s'))
->setParameter('end', $nextDay->format('Y-m-d H:i:s'))
->setParameter('typeVirtuelle', 'virtuelle')
->orderBy('v.dateVente', 'DESC');
// Filtrer par boutique si l'utilisateur n'est pas admin
if (!$isSuperAdmin && !$isAdmin) {
if ($user && method_exists($user, 'getBoutique') && $user->getBoutique()) {
$queryBuilder->andWhere('v.boutique = :boutique')
->setParameter('boutique', $user->getBoutique());
} else {
return $this->json([]);
}
}
$ventes = $queryBuilder->getQuery()->getResult();
$data = [];
foreach ($ventes as $vente) {
try {
// Calculer le montant total de la vente
$montantTotal = $this->paiementService->calculerMontantTotalVente($vente);
$montantPaye = $this->paiementService->calculerMontantPayeVente($vente);
$reste = $montantTotal - $montantPaye;
// Ne garder que les ventes avec un reste à payer > 0
if ($reste > 0) {
$client = $vente->getClient();
$boutique = $vente->getBoutique();
$data[] = [
'client' => $client ? $client->getNom() : 'Client non spécifié',
'phone' => $client ? $client->getPhone() : null,
'boutique' => $boutique ? $boutique->getNom() : null,
'montant' => $reste,
'date' => $vente->getDateVente() ? $vente->getDateVente()->format('d/m/Y H:i') : 'Date inconnue',
'statut' => 'En attente'
];
}
} catch (\Exception $e) {
// Ignorer les ventes problématiques et continuer
continue;
}
}
return $this->json($data);
} catch (\Exception $e) {
// Log l'erreur pour le débogage
error_log('Erreur dans creditsGivenDetails: ' . $e->getMessage());
return $this->json([
'error' => 'Erreur lors du chargement des données',
'message' => 'Une erreur est survenue lors de la récupération des crédits accordés'
], 500);
}
}
}