Files
crm_ecosplay/src/Command/CheckNddCommand.php
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

109 lines
3.6 KiB
PHP

<?php
namespace App\Command;
use App\Entity\Domain;
use App\Service\MailerService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Twig\Environment;
#[AsCommand(
name: 'app:ndd:check',
description: 'Verifie les dates expiration des noms de domaine et envoie un mail groupe (<= 30 jours)',
)]
class CheckNddCommand extends Command
{
private const EXPIRATION_THRESHOLD_DAYS = 30;
private const MONITOR_EMAIL = 'monitor@e-cosplay.fr';
public function __construct(
private EntityManagerInterface $em,
private MailerService $mailer,
private Environment $twig,
private LoggerInterface $logger,
) {
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$io->title('Verification expiration des noms de domaine');
$now = new \DateTimeImmutable();
$limit = $now->modify('+'.self::EXPIRATION_THRESHOLD_DAYS.' days');
/** @var Domain[] $domains */
$domains = $this->em->createQueryBuilder()
->select('d')
->from(Domain::class, 'd')
->where('d.expiredAt IS NOT NULL')
->andWhere('d.expiredAt <= :limit')
->orderBy('d.expiredAt', 'ASC')
->setParameter('limit', $limit)
->getQuery()
->getResult();
$items = [];
foreach ($domains as $domain) {
$customer = $domain->getCustomer();
$diff = $now->diff($domain->getExpiredAt());
$days = (int) $diff->format('%r%a');
$items[] = [
'fqdn' => $domain->getFqdn(),
'registrar' => $domain->getRegistrar(),
'customerName' => $customer->getFullName(),
'customerEmail' => $customer->getEmail(),
'expiredAt' => $domain->getExpiredAt(),
'daysLeft' => $days,
'isExpired' => $days < 0,
];
$io->text(sprintf(' %s -> %s (%d j)', $domain->getFqdn(), $customer->getEmail() ?? '-', $days));
}
if ([] === $items) {
$subject = 'Nom de domaine - Aucune expiration prochaine';
$message = 'Aucun nom de domaine en expiration.';
} else {
$subject = 'Nom de domaine - '.\count($items).' expiration(s) prochaine(s)';
$message = null;
}
try {
$html = $this->twig->render('emails/ndd_expiration.html.twig', [
'domains' => $items,
'message' => $message,
'thresholdDays' => self::EXPIRATION_THRESHOLD_DAYS,
]);
$this->mailer->sendEmail(
self::MONITOR_EMAIL,
$subject,
$html,
null,
null,
false,
);
} catch (\Throwable $e) {
$this->logger->error('CheckNdd: erreur envoi mail: '.$e->getMessage());
$io->error('Erreur envoi mail : '.$e->getMessage());
return Command::FAILURE;
}
if ([] === $items) {
$io->success('Aucun nom de domaine en expiration. Rapport envoye a '.self::MONITOR_EMAIL);
} else {
$io->success(\count($items).' domaine(s) en expiration. Rapport envoye a '.self::MONITOR_EMAIL);
}
return Command::SUCCESS;
}
}