Files
crm_ecosplay/templates/status/index.html.twig
Serreau Jovann 8b35e2b6d2 feat: comptabilite + prestataires + rapport financier + stats dynamiques
Comptabilite (Super Admin) :
- ComptabiliteController avec 7 exports CSV/JSON compatibles SAGE
  (journal ventes, grand livre, FEC, balance agee, reglements,
  commissions Stripe 1.5%+0.25E, couts services)
- Export PDF via ComptaPdf (FPDF) avec bloc legal pre-rempli,
  tableau pagine, champ signature DocuSeal
- Signature electronique DocuSeal + callback + envoi email signe
  avec template dedie (compta_export_signed.html.twig)
- Rapport financier public (RapportFinancierPdf) : recettes par
  service, depenses (Stripe, infra, prestataires), bilan excedent/deficit
- Codes comptables clients EC-XXXX (plus de 411xxx)

Prestataires (Super Admin) :
- Entite Prestataire (raisonSociale, siret, email, phone, adresse)
- Entite FacturePrestataire (numFacture, montantHt, montantTtc,
  year, month, isPaid, PDF via Vich)
- CRUD complet avec recherche SIRET via proxy API data.gouv.fr
- Commande cron app:reminder:factures-prestataire (5 du mois)
- Factures prestataires integrees dans export couts services
- Sidebar Super Admin : entree Prestataires + Comptabilite

Stats (/admin/stats) :
- Cout prestataire dynamique depuis FacturePrestataire
- Fusion Infra + Prestataire en "Cout de fonctionnement"
- Commission Stripe corrigee (1.5% + 0.25E par transaction)

Divers :
- DocuSealService::sendComptaForSignature() + getApi()
- Customer::generateCodeComptable() format EC-XXXX-XXXXX
- Protection double prefixe EC- a la creation client
- Bouton regenerer PDF cache quand advert state=accepted
- Modals sans script inline (data-modal-open/close dans app.js)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 23:39:31 +02:00

189 lines
11 KiB
Twig

{% extends 'legal/_layout.html.twig' %}
{% block title %}Status des services - E-Cosplay{% endblock %}
{% block description %}Etat en temps reel des services proposes par la Association E-Cosplay.{% endblock %}
{% block body %}
<div class="page-container">
{# Banner global #}
<div class="mb-8 p-6 glass text-center
{% if globalStatus == 'up' %}bg-green-50
{% elseif globalStatus == 'degraded' %}bg-yellow-50
{% elseif globalStatus == 'down' %}bg-red-50
{% else %}bg-blue-50
{% endif %}
">
<div class="flex items-center justify-center gap-3 mb-2">
<span class="w-4 h-4
{% if globalStatus == 'up' %}bg-green-500
{% elseif globalStatus == 'degraded' %}bg-yellow-500
{% elseif globalStatus == 'down' %}bg-red-500
{% else %}bg-blue-500
{% endif %}
"></span>
<h1 class="text-2xl font-bold">
{% if globalStatus == 'up' %}Tous les systemes sont operationnels
{% elseif globalStatus == 'degraded' %}Performances degradees
{% elseif globalStatus == 'down' %}Incident en cours
{% else %}Maintenance en cours
{% endif %}
</h1>
</div>
<p class="text-xs text-gray-500">Derniere verification : {{ "now"|date('d/m/Y a H:i') }}</p>
</div>
{# Messages globaux actifs #}
{% if globalMessages|length > 0 %}
<div class="mb-8 flex flex-col gap-3">
{% for msg in globalMessages %}
<div class="p-4 border-2
{% if msg.severity == 'critical' %}border-red-600 bg-red-50
{% elseif msg.severity == 'warning' %}border-yellow-600 bg-yellow-50
{% else %}border-blue-600 bg-blue-50
{% endif %}
">
<div class="flex items-center gap-2 mb-1">
<span class="px-2 py-0.5 font-bold uppercase text-[10px] tracking-widest
{% if msg.severity == 'critical' %}bg-red-600 text-white
{% elseif msg.severity == 'warning' %}bg-yellow-600 text-white
{% else %}bg-blue-600 text-white
{% endif %}
">{{ msg.severity }}</span>
<span class="font-bold text-sm">{{ msg.title }}</span>
<span class="text-[10px] text-gray-400 ml-auto">{{ msg.createdAt|date('d/m/Y H:i') }}</span>
</div>
<p class="text-xs text-gray-700">{{ msg.content }}</p>
{% if msg.author %}
<p class="text-[10px] text-gray-400 mt-1">Par {{ msg.author.fullName }}</p>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
<div class="flex flex-col gap-8">
{% for data in servicesData %}
<section>
<h2 class="text-xl font-bold uppercase mb-4">{{ data.category.name }}</h2>
<div class="flex flex-col gap-4">
{% for item in data.services %}
{% set service = item.service %}
{% set uptime = item.uptime %}
{% set dailyStatus = item.dailyStatus %}
<div class="glass">
{# Header service #}
<div class="flex items-center justify-between px-4 py-3">
<div class="flex items-center gap-3">
<span class="w-3 h-3 flex-shrink-0
{% if service.status == 'up' %}bg-green-500
{% elseif service.status == 'degraded' %}bg-yellow-500
{% elseif service.status == 'down' %}bg-red-500
{% elseif service.status == 'maintenance' %}bg-blue-500
{% else %}bg-gray-400
{% endif %}
"></span>
<span class="font-bold text-sm uppercase">{{ service.name }}</span>
{% if service.external %}
<span class="px-1.5 py-0.5 bg-gray-100 text-gray-500 text-[8px] font-bold uppercase">Externe</span>
{% endif %}
</div>
<div class="flex items-center gap-3">
<span class="px-2 py-0.5 font-bold uppercase text-[10px] tracking-widest
{% if service.status == 'up' %}bg-green-100 text-green-800
{% elseif service.status == 'degraded' %}bg-yellow-100 text-yellow-800
{% elseif service.status == 'down' %}bg-red-100 text-red-800
{% elseif service.status == 'maintenance' %}bg-blue-100 text-blue-800
{% else %}bg-gray-100 text-gray-600
{% endif %}
">
{% if service.status == 'up' %}Operationnel
{% elseif service.status == 'degraded' %}Degrade
{% elseif service.status == 'down' %}Hors service
{% elseif service.status == 'maintenance' %}Maintenance
{% else %}Bientot
{% endif %}
</span>
<span class="text-xs font-bold {{ uptime >= 99 ? 'text-green-600' : (uptime >= 95 ? 'text-yellow-600' : 'text-red-600') }}">{{ uptime }}%</span>
</div>
</div>
{# Message service #}
{% if service.message %}
<div class="px-4 py-2 bg-gray-50 text-xs text-gray-600 border-t border-gray-200">
{{ service.message }}
</div>
{% endif %}
{# Messages actifs #}
{% for msg in item.messages %}
<div class="px-4 py-2 border-t text-xs
{% if msg.severity == 'critical' %}border-red-200 bg-red-50 text-red-700
{% elseif msg.severity == 'warning' %}border-yellow-200 bg-yellow-50 text-yellow-700
{% else %}border-blue-200 bg-blue-50 text-blue-700
{% endif %}
">
<strong>{{ msg.title }}</strong> — {{ msg.content }}
<span class="text-[10px] opacity-70 ml-1">{{ msg.createdAt|date('H:i') }}</span>
</div>
{% endfor %}
{# Graphique 30 jours #}
<div class="px-4 py-2 border-t border-gray-200 flex items-center gap-[2px]">
{% for day in dailyStatus %}
<div class="flex-1 h-5
{% if day.status == 'up' %}bg-green-400
{% elseif day.status == 'degraded' %}bg-yellow-400
{% elseif day.status == 'down' %}bg-red-400
{% elseif day.status == 'maintenance' %}bg-blue-400
{% else %}bg-gray-300
{% endif %}
" title="{{ day.date }} : {{ day.status }}"></div>
{% endfor %}
</div>
<div class="px-4 pb-1 flex justify-between text-[9px] text-gray-400">
<span>30 jours</span>
<span>Aujourd'hui</span>
</div>
{# Logs recents #}
{% if item.logs|length > 0 %}
<div class="px-4 py-2 border-t border-gray-200">
<p class="text-[9px] font-bold uppercase tracking-wider text-gray-400 mb-1">Historique (7j)</p>
{% for log in item.logs %}
<div class="flex items-center gap-2 text-[10px] text-gray-500 py-0.5">
<span class="text-gray-400">{{ log.createdAt|date('d/m H:i') }}</span>
<span class="px-1 py-0.5 font-bold uppercase text-[8px]
{% if log.fromStatus == 'up' %}text-green-600
{% elseif log.fromStatus == 'down' %}text-red-600
{% else %}text-yellow-600
{% endif %}
">{{ log.fromStatus }}</span>
<span>&rarr;</span>
<span class="px-1 py-0.5 font-bold uppercase text-[8px]
{% if log.toStatus == 'up' %}text-green-600
{% elseif log.toStatus == 'down' %}text-red-600
{% else %}text-yellow-600
{% endif %}
">{{ log.toStatus }}</span>
<span class="text-gray-300">({{ log.source }})</span>
</div>
{% endfor %}
</div>
{% endif %}
</div>
{% endfor %}
</div>
</section>
{% else %}
<p class="text-gray-400 text-sm font-bold">Aucun service configure.</p>
{% endfor %}
</div>
<div class="mt-8 text-center text-xs text-gray-400">
<p>Page de status — <a href="https://www.e-cosplay.fr" class="underline hover:text-gray-600">Association E-Cosplay</a></p>
</div>
</div>
{% endblock %}