Thanasoft-Hytha/gestion/lib/Service/InvoicePdfService.php

699 lines
27 KiB
PHP

<?php
declare(strict_types=1);
/**
* Calendar App
*
* @copyright 2021 Anna Larch <anna.larch@gmx.net>
*
* @author Anna Larch <anna.larch@gmx.net>
* @author Richard Steinmetz <richard@steinmetz.cloud>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Gestion\Service;
use DateTime;
use Exception;
use OCA\Gestion\Db\Bdd;
use OCP\Files\IRootFolder;
use OCA\Gestion\Helpers\DateHelpers;
use OCA\Gestion\Constants\BddConstant;
use OCA\Gestion\Service\HtmlToPdfService;
use OCA\Gestion\Exception\TemplateException;
use OCA\Gestion\Constants\FactureTypeConstant;
use OCA\Gestion\Constants\DevisMentionConstant;
use OCA\Gestion\Constants\ClientTemplateTypeConstant;
use OCA\Gestion\Constants\MultipleFactureTypeConstant;
use OCA\Gestion\Service\InvoiceRecap\InvoiceRecapService;
use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceOgfPdfHandler;
use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceGroupPdfHandler;
use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceFunecapPdfHandler;
class InvoicePdfService
{
/** @var Bdd */
private $gestionBdd;
/** @var IRootFolder */
private $rootFolder;
/** @var InvoiceRecapService */
private $invoiceRecapService;
private $htmlToPdfService;
private const DEFAULT_NEXTCLOUD_ADMIN = "admin";
public function __construct(
Bdd $gestionBdd,
IRootFolder $rootFolder,
InvoiceRecapService $invoiceRecapService
) {
$this->gestionBdd = $gestionBdd;
$this->rootFolder = $rootFolder;
$this->invoiceRecapService = $invoiceRecapService;
$this->htmlToPdfService = new HtmlToPdfService();
}
private function getLogo()
{
$storage = $this->rootFolder->getUserFolder(self::DEFAULT_NEXTCLOUD_ADMIN);
try {
try {
if(isset($storage)) {
$file = $storage->get('/.gestion/logo.png');
} else {
return "nothing";
}
} catch(\OCP\Files\NotFoundException $e) {
$file = $storage->get('/.gestion/logo.jpeg');
}
} catch(\OCP\Files\NotFoundException $e) {
return "nothing";
}
return base64_encode($file->getContent());
}
private function generateFactureSinglePdfByFactureId($factureId, $idNextCloud)
{
$storage = $this->rootFolder->getUserFolder($idNextCloud);
$configs = json_decode($this->gestionBdd->getConfiguration(self::DEFAULT_NEXTCLOUD_ADMIN));
$currentConfig = $configs[0];
$logo = $this->getLogo();
$invoicePdfData = $this->gestionBdd->getInvoicePdfData($factureId, $currentConfig);
if($invoicePdfData == null) {
return null;
}
$clean_folder = html_entity_decode(string: $currentConfig->path).'/';
$factureFolders = $this->getFacturesFolder($invoicePdfData, $clean_folder);
$pdf = new InvoicePdfHandler();
$pdf->AddFont('ComicSans', '', 'Comic Sans MS.php');
$pdf->AddFont('ComicSans', 'B', 'comic-sans-bold.php');
$pdf->InvoicePdfFactory($invoicePdfData, $logo);
$pdf->SetFactureContent();
$pdfContent = $pdf->Output('', 'S');
$pdfFilename = $pdf->GetInvoiceFilename();
$prefixPdf = "FACTURE";
if($invoicePdfData['is_negative']) {
$prefixPdf = "AVOIR";
}
$pdfFilename = $prefixPdf."_".$pdfFilename;
$filenames = [];
$filenames = $this->savePdfToFolders($factureFolders, $pdfFilename, $pdfContent, $storage);
$this->gestionBdd->setFactureGeneratedDate($factureId);
return [
"content" => $pdfContent,
"filenames" => $filenames
];
}
public function generateFacturePdfByFactureId($factureId, $idNextCloud)
{
$factureType = $this->gestionBdd->getFactureTypeByFactureId($factureId);
if($factureType == FactureTypeConstant::TYPE_SINGLE) {
return $this->generateFactureSinglePdfByFactureId($factureId, $idNextCloud);
} else {
return $this->generateFactureGroupPdfByFactureId($factureId, $idNextCloud);
}
}
private function getGroupFactureFolder(array $factureData, $racinePath)
{
$clientRacineFolder = $racinePath.'CLIENTS/'.mb_strtoupper($factureData["group_name"], 'UTF-8').'/';
$factureDate = $factureData['date_paiement'];
$factureDatetime = new DateTime($factureDate);
$factureDateYear = $factureDatetime->format('Y');
$factureMonth = DateHelpers::GetDateWithFormatDayAndMonthPlainString($factureData['date_paiement']);
$factureByYearFolder = $clientRacineFolder."$factureDateYear".'/'.$factureMonth.'/'.'FACTURES'.'/';
return [
$factureByYearFolder
];
}
private function getFacturesFolder(array $factureData, $racinePath)
{
$clientRacineFolder = $racinePath.'CLIENTS/'.mb_strtoupper($factureData["client_nom"], 'UTF-8').'/';
$defuntsFolder = $clientRacineFolder.'DEFUNTS/'.mb_strtoupper($factureData['defunt_nom'], 'UTF-8').'/'.'FACTURES'.'/';
$devisDate = $factureData['devis_date'];
$devisDatetime = new DateTime($devisDate);
$devisDateYear = $devisDatetime->format('Y');
$devisMonth = DateHelpers::GetDateWithFormatDayAndMonthPlainString($factureData['devis_date']);
$factureByYearFolder = $clientRacineFolder."$devisDateYear".'/'.$devisMonth.'/'.'FACTURES'.'/';
return [
$defuntsFolder,
$factureByYearFolder
];
}
private function generateFactureGroupPdfByFactureId($factureId, $idNextCloud)
{
$storage = $this->rootFolder->getUserFolder($idNextCloud);
$configs = json_decode($this->gestionBdd->getConfiguration(self::DEFAULT_NEXTCLOUD_ADMIN));
$currentConfig = $configs[0];
$logo = $this->getLogo();
$invoicePdfData = $this->gestionBdd->getInvoiceGroupPdfData($factureId, $currentConfig);
if($invoicePdfData == null) {
return "";
}
// NOUVELLE LOGIQUE : Vérifier si TVA exonérée
if ($this->isTvaExempt($invoicePdfData)) {
return $this->generateWithHtmlTemplate($invoicePdfData, $storage);
}
$templateType = $invoicePdfData['template_type_key'];
$clean_folder = html_entity_decode(string: $currentConfig->path).'/';
$factureFolders = $this->getGroupFactureFolder($invoicePdfData, $clean_folder);
//For testing
// $templateType = ClientTemplateTypeConstant::OGF;
switch ($templateType) {
case ClientTemplateTypeConstant::FUNECAP:
$pdf = new InvoiceFunecapPdfHandler();
break;
case ClientTemplateTypeConstant::OGF:
$pdf = new InvoiceOgfPdfHandler();
break;
default:
$pdf = new InvoiceGroupPdfHandler();
break;
}
$pdf->AddFont('ComicSans', '', 'Comic Sans MS.php');
$pdf->AddFont('ComicSans', 'B', 'comic-sans-bold.php');
$pdf->InvoicePdfFactory($invoicePdfData, $logo);
$pdf->SetFactureContent();
$pdfContent = $pdf->Output('', 'S');
$pdfFilename = $pdf->GetInvoiceFilename();
$filenames = [];
$filenames = $this->savePdfToFolders($factureFolders, $pdfFilename, $pdfContent, $storage);
$this->gestionBdd->setFactureGeneratedDate($factureId);
return [
"content" => $pdfContent,
"filenames" => $filenames
];
}
public function sanitizePathDev(string $path): string
{
$path = ltrim($path, '/');
// Remplacer accents UTF-8 par ASCII
$path = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $path);
// Supprimer caractères interdits par Nextcloud/Docker
$path = preg_replace('#[<>:"/\\|?*]#', '_', $path);
// Supprimer doublons d'espaces
$path = preg_replace('#\s+#', ' ', $path);
return trim($path);
}
public function generateFacturePdfByFactureIds(array $factureIds, $idNextCloud)
{
foreach($factureIds as $factureId) {
$this->generateFacturePdfByFactureId($factureId, $idNextCloud);
}
}
public function generateMultipleInvoicePdfByClientAndMonthYear($filter, $month, $year, $idNextCloud, $filterType)
{
$storage = $this->rootFolder->getUserFolder($idNextCloud);
$configs = json_decode($this->gestionBdd->getConfiguration(self::DEFAULT_NEXTCLOUD_ADMIN));
$currentConfig = $configs[0];
$logo = $this->getLogo();
$invoiceData = $this->gestionBdd->getInvoicePdfDataByClientAndMonthYear($filter, $month, $year, $currentConfig, $filterType);
if(empty($invoiceData)) {
return null;
}
$pdf = new InvoicePdfHandler();
$pdf->AddFont('ComicSans', '', 'Comic Sans MS.php');
$pdf->AddFont('ComicSans', 'B', 'comic-sans-bold.php');
$pdf->MutlipleInvoicePdfFactory($invoiceData, $logo);
$pdf->SetMultipleFactureContent();
$racinePath = html_entity_decode(string: $currentConfig->path).'/';
$clientNameInFolder = $invoiceData[0]["client_nom"];
if($invoiceData[0]['facture_type'] == MultipleFactureTypeConstant::GROUP_FILTER_TYPE) {
if($invoiceData[0]["group_name"] != null && $invoiceData[0]["group_name"] != "") {
$clientNameInFolder = $invoiceData[0]["group_name"];
}
}
$clientRacineFolder = $racinePath.'CLIENTS/'.mb_strtoupper($clientNameInFolder, 'UTF-8').'/';
$filename = "FACTURE".'_'.$pdf->GetMultipleInvoiceFilename($month, $year);
$pdfContent = $pdf->Output('', 'S');
$singleFolderArray = [$clientRacineFolder];
$filenames = $this->savePdfToFolders($singleFolderArray, $filename, $pdfContent, $storage);
return $filenames[0];
}
public function generateInvoiceRecap($filter, $filterType, $date, $idNextCloud)
{
$this->invoiceRecapService->generateInvoiceRecap($filter, $filterType, $date, $idNextCloud);
}
public function exportGroupOfDevisIntoFacture($clientId, $clientType, $month, $year, $facturationDate, $idNextcloud = BddConstant::DEFAULT_ADMIN_ID_NEXTCLOUD)
{
try {
$datetime = new Datetime();
$month = $month ?? $datetime->format('m');
$year = $year ?? $datetime->format('Y');
$factureId = null;
$fkClientId = null;
$fkClientGroupFacturationId = null;
$devisMentionFiltersToBeInvoiced = [
DevisMentionConstant::NEW,
DevisMentionConstant::MENTION
];
// Recuperer les devis non facturés du client avant la date de facturation du mois
//Si il a devis qui n est pas encore facturés
//Cree un facture, atttaché l ID du facture au devis et generer le pdf
if($clientType == MultipleFactureTypeConstant::CLIENT_FILTER_TYPE) {
$devisIds = $this->gestionBdd->getDevisIdsByClientIdAndDate($clientId, $facturationDate, $devisMentionFiltersToBeInvoiced);
$fkClientId = $clientId;
$factureId = $this->gestionBdd->getFactureIdByClientIdAndDate($clientId, $facturationDate);
} else {
$devisIds = $this->gestionBdd->getDevisIdsByClientGroupFacturationIdAnDate($clientId, $facturationDate, $devisMentionFiltersToBeInvoiced);
$fkClientGroupFacturationId = $clientId;
$factureId = $this->gestionBdd->getFactureIdByClientGroupFacturationIdAndDate($clientId, $facturationDate);
}
// if($clientType == MultipleFactureTypeConstant::CLIENT_FILTER_TYPE){
// $devisIds = $this->gestionBdd->getDevisIdsByClientIdAndMonthYear($clientId,$month,$year,$devisMentionFiltersToBeInvoiced);
// $fkClientId = $clientId;
// }
// else{
// $factureId = $this->gestionBdd->getFactureIdByClientGroupFacturationIdAndMonthYear($clientId,$month,$year);
// $devisIds = $this->gestionBdd->getDevisIdsByClientGroupFacturationIdAndMonthYear($clientId,$month,$year);
// $fkClientGroupFacturationId = $clientId;
// }
// $clientIsAlreadyFacturedForThisMonthAndYear = $factureId != null && $factureId != 0;
// if($clientIsAlreadyFacturedForThisMonthAndYear == false){
// $factureId = $this->gestionBdd->createFactureAndReturnFactureId(
// $facturationDate,
// FactureTypeConstant::TYPE_GROUP,
// $month,
// $year,
// $fkClientId,
// $fkClientGroupFacturationId);
// }
if (!empty($devisIds)) {
//Get facture by date and client
$clientIsAlreadyFacturedForThisDate = $factureId != null && $factureId != 0;
if (!$clientIsAlreadyFacturedForThisDate) {
$factureId = $this->gestionBdd->createFactureAndReturnFactureId(
$facturationDate,
FactureTypeConstant::TYPE_GROUP,
$month,
$year,
$fkClientId,
$fkClientGroupFacturationId
);
}
$this->gestionBdd->invoiceListOfDevisIds($devisIds, $factureId);
$factureGeneratedResponse = $this->generateFactureGroupPdfByFactureId($factureId, $idNextcloud);
return $factureGeneratedResponse["filenames"];
}
return null;
} catch(Exception) {
return null;
}
}
/**
* NOUVELLE MÉTHODE : Génération avec template HTML
*/
private function generateWithHtmlTemplate($invoicePdfData, $storage)
{
try {
// Préparer les données pour le template HTML
$templateData = $this->prepareHtmlTemplateData($invoicePdfData);
// Générer le PDF avec le nouveau système
$pdfContent = $this->htmlToPdfService->generatePdf('facture_dv_thanato', $templateData);
// Nom du fichier
$pdfFilename = $this->htmlToPdfService->generateInvoiceFilename($invoicePdfData);
// Sauvegarder dans Nextcloud
$clean_folder = html_entity_decode(string: $invoicePdfData['configuration']->path).'/';
$factureFolders = $this->getGroupFactureFolder($invoicePdfData, $clean_folder);
$filenames = [];
foreach ($factureFolders as $folder) {
// --- GESTION DU CHEMIN ---
if (($_ENV['APP_ENV'] ?? 'prod') === 'dev') {
// En dev : remplacer les accents et caractères spéciaux pour Docker
$relativeFolder = $this->sanitizePathDev($folder);
$pdfFileNameSafe = $this->sanitizePathDev($pdfFilename);
} else {
// En prod : garder UTF-8, juste retirer slash initial
$relativeFolder = ltrim($folder, '/');
$pdfFileNameSafe = $pdfFilename;
}
// --- CREATION DU DOSSIER ---
try {
if (!$storage->nodeExists($relativeFolder)) {
$storage->newFolder($relativeFolder);
}
} catch (\Exception $e) {
echo "ERROR creating folder '$relativeFolder': " . $e->getMessage();
exit;
}
// --- CHEMIN COMPLET DU FICHIER ---
$ff_pdf = rtrim($relativeFolder, '/') . '/' . $pdfFileNameSafe . '.pdf';
// --- CREATION OU MISE A JOUR DU FICHIER ---
try {
if ($storage->nodeExists($ff_pdf)) {
$file_pdf = $storage->get($ff_pdf);
} else {
$file_pdf = $storage->newFile($ff_pdf);
}
$file_pdf->putContent($pdfContent);
$filenames[] = $ff_pdf;
} catch (\Throwable $e) {
echo "ERROR on file '$ff_pdf': " . $e->getMessage();
exit;
}
}
$this->gestionBdd->setFactureGeneratedDate($invoicePdfData['id']);
return [
"content" => $pdfContent,
"filenames" => $filenames
];
} catch (TemplateException $e) {
error_log('HTML Template PDF Error: ' . $e->getMessage());
throw $e;
}
}
/**
* NOUVELLE MÉTHODE : Détecte si TVA exonérée
*/
private function isTvaExempt($invoicePdfData)
{
// Vérifier si c'est un client unique avec TVA = 0
if (isset($invoicePdfData['fk_client_id']) && $invoicePdfData['fk_client_id'] != null && $invoicePdfData['fk_client_id'] != 0) {
$client = $this->gestionBdd->getClientById($invoicePdfData['fk_client_id']);
if (isset($client['tva']) && $client['tva'] == 0) {
return true;
}
}
// Vérification alternative dans les totaux si la première méthode ne fonctionne pas
if (isset($invoicePdfData['totalPrices'])) {
foreach ($invoicePdfData['totalPrices'] as $label => $amount) {
if (strpos($label, 'TVA') !== false && (strpos($label, 'exonéré') !== false || $amount == 0)) {
return true;
}
}
}
return false;
}
/**
* Prépare les données pour le template HTML - Version refactorisée
*/
private function prepareHtmlTemplateData($invoicePdfData)
{
return [
'company' => $this->prepareCompanyData($invoicePdfData),
'client' => $this->prepareClientData($invoicePdfData),
'facture' => $this->prepareInvoiceData($invoicePdfData),
'groupedArticles' => $this->prepareGroupedArticles($invoicePdfData),
'totals' => $this->prepareTotals($invoicePdfData),
'bank' => $this->prepareBankData($invoicePdfData),
'legal_text' => $this->getLegalText()
];
}
/**
* Prépare les données de l'entreprise
*/
private function prepareCompanyData($invoicePdfData)
{
$config = $invoicePdfData['configuration'];
return [
'name' => $config->entreprise ?? 'DV Thanato',
'address' => $invoicePdfData['configuration_adresse'] ?? '47 rue Boldoduc',
'city' => $invoicePdfData['configuration_adresse_city'] ?? '59800 Lille',
'phone' => $config->telephone ?? '06.13.57.29.84',
'email' => $config->mail ?? 'soins@dvthanato.fr',
'logo' => 'logo_dv_thanato.png'
];
}
/**
* Prépare les données du client
*/
private function prepareClientData($invoicePdfData)
{
return [
'name' => $invoicePdfData['group_name'] ?? '',
'address' => $invoicePdfData['client_real_adress'] ?? '',
'city' => $invoicePdfData['client_adress_city'] ?? '',
'siret' => $invoicePdfData['siret'] ?? ''
];
}
/**
* Prépare les données de la facture
*/
private function prepareInvoiceData($invoicePdfData)
{
$numero = $invoicePdfData['num'] ?? '';
return [
'date' => date('d-m-Y'),
'number' => 'FAC' . str_pad((string)$numero, 6, '0', STR_PAD_LEFT),
'echeance' => date('d-m-Y', strtotime('+30 days')),
'period_start' => date('d/m/Y', strtotime($invoicePdfData['date'] ?? 'now')),
'period_end' => date('d/m/Y', strtotime($invoicePdfData['date_paiement'] ?? 'now'))
];
}
/**
* Prépare les articles groupés par date et défunt
*/
private function prepareGroupedArticles($invoicePdfData)
{
if (!isset($invoicePdfData['devis']) || !is_array($invoicePdfData['devis'])) {
return [];
}
$groupedByDate = [];
foreach ($invoicePdfData['devis'] as $devis) {
$this->processDevis($devis, $groupedByDate);
}
return $this->convertToIndexedArray($groupedByDate);
}
/**
* Traite un devis et l'ajoute aux données groupées
*/
private function processDevis($devis, &$groupedByDate)
{
$dateDevis = date('d/m/Y', strtotime($devis['devis_date'] ?? 'now'));
$defuntNom = $devis['defunt_nom'] ?? 'Non défini';
$this->initializeDateGroup($groupedByDate, $dateDevis);
$this->initializeDefuntGroup($groupedByDate, $dateDevis, $defuntNom);
$this->addServicesToDefunt($groupedByDate, $dateDevis, $defuntNom, $devis['products'] ?? []);
}
/**
* Initialise un groupe de date
*/
private function initializeDateGroup(&$groupedByDate, $dateDevis)
{
if (!isset($groupedByDate[$dateDevis])) {
$groupedByDate[$dateDevis] = [
'date' => $dateDevis,
'defunts' => []
];
}
}
/**
* Initialise un groupe de défunt
*/
private function initializeDefuntGroup(&$groupedByDate, $dateDevis, $defuntNom)
{
if (!isset($groupedByDate[$dateDevis]['defunts'][$defuntNom])) {
$groupedByDate[$dateDevis]['defunts'][$defuntNom] = [
'nom' => $defuntNom,
'services' => []
];
}
}
/**
* Ajoute les services à un défunt
*/
private function addServicesToDefunt(&$groupedByDate, $dateDevis, $defuntNom, $products)
{
foreach ($products as $product) {
$service = $this->createServiceFromProduct($product);
$groupedByDate[$dateDevis]['defunts'][$defuntNom]['services'][] = $service;
}
}
/**
* Crée un service à partir d'un produit
*/
private function createServiceFromProduct($product)
{
$prixHt = ($product['produit_price'] ?? 0) * ($product['quantite'] ?? 1);
return [
'reference' => $product['produit_reference'] ?? '',
'description' => $product['produit_description'] ?? 'Produit inconnu',
'prix_ht' => number_format($prixHt, 2, ',', ' '),
'quantite' => number_format($product['quantite'] ?? 1, 2, ',', ' '),
'prix_ttc' => number_format($prixHt, 2, ',', ' ')
];
}
/**
* Convertit les données groupées en array indexé
*/
private function convertToIndexedArray($groupedByDate)
{
$groupedArticles = [];
foreach ($groupedByDate as $dateGroup) {
$defuntsArray = array_values($dateGroup['defunts']);
$dateGroup['defunts'] = $defuntsArray;
$groupedArticles[] = $dateGroup;
}
return $groupedArticles;
}
/**
* Prépare les totaux
*/
private function prepareTotals($invoicePdfData)
{
$totalPrices = $invoicePdfData['totalPrices'] ?? [];
return [
'total_ht' => number_format($totalPrices['TOTAL HT'] ?? 0, 2, ',', ' '),
'total_tva' => '0,00',
'total_ttc' => number_format($totalPrices['TOTAL TTC'] ?? 0, 2, ',', ' '),
'tva_label' => 'TVA (exonéré)'
];
}
/**
* Prépare les données bancaires
*/
private function prepareBankData($invoicePdfData)
{
$config = $invoicePdfData['configuration'];
return [
'iban' => 'FR76 1670 6052 4453 9757 9734 871',
'swift' => 'AGRI FR PP867',
'rcs' => $config->legal_one ?? '901 115 931 R.C.S Lille Métropole'
];
}
/**
* Texte légal
*/
private function getLegalText()
{
return "Tout retard de paiement entraînera de plein droit une pénalité de retard de 3 fois le taux légal " .
"(Loi 2008-776 du 4 août 2008) et une indemnité forfaitaire de 40 EUR pour frais de recouvrement sera appliquée.\n" .
"Si les frais de recouvrement sont supérieurs à ce montant forfaitaire, une indemnisation complémentaire " .
"sera due sur présentation de justificatifs (articles L 441-3 et L 441-6 du code de commerce).";
}
/**
* Fonction générique pour sauvegarder un fichier PDF dans plusieurs dossiers
*
* @param array $factureFolders Liste des dossiers où sauvegarder
* @param string $pdfFilename Nom du fichier PDF (sans extension)
* @param string $pdfContent Contenu binaire du PDF
* @param mixed $storage Instance de stockage Nextcloud
* @return array Liste des chemins des fichiers créés
*/
private function savePdfToFolders(array $factureFolders, string $pdfFilename, string $pdfContent, $storage): array
{
$filenames = [];
foreach ($factureFolders as $folder) {
// --- GESTION DU CHEMIN ---
if (($_ENV['APP_ENV'] ?? 'prod') === 'dev') {
// En dev : remplacer les accents et caractères spéciaux pour Docker
$relativeFolder = $this->sanitizePathDev($folder);
$pdfFileNameSafe = $this->sanitizePathDev($pdfFilename);
} else {
// En prod : garder UTF-8, juste retirer slash initial
$relativeFolder = ltrim($folder, '/');
$pdfFileNameSafe = $pdfFilename;
}
// --- CREATION DU DOSSIER ---
try {
if (!$storage->nodeExists($relativeFolder)) {
$storage->newFolder($relativeFolder);
}
} catch (\Exception $e) {
error_log("ERROR creating folder '$relativeFolder': " . $e->getMessage());
// Ne pas faire exit, continuer avec les autres dossiers
continue;
}
// --- CHEMIN COMPLET DU FICHIER ---
$ff_pdf = rtrim($relativeFolder, '/') . '/' . $pdfFileNameSafe . '.pdf';
// --- CREATION OU MISE A JOUR DU FICHIER ---
try {
if ($storage->nodeExists($ff_pdf)) {
$file_pdf = $storage->get($ff_pdf);
} else {
$file_pdf = $storage->newFile($ff_pdf);
}
$file_pdf->putContent($pdfContent);
$filenames[] = $ff_pdf;
} catch (\Throwable $e) {
error_log("ERROR on file '$ff_pdf': " . $e->getMessage());
// Ne pas faire exit, continuer avec les autres fichiers
continue;
}
}
return $filenames;
}
}