On release/v3.1.4: Sauvegarde temporaire pour changement de branche

This commit is contained in:
2025-08-21 17:51:22 +02:00
parent 6c8853e553
commit 41a4505b4b
1697 changed files with 167987 additions and 231472 deletions

View File

@@ -37,7 +37,7 @@ class ExportService {
}
// Créer le dossier de destination
$exportDir = $this->fileService->createDirectory($entiteId, "/{$entiteId}/operations/{$operationId}/exports/excel");
$exportDir = $this->fileService->createDirectory($entiteId, "/{$entiteId}/operations/{$operationId}");
LogService::log('exportDir', [
'level' => 'warning',
@@ -138,7 +138,7 @@ class ExportService {
$exportData = $this->collectOperationData($operationId, $entiteId);
// Créer le dossier de destination
$exportDir = $this->fileService->createDirectory($entiteId, "/{$entiteId}/operations/{$operationId}/exports/json");
$exportDir = $this->fileService->createDirectory($entiteId, "/{$entiteId}/operations/{$operationId}");
// Initialiser le service de chiffrement
$backupService = new BackupEncryptionService();

View File

@@ -7,6 +7,7 @@ namespace App\Services;
require_once __DIR__ . '/LogService.php';
require_once __DIR__ . '/ApiService.php';
require_once __DIR__ . '/FileService.php';
require_once __DIR__ . '/ReceiptPDFGenerator.php';
use PDO;
use Database;
@@ -24,6 +25,8 @@ class ReceiptService {
private PDO $db;
private FileService $fileService;
private const DEFAULT_LOGO_PATH = __DIR__ . '/../../docs/_logo_recu.png';
private const LOGO_WIDTH = 40; // Largeur du logo en mm (80 est trop grand pour un A4)
private const LOGO_HEIGHT = 40; // Hauteur du logo en mm
public function __construct() {
$this->db = Database::getInstance();
@@ -89,7 +92,7 @@ class ReceiptService {
$pdfContent = $this->generateOptimizedPDF($receiptData, $logoPath);
// Créer le répertoire de stockage
$uploadPath = "/entites/{$operationData['fk_entite']}/recus/{$operationData['id']}";
$uploadPath = "/{$operationData['fk_entite']}/recus/{$operationData['id']}";
$fullPath = $this->fileService->createDirectory($operationData['fk_entite'], $uploadPath);
// Nom du fichier
@@ -141,181 +144,13 @@ class ReceiptService {
}
/**
* Génère un PDF ultra-optimisé (< 20KB)
* Utilise le format PDF natif pour minimiser la taille
* Génère un PDF optimisé avec logo et mise en page épurée
*/
private function generateOptimizedPDF(array $data, ?string $logoPath): string {
// Début du PDF
$pdf = "%PDF-1.3\n";
$objects = [];
$xref = [];
// Object 1 - Catalog
$objects[1] = "1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n";
// Object 2 - Pages
$objects[2] = "2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n";
// Object 3 - Page
$objects[3] = "3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 595 842] /Resources << /Font << /F1 4 0 R >> >> /Contents 5 0 R >>\nendobj\n";
// Object 4 - Font (Helvetica)
$objects[4] = "4 0 obj\n<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>\nendobj\n";
// Contenu de la page (texte du reçu)
$content = $this->generatePDFContent($data);
// Object 5 - Content stream
$contentLength = strlen($content);
$objects[5] = "5 0 obj\n<< /Length $contentLength >>\nstream\n$content\nendstream\nendobj\n";
// Construction du PDF final
$offset = strlen($pdf);
foreach ($objects as $obj) {
$xref[] = $offset;
$pdf .= $obj;
$offset += strlen($obj);
}
// Table xref
$pdf .= "xref\n";
$pdf .= "0 " . (count($objects) + 1) . "\n";
$pdf .= "0000000000 65535 f \n";
foreach ($xref as $off) {
$pdf .= sprintf("%010d 00000 n \n", $off);
}
// Trailer
$pdf .= "trailer\n";
$pdf .= "<< /Size " . (count($objects) + 1) . " /Root 1 0 R >>\n";
$pdf .= "startxref\n";
$pdf .= "$offset\n";
$pdf .= "%%EOF\n";
return $pdf;
$pdf = new ReceiptPDFGenerator();
return $pdf->generateReceipt($data, $logoPath);
}
/**
* Génère le contenu textuel du reçu pour le PDF
*/
private function generatePDFContent(array $data): string {
$content = "BT\n";
$content .= "/F1 12 Tf\n";
$y = 750;
// En-tête
$content .= "50 $y Td\n";
$content .= "(" . $this->escapeString($data['entite_name']) . ") Tj\n";
$y -= 20;
if (!empty($data['entite_address'])) {
$content .= "0 -20 Td\n";
$content .= "(" . $this->escapeString($data['entite_address']) . ") Tj\n";
$y -= 20;
}
// Titre du reçu
$y -= 40;
$content .= "/F1 16 Tf\n";
$content .= "0 -40 Td\n";
$content .= "(RECU DE DON N° " . $data['receipt_number'] . ") Tj\n";
$content .= "/F1 10 Tf\n";
$content .= "0 -15 Td\n";
$content .= "(Article 200 du Code General des Impots) Tj\n";
// Informations du donateur
$y -= 60;
$content .= "/F1 12 Tf\n";
$content .= "0 -45 Td\n";
$content .= "(DONATEUR) Tj\n";
$content .= "/F1 11 Tf\n";
$content .= "0 -20 Td\n";
$content .= "(Nom : " . $this->escapeString($data['donor_name']) . ") Tj\n";
if (!empty($data['donor_address'])) {
$content .= "0 -15 Td\n";
$content .= "(Adresse : " . $this->escapeString($data['donor_address']) . ") Tj\n";
}
if (!empty($data['donor_email'])) {
$content .= "0 -15 Td\n";
$content .= "(Email : " . $this->escapeString($data['donor_email']) . ") Tj\n";
}
// Détails du don
$content .= "0 -30 Td\n";
$content .= "/F1 12 Tf\n";
$content .= "(DETAILS DU DON) Tj\n";
$content .= "/F1 11 Tf\n";
$content .= "0 -20 Td\n";
$content .= "(Date : " . $data['donation_date'] . ") Tj\n";
$content .= "0 -15 Td\n";
$content .= "(Montant : " . $data['amount'] . " EUR) Tj\n";
$content .= "0 -15 Td\n";
$content .= "(Mode de reglement : " . $this->escapeString($data['payment_method']) . ") Tj\n";
if (!empty($data['operation_name'])) {
$content .= "0 -15 Td\n";
$content .= "(Campagne : " . $this->escapeString($data['operation_name']) . ") Tj\n";
}
// Mention légale
$content .= "/F1 9 Tf\n";
$content .= "0 -40 Td\n";
$content .= "(Reduction d'impot egale a 66% du montant verse dans la limite de 20% du revenu imposable) Tj\n";
// Date et signature
$content .= "/F1 11 Tf\n";
$content .= "0 -30 Td\n";
$content .= "(Fait a " . $this->escapeString($data['entite_city']) . ", le " . $data['signature_date'] . ") Tj\n";
$content .= "0 -20 Td\n";
$content .= "(Le President) Tj\n";
$content .= "ET\n";
return $content;
}
/**
* Échappe les caractères spéciaux pour le PDF
*/
private function escapeString(string $str): string {
// Échapper les caractères spéciaux PDF
$str = str_replace('\\', '\\\\', $str);
$str = str_replace('(', '\\(', $str);
$str = str_replace(')', '\\)', $str);
// Remplacer manuellement les caractères accentués les plus courants
$accents = [
'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A', 'Å' => 'A',
'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ä' => 'a', 'å' => 'a',
'È' => 'E', 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E',
'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e',
'Ì' => 'I', 'Í' => 'I', 'Î' => 'I', 'Ï' => 'I',
'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i',
'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', 'Õ' => 'O', 'Ö' => 'O',
'ò' => 'o', 'ó' => 'o', 'ô' => 'o', 'õ' => 'o', 'ö' => 'o',
'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ü' => 'U',
'ù' => 'u', 'ú' => 'u', 'û' => 'u', 'ü' => 'u',
'Ñ' => 'N', 'ñ' => 'n',
'Ç' => 'C', 'ç' => 'c',
'Œ' => 'OE', 'œ' => 'oe',
'Æ' => 'AE', 'æ' => 'ae'
];
$str = strtr($str, $accents);
// Supprimer tout caractère non-ASCII restant
$str = preg_replace('/[^\x20-\x7E]/', '', $str);
return $str;
}
/**
* Récupère les données du passage