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>
109 lines
3.6 KiB
PHP
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;
|
|
}
|
|
}
|