diff --git a/admin/setup_mvp.php b/admin/setup_mvp.php
index 52484c8..c65f655 100644
--- a/admin/setup_mvp.php
+++ b/admin/setup_mvp.php
@@ -259,9 +259,91 @@ if (empty($mappings_by_line)) {
}
}
+// Template Management Section
+print '
';
+print '
';
+
+// Load PDF class
+require_once DOL_DOCUMENT_ROOT . '/custom/declarationtva/core/class/declarationtva_pdf.class.php';
+$pdf_generator = new DeclarationTVA_PDF($db);
+
+// Handle template upload
+if ($action == 'upload_template') {
+ $uploaded_file = $_FILES['template_file'];
+ if ($pdf_generator->uploadCustomTemplate($uploaded_file)) {
+ setEventMessages($langs->trans("TemplateUploaded"), null, 'mesgs');
+ } else {
+ setEventMessages($pdf_generator->error, null, 'errors');
+ }
+}
+
+// Handle template reset
+if ($action == 'reset_template') {
+ if ($pdf_generator->resetToDefaultTemplate()) {
+ setEventMessages($langs->trans("TemplateReset"), null, 'mesgs');
+ } else {
+ setEventMessages($langs->trans("TemplateResetFailed"), null, 'errors');
+ }
+}
+
+// Get template information
+$template_info = $pdf_generator->getTemplateInfo();
+
+print '
';
+
+print '
';
+print '
';
+
print '';
// Print footer
llxFooter();
-?>
?>
\ No newline at end of file
diff --git a/core/class/declarationtva_pdf.class.php b/core/class/declarationtva_pdf.class.php
new file mode 100644
index 0000000..61be6f8
--- /dev/null
+++ b/core/class/declarationtva_pdf.class.php
@@ -0,0 +1,334 @@
+.
+ */
+
+/**
+ * \file core/class/declarationtva_pdf.class.php
+ * \ingroup declarationtva
+ * \brief PDF generation for CA-3 declarations
+ */
+
+require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
+
+/**
+ * Class to generate CA-3 declaration PDF
+ */
+class DeclarationTVA_PDF
+{
+ /**
+ * @var DoliDB Database handler
+ */
+ public $db;
+
+ /**
+ * @var string Error code (or message)
+ */
+ public $error = '';
+
+ /**
+ * @var string[] Several error codes (or messages)
+ */
+ public $errors = array();
+
+ /**
+ * @var int Entity
+ */
+ public $entity;
+
+ /**
+ * @var string Template path
+ */
+ public $template_path;
+
+ /**
+ * @var string Template version
+ */
+ public $template_version = '30';
+
+ /**
+ * @var string Template document number
+ */
+ public $template_document = '10963';
+
+ /**
+ * Constructor
+ *
+ * @param DoliDB $db Database handler
+ */
+ public function __construct($db)
+ {
+ $this->db = $db;
+ $this->entity = (int) $conf->entity;
+ $this->template_path = DOL_DOCUMENT_ROOT.'/custom/declarationtva/templates/declarationtva/';
+ }
+
+ /**
+ * Generate CA-3 declaration PDF
+ *
+ * @param int $declaration_id Declaration ID
+ * @param string $outputlangs Output language
+ * @return string|false PDF file path or false on error
+ */
+ public function generateCA3PDF($declaration_id, $outputlangs = '')
+ {
+ global $conf, $langs, $user;
+
+ // Load declaration data
+ $declaration = new DeclarationTVA($this->db);
+ $result = $declaration->fetch($declaration_id);
+ if ($result <= 0) {
+ $this->error = 'Declaration not found';
+ return false;
+ }
+
+ // Get CA-3 line data
+ $ca3_data = $declaration->getCA3Lines($declaration_id);
+ if (empty($ca3_data)) {
+ $this->error = 'No CA-3 data found';
+ return false;
+ }
+
+ // Get company information
+ $company = new Societe($this->db);
+ $company->fetch($conf->entity);
+
+ // Generate PDF filename
+ $filename = 'CA3_' . $declaration->declaration_number . '_' . date('Y-m-d') . '.pdf';
+ $filepath = DOL_DATA_ROOT . '/declarationtva/' . $filename;
+
+ // Ensure directory exists
+ if (!is_dir(DOL_DATA_ROOT . '/declarationtva/')) {
+ dol_mkdir(DOL_DATA_ROOT . '/declarationtva/');
+ }
+
+ // Check if we have a custom template
+ $template_file = $this->getTemplatePath();
+ if (!$template_file) {
+ $this->error = 'CA-3 template not found';
+ return false;
+ }
+
+ // Generate PDF using FPDI or similar library
+ $result = $this->fillPDFTemplate($template_file, $filepath, $declaration, $ca3_data, $company);
+
+ if ($result) {
+ return $filepath;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Get the template file path (custom or default)
+ *
+ * @return string|false Template file path or false if not found
+ */
+ private function getTemplatePath()
+ {
+ // Check for custom template first
+ $custom_template = $this->template_path . 'ca3_custom_template.pdf';
+ if (file_exists($custom_template)) {
+ return $custom_template;
+ }
+
+ // Fall back to default template
+ $default_template = $this->template_path . 'ca3_official_template.pdf';
+ if (file_exists($default_template)) {
+ return $default_template;
+ }
+
+ return false;
+ }
+
+ /**
+ * Fill PDF template with declaration data
+ *
+ * @param string $template_path Template file path
+ * @param string $output_path Output file path
+ * @param DeclarationTVA $declaration Declaration object
+ * @param array $ca3_data CA-3 line data
+ * @param Societe $company Company object
+ * @return bool Success
+ */
+ private function fillPDFTemplate($template_path, $output_path, $declaration, $ca3_data, $company)
+ {
+ // This is a placeholder - we'll need to implement actual PDF filling
+ // For now, we'll create a simple PDF with the data
+
+ try {
+ // Create a new PDF document
+ $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
+
+ // Set document information
+ $pdf->SetCreator('DeclarationTVA Module');
+ $pdf->SetAuthor($company->name);
+ $pdf->SetTitle('CA-3 Declaration ' . $declaration->declaration_number);
+ $pdf->SetSubject('French VAT Declaration');
+
+ // Set margins
+ $pdf->SetMargins(15, 15, 15);
+ $pdf->SetHeaderMargin(5);
+ $pdf->SetFooterMargin(10);
+
+ // Add a page
+ $pdf->AddPage();
+
+ // Add title
+ $pdf->SetFont('helvetica', 'B', 16);
+ $pdf->Cell(0, 10, 'Déclaration TVA CA-3', 0, 1, 'C');
+ $pdf->Ln(10);
+
+ // Add declaration information
+ $pdf->SetFont('helvetica', '', 12);
+ $pdf->Cell(0, 8, 'Numéro de déclaration: ' . $declaration->declaration_number, 0, 1);
+ $pdf->Cell(0, 8, 'Période: ' . dol_print_date($declaration->start_date, 'day') . ' - ' . dol_print_date($declaration->end_date, 'day'), 0, 1);
+ $pdf->Cell(0, 8, 'Statut: ' . $declaration->status, 0, 1);
+ $pdf->Ln(10);
+
+ // Add CA-3 sections
+ $this->addCA3Section($pdf, 'A. Opérations imposables', $ca3_data, array('A1', 'A2', 'A3', 'A4', 'A5'));
+ $this->addCA3Section($pdf, 'B. TVA due', $ca3_data, array('08', '09', '9B', '17'));
+ $this->addCA3Section($pdf, 'C. TVA déductible', $ca3_data, array('20', '21', '22'));
+ $this->addCA3Section($pdf, 'D. Résultat', $ca3_data, array('25', '26', 'TD', '28', '29'));
+
+ // Add totals
+ $pdf->Ln(10);
+ $pdf->SetFont('helvetica', 'B', 12);
+ $pdf->Cell(0, 8, 'TOTAL TVA COLLECTÉE: ' . price($declaration->total_vat_collected, 0, '', 1, 0), 0, 1);
+ $pdf->Cell(0, 8, 'TOTAL TVA DÉDUCTIBLE: ' . price($declaration->total_vat_deductible, 0, '', 1, 0), 0, 1);
+ $pdf->Cell(0, 8, 'TVA NETTE DUE: ' . price($declaration->net_vat_due, 0, '', 1, 0), 0, 1);
+
+ if ($declaration->vat_credit > 0) {
+ $pdf->Cell(0, 8, 'CRÉDIT DE TVA: ' . price($declaration->vat_credit, 0, '', 1, 0), 0, 1);
+ }
+
+ // Output PDF
+ $pdf->Output($output_path, 'F');
+
+ return true;
+
+ } catch (Exception $e) {
+ $this->error = 'PDF generation failed: ' . $e->getMessage();
+ return false;
+ }
+ }
+
+ /**
+ * Add CA-3 section to PDF
+ *
+ * @param TCPDF $pdf PDF object
+ * @param string $section_title Section title
+ * @param array $ca3_data CA-3 data
+ * @param array $lines Lines to include
+ */
+ private function addCA3Section($pdf, $section_title, $ca3_data, $lines)
+ {
+ $pdf->SetFont('helvetica', 'B', 12);
+ $pdf->Cell(0, 8, $section_title, 0, 1);
+
+ $pdf->SetFont('helvetica', '', 10);
+ foreach ($lines as $line) {
+ if (isset($ca3_data[$line])) {
+ $data = $ca3_data[$line];
+ $amount = isset($data['vat_amount']) ? $data['vat_amount'] : 0;
+ $pdf->Cell(20, 6, $line, 1, 0, 'C');
+ $pdf->Cell(100, 6, $data['line_label'], 1, 0);
+ $pdf->Cell(30, 6, price($amount, 0, '', 1, 0), 1, 1, 'R');
+ }
+ }
+ $pdf->Ln(5);
+ }
+
+ /**
+ * Upload custom template
+ *
+ * @param array $file Uploaded file array
+ * @return bool Success
+ */
+ public function uploadCustomTemplate($file)
+ {
+ if (!isset($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) {
+ $this->error = 'No file uploaded';
+ return false;
+ }
+
+ // Validate file type
+ $file_info = pathinfo($file['name']);
+ if (strtolower($file_info['extension']) !== 'pdf') {
+ $this->error = 'Only PDF files are allowed';
+ return false;
+ }
+
+ // Validate file size (max 10MB)
+ if ($file['size'] > 10 * 1024 * 1024) {
+ $this->error = 'File too large (max 10MB)';
+ return false;
+ }
+
+ // Move uploaded file
+ $target_path = $this->template_path . 'ca3_custom_template.pdf';
+ if (!is_dir($this->template_path)) {
+ dol_mkdir($this->template_path);
+ }
+
+ if (move_uploaded_file($file['tmp_name'], $target_path)) {
+ return true;
+ } else {
+ $this->error = 'Failed to save template';
+ return false;
+ }
+ }
+
+ /**
+ * Get template information
+ *
+ * @return array Template information
+ */
+ public function getTemplateInfo()
+ {
+ $info = array(
+ 'version' => $this->template_version,
+ 'document' => $this->template_document,
+ 'official_number' => $this->template_document . '*' . $this->template_version,
+ 'custom_template' => false,
+ 'template_path' => ''
+ );
+
+ $custom_template = $this->template_path . 'ca3_custom_template.pdf';
+ if (file_exists($custom_template)) {
+ $info['custom_template'] = true;
+ $info['template_path'] = $custom_template;
+ }
+
+ return $info;
+ }
+
+ /**
+ * Reset to default template
+ *
+ * @return bool Success
+ */
+ public function resetToDefaultTemplate()
+ {
+ $custom_template = $this->template_path . 'ca3_custom_template.pdf';
+ if (file_exists($custom_template)) {
+ return unlink($custom_template);
+ }
+ return true;
+ }
+}
diff --git a/declarationtva_view.php b/declarationtva_view.php
index 281563f..9f638d2 100644
--- a/declarationtva_view.php
+++ b/declarationtva_view.php
@@ -54,6 +54,28 @@ if ($action == 'recalculate' && $token) {
}
}
+if ($action == 'export_pdf') {
+ // Load PDF generator
+ require_once DOL_DOCUMENT_ROOT . '/custom/declarationtva/core/class/declarationtva_pdf.class.php';
+ $pdf_generator = new DeclarationTVA_PDF($db);
+
+ // Generate PDF
+ $pdf_path = $pdf_generator->generateCA3PDF($id);
+
+ if ($pdf_path && file_exists($pdf_path)) {
+ // Set headers for PDF download
+ header('Content-Type: application/pdf');
+ header('Content-Disposition: attachment; filename="CA3_' . $declarationtva->declaration_number . '.pdf"');
+ header('Content-Length: ' . filesize($pdf_path));
+
+ // Output PDF
+ readfile($pdf_path);
+ exit;
+ } else {
+ setEventMessages($pdf_generator->error ?: $langs->trans("ErrorGeneratingPDF"), null, 'errors');
+ }
+}
+
// Fetch declaration
if ($declarationtva->fetch($id) < 0) {
setEventMessages($langs->trans("DeclarationNotFound"), null, 'errors');
@@ -357,6 +379,9 @@ print '';
// Recalculate button (always available)
print '
' . $langs->trans("Recalculate") . ' ';
+// PDF Export button (always available)
+print '
' . $langs->trans("ExportPDF") . ' ';
+
if ($declarationtva->status == 'draft') {
print '
' . $langs->trans("Validate") . ' ';
} elseif ($declarationtva->status == 'validated') {
diff --git a/langs/en_US/declarationtva.lang b/langs/en_US/declarationtva.lang
index 6cec5eb..60d045e 100644
--- a/langs/en_US/declarationtva.lang
+++ b/langs/en_US/declarationtva.lang
@@ -466,3 +466,8 @@ VATAccounts = VAT Accounts
SubtotalBaseAccounts = Subtotal Base Accounts
SubtotalVATAccounts = Subtotal VAT Accounts
GrandTotal = Grand Total
+ExportPDF = Export PDF
+TemplateUploaded = PDF template uploaded successfully
+TemplateReset = Reset to official template
+TemplateResetFailed = Error resetting to official template
+ErrorGeneratingPDF = Error generating PDF
diff --git a/langs/fr_FR/declarationtva.lang b/langs/fr_FR/declarationtva.lang
index e451294..67c594d 100644
--- a/langs/fr_FR/declarationtva.lang
+++ b/langs/fr_FR/declarationtva.lang
@@ -455,3 +455,8 @@ VATAccounts = Comptes de TVA
SubtotalBaseAccounts = Sous-total comptes de base
SubtotalVATAccounts = Sous-total comptes de TVA
GrandTotal = Total général
+ExportPDF = Exporter PDF
+TemplateUploaded = Modèle PDF téléchargé avec succès
+TemplateReset = Retour au modèle officiel
+TemplateResetFailed = Erreur lors du retour au modèle officiel
+ErrorGeneratingPDF = Erreur lors de la génération du PDF
diff --git a/templates/declarationtva/README.md b/templates/declarationtva/README.md
new file mode 100644
index 0000000..d017e04
--- /dev/null
+++ b/templates/declarationtva/README.md
@@ -0,0 +1,26 @@
+# CA-3 Template Directory
+
+This directory contains the CA-3 PDF templates for the DeclarationTVA module.
+
+## Template Files
+
+- `ca3_official_template.pdf` - Official CA-3 template (version 30, document 10963)
+- `ca3_custom_template.pdf` - Custom template uploaded by user (if any)
+
+## Template Information
+
+- **Official Number**: 10963*30
+- **Version**: 30
+- **Document**: 10963
+- **Source**: French Tax Authorities
+
+## Template Management
+
+The module will:
+1. Use the custom template if available (`ca3_custom_template.pdf`)
+2. Fall back to the official template (`ca3_official_template.pdf`)
+3. Allow users to upload updated templates via the configuration page
+
+## File Permissions
+
+Ensure the web server has write permissions to this directory for template uploads.