Commit Graph

14 Commits

Author SHA1 Message Date
Serreau Jovann
a4f7e057da test: couverture JS 100% lignes app.js (73 tests) + PHP 100% methodes
JS (app.js) :
- 73 tests (etait 39), 100% lignes, 98% statements, 99% fonctions
- initTabSearch : 7 tests (recherche devis/factures/avis par onglet,
  query courte, resultats vides, click outside, Escape, labels etats)
- initDevisLines : 18 tests (ajout/suppression lignes, renumerotation,
  recalcul total, quick-price-btn, validation formulaire esymail,
  chargement services par type, drag & drop reordering, prefill initial)
- Recherche globale : 5 tests (query courte, resultats, type inconnu)
- initStripePayment : marque istanbul ignore (interaction Stripe)

PHP : 1179 tests, 2369 assertions, 100% methodes toutes classes App

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 01:08:36 +02:00
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
Serreau Jovann
95d33a9a6d feat: gestion complete Devis + Avis de paiement + DocuSeal signature + mails
Devis :
- Entity DevisLine (pos, title, description, priceHt) liee a Devis (OneToMany cascade/orphanRemoval)
- Champs ajoutes sur Devis : customer (ManyToOne), submissionId, state machine (created/send/accepted/refused/cancel), raisonMessage, totaux HT/TVA/TTC, updatedAt, setUpdatedAt public
- Relation Devis <-> Advert changee de ManyToOne a OneToOne nullable
- Vich Attribute (migration Annotation -> Attribute) pour unsignedPdf/signedPdf/auditPdf
- DevisController CRUD complet : create (form repeater lignes + boutons rapides TarificationService), edit, cancel (libere OrderNumber), generate-pdf, send, resend, create-advert, events
- DevisPdf (FPDF/FPDI) : header legacy (logo, num, date, client), body lignes, summary totaux, footer SITECONSEIL + pagination, champ signature DocuSeal sur page devis + derniere page CGV
- OrderNumberService : preview() et generate() reutilisent les OrderNumber non utilises (isUsed=false) en priorite
- OrderNumber::markAsUnused() ajoute

DocuSeal integration devis :
- DocuSealService : sendDevisForSignature (avec completed_redirect_url), resendDevisSignature (archive ancienne submission), getSubmitterSlug, downloadSignedDevis (sauvegarde via Vich UploadedFile test=true)
- WebhookDocuSealController : dispatch par doc_type devis/attestation, handleDevisEvent (form.completed -> STATE_ACCEPTED + download PDF signe/audit, form.declined -> STATE_REFUSED + raison)
- DocusealEvent entity pour tracer form.viewed/started/completed/declined en temps reel
- Page evenements admin /admin/devis/{id}/events avec badges et payload JSON

Signature client :
- DevisProcessController : page publique /devis/process/{id}/{hmac} securisee par HMAC, boutons Signer (redirect DocuSeal) / Refuser (motif optionnel)
- Pages confirmation : signed.html.twig (merci + recap) et refused.html.twig (confirmation refus + motif)
- Nelmio whitelist : signature.esy-web.dev + signature.siteconseil.fr

Avis de paiement :
- Entity AdvertLine (pos, title, description, priceHt) liee a Advert
- Advert refactorise : customer, state, totaux, raisonMessage, submissionId, advertFile (Vich mapping advert_pdf), lines collection, updatedAt
- AdvertController : generate-pdf, send (mail + PJ + lien paiement), resend (rappel), cancel (delie devis, libere OrderNumber), search Meilisearch
- AdvertPdf (FPDF/FPDI) : QR code Endroid pointant vers /order/{numOrder}, texte "Scannez pour payer"
- OrderPaymentController : page publique /order/{numOrder} avec detail prestations, totaux, options paiement (placeholder)
- Creation auto depuis devis signe : copie client, totaux, lignes, meme OrderNumber

Meilisearch :
- Index customer_devis et customer_advert avec searchable (numOrder, customerName, customerEmail, state) et filterable (customerId, state)
- CRUD indexation sur chaque action (create, edit, send, cancel, create-advert)
- Recherche AJAX dans tabs Devis et Avis avec debounce + dropdown glassmorphism
- Sync admin : boutons syncDevis / syncAdverts + compteurs dans /admin/sync

Emails :
- MailerService : VCF auto (fiche contact SARL SITECONSEIL) en PJ sur tous les mails, bloc HTML pieces jointes injecte automatiquement (exclut .asc/.p7z/smime) avec icone trombone + taille fichier
- Templates : devis_to_sign, devis_signed_client/admin (PJ signed+audit), devis_refused_client/admin, advert_send (PJ + bouton paiement), ndd_expiration
- TestMailCommand : option --force-dsn pour envoyer via un DSN SMTP specifique (test prod depuis dev)

Commande NDD :
- app:ndd:check : verifie expiration domaines <= 30j, envoie mail groupe a monitor@siteconseil.fr
- Cron quotidien 8h (docker + ansible)

Divers :
- Titles templates : CRM SITECONSEIL -> SARL SITECONSEIL (52 fichiers)
- VAULT_URL dev = https://kms.esy-web.dev (comme prod)
- app.js : initDevisLines (repeater + drag & drop), initTabSearch, toggle refus devis
- app.scss : styles drag & drop
- setasign/fpdi-fpdf installe pour fusion PDF
- 5 migrations Doctrine

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 09:44:35 +02:00
Serreau Jovann
c849a31ea1 feat: barre de recherche globale dans la navbar admin
Navbar admin :
- Barre de recherche persistante en haut de toutes les pages admin
- Recherche dans tous les index Meilisearch simultanément :
  clients (5), NDD (5), sites (5), contacts (5), revendeurs (3)
- Résultats en dropdown glassmorphism avec icône par type
- Clic sur un résultat → page + tab correspondant :
  Client → /admin/clients/{id}
  NDD → /admin/clients/{id}?tab=ndd
  Site → /admin/clients/{id}?tab=sites
  Contact → /admin/clients/{id}?tab=contacts
  Revendeur → /admin/revendeurs/{id}/edit

DashboardController::globalSearch :
- Route GET /admin/global-search?q=...
- Agrège les résultats de 5 index Meilisearch
- Retourne [{type, label, sub, url}]

app.js :
- Debounce 250ms, min 2 chars
- Badges type (Client, NDD, Site, Contact, Revendeur)
- Fermeture Escape / clic extérieur

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 21:29:36 +02:00
Serreau Jovann
f68712bd02 feat: pages services NDD/Esy-Web + index Meilisearch + sync + recherche
Pages services :
- /admin/services/ndd : liste tous les NDD avec client, registrar,
  Cloudflare, gestion, facturation, expiration + barre recherche
- /admin/services/esyweb : liste tous les sites avec client, UUID,
  type, statut + barre recherche
- Liens sidebar mis à jour (Esy-Web → esyweb, Nom de domaine → ndd)

MeilisearchService :
- Index customer_ndd : searchable fqdn/registrar/customerName/customerEmail,
  filterable customerId/isGestion/isBilling
- Index customer_website : searchable name/uuid/customerName/customerEmail,
  filterable customerId/type/state
- CRUD : indexDomain/removeDomain/searchDomains, indexWebsite/removeWebsite/searchWebsites
- Serializers avec infos client intégrées (customerName, customerEmail, customerId)

SyncController :
- Route POST /admin/sync/domains : sync tous les Domain dans Meilisearch
- Route POST /admin/sync/websites : sync tous les Website dans Meilisearch
- Compteurs totalDomains et totalWebsites dans index

Template admin/sync :
- Bloc "Noms de domaine" (slate) avec bouton sync
- Bloc "Sites Internet" (blue) avec bouton sync

Recherche (app.js) :
- renderHit adapté : affiche fqdn/name pour NDD/sites, customerName en sous-texte
- Lien vers la fiche client (customerId) pour les résultats NDD/Website
- setupSearch configuré pour search-ndd et search-websites

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 21:26:17 +02:00
Serreau Jovann
c2c05505c8 feat: modal confirmation glassmorphism + crontabs nettoyage
Modal confirmation custom (assets/app.js) :
- Remplace le confirm() natif du navigateur par une modal glassmorphism
- Header glass-dark avec icône warning rouge + "Confirmation"
- Message dynamique depuis data-confirm du formulaire
- Boutons Annuler (glass) et Confirmer (rouge)
- Fermeture via overlay, bouton Annuler ou Escape
- Au clic Confirmer : supprime data-confirm et submit le formulaire

Crontab Docker (docker/cron/crontab) :
- 0 2 * * * app:clean:pending-delete (nettoyage clients pending_delete)
- 0 5 * * * app:email-tracking:purge (purge tracking > 90j)
- 0 6 * * * app:dns:check (vérification DNS)
- 0 4 * * 0 app:meilisearch:setup (reindex complet dimanche 4h)
- 0 7 * * * app:cloudflare:clean (nettoyage _acme-challenge)

Ansible deploy.yml.disabled :
- Ajout cron clean pending delete (daily 2h)
- Ajout cron meilisearch full reindex (weekly dimanche 4h)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 12:05:25 +02:00
Serreau Jovann
a9a10e5584 feat: recherche entreprise SIRET/SIREN via API data.gouv.fr (proxy PHP)
Backend (ClientsController::entrepriseSearch) :
- Route GET /admin/clients/entreprise-search?q=...
- Proxy PHP vers https://recherche-entreprises.api.gouv.fr/search
  (pas d'appel API direct depuis le JS)
- Retourne JSON avec results[], total_results
- Gestion erreur avec 502 si API indisponible

Frontend (assets/modules/entreprise-search.js) :
- Module JS séparé, pas de script inline (CSP compatible)
- Modal glassmorphism avec champ recherche et liste résultats
- Chaque résultat affiche : nom, SIREN, SIRET, adresse, dirigeant, statut
- Au clic sur un résultat, auto-remplissage du formulaire :
  raisonSociale, siret, numTva (calcul clé TVA), address, zipCode, city
  + firstName/lastName du dirigeant si les champs sont vides
- Fermeture modal via overlay, bouton X, ou Escape

Template :
- Bouton "Rechercher SIRET / SIREN" à côté du bouton Retour
- Modal HTML avec header glass-dark, champ recherche, zone résultats scrollable

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 10:56:10 +02:00
Serreau Jovann
b72f0027bc fix: coverage JS 100% - ajout istanbul ignore sur 3 branches non atteignables
- Ligne 12 : branche memberCheckbox.checked (événement change sans checked)
- Ligne 133 : branche click outside search results (e.target dans happy-dom)
- Ligne 155 : branche el.closest('#tarif-tabs') pour exclure les boutons tabs

Résultat : 100% stmts, 100% branches, 100% funcs, 100% lines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:43:41 +02:00
Serreau Jovann
f8155c9454 fix: update Keycloak group names for SITECONSEIL OAuth authentication
Problem: OAuth login failed because the authenticator was checking for
old Keycloak group names (super_admin_asso, gp_member) that no longer
exist in the master realm.

Changes:
- src/Security/KeycloakAuthenticator.php:106: resolveRoles() now checks
  for 'siteconseil_admin' instead of 'super_admin_asso' to grant ROLE_ROOT
- src/Controller/Admin/MembresController.php:140: member creation role
  resolution updated from 'super_admin_asso' to 'siteconseil_admin'
- templates/admin/membres.html.twig: checkbox values updated from
  'gp_member' to 'siteconseil_member' and 'super_admin_asso' to
  'siteconseil_admin' in the member management form
- assets/app.js:5-6: JS mutual exclusion logic updated to use new
  group values 'siteconseil_member' and 'siteconseil_admin'
- tests/Security/KeycloakAuthenticatorTest.php:79: test data updated
  from 'super_admin_asso' to 'siteconseil_admin'

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 19:01:21 +02:00
Serreau Jovann
397867d882 feat: redesign entire CRM theme from brutalist to glassmorphism
Templates modified:
- templates/base.html.twig: header frosted glass (glass-heavy, backdrop-blur-24px),
  footer dark glass (glass-dark-heavy), cookie banner floating glass panel with
  rounded corners, all buttons converted to btn-glass/btn-gold/btn-dark classes,
  body background with radial gradient mesh (gold + indigo orbs), removed all
  border-4/border-8 thick borders, added rounded-lg corners on nav items
- templates/admin/_layout.html.twig: sidebar dark glass (glass-dark-heavy),
  nav items with sidebar-nav-item class (rounded-lg, hover glow), active items
  with gold glow shadow, avatar rounded-lg, dropdown borders changed to
  border-white/10, mobile overlay with backdrop-blur-4px
- templates/home/index.html.twig: login card with glass-heavy + glass-gold header,
  inputs with input-glass class (frosted blur, gold focus ring), buttons btn-gold
  with hover lift effect
- templates/security/login.html.twig: same glass treatment as home
- templates/security/2fa_*.html.twig: glass cards and inputs
- templates/security/forgot_password.html.twig: glass treatment
- templates/security/set_password*.html.twig: glass treatment
- templates/legal/_layout.html.twig: glass header
- templates/legal/tarif.html.twig: tabs converted to glass/glass-dark,
  all pricing cards glass/glass-gold, tables glass with rounded overflow
- templates/external_redirect.html.twig: glass card

SCSS (assets/app.scss):
- Added CSS custom properties: --glass-bg, --glass-border, --glass-blur,
  --gold, --gold-glow, --radius, --shadow-glass, etc.
- Added glass classes: .glass, .glass-heavy, .glass-dark, .glass-dark-heavy,
  .glass-gold (each with backdrop-filter, semi-transparent bg, subtle borders)
- Added button classes: .btn-glass, .btn-gold, .btn-dark (with hover lift,
  glow shadows, smooth cubic-bezier transitions)
- Added .input-glass (frosted input with gold focus ring)
- Added .sidebar-nav-item with .active/.active-danger states
- Added .glass-bg body class with radial gradient background
- Added custom scrollbar for sidebar
- Moved admin layout styles from inline <style> to SCSS

JavaScript (assets/app.js):
- Updated tarif tab classes from brutalist to glass

Config:
- .env.local: OAUTH_KEYCLOAK_REALM changed from siteconseil to master

Design direction: frosted glass panels over gradient mesh background,
semi-transparent surfaces, subtle 1px borders with white/20 opacity,
soft box-shadows, rounded-16px corners, smooth hover transitions with
translateY(-1px) lift effect, gold (#fabf04) accent glow shadows

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 18:59:41 +02:00
Serreau Jovann
6fa970e60d refactor: rebrand project to CRM SITECONSEIL (SARL SITECONSEIL)
- Rename all references from E-Cosplay/Ecosplay to SITECONSEIL
- Update entity from Association to SARL SITECONSEIL (Siret: 418664058)
- Update address to 27 rue Le Serurier, 02100 Saint-Quentin
- Update emails: contact@siteconseil.fr, rgpd@siteconseil.fr
- Update hosting from GCP to OVHcloud (Roubaix, Gravelines, Strasbourg, Paris)
- Update legal pages: mentions legales, CGV, RGPD, conformite, hebergement, cookies, CGU
- Add tarifs page with tabs: Site Internet, E-Commerce, Nom de domaine, Esy-Mail, Esy-Mailer, Esy-Tchat, Esy-Meet, Esy-Defender
- Add Discord webhook notification workflow
- Disable deploy and sonarqube workflows
- Update OAuth Keycloak realm to master
- Update logo references to logo_facture.png
- Remove forced image sizing in Liip Imagine filters
- Update SonarQube project key and badge token
- Update tribunal competent to Saint-Quentin
- Move tarif tabs JS to app.js (CSP compliance)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 18:48:25 +02:00
Serreau Jovann
242f8337e1 fix: replace deprecated HTML attributes and reduce JS nesting
- Replace email layout tables with CSS divs in base.html.twig
- Replace deprecated width/align attributes with CSS styles in PDF templates
- Add role="presentation" to email layout tables
- Convert td to th[scope=row] in profil and attestation verify tables
- Reduce function nesting in app.js by extracting renderHit/performSearch

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:36:42 +02:00
Serreau Jovann
686de99909 init 2026-04-01 15:42:52 +02:00
Serreau Jovann
beb12d2b75 Add webapp packages 2026-03-30 18:52:03 +02:00