v2.3.0: Complete journal table implementation with proper balancing and formatting

- Added journal entry table to detailed PDF with columns: Code compte, Libellé compte, Libellé écriture, Débit, Crédit
- Implemented complex balancing logic for TD > 0 and TD <= 0 cases
- Added account label lookup with proper mapping for 4455100, 4456700, 658000, 758000
- Fixed account label retrieval to use custom uppercase labels from chart of accounts
- Optimized table layout with centered positioning and appropriate column widths
- Reduced font sizes for better page fit while maintaining readability
- Added final balancing entries using 658000 (debit) and 758000 (credit) accounts
- Removed all debug logging for production-ready code
This commit is contained in:
Frank Cools 2025-10-07 18:28:10 +02:00
parent db687bdb77
commit 6918e92168
2 changed files with 159 additions and 66 deletions

View File

@ -1811,13 +1811,21 @@ class DeclarationTVA_PDF
}
// Table header
$pdf->SetFont('helvetica', 'B', 10);
$pdf->SetFont('helvetica', 'B', 8);
$pdf->SetFillColor(240, 240, 240);
// Column widths
$col_widths = array(25, 50, 60, 25, 25);
// Column widths - reduced and centered
$col_widths = array(20, 60, 40, 20, 20);
$col_headers = array('Code compte', 'Libellé compte', 'Libellé écriture', 'Débit', 'Crédit');
// Calculate table width and center position
$table_width = array_sum($col_widths);
$page_width = $pdf->getPageWidth() - $pdf->getMargins()['left'] - $pdf->getMargins()['right'];
$start_x = ($page_width - $table_width) / 2 + $pdf->getMargins()['left'];
// Set X position to center the table
$pdf->SetX($start_x);
// Draw header
for ($i = 0; $i < count($col_headers); $i++) {
$pdf->Cell($col_widths[$i], 8, $col_headers[$i], 1, 0, 'C', true);
@ -1825,10 +1833,13 @@ class DeclarationTVA_PDF
$pdf->Ln();
// Table content
$pdf->SetFont('helvetica', '', 9);
$pdf->SetFont('helvetica', '', 7);
$pdf->SetFillColor(255, 255, 255);
foreach ($journal_entries as $entry) {
// Set X position to center the table for each row
$pdf->SetX($start_x);
$pdf->Cell($col_widths[0], 6, $entry['account_code'], 1, 0, 'C');
$pdf->Cell($col_widths[1], 6, $entry['account_label'], 1, 0, 'L');
$pdf->Cell($col_widths[2], 6, $entry['entry_label'], 1, 0, 'L');
@ -1857,22 +1868,13 @@ class DeclarationTVA_PDF
$line20_entries = $this->getLine20Accounts($declaration, $ca3_lookup);
$entries = array_merge($entries, $line20_entries);
// Add VAT result on account 4455100 (changed from 4456700)
$vat_result_entry = $this->getVATResultEntry($declaration, $ca3_lookup);
if ($vat_result_entry) {
$entries[] = $vat_result_entry;
}
// Add balancing entry to ensure debits equal credits
$balancing_entries = $this->getBalancingEntries($declaration, $entries);
error_log("DeclarationTVA: Found " . count($balancing_entries) . " balancing entries");
foreach ($balancing_entries as $entry) {
if ($entry) {
error_log("DeclarationTVA: Adding balancing entry: " . $entry['account_code'] . " " . $entry['debit'] . " " . $entry['credit']);
$entries[] = $entry;
}
}
error_log("DeclarationTVA: Total entries after balancing: " . count($entries));
return $entries;
}
@ -1954,7 +1956,7 @@ class DeclarationTVA_PDF
}
/**
* Get VAT result entry on account 4456700
* Get VAT result entry on account 4455100 or 4456700
*
* @param DeclarationTVA $declaration Declaration object
* @param array $ca3_lookup CA-3 data lookup array
@ -1962,15 +1964,40 @@ class DeclarationTVA_PDF
*/
private function getVATResultEntry($declaration, $ca3_lookup)
{
// Calculate VAT result (line 28 - line 29)
$line28_amount = isset($ca3_lookup['28']) ? $ca3_lookup['28']['vat_amount'] : 0;
$line29_amount = isset($ca3_lookup['29']) ? $ca3_lookup['29']['vat_amount'] : 0;
$vat_result = $line28_amount - $line29_amount;
// Get TD line amount (Line 16 - Line 23)
$line_16_amount = $this->getLineAmount($declaration, '16');
$line_23_amount = $this->getLineAmount($declaration, '23');
$td_amount = $line_16_amount - $line_23_amount;
if ($vat_result == 0) {
return null;
error_log("DeclarationTVA: TD amount: " . $td_amount);
// If TD = 0, use line 27 value and account 4456700
if (abs($td_amount) < 0.01) {
$line27_amount = $this->getLineAmount($declaration, '27');
error_log("DeclarationTVA: TD is 0, using line 27 amount: " . $line27_amount);
if (abs($line27_amount) < 0.01) {
return null;
}
$entry = array(
'account_code' => '4456700',
'account_label' => $this->getAccountLabel('4456700'),
'entry_label' => $declaration->declaration_name,
'debit' => '',
'credit' => ''
);
// Put line 23 amount on debit side
$line23_amount = $this->getLineAmount($declaration, '23');
if ($line23_amount > 0) {
$entry['debit'] = $this->formatAmount($line23_amount);
}
return $entry;
}
// If TD > 0, use TD value and account 4455100 (existing logic)
$entry = array(
'account_code' => '4455100',
'account_label' => $this->getAccountLabel('4455100'),
@ -1979,10 +2006,10 @@ class DeclarationTVA_PDF
'credit' => ''
);
if ($vat_result < 0) {
$entry['debit'] = $this->formatAmountReal(abs($vat_result));
if ($td_amount < 0) {
$entry['debit'] = $this->formatAmount(abs($td_amount));
} else {
$entry['credit'] = $this->formatAmountReal($vat_result);
$entry['credit'] = $this->formatAmount($td_amount);
}
return $entry;
@ -2075,23 +2102,35 @@ class DeclarationTVA_PDF
$balancing_entries = array();
// Debug logging
error_log("DeclarationTVA: Total debits: " . $total_debits);
error_log("DeclarationTVA: Total credits: " . $total_credits);
error_log("DeclarationTVA: Total difference: " . $difference);
error_log("DeclarationTVA: Difference > 0: " . ($difference > 0 ? 'true' : 'false'));
// Use TD line calculation (Line 16 - Line 23) as main balancing amount
$line_16_amount = $this->getLineAmount($declaration, '16');
$line_23_amount = $this->getLineAmount($declaration, '23');
$td_amount = $line_16_amount - $line_23_amount;
error_log("DeclarationTVA: Line 16: " . $line_16_amount . ", Line 23: " . $line_23_amount . ", TD: " . $td_amount);
// If TD <= 0, use line 26 or 27 (whichever is not 0) and account 4456700 on debit side
if ($td_amount <= 0) {
$line26_amount = $this->getLineAmount($declaration, '26');
$line27_amount = $this->getLineAmount($declaration, '27');
if (abs($td_amount) >= 0.01) {
error_log("DeclarationTVA: TD amount: " . $td_amount . " (already rounded)");
// Use whichever line is not 0
$selected_amount = 0;
if (abs($line26_amount) >= 0.01) {
$selected_amount = $line26_amount;
} elseif (abs($line27_amount) >= 0.01) {
$selected_amount = $line27_amount;
}
// TD amount is already rounded, so just use it directly
if (abs($selected_amount) >= 0.01) {
$balancing_entries[] = array(
'account_code' => '4456700',
'account_label' => $this->getAccountLabel('4456700'),
'entry_label' => $declaration->declaration_name,
'debit' => $this->formatAmount($selected_amount),
'credit' => ''
);
}
} else {
// If TD > 0, use TD value and account 4455100
$balancing_entries[] = array(
'account_code' => '4455100',
'account_label' => $this->getAccountLabel('4455100'),
@ -2101,6 +2140,55 @@ class DeclarationTVA_PDF
);
}
// Add final balancing entry to ensure debits equal credits
$final_debits = 0;
$final_credits = 0;
// Calculate totals including the main balancing entries we just added
foreach ($balancing_entries as $entry) {
if (!empty($entry['debit'])) {
$final_debits += $this->parseAmount($entry['debit']);
}
if (!empty($entry['credit'])) {
$final_credits += $this->parseAmount($entry['credit']);
}
}
// Add the existing entries to the calculation
foreach ($entries as $entry) {
if (!empty($entry['debit'])) {
$final_debits += $this->parseAmount($entry['debit']);
}
if (!empty($entry['credit'])) {
$final_credits += $this->parseAmount($entry['credit']);
}
}
$final_difference = $final_debits - $final_credits;
// If there's still a difference, add final balancing entry
if (abs($final_difference) >= 0.01) {
if ($final_difference > 0) {
// More debits, need credit entry on 758000
$balancing_entries[] = array(
'account_code' => '758000',
'account_label' => $this->getAccountLabel('758000'),
'entry_label' => $declaration->declaration_name,
'debit' => '',
'credit' => $this->formatAmountReal($final_difference)
);
} else {
// More credits, need debit entry on 658000
$balancing_entries[] = array(
'account_code' => '658000',
'account_label' => $this->getAccountLabel('658000'),
'entry_label' => $declaration->declaration_name,
'debit' => $this->formatAmountReal(abs($final_difference)),
'credit' => ''
);
}
}
return $balancing_entries;
}
@ -2115,8 +2203,7 @@ class DeclarationTVA_PDF
{
$sql = "SELECT vat_amount FROM " . MAIN_DB_PREFIX . "declarationtva_ca3_lines
WHERE declaration_id = " . $declaration->rowid . "
AND ca3_line = '" . $this->db->escape($line_code) . "'
AND entity = " . $this->entity;
AND ca3_line = '" . $this->db->escape($line_code) . "'";
$result = $this->db->query($sql);
if ($result && $this->db->num_rows($result) > 0) {
@ -2175,39 +2262,45 @@ class DeclarationTVA_PDF
*/
private function getAccountLabel($account_code)
{
// Try multiple approaches to find the account
$possible_queries = array(
// With entity filter
"SELECT label FROM " . MAIN_DB_PREFIX . "accounting_account
WHERE account_number = '" . $this->db->escape($account_code) . "'
AND entity = " . $this->entity . "
AND active = 1
LIMIT 1",
// Without entity filter
"SELECT label FROM " . MAIN_DB_PREFIX . "accounting_account
WHERE account_number = '" . $this->db->escape($account_code) . "'
AND active = 1
LIMIT 1",
// Without active filter
"SELECT label FROM " . MAIN_DB_PREFIX . "accounting_account
WHERE account_number = '" . $this->db->escape($account_code) . "'
LIMIT 1"
// Map the hardcoded account codes to the actual account numbers in the database
$account_mapping = array(
'4455100' => '44551', // TVA A DECAISSER
'4456700' => '44567', // TVA A PAYER
'658000' => '658', // AUTRES CHARGES DE GESTION COURANTE
'758000' => '758' // AUTRES PRODUITS DE GESTION COURANT
);
foreach ($possible_queries as $sql) {
error_log("DeclarationTVA: Trying query: " . $sql);
// Use mapped account code if available, otherwise use original
$search_code = isset($account_mapping[$account_code]) ? $account_mapping[$account_code] : $account_code;
$result = $this->db->query($sql);
if ($result && $this->db->num_rows($result) > 0) {
$obj = $this->db->fetch_object($result);
error_log("DeclarationTVA: Found account label: " . $obj->label);
return $obj->label;
}
// Use the same approach as getAccountMappings() in the main class
// Order by rowid ASC to get the oldest entry (custom uppercase labels)
$sql = "SELECT a.label
FROM " . MAIN_DB_PREFIX . "accounting_account a
WHERE a.account_number = '" . $this->db->escape($search_code) . "'
AND a.entity = " . $this->entity . "
ORDER BY a.rowid ASC
LIMIT 1";
$result = $this->db->query($sql);
if ($result && $this->db->num_rows($result) > 0) {
$obj = $this->db->fetch_object($result);
return $obj->label;
}
// If not found with entity, try without entity filter
$sql = "SELECT a.label
FROM " . MAIN_DB_PREFIX . "accounting_account a
WHERE a.account_number = '" . $this->db->escape($search_code) . "'
ORDER BY a.rowid ASC
LIMIT 1";
$result = $this->db->query($sql);
if ($result && $this->db->num_rows($result) > 0) {
$obj = $this->db->fetch_object($result);
return $obj->label;
}
error_log("DeclarationTVA: Account " . $account_code . " not found in any query, using generic label");
// If account not found in chart of accounts, return generic label
return 'Compte ' . $account_code;
}

View File

@ -76,7 +76,7 @@ class modDeclarationTVA extends DolibarrModules
$this->editor_squarred_logo = ''; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@declarationtva'
// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z'
$this->version = '2.2.0';
$this->version = '2.3.0';
// Url to the file with your last numberversion of this module
//$this->url_last_version = 'http://www.example.com/versionmodule.txt';