src/Controller/Admin/DashboardController.php line 119
<?phpnamespace App\Controller\Admin;use App\Controller\Admin\PaidOrdersCrudController;use App\Controller\Admin\UnpaidOrdersCrudController;use App\Entity\Application;use App\Entity\CurrencyExchangeRate;use App\Entity\EntityLog;use App\Entity\ExportExcel;use App\Entity\FrontTheme;use App\Entity\Link;use App\Entity\LinkType;use App\Entity\LogHistory;use App\Entity\Notification;use App\Entity\Role;use App\Entity\Settings;use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;use Symfony\Component\HttpFoundation\Response;use Symfony\Component\Routing\Annotation\Route;use App\Entity\User;use App\Entity\WebsiteTheme;use App\IlaveU\ShopBundle\Entity\Order\Order;use App\IlaveU\ShopBundle\Entity\Product\Product;use App\IlaveU\ShopBundle\Entity\Store\Store;use App\IlaveU\ShopBundle\Entity\Vendor\Vendor;use App\IlaveU\ShopBundle\Service\IlaveUShopStatisticProvider;use App\Repository\ApplicationRepository;use App\Service\IlaveUSettingsProvider;use Doctrine\Persistence\ManagerRegistry;use EasyCorp\Bundle\EasyAdminBundle\Config\Action;use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;use Symfony\Component\Filesystem\Filesystem;use Symfony\Component\Finder\Finder;use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;use EasyCorp\Bundle\EasyAdminBundle\Config\Assets;use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;use EasyCorp\Bundle\EasyAdminBundle\Contracts\Orm\EntityRepositoryInterface;use EasyCorp\Bundle\EasyAdminBundle\Orm\EntityRepository;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\RequestStack;class DashboardController extends AbstractDashboardController{public function __construct(private readonly ManagerRegistry $doctrine,private readonly IlaveUShopStatisticProvider $ilaveShopStatisticProvider,private readonly RequestStack $requestStack,) {}#[Route(path: '/admin', name: 'admin_non_locale')]public function indexNonLocale(Request $request): Response{return $this->redirectToRoute("admin", ["_locale" => $request->getLocale()]);}#[Route('/{_locale}/admin/website-theme/grapesjs_edit', name: 'website_theme_grapesjs_edit')]public function website_theme_grapesjs_edit(): Response{return $this->render('@IlaveU/FrontBundle/Themes/' . $this->container->get('twig')->getGlobals()["settings"]->get()->getAssetFolderName() . '/templates/admin/website-theme/grapesjs.html.twig');}#[Route(path: '/{_locale}/admin/apps-store', name: 'app_store')]public function appStore(Request $request, ApplicationRepository $applicationRepository, IlaveUSettingsProvider $ilaveSettingsProvider): Response{$appsArray = [];foreach ($applicationRepository->findAll() as $singleApp) {$appsArray[] = ["id" => $singleApp->getId(),"name" => $singleApp->getName(),"image" => $singleApp->getImage(),"price" => $singleApp->getPrice(),"pageUrl" => $singleApp->getPageUrl(),];}return $this->render("admin/app-store.html.twig", ["installedApps" => $appsArray,"JWT" => $ilaveSettingsProvider->createJWTForUser($this->getUser())]);}#[Route(path: '/{_locale}/admin', name: 'admin')]public function index(): Response{$url = $this->requestStack->getCurrentRequest()->server->get('REQUEST_URI');$parsedUrl = parse_url($url);parse_str($parsedUrl['query'] ?? '', $queryParams);if (count($queryParams) == 0) {$queryParams['store'] = null;$queryParams['range'] = null;$queryParams['from'] = null;$queryParams['to'] = null;}$range = $queryParams['range'] ?? 'today';$from = $queryParams['from'] ?? null;$to = $queryParams['to'] ?? null;$storeParam = (int)$queryParams['store'] ?? null;$store = null;// Check if user has ROLE_STORE and get their storeif ($this->isGranted('ROLE_STORE')) {$currentUser = $this->getUser();if ($currentUser) {$storeEntity = $this->doctrine->getRepository(Store::class)->findOneBy(["user" => $currentUser]);$store = $storeEntity;}} elseif ($storeParam != 0) {$storeEntity = $this->doctrine->getRepository(Store::class)->findOneBy(["id" => $storeParam]);$store = $storeEntity;}//dd($request);// Get list of stores$stores = $this->doctrine->getRepository(Store::class)->findAll();// Handle predefined ranges$now = new \DateTimeImmutable();// If custom date range provided, it overrides predefined rangeif ($from && $to) {$start = \DateTimeImmutable::createFromFormat('Y-m-d', $from)?->setTime(0, 0);$end = \DateTimeImmutable::createFromFormat('Y-m-d', $to)?->setTime(23, 59, 59);} elseif ($range === 'today') {$start = $now->modify('today')->setTime(0, 0);$end = $now->modify('today')->setTime(23, 59, 59);} elseif ($range === 'yesterday') {$start = $now->modify('yesterday')->setTime(0, 0);$end = $now->modify('yesterday')->setTime(23, 59, 59);} elseif ($range === 'week') {$start = $now->modify('this week')->setTime(0, 0);$end = $now->modify('next week')->setTime(0, 0)->modify('-1 second');} elseif ($range === 'month') {$start = $now->modify('first day of this month')->setTime(0, 0);$end = $now->modify('last day of this month')->setTime(23, 59, 59);} elseif ($range === 'year') {$start = $now->modify('first day of January')->setTime(0, 0);$end = $now->modify('last day of December')->setTime(23, 59, 59);} else { // Month By Default$start = $now->modify('today')->setTime(0, 0);$end = $now->modify('today')->setTime(23, 59, 59);}// If custom date range provided (overrides predefined range)$validOrders = $this->doctrine->getRepository(Order::class)->createQueryBuilder('orderAlias')->select('count(orderAlias.id)')->andWhere("orderAlias.status <> 'draft'")->andWhere("orderAlias.status <> 'cancelled'")->andWhere("orderAlias.statusShipping <> 'annulee'")->andWhere('orderAlias.createdAt BETWEEN :start AND :end')->setParameter('start', $start)->setParameter('end', $end);if($store){$validOrders->andWhere("orderAlias.store = :store");$validOrders->setParameter('store', $store);}$validOrders = $validOrders->getQuery()->getSingleScalarResult();$cancelledOrders = $this->doctrine->getRepository(Order::class)->createQueryBuilder('orderAlias')->select('count(orderAlias.id)')->andWhere("orderAlias.status = 'cancelled' OR orderAlias.statusShipping = 'annulee'")->andWhere('orderAlias.createdAt BETWEEN :start AND :end')->setParameter('start', $start)->setParameter('end', $end);if($store){$cancelledOrders->andWhere("orderAlias.store = :store");$cancelledOrders->setParameter('store', $store);}$cancelledOrders = $cancelledOrders->getQuery()->getSingleScalarResult();$shippedOrders = $this->doctrine->getRepository(Order::class)->createQueryBuilder('orderAlias')->select('count(orderAlias.id)')->andWhere("orderAlias.statusShipping = 'shipped'")->andWhere("orderAlias.status <> 'draft'")->andWhere("orderAlias.status <> 'cancelled'")->andWhere("orderAlias.statusShipping <> 'annulee'")->andWhere('orderAlias.createdAt BETWEEN :start AND :end')->setParameter('start', $start)->setParameter('end', $end);if($store){$shippedOrders->andWhere("orderAlias.store = :store");$shippedOrders->setParameter('store', $store);}$shippedOrders = $shippedOrders->getQuery()->getSingleScalarResult();$soldProducts = $this->doctrine->getRepository(Order::class)->createQueryBuilder('orderAlias')->select('sum(orderItems.quantity)')->leftJoin("orderAlias.orderItems", "orderItems")->andWhere("orderAlias.status <> 'draft'")->andWhere("orderAlias.status <> 'cancelled'")->andWhere("orderAlias.statusShipping <> 'annulee'")->andWhere('orderAlias.createdAt BETWEEN :start AND :end')->setParameter('start', $start)->setParameter('end', $end);if($store){$soldProducts->andWhere("orderAlias.store = :store");$soldProducts->setParameter('store', $store);}$soldProducts = $soldProducts->getQuery()->getSingleScalarResult();$revenuedProducts = $this->doctrine->getRepository(Order::class)->createQueryBuilder('orderAlias')->select('sum(orderItems.quantity * orderItems.price)')->leftJoin("orderAlias.orderItems", "orderItems")->andWhere("orderAlias.status <> 'draft'")->andWhere("orderAlias.status <> 'cancelled'")->andWhere("orderAlias.statusShipping <> 'annulee'")->andWhere('orderAlias.createdAt BETWEEN :start AND :end')->setParameter('start', $start)->setParameter('end', $end);if($store){$revenuedProducts->andWhere("orderAlias.store = :store");$revenuedProducts->setParameter('store', $store);}$revenuedProducts = $revenuedProducts->getQuery()->getSingleScalarResult();$averageOrderAmount = $validOrders > 0 ? $revenuedProducts / $validOrders : 0;//$inTypes = Order::IN_TYPES;//$outTypes = Order::OUT_TYPES;// $productInStock = $this->doctrine->createQueryBuilder()// ->select('p.id AS product_id, p.name AS product_name,p.initialStock AS initial_stock')// ->addSelect('// SUM(CASE WHEN o.type IN (:inTypes) THEN oi.quantity ELSE 0 END) AS stock_in,// SUM(CASE WHEN o.type IN (:outTypes) THEN oi.quantity ELSE 0 END) AS stock_out,// (// p.initialStock +// SUM(CASE WHEN o.type IN (:inTypes) THEN oi.quantity ELSE 0 END) -// SUM(CASE WHEN o.type IN (:outTypes) THEN oi.quantity ELSE 0 END)// ) AS current_stock// ')// ->from(Product::class, 'p')// ->leftJoin('p.orderItems', 'oi')// ->leftJoin('oi.parentOrder', 'o')// ->groupBy('p.id')// ->having('// (// p.initialStock +// SUM(CASE WHEN o.type IN (:inTypes) THEN oi.quantity ELSE 0 END) -// SUM(CASE WHEN o.type IN (:outTypes) THEN oi.quantity ELSE 0 END)// ) > 0// ')// ->andWhere("o.status = '".Order::STATUS_VALIDATED."'")// //->andWhere('o.createdAt BETWEEN :start AND :end')// // ->setParameter('start', $start)// // ->setParameter('end', $end)// ->setMaxResults(16)// ->orderBy('current_stock', 'DESC')// ->getQuery()// ->getArrayResult();$mostOrderedCategory = $this->doctrine->getRepository(Order::class)->createQueryBuilder('o')->select('c.id, c.name as categoryName, COUNT(DISTINCT o.id) as orderCount')->join('o.orderItems', 'oi')->join('oi.product', 'p')->join('p.categoriesProduct', 'c') // Assuming products have a many-to-many relationship with categories->where("o.status NOT IN ('draft', 'cancelled') AND o.statusShipping <> 'annulee'")->andWhere('o.createdAt BETWEEN :start AND :end')->groupBy('c.id, c.name')->orderBy('orderCount', 'DESC')->setMaxResults(1) // Get only the top category->setParameter('start', $start)->setParameter('end', $end);if($store){$mostOrderedCategory->andWhere("o.store = :store");$mostOrderedCategory->setParameter('store', $store);}$mostOrderedCategory->getQuery()->getOneOrNullResult();$mostOrderedCategory = $mostOrderedCategory->getQuery()->getOneOrNullResult();$mostOrderedCategoryName = $mostOrderedCategory ? $mostOrderedCategory['categoryName'] : 'N/A';// Get the most ordered product$mostOrderedProduct = $this->doctrine->getRepository(Order::class)->createQueryBuilder('o')->select('p.id, p.name as productName, SUM(oi.quantity) as totalQuantity, COUNT(DISTINCT o.id) as orderCount')->join('o.orderItems', 'oi')->join('oi.product', 'p')->where("o.status NOT IN ('draft', 'cancelled') AND o.statusShipping <> 'annulee'")->andWhere('o.createdAt BETWEEN :start AND :end')->groupBy('p.id, p.name')->orderBy('totalQuantity', 'DESC')->setMaxResults(1)->setParameter('start', $start)->setParameter('end', $end);if($store){$mostOrderedProduct->andWhere("o.store = :store");$mostOrderedProduct->setParameter('store', $store);}$mostOrderedProduct = $mostOrderedProduct->getQuery()->getOneOrNullResult();$mostOrderedProductName = $mostOrderedProduct ? $mostOrderedProduct['productName'] : 'N/A';// Payment status stats - separate queries for different payment statuses// Paid orders: filter by paidAt date$paidOrdersQuery = $this->doctrine->getRepository(Order::class)->createQueryBuilder('orderAlias')->select('count(orderAlias.id)')->andWhere("orderAlias.status <> 'draft'")->andWhere("orderAlias.status <> 'cancelled'")->andWhere("orderAlias.statusShipping <> 'annulee'")->andWhere('orderAlias.paidAt BETWEEN :start AND :end')->setParameter('start', $start)->setParameter('end', $end);if($store){$paidOrdersQuery->andWhere("orderAlias.store = :store");$paidOrdersQuery->setParameter('store', $store);}$paidOrders = $paidOrdersQuery->getQuery()->getSingleScalarResult();// Unpaid orders: filter by same date range as other stats$unpaidOrdersQuery = $this->doctrine->getRepository(Order::class)->createQueryBuilder('orderAlias')->select('count(orderAlias.id)')->andWhere("orderAlias.status <> 'draft'")->andWhere("orderAlias.status <> 'cancelled'")->andWhere("orderAlias.statusShipping = 'livree'")->andWhere('orderAlias.payedAmount = 0')->andWhere("orderAlias.status NOT IN ('paid', 'partially-paid')")->andWhere('orderAlias.createdAt BETWEEN :start AND :end')->setParameter('start', $start)->setParameter('end', $end);if($store){$unpaidOrdersQuery->andWhere("orderAlias.store = :store");$unpaidOrdersQuery->setParameter('store', $store);}$unpaidOrders = $unpaidOrdersQuery->getQuery()->getSingleScalarResult();// Calculate total amounts for paid orders (filtered by paidAt date)$paidOrdersAmountQuery = $this->doctrine->getRepository(Order::class)->createQueryBuilder('orderAlias')->select('sum(orderAlias.payedAmount)')->andWhere("orderAlias.status <> 'draft'")->andWhere("orderAlias.status <> 'cancelled'")->andWhere("orderAlias.statusShipping <> 'annulee'")->andWhere('orderAlias.paidAt BETWEEN :start AND :end')->setParameter('start', $start)->setParameter('end', $end);if($store){$paidOrdersAmountQuery->andWhere("orderAlias.store = :store");$paidOrdersAmountQuery->setParameter('store', $store);}$paidOrdersAmount = $paidOrdersAmountQuery->getQuery()->getSingleScalarResult() ?: 0;// Calculate total amounts for unpaid orders (filtered by same date range)$unpaidOrdersAmountQuery = $this->doctrine->getRepository(Order::class)->createQueryBuilder('orderAlias')->select('sum(orderItems.quantity * orderItems.price)')->leftJoin("orderAlias.orderItems", "orderItems")->andWhere("orderAlias.status <> 'draft'")->andWhere("orderAlias.status <> 'cancelled'")->andWhere("orderAlias.statusShipping = 'livree'")->andWhere('orderAlias.payedAmount = 0')->andWhere("orderAlias.status NOT IN ('paid', 'partially-paid')")->andWhere('orderAlias.createdAt BETWEEN :start AND :end')->setParameter('start', $start)->setParameter('end', $end);if($store){$unpaidOrdersAmountQuery->andWhere("orderAlias.store = :store");$unpaidOrdersAmountQuery->setParameter('store', $store);}$unpaidOrdersAmount = $unpaidOrdersAmountQuery->getQuery()->getSingleScalarResult() ?: 0;// Breakdown: paid amounts grouped by payment method$paidByMethodQB = $this->doctrine->getRepository(Order::class)->createQueryBuilder('orderAlias')->select('pm.name AS methodName, pm.code AS methodCode, SUM(orderAlias.payedAmount) AS totalAmount')->leftJoin('orderAlias.paymentMethod', 'pm')->andWhere("orderAlias.status <> 'draft'")->andWhere("orderAlias.status <> 'cancelled'")->andWhere("orderAlias.statusShipping <> 'annulee'")->andWhere('orderAlias.paidAt BETWEEN :start AND :end')->groupBy('pm.id, pm.name, pm.code')->setParameter('start', $start)->setParameter('end', $end);if ($store) {$paidByMethodQB->andWhere('orderAlias.store = :store')->setParameter('store', $store);}$paidByMethod = $paidByMethodQB->getQuery()->getArrayResult();// Breakdown: unpaid amounts grouped by payment method$unpaidByMethodQB = $this->doctrine->getRepository(Order::class)->createQueryBuilder('orderAlias')->select('pm.name AS methodName, pm.code AS methodCode, SUM(orderItems.quantity * orderItems.price) AS totalAmount')->leftJoin('orderAlias.paymentMethod', 'pm')->leftJoin('orderAlias.orderItems', 'orderItems')->andWhere("orderAlias.status <> 'draft'")->andWhere("orderAlias.status <> 'cancelled'")->andWhere("orderAlias.statusShipping = 'livree'")->andWhere('orderAlias.payedAmount = 0')->andWhere("orderAlias.status NOT IN ('paid', 'partially-paid')")->andWhere('orderAlias.createdAt BETWEEN :start AND :end')->groupBy('pm.id, pm.name, pm.code')->setParameter('start', $start)->setParameter('end', $end);if ($store) {$unpaidByMethodQB->andWhere('orderAlias.store = :store')->setParameter('store', $store);}$unpaidByMethod = $unpaidByMethodQB->getQuery()->getArrayResult();$stats = [['label' => 'Chiffre d\'affaires','value' => (float)round($revenuedProducts, 2),'icon' => 'fa-coins','cssClass' => 'stat-revenue','description' => 'Revenu total généré par les ventes','url' => null,'unit' => 'MAD',],['label' => 'Ventes','value' => (int)$validOrders,'icon' => 'fa-calendar-check','cssClass' => 'stat-monthly-orders','description' => 'Nombre de ventes validées','url' => null,'unit' => null,],['label' => 'Produits vendus','value' => (int)$soldProducts,'icon' => 'fa-boxes','cssClass' => 'stat-products-sold','description' => 'Nombre total de produits vendus','url' => null,'unit' => null,],['label' => 'Panier moyen','value' => (float)round($averageOrderAmount, 2),'icon' => 'fa-shopping-basket','cssClass' => 'stat-average-basket','description' => 'Montant moyen dépensé par commande','url' => null,'unit' => 'MAD',],['label' => 'Commandes annulées','value' => (float)$cancelledOrders,'icon' => 'fa-undo','cssClass' => 'stat-refunds','description' => 'Nombre de commandes annulées','url' => null,'unit' => null,],['label' => 'Commandes livrées','value' => (float)$shippedOrders,'icon' => 'fa-truck','cssClass' => 'stat-delivered-orders','description' => 'Nombre de commandes livrées','url' => null,'unit' => null,],['label' => 'Catégorie phare','value' => $mostOrderedCategoryName,'icon' => 'fa-star','cssClass' => 'stat-top-category','description' => 'Catégorie la plus vendue ce mois-ci','url' => null,'unit' => null,],['label' => 'Produit phare','value' => $mostOrderedProductName,'icon' => 'fa-star','cssClass' => 'stat-top-product','description' => 'Produit la plus vendu ce mois-ci','url' => null,'unit' => null,],['label' => 'Commandes réglées','value' => $paidOrders,'amount' => (float)$paidOrdersAmount,'icon' => 'fa-check-circle','cssClass' => 'stat-paid-orders','description' => 'Nombre de commandes entièrement réglées','url' => null,'unit' => null,'breakdown' => array_map(function(array $row) { return ['label' => $row['methodName'] ?? '—', 'amount' => (float)($row['totalAmount'] ?? 0)]; }, $paidByMethod),],['label' => 'Commandes à régler','value' => $unpaidOrders,'amount' => (float)$unpaidOrdersAmount,'icon' => 'fa-clock','cssClass' => 'stat-unpaid-orders','description' => 'Nombre de commandes en attente de réglement','url' => null,'unit' => null,'breakdown' => array_map(function(array $row) { return ['label' => $row['methodName'] ?? '—', 'amount' => (float)($row['totalAmount'] ?? 0)]; }, $unpaidByMethod),],];$productLabels = [];$productChartData = [];// foreach ($productInStock as $product) {// $productLabels[] = $product['product_name'];// $productChartData[] = (float) $product['current_stock']; // cast to float for Chart.js// }// $productChartData = [// 'labels' => $productLabels,// 'data' => $productChartData,// ];return $this->render("bundles/EasyAdminBundle/welcome.html.twig",['stores' => $stores,'store' => $store,'stats' => $stats,'productChartData' => $productChartData,'queryParams' => $queryParams,]);}public function configureCrud(): Crud{returnCrud::new()->setDefaultSort(["id" => 'DESC'])->setPaginatorPageSize(12);}public function configureDashboard(): Dashboard{$mainSettings = $this->doctrine->getManager()->getRepository(Settings::class)->findOneBy(["code" => "main"]);$nameSpaceTrans = strtolower($mainSettings->getProjectName()) . "-admin";$urlImage = "../themes/" . strtolower($mainSettings->getAssetFolderName()) . "/admin/images/logo.png";return Dashboard::new()->setTitle('<img title="Dashboard" src="' . $urlImage . '" />')//->renderContentMaximized()->setFaviconPath("../themes/" . strtolower($mainSettings->getAssetFolderName()) . "/admin/images/icon.png")->setTranslationDomain($nameSpaceTrans)->disableUrlSignatures()->setLocales(['fr' => 'Français','en' => 'English','ar' => 'Arabe',]);}public function configureMenuItems(): iterable{/* START : Les Extensions IlaveU */$applications = $this->doctrine->getManager()->getRepository(Application::class)->findBy(["isEnabled" => true], ["menuOrder" => "ASC"]);$settings = $this->doctrine->getManager()->getRepository(Settings::class)->findOneBy(["code" => "main"]);//$finder = new Finder();$filesystem = new Filesystem();//$finder->directories()->in(__DIR__."/../../IlaveU")->depth('== 0');// For Principal Bundles (ShopBundle + FrontBundle + ...)foreach ($applications as $singleApplication) {$bundleExist = $filesystem->exists(__DIR__ . "/../../IlaveU/" . $singleApplication->getName() . "/IlaveU" . $singleApplication->getName() . ".php");if (!$bundleExist) {continue;}$bundleName = $singleApplication->getName();// Les themes systemes IlaveU (FrontBundle Themes)if ($bundleName == "FrontBundle") {$bundleDashboardController = 'App\IlaveU\FrontBundle\Themes\\' . $settings->getFrontTheme() . '\Controller\DashboardController';} else {$bundleDashboardController = 'App\IlaveU\\' . $bundleName . '\Controller\DashboardController';}$dashboard = new $bundleDashboardController();foreach ($dashboard->configureMenuItems() as $menu) {yield $menu;}}// For Additional Apps Bundles (POSBundle + OtherBundle + ...)foreach ($applications as $singleApplication) {if ($singleApplication->getParentApplication()) {continue;}$menuArray = [];$bundleExist = $filesystem->exists(__DIR__ . "/../../IlaveU/Apps/" . $singleApplication->getName() . "/IlaveU" . $singleApplication->getName() . ".php");if (!$bundleExist) {continue;}$bundleName = $singleApplication->getName();$bundleDashboardController = 'App\IlaveU\Apps\\' . $bundleName . '\Controller\DashboardController';$dashboard = new $bundleDashboardController();foreach ($dashboard->configureMenuItems() as $menu) {yield $menu;}//SubApplicationsforeach ($singleApplication->getSubApplications() as $subApplication) {$bundleExist = $filesystem->exists(__DIR__ . "/../../IlaveU/Apps/" . $subApplication->getName() . "/IlaveU" . $subApplication->getName() . ".php");if (!$bundleExist) {continue;}$bundleName = $subApplication->getName();$bundleDashboardController = 'App\IlaveU\Apps\\' . $bundleName . '\Controller\DashboardController';$dashboard = new $bundleDashboardController();foreach ($dashboard->configureMenuItems() as $menu) {yield $menu;}}}/* END : Les Extensions IlaveU */yield MenuItem::section('Commandes');yield MenuItem::linkToCrud('Commandes réglées', 'fas fa-check-circle', Order::class)->setController(PaidOrdersCrudController::class);yield MenuItem::linkToCrud('Commandes à payer', 'fas fa-clock', Order::class)->setController(UnpaidOrdersCrudController::class);yield MenuItem::section('Parametres');yield MenuItem::linkToRoute('Theme Designer', 'fas fa-shield-alt', "website_theme_grapesjs_edit")->setPermission("ROLE_ADMIN_DEV");yield MenuItem::linkToRoute('Apps Store', 'fas fa-shield-alt', "app_store")->setPermission("ROLE_ADMIN_DEV");yield MenuItem::linkToCrud('Utilisateurs', 'fas fa-shield-alt', User::class)->setController(UserCrudController::class);yield MenuItem::linkToCrud('Passwords', 'fas fa-shield-alt', User::class)->setController(UserPasswordCrudController::class);yield MenuItem::linkToCrud('Roles', 'fas fa-shield-alt', Role::class);yield MenuItem::linkToCrud('LinkType', 'fas fa-gears', LinkType::class)->setPermission("ROLE_ADMIN_DEV");yield MenuItem::linkToCrud('Link', 'fas fa-gears', Link::class)->setPermission("ROLE_ADMIN_DEV");yield MenuItem::linkToCrud('Applications', 'fas fa-shield-alt', Application::class)->setPermission("ROLE_ADMIN_DEV");yield MenuItem::linkToCrud('Notifications', 'fas fa-shield-alt', Notification::class)->setPermission("ROLE_ADMIN_DEV");yield MenuItem::linkToRoute('Text to speech', 'fas fa-shield-alt', "open_ai_tts")->setPermission("ROLE_ADMIN_DEV");yield MenuItem::linkToCrud('Historique', 'fas fa-shield-alt', EntityLog::class)->setPermission("ROLE_ADMIN");yield MenuItem::linkToCrud('Settings', 'fas fa-shield-alt', Settings::class)->setAction("edit")->setEntityId($settings->getId());yield MenuItem::linkToCrud('Currency Exchange', 'fas fa-shield-alt', CurrencyExchangeRate::class);yield MenuItem::linkToCrud('Web site theme', 'fas fa-shield-alt', WebsiteTheme::class)->setPermission("ROLE_ADMIN_DEV");yield MenuItem::linkToCrud('Front Themes', 'fas fa-shield-alt', FrontTheme::class)->setPermission("ROLE_ADMIN_DEV");yield MenuItem::linkToCrud('Export Excel', 'fas fa-shield-alt', ExportExcel::class)->setController(ExportExcelCrudController::class)->setPermission("ROLE_ADMIN_DEV");}}