templates/home/index.html.twig line 1

Open in your IDE?
  1. {% extends 'base.html.twig' %}
  2. {% block title %}Tableau de bord{% endblock %}
  3. {% block body %}
  4.     <style>
  5.         .dashboard-page {
  6.             --dashboard-primary: #405189;
  7.             --dashboard-success: #0ab39c;
  8.             --dashboard-danger: #f06548;
  9.             --dashboard-warning: #f7b84b;
  10.             --dashboard-info: #299cdb;
  11.             --dashboard-border: #e7eaf3;
  12.             --dashboard-muted: #74788d;
  13.         }
  14.         .dashboard-hero {
  15.             border: 1px solid var(--dashboard-border);
  16.             border-radius: 8px;
  17.             background: linear-gradient(135deg, #ffffff 0%, #f8fbff 55%, #f4fbf9 100%);
  18.             box-shadow: 0 12px 28px rgba(15, 34, 58, .07);
  19.             padding: 24px;
  20.             position: relative;
  21.             overflow: hidden;
  22.         }
  23.         .dashboard-hero::before {
  24.             content: "";
  25.             position: absolute;
  26.             inset: 0 auto 0 0;
  27.             width: 5px;
  28.             background: linear-gradient(180deg, var(--dashboard-primary), var(--dashboard-success));
  29.         }
  30.         .dashboard-hero-kicker {
  31.             color: var(--dashboard-primary);
  32.             font-size: 12px;
  33.             font-weight: 700;
  34.             letter-spacing: .08em;
  35.             text-transform: uppercase;
  36.         }
  37.         .dashboard-hero-title {
  38.             color: #24324b;
  39.             font-size: 24px;
  40.             font-weight: 700;
  41.         }
  42.         .dashboard-hero-subtitle {
  43.             color: var(--dashboard-muted);
  44.             max-width: 720px;
  45.         }
  46.         .dashboard-hero-pill {
  47.             border: 1px solid rgba(64, 81, 137, .12);
  48.             border-radius: 999px;
  49.             background: rgba(255, 255, 255, .78);
  50.             color: #344050;
  51.             font-size: 13px;
  52.             font-weight: 600;
  53.             padding: 7px 12px;
  54.         }
  55.         .dashboard-reset-btn {
  56.             border: 1px solid var(--dashboard-border);
  57.             border-radius: 6px;
  58.             background: #fff;
  59.             color: #344050;
  60.             font-weight: 600;
  61.             min-height: 40px;
  62.         }
  63.         .dashboard-reset-btn:hover {
  64.             border-color: rgba(64, 81, 137, .28);
  65.             color: var(--dashboard-primary);
  66.         }
  67.         .dashboard-filter-card,
  68.         .dashboard-kpi-card,
  69.         .dashboard-type-card,
  70.         .dashboard-chart-card,
  71.         .dashboard-table-card {
  72.             border: 1px solid var(--dashboard-border);
  73.             border-radius: 8px;
  74.             box-shadow: 0 10px 24px rgba(15, 34, 58, .06);
  75.         }
  76.         .dashboard-filter-card {
  77.             overflow: visible;
  78.         }
  79.         .dashboard-filter-card .card-body {
  80.             padding: 18px;
  81.         }
  82.         .dashboard-filter-card .form-label {
  83.             color: #344050;
  84.             font-size: 12px;
  85.             font-weight: 700;
  86.             letter-spacing: .03em;
  87.             margin-bottom: .45rem;
  88.             text-transform: uppercase;
  89.         }
  90.         .dashboard-filter-card .form-control,
  91.         .dashboard-filter-card .form-select,
  92.         .dashboard-filter-card .select2-container--default .select2-selection--single {
  93.             border-color: #dce2ef;
  94.             border-radius: 6px;
  95.             min-height: 42px;
  96.         }
  97.         .dashboard-filter-card .form-control:focus,
  98.         .dashboard-filter-card .form-select:focus {
  99.             border-color: rgba(64, 81, 137, .45);
  100.             box-shadow: 0 0 0 .15rem rgba(64, 81, 137, .1);
  101.         }
  102.         .dashboard-filter-card .input-group .form-control {
  103.             border-radius: 6px 0 0 6px;
  104.         }
  105.         .dashboard-filter-card .select2-container--default .select2-selection--single .select2-selection__rendered {
  106.             line-height: 40px;
  107.         }
  108.         .dashboard-filter-card .select2-container--default .select2-selection--single .select2-selection__arrow {
  109.             height: 40px;
  110.         }
  111.         .dashboard-filter-card .btn {
  112.             border-radius: 6px;
  113.             font-weight: 700;
  114.             min-height: 42px;
  115.         }
  116.         #datePickerButton {
  117.             border-radius: 0 6px 6px 0;
  118.             cursor: pointer;
  119.             justify-content: center;
  120.             min-width: 48px;
  121.         }
  122.         .dashboard-payment-filter {
  123.             min-height: 42px;
  124.             padding: .55rem .8rem;
  125.             border: 1px solid #dce2ef;
  126.             border-radius: 6px;
  127.             background: #fff;
  128.         }
  129.         .dashboard-payment-filter .form-check-input {
  130.             cursor: pointer;
  131.             height: 1.1rem;
  132.             width: 2.15rem;
  133.         }
  134.         .dashboard-payment-filter .form-check-input:checked {
  135.             background-color: var(--dashboard-danger);
  136.             border-color: var(--dashboard-danger);
  137.         }
  138.         .dashboard-kpi-card {
  139.             overflow: hidden;
  140.             position: relative;
  141.         }
  142.         .dashboard-kpi-card::before {
  143.             content: "";
  144.             height: 3px;
  145.             left: 0;
  146.             position: absolute;
  147.             right: 0;
  148.             top: 0;
  149.         }
  150.         .dashboard-kpi-card.metric-info::before {
  151.             background: var(--dashboard-info);
  152.         }
  153.         .dashboard-kpi-card.metric-primary::before {
  154.             background: var(--dashboard-primary);
  155.         }
  156.         .dashboard-kpi-card.metric-success::before {
  157.             background: var(--dashboard-success);
  158.         }
  159.         .dashboard-kpi-card.metric-danger::before {
  160.             background: var(--dashboard-danger);
  161.         }
  162.         .dashboard-kpi-card .card-body {
  163.             min-height: 148px;
  164.             padding: 22px 20px;
  165.         }
  166.         .dashboard-kpi-label,
  167.         .dashboard-type-label {
  168.             color: var(--dashboard-muted);
  169.             font-size: 12px;
  170.             font-weight: 700;
  171.             letter-spacing: .04em;
  172.             text-transform: uppercase;
  173.         }
  174.         .dashboard-kpi-value {
  175.             color: #26364f;
  176.             font-size: 24px;
  177.             font-weight: 800;
  178.             line-height: 1.25;
  179.         }
  180.         .dashboard-kpi-copy {
  181.             color: var(--dashboard-muted);
  182.             font-size: 13px;
  183.         }
  184.         .dashboard-icon-badge {
  185.             border-radius: 8px;
  186.             height: 48px;
  187.             width: 48px;
  188.         }
  189.         .dashboard-type-card {
  190.             transition: transform .15s ease, box-shadow .15s ease;
  191.         }
  192.         .dashboard-type-card:hover {
  193.             box-shadow: 0 14px 28px rgba(15, 34, 58, .09);
  194.             transform: translateY(-2px);
  195.         }
  196.         .dashboard-type-card .card-body {
  197.             min-height: 188px;
  198.             padding: 20px;
  199.         }
  200.         .dashboard-type-value {
  201.             color: #26364f;
  202.             font-size: 21px;
  203.             font-weight: 800;
  204.         }
  205.         .dashboard-type-meta {
  206.             color: var(--dashboard-muted);
  207.             font-size: 13px;
  208.         }
  209.         .dashboard-progress {
  210.             background: #edf1f7;
  211.             border-radius: 999px;
  212.             display: flex;
  213.             height: 7px;
  214.             overflow: hidden;
  215.         }
  216.         .dashboard-progress-paid {
  217.             background: var(--dashboard-success);
  218.         }
  219.         .dashboard-progress-remaining {
  220.             background: var(--dashboard-danger);
  221.         }
  222.         .dashboard-chart-card .card-header,
  223.         .dashboard-table-card .card-header {
  224.             background: #fff;
  225.             border-bottom: 1px solid var(--dashboard-border);
  226.             padding: 18px 20px;
  227.         }
  228.         .dashboard-chart-card .card-title,
  229.         .dashboard-table-card .card-title {
  230.             color: #26364f;
  231.             font-weight: 700;
  232.         }
  233.         .dashboard-table-scroll {
  234.             max-height: 774px;
  235.             overflow: auto;
  236.             border: 1px solid var(--dashboard-border);
  237.             border-radius: 8px;
  238.         }
  239.         .dashboard-table-scroll table {
  240.             margin-bottom: 0;
  241.             min-width: 1060px;
  242.         }
  243.         .dashboard-table-scroll thead th {
  244.             position: sticky;
  245.             top: 0;
  246.             z-index: 2;
  247.             background: #f6f8fb;
  248.             box-shadow: inset 0 -1px 0 var(--dashboard-border);
  249.             color: #566176;
  250.             font-size: 12px;
  251.             letter-spacing: .03em;
  252.             text-transform: uppercase;
  253.         }
  254.         .dashboard-table-scroll tbody tr {
  255.             height: 48px;
  256.         }
  257.         .dashboard-table-scroll tbody tr:hover {
  258.             background: #f8fbff;
  259.         }
  260.         .dashboard-table-scroll .btn {
  261.             border-radius: 6px;
  262.             font-weight: 700;
  263.             white-space: nowrap;
  264.         }
  265.         .dashboard-client-cell {
  266.             max-width: 280px;
  267.             white-space: normal;
  268.         }
  269.         .dashboard-money {
  270.             font-variant-numeric: tabular-nums;
  271.             white-space: nowrap;
  272.         }
  273.         .dashboard-empty-state {
  274.             color: var(--dashboard-muted);
  275.             padding: 34px 16px;
  276.         }
  277.         @media (max-width: 575.98px) {
  278.             .dashboard-hero {
  279.                 padding: 18px;
  280.             }
  281.             .dashboard-hero-title {
  282.                 font-size: 21px;
  283.             }
  284.             .dashboard-filter-card .d-flex.gap-2 {
  285.                 flex-direction: column;
  286.             }
  287.         }
  288.     </style>
  289.     <div class="page-content dashboard-page">
  290.         <div class="container-fluid">
  291.             <div class="row mb-4">
  292.                 <div class="col-12">
  293.                     <div class="dashboard-hero d-flex flex-column flex-lg-row align-items-lg-center justify-content-between gap-3">
  294.                         <div>
  295.                             <div class="dashboard-hero-kicker mb-2">Suivi paiements</div>
  296.                             <h4 class="dashboard-hero-title mb-2">Tableau de bord des restes a payer</h4>
  297.                             <p class="dashboard-hero-subtitle mb-3">Consultez les factures, BL, BLP et BS avec recherche par periode, client, type de fichier et statut de paiement.</p>
  298.                             <div class="d-flex flex-wrap gap-2">
  299.                                 <span class="dashboard-hero-pill">
  300.                                     <i class="ri-file-list-3-line align-bottom me-1"></i>{{ totals.count }} document{{ totals.count > 1 ? 's' : '' }}
  301.                                 </span>
  302.                                 <span class="dashboard-hero-pill">
  303.                                     <i class="ri-error-warning-line align-bottom me-1"></i>{{ totals.remaining|number_format(3, '.', ' ') }} DT reste a payer
  304.                                 </span>
  305.                                 {% if filters.unpaid_only %}
  306.                                     <span class="dashboard-hero-pill text-danger">
  307.                                         <i class="ri-filter-3-line align-bottom me-1"></i>Non payes seulement
  308.                                     </span>
  309.                                 {% endif %}
  310.                             </div>
  311.                         </div>
  312.                         <div>
  313.                             <a href="{{ path('app_home') }}" class="btn dashboard-reset-btn">
  314.                                 <i class="ri-refresh-line align-bottom me-1"></i> Reinitialiser
  315.                             </a>
  316.                         </div>
  317.                     </div>
  318.                 </div>
  319.             </div>
  320.             <div class="card dashboard-filter-card mb-4">
  321.                 <div class="card-body">
  322.                     <form method="get" action="{{ path('app_home') }}" class="row g-3 align-items-end">
  323.                         <div class="col-xl-3 col-md-6">
  324.                             <label for="dashboard_client" class="form-label">Client</label>
  325.                             <select id="dashboard_client" name="client" class="form-select">
  326.                                 <option value="">Tous les clients</option>
  327.                                 {% for client in clients %}
  328.                                     {% set clientLabel = client.raisonsocial ?: ((client.nom ~ ' ' ~ client.prenom)|trim) %}
  329.                                     <option value="{{ client.id }}" {% if filters.client == client.id %}selected{% endif %}>
  330.                                         {{ clientLabel ?: ('Client #' ~ client.id) }}
  331.                                     </option>
  332.                                 {% endfor %}
  333.                             </select>
  334.                         </div>
  335.                         <div class="col-xl-3 col-md-6">
  336.                             <label for="dateRangePicker" class="form-label d-block">Période</label>
  337.                             <div class="input-group">
  338.                                 <input
  339.                                         id="dateRangePicker"
  340.                                         name="dateRangePicker"
  341.                                         type="text"
  342.                                         class="form-control"
  343.                                         placeholder="Choisissez une plage de dates"
  344.                                         readonly
  345.                                         value="{{ filters.date_range }}"
  346.                                 />
  347.                                 <span id="datePickerButton" class="input-group-text bg-primary border-primary text-white">
  348.                                     <i class="ri-calendar-2-line"></i>
  349.                                 </span>
  350.                             </div>
  351.                         </div>
  352.                         <div class="col-xl-2 col-md-6">
  353.                             <label for="dashboard_type" class="form-label">Type fichier</label>
  354.                             <select id="dashboard_type" name="type" class="form-select">
  355.                                 <option value="">Tous les types</option>
  356.                                 {% for type, item in stats %}
  357.                                     <option value="{{ type }}" {% if filters.type == type %}selected{% endif %}>
  358.                                         {{ item.shortLabel }} - {{ item.label }}
  359.                                     </option>
  360.                                 {% endfor %}
  361.                             </select>
  362.                         </div>
  363.                         <div class="col-xl-2 col-md-6">
  364.                             <label for="dashboard_unpaid_only" class="form-label">Paiement</label>
  365.                             <div class="form-check form-switch dashboard-payment-filter d-flex align-items-center gap-2">
  366.                                 <input class="form-check-input m-0" type="checkbox" id="dashboard_unpaid_only" name="unpaid_only" value="1" {% if filters.unpaid_only %}checked{% endif %}>
  367.                                 <label class="form-check-label small mb-0" for="dashboard_unpaid_only">Non payé</label>
  368.                             </div>
  369.                         </div>
  370.                         <div class="col-xl-2 col-md-12">
  371.                             <div class="d-flex gap-2">
  372.                                 <button type="submit" class="btn btn-primary flex-fill">
  373.                                     <i class="ri-search-line align-bottom me-1"></i> Filtrer
  374.                                 </button>
  375.                                 <button type="submit" formaction="{{ path('app_home_export_excel') }}" formmethod="get" class="btn btn-success flex-fill">
  376.                                     <i class="ri-file-excel-2-line align-bottom me-1"></i> Excel
  377.                                 </button>
  378.                             </div>
  379.                         </div>
  380.                     </form>
  381.                 </div>
  382.             </div>
  383.             <div class="row">
  384.                 <div class="col-xl-3 col-md-6">
  385.                     <div class="card card-animate dashboard-kpi-card metric-info">
  386.                         <div class="card-body">
  387.                             <div class="d-flex align-items-center">
  388.                                 <div class="flex-grow-1 overflow-hidden">
  389.                                     <p class="dashboard-kpi-label text-truncate mb-0">Total documents</p>
  390.                                 </div>
  391.                                 <div class="avatar-sm flex-shrink-0">
  392.                                     <span class="avatar-title dashboard-icon-badge bg-soft-info fs-3">
  393.                                         <i class="ri-stack-line text-info"></i>
  394.                                     </span>
  395.                                 </div>
  396.                             </div>
  397.                             <div class="mt-4">
  398.                                 <h4 class="dashboard-kpi-value ff-secondary mb-2">{{ totals.count }}</h4>
  399.                                 <p class="dashboard-kpi-copy mb-0">Documents trouves avec les filtres actifs.</p>
  400.                             </div>
  401.                         </div>
  402.                     </div>
  403.                 </div>
  404.                 <div class="col-xl-3 col-md-6">
  405.                     <div class="card card-animate dashboard-kpi-card metric-primary">
  406.                         <div class="card-body">
  407.                             <div class="d-flex align-items-center">
  408.                                 <div class="flex-grow-1 overflow-hidden">
  409.                                     <p class="dashboard-kpi-label text-truncate mb-0">Montant total</p>
  410.                                 </div>
  411.                                 <div class="avatar-sm flex-shrink-0">
  412.                                     <span class="avatar-title dashboard-icon-badge bg-soft-primary fs-3">
  413.                                         <i class="ri-money-dollar-circle-line text-primary"></i>
  414.                                     </span>
  415.                                 </div>
  416.                             </div>
  417.                             <div class="mt-4">
  418.                                 <h4 class="dashboard-kpi-value ff-secondary mb-2">{{ totals.total|number_format(3, '.', ' ') }} DT</h4>
  419.                                 <p class="dashboard-kpi-copy mb-0">Total TTC des documents.</p>
  420.                             </div>
  421.                         </div>
  422.                     </div>
  423.                 </div>
  424.                 <div class="col-xl-3 col-md-6">
  425.                     <div class="card card-animate dashboard-kpi-card metric-success">
  426.                         <div class="card-body">
  427.                             <div class="d-flex align-items-center">
  428.                                 <div class="flex-grow-1 overflow-hidden">
  429.                                     <p class="dashboard-kpi-label text-truncate mb-0">Montant paye</p>
  430.                                 </div>
  431.                                 <div class="avatar-sm flex-shrink-0">
  432.                                     <span class="avatar-title dashboard-icon-badge bg-soft-success fs-3">
  433.                                         <i class="ri-checkbox-circle-line text-success"></i>
  434.                                     </span>
  435.                                 </div>
  436.                             </div>
  437.                             <div class="mt-4">
  438.                                 <h4 class="dashboard-kpi-value ff-secondary mb-2">{{ totals.paid|number_format(3, '.', ' ') }} DT</h4>
  439.                                 <p class="dashboard-kpi-copy mb-0">Montant deja regle.</p>
  440.                             </div>
  441.                         </div>
  442.                     </div>
  443.                 </div>
  444.                 <div class="col-xl-3 col-md-6">
  445.                     <div class="card card-animate dashboard-kpi-card metric-danger">
  446.                         <div class="card-body">
  447.                             <div class="d-flex align-items-center">
  448.                                 <div class="flex-grow-1 overflow-hidden">
  449.                                     <p class="dashboard-kpi-label text-truncate mb-0">Reste a payer</p>
  450.                                 </div>
  451.                                 <div class="avatar-sm flex-shrink-0">
  452.                                     <span class="avatar-title dashboard-icon-badge bg-soft-danger fs-3">
  453.                                         <i class="ri-error-warning-line text-danger"></i>
  454.                                     </span>
  455.                                 </div>
  456.                             </div>
  457.                             <div class="mt-4">
  458.                                 <h4 class="dashboard-kpi-value ff-secondary mb-2">{{ totals.remaining|number_format(3, '.', ' ') }} DT</h4>
  459.                                 <p class="dashboard-kpi-copy mb-0">Somme restante sur la selection.</p>
  460.                             </div>
  461.                         </div>
  462.                     </div>
  463.                 </div>
  464.             </div>
  465.             <div class="row">
  466.                 {% for key, item in stats %}
  467.                     {% set paidPercent = item.total > 0 ? ((item.paid / item.total) * 100)|round(0, 'floor') : 0 %}
  468.                     {% set paidPercent = paidPercent > 100 ? 100 : paidPercent %}
  469.                     {% set remainingPercent = 100 - paidPercent %}
  470.                     <div class="col-xl-3 col-md-6">
  471.                         <div class="card dashboard-type-card">
  472.                             <div class="card-body">
  473.                                 <div class="d-flex align-items-center mb-3">
  474.                                     <div class="avatar-sm flex-shrink-0 me-3">
  475.                                         <span class="avatar-title dashboard-icon-badge bg-soft-{{ item.color }} text-{{ item.color }} fs-3">
  476.                                             <i class="{{ item.icon }}"></i>
  477.                                         </span>
  478.                                     </div>
  479.                                     <div class="flex-grow-1">
  480.                                         <h5 class="mb-1">{{ item.label }}</h5>
  481.                                         <p class="dashboard-type-meta mb-0">{{ item.count }} document{{ item.count > 1 ? 's' : '' }}</p>
  482.                                     </div>
  483.                                 </div>
  484.                                 <p class="dashboard-type-label mb-1">Reste a payer</p>
  485.                                 <h4 class="dashboard-type-value mb-2">{{ item.remaining|number_format(3, '.', ' ') }} DT</h4>
  486.                                 <div class="d-flex justify-content-between dashboard-type-meta">
  487.                                     <span>Total: {{ item.total|number_format(3, '.', ' ') }}</span>
  488.                                     <span>Paye: {{ item.paid|number_format(3, '.', ' ') }}</span>
  489.                                 </div>
  490.                                 <div class="dashboard-progress mt-3" aria-label="Progression paiement {{ item.shortLabel }}">
  491.                                     <span class="dashboard-progress-paid" style="width: {{ paidPercent }}%"></span>
  492.                                     <span class="dashboard-progress-remaining" style="width: {{ remainingPercent }}%"></span>
  493.                                 </div>
  494.                                 <div class="d-flex justify-content-between dashboard-type-meta mt-2">
  495.                                     <span>{{ paidPercent }}% paye</span>
  496.                                     <span>{{ remainingPercent }}% reste</span>
  497.                                 </div>
  498.                                 <div class="mt-3">
  499.                                     <a href="{{ path(item.route) }}" class="link-{{ item.color }}">
  500.                                         Voir la liste <i class="ri-arrow-right-line align-bottom"></i>
  501.                                     </a>
  502.                                 </div>
  503.                             </div>
  504.                         </div>
  505.                     </div>
  506.                 {% endfor %}
  507.             </div>
  508.             <div class="row">
  509.                 <div class="col-xl-8">
  510.                     <div class="card dashboard-chart-card">
  511.                         <div class="card-header">
  512.                             <h4 class="card-title mb-1">Reste a payer par type</h4>
  513.                             <p class="text-muted mb-0">Comparaison entre total TTC, montant paye et reste.</p>
  514.                         </div>
  515.                         <div class="card-body">
  516.                             <div id="dashboard_reste_bar" class="apex-charts" style="min-height: 330px;"></div>
  517.                         </div>
  518.                     </div>
  519.                 </div>
  520.                 <div class="col-xl-4">
  521.                     <div class="card dashboard-chart-card">
  522.                         <div class="card-header">
  523.                             <h4 class="card-title mb-1">Repartition du reste</h4>
  524.                             <p class="text-muted mb-0">Poids de chaque type dans le montant restant.</p>
  525.                         </div>
  526.                         <div class="card-body">
  527.                             <div id="dashboard_reste_donut" class="apex-charts" style="min-height: 330px;"></div>
  528.                         </div>
  529.                     </div>
  530.                 </div>
  531.             </div>
  532.             <div class="row">
  533.                 <div class="col-12">
  534.                     <div class="card dashboard-table-card">
  535.                         <div class="card-header d-flex flex-column flex-lg-row align-items-lg-center justify-content-between gap-2">
  536.                             <div>
  537.                                 <h4 class="card-title mb-1">Documents avec reste a payer</h4>
  538.                                 <p class="text-muted mb-0">15 lignes visibles, puis defilement vertical pour le reste.</p>
  539.                             </div>
  540.                             <div class="d-flex flex-wrap align-items-center gap-2">
  541.                                 {% if filters.type %}
  542.                                     <span class="badge bg-soft-info text-info">Type: {{ stats[filters.type].shortLabel }}</span>
  543.                                 {% endif %}
  544.                                 {% if filters.unpaid_only %}
  545.                                     <span class="badge bg-soft-danger text-danger">Non payés seulement</span>
  546.                                 {% endif %}
  547.                                 <span class="badge bg-soft-primary text-primary">{{ documents|length }} ligne{{ documents|length > 1 ? 's' : '' }}</span>
  548.                             </div>
  549.                         </div>
  550.                         <div class="card-body">
  551.                             <div class="table-responsive dashboard-table-scroll">
  552.                                 <table class="table table-hover table-nowrap align-middle">
  553.                                     <thead class="table-light">
  554.                                     <tr>
  555.                                         <th>Type</th>
  556.                                         <th>Numero</th>
  557.                                         <th>Date</th>
  558.                                         <th>Client</th>
  559.                                         <th class="text-end">Total TTC</th>
  560.                                         <th class="text-end">Paye</th>
  561.                                         <th class="text-end">Reste a payer</th>
  562.                                         <th class="text-end">Action</th>
  563.                                     </tr>
  564.                                     </thead>
  565.                                     <tbody>
  566.                                     {% for document in documents %}
  567.                                         <tr>
  568.                                             <td>
  569.                                                 <span class="badge bg-soft-{{ document.typeColor }} text-{{ document.typeColor }}">{{ document.typeLabel }}</span>
  570.                                             </td>
  571.                                             <td class="fw-medium">{{ document.number }}</td>
  572.                                             <td>{{ document.date ? document.date|date('d/m/Y') : '-' }}</td>
  573.                                             <td class="dashboard-client-cell">{{ document.client }}</td>
  574.                                             <td class="text-end dashboard-money">{{ document.total|number_format(3, '.', ' ') }} DT</td>
  575.                                             <td class="text-end text-success dashboard-money">{{ document.paid|number_format(3, '.', ' ') }} DT</td>
  576.                                             <td class="text-end fw-semibold text-danger dashboard-money">{{ document.remaining|number_format(3, '.', ' ') }} DT</td>
  577.                                             <td class="text-end">
  578.                                                 <a href="{{ document.url }}" class="btn btn-sm btn-soft-primary">
  579.                                                     Voir
  580.                                                 </a>
  581.                                             </td>
  582.                                         </tr>
  583.                                     {% else %}
  584.                                         <tr>
  585.                                             <td colspan="8" class="text-center dashboard-empty-state">
  586.                                                 <div class="fs-2 mb-2"><i class="ri-search-eye-line"></i></div>
  587.                                                 <div class="fw-semibold">Aucun document trouve</div>
  588.                                                 <div class="small">Changez la periode, le client ou le type de fichier.</div>
  589.                                             </td>
  590.                                         </tr>
  591.                                     {% endfor %}
  592.                                     </tbody>
  593.                                 </table>
  594.                             </div>
  595.                         </div>
  596.                     </div>
  597.                 </div>
  598.             </div>
  599.         </div>
  600.     </div>
  601.     <script>
  602.         document.addEventListener('DOMContentLoaded', function () {
  603.             var dateRangeInput = document.getElementById('dateRangePicker');
  604.             var datePickerButton = document.getElementById('datePickerButton');
  605.             if (dateRangeInput && typeof flatpickr !== 'undefined') {
  606.                 var datePickerInstance = flatpickr(dateRangeInput, {
  607.                     mode: 'range',
  608.                     dateFormat: 'Y-m-d',
  609.                     allowInput: true
  610.                 });
  611.                 if (datePickerButton) {
  612.                     datePickerButton.addEventListener('click', function () {
  613.                         datePickerInstance.open();
  614.                     });
  615.                 }
  616.             }
  617.             if (window.jQuery && jQuery.fn.select2) {
  618.                 jQuery('#dashboard_client').select2({
  619.                     width: '100%',
  620.                     placeholder: 'Tous les clients',
  621.                     allowClear: true
  622.                 });
  623.                 jQuery('#dashboard_type').select2({
  624.                     width: '100%',
  625.                     minimumResultsForSearch: Infinity
  626.                 });
  627.             }
  628.             if (typeof ApexCharts === 'undefined') {
  629.                 return;
  630.             }
  631.             var labels = {{ chart.labels|json_encode|raw }};
  632.             var remaining = {{ chart.remaining|json_encode|raw }};
  633.             var paid = {{ chart.paid|json_encode|raw }};
  634.             var total = {{ chart.total|json_encode|raw }};
  635.             var colors = ['#405189', '#0ab39c', '#f7b84b', '#f06548'];
  636.             var barElement = document.querySelector('#dashboard_reste_bar');
  637.             if (barElement) {
  638.                 new ApexCharts(barElement, {
  639.                     series: [
  640.                         {name: 'Reste a payer', data: remaining},
  641.                         {name: 'Montant paye', data: paid},
  642.                         {name: 'Total TTC', data: total}
  643.                     ],
  644.                     chart: {
  645.                         type: 'bar',
  646.                         height: 330,
  647.                         fontFamily: 'inherit',
  648.                         foreColor: '#74788d',
  649.                         toolbar: {show: false}
  650.                     },
  651.                     grid: {
  652.                         borderColor: '#edf1f7',
  653.                         strokeDashArray: 4
  654.                     },
  655.                     plotOptions: {
  656.                         bar: {
  657.                             borderRadius: 6,
  658.                             columnWidth: '42%'
  659.                         }
  660.                     },
  661.                     dataLabels: {enabled: false},
  662.                     colors: ['#f06548', '#0ab39c', '#405189'],
  663.                     xaxis: {
  664.                         categories: labels,
  665.                         axisBorder: {show: false},
  666.                         axisTicks: {show: false}
  667.                     },
  668.                     yaxis: {
  669.                         labels: {
  670.                             formatter: function (value) {
  671.                                 return Number(value || 0).toFixed(3);
  672.                             }
  673.                         }
  674.                     },
  675.                     tooltip: {
  676.                         theme: 'light',
  677.                         y: {
  678.                             formatter: function (value) {
  679.                                 return Number(value || 0).toFixed(3) + ' DT';
  680.                             }
  681.                         }
  682.                     },
  683.                     legend: {
  684.                         horizontalAlign: 'right',
  685.                         markers: {radius: 99},
  686.                         position: 'top'
  687.                     }
  688.                 }).render();
  689.             }
  690.             var donutElement = document.querySelector('#dashboard_reste_donut');
  691.             if (donutElement) {
  692.                 new ApexCharts(donutElement, {
  693.                     series: remaining,
  694.                     labels: labels,
  695.                     chart: {
  696.                         type: 'donut',
  697.                         height: 330,
  698.                         fontFamily: 'inherit',
  699.                         foreColor: '#74788d'
  700.                     },
  701.                     colors: colors,
  702.                     dataLabels: {
  703.                         dropShadow: {enabled: false}
  704.                     },
  705.                     plotOptions: {
  706.                         pie: {
  707.                             donut: {
  708.                                 size: '68%',
  709.                                 labels: {
  710.                                     show: true,
  711.                                     total: {
  712.                                         show: true,
  713.                                         label: 'Reste',
  714.                                         formatter: function (w) {
  715.                                             var sum = w.globals.seriesTotals.reduce(function (a, b) {
  716.                                                 return a + b;
  717.                                             }, 0);
  718.                                             return Number(sum || 0).toFixed(3) + ' DT';
  719.                                         }
  720.                                     },
  721.                                     value: {
  722.                                         formatter: function (value) {
  723.                                             return Number(value || 0).toFixed(3);
  724.                                         }
  725.                                     }
  726.                                 }
  727.                             }
  728.                         }
  729.                     },
  730.                     stroke: {width: 0},
  731.                     legend: {
  732.                         markers: {radius: 99},
  733.                         position: 'bottom'
  734.                     },
  735.                     tooltip: {
  736.                         y: {
  737.                             formatter: function (value) {
  738.                                 return Number(value || 0).toFixed(3) + ' DT';
  739.                             }
  740.                         }
  741.                     },
  742.                     noData: {
  743.                         text: 'Aucune donnee'
  744.                     }
  745.                 }).render();
  746.             }
  747.         });
  748.     </script>
  749. {% endblock %}