DeclarationTVA/core/class/declarationtva.class.php
Frank Cools 91ebf73866 Clean up debug logging statements
- Removed all error_log debug statements from PDF generation
- Removed debug logging from CA-3 data processing
- Removed debug logging from account amount calculations
- Cleaned up merge methods debug output
- Production-ready code without debug noise
2025-10-06 16:50:46 +02:00

1009 lines
37 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* DeclarationTVA Class
* French CA-3 VAT Declaration Module for Dolibarr
* MVP Version - Phase 1
*/
class DeclarationTVA
{
/**
* @var DoliDB Database handler
*/
public $db;
/**
* @var int Entity ID
*/
public $entity;
/**
* @var string Error message
*/
public $error;
/**
* @var int Declaration ID
*/
public $rowid;
/**
* @var int Period ID
*/
public $period_id;
/**
* @var string Declaration number
*/
public $declaration_number;
/**
* @var string Declaration name
*/
public $declaration_name;
/**
* @var string Start date
*/
public $start_date;
/**
* @var string End date
*/
public $end_date;
/**
* @var string Status
*/
public $status;
/**
* Constructor
*
* @param DoliDB $db Database handler
* @param int $entity Entity ID
*/
public function __construct($db, $entity = 1)
{
$this->db = $db;
$this->entity = $entity;
}
/**
* Fetch declaration by ID
*
* @param int $id Declaration ID
* @return int 1 if found, 0 if not found, -1 if error
*/
public function fetch($id)
{
$sql = "SELECT * FROM " . MAIN_DB_PREFIX . "declarationtva_declarations
WHERE rowid = " . (int)$id . " AND entity = " . $this->entity;
$result = $this->db->query($sql);
if ($result) {
$obj = $this->db->fetch_object($result);
if ($obj) {
$this->rowid = $obj->rowid;
$this->period_id = $obj->period_id;
$this->declaration_number = $obj->declaration_number;
$this->declaration_name = $obj->declaration_name;
$this->start_date = $obj->start_date;
$this->end_date = $obj->end_date;
$this->status = $obj->status;
$this->created_date = $obj->created_date;
return 1;
}
}
return 0;
}
/**
* Create a new declaration for a period
*
* @param int $period_id Period ID
* @return int Declaration ID or -1 if error
*/
public function createDeclaration($period_id)
{
global $user;
$this->db->begin();
// Get period information
$period = $this->getPeriod($period_id);
if (!$period) {
$this->error = "Period not found";
$this->db->rollback();
return -1;
}
// Generate declaration number
$declaration_number = $this->generateDeclarationNumber($period);
// Create declaration record
$sql = "INSERT INTO " . MAIN_DB_PREFIX . "declarationtva_declarations
(entity, period_id, declaration_number, status, created_date)
VALUES (" . $this->entity . ", " . $period_id . ", '" . $declaration_number . "', 'draft', NOW())";
$result = $this->db->query($sql);
if (!$result) {
$this->error = "Error creating declaration: " . $this->db->lasterror();
$this->db->rollback();
return -1;
}
$declaration_id = $this->db->last_insert_id(MAIN_DB_PREFIX . "declarationtva_declarations");
// Calculate CA-3 amounts
$this->calculateCA3Amounts($declaration_id, $period);
$this->db->commit();
return $declaration_id;
}
/**
* Create a new declaration with specific dates
*
* @param string $start_date Start date (YYYY-MM-DD)
* @param string $end_date End date (YYYY-MM-DD)
* @param string $declaration_name Declaration name
* @return int Declaration ID or -1 if error
*/
public function createDeclarationWithDates($start_date, $end_date, $declaration_name = '')
{
global $user;
$this->db->begin();
// Generate declaration number
$declaration_number = $this->generateDeclarationNumberFromDates($start_date, $end_date);
// Create declaration record
$sql = "INSERT INTO " . MAIN_DB_PREFIX . "declarationtva_declarations
(entity, period_id, declaration_number, declaration_name, start_date, end_date, status, created_date)
VALUES (" . $this->entity . ", 0, '" . $declaration_number . "', '" . $this->db->escape($declaration_name) . "', '" . $start_date . "', '" . $end_date . "', 'draft', NOW())";
$result = $this->db->query($sql);
if (!$result) {
$this->error = "Error creating declaration: " . $this->db->lasterror();
$this->db->rollback();
return -1;
}
$declaration_id = $this->db->last_insert_id(MAIN_DB_PREFIX . "declarationtva_declarations");
// Calculate CA-3 amounts
$period = array('start_date' => $start_date, 'end_date' => $end_date);
$this->calculateCA3Amounts($declaration_id, $period);
$this->db->commit();
return $declaration_id;
}
/**
* Calculate CA-3 amounts for a declaration
*
* @param int $declaration_id Declaration ID
* @param array $period Period information
* @return bool Success
*/
public function calculateCA3Amounts($declaration_id, $period)
{
// Get account mappings grouped by CA-3 line
$mappings = $this->getAccountMappings();
// Group mappings by CA-3 line
$grouped_mappings = array();
foreach ($mappings as $mapping) {
$ca3_line = $mapping['ca3_line'];
if (!isset($grouped_mappings[$ca3_line])) {
$grouped_mappings[$ca3_line] = array();
}
$grouped_mappings[$ca3_line][] = $mapping;
}
// Define all CA-3 lines that should be processed
$all_ca3_lines = array('A1', 'A2', 'A3', 'A4', 'A5', 'E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'F1', 'F2', 'F6', 'F7', 'F8', '08', '09', '9B', '17', '18', '19', '20', '21', '22', '25', '26', '28', '29');
$total_vat_collected = 0;
$total_vat_deductible = 0;
// Process ALL CA-3 lines (even those without mappings)
foreach ($all_ca3_lines as $ca3_line) {
$line_total_base = 0;
$line_total_vat = 0;
$line_total_amount = 0;
$account_labels = array();
// Special handling for lines 08, 09, 9B (need separate base and VAT accounts)
if (in_array($ca3_line, array('08', '09', '9B'))) {
// Get base accounts (sales)
$base_mappings = isset($grouped_mappings[$ca3_line . '_BASE']) ? $grouped_mappings[$ca3_line . '_BASE'] : array();
foreach ($base_mappings as $mapping) {
$amounts = $this->getAccountAmounts($mapping['account_code'], $period['start_date'], $period['end_date']);
$line_total_base += $amounts['base_amount'];
$account_labels[] = $mapping['account_label'] . ' (base)';
}
// Get VAT accounts
$vat_mappings = isset($grouped_mappings[$ca3_line . '_VAT']) ? $grouped_mappings[$ca3_line . '_VAT'] : array();
foreach ($vat_mappings as $mapping) {
$amounts = $this->getAccountAmounts($mapping['account_code'], $period['start_date'], $period['end_date']);
$line_total_vat += $amounts['vat_amount'];
$account_labels[] = $mapping['account_label'] . ' (VAT)';
}
$line_total_amount = $line_total_base + $line_total_vat;
} else {
// Normal processing for other lines
if (isset($grouped_mappings[$ca3_line])) {
foreach ($grouped_mappings[$ca3_line] as $mapping) {
$amounts = $this->getAccountAmounts($mapping['account_code'], $period['start_date'], $period['end_date']);
$line_total_base += $amounts['base_amount'];
$line_total_vat += $amounts['vat_amount'];
$line_total_amount += $amounts['total_amount'];
$account_labels[] = $mapping['account_label'];
}
}
}
// Create CA-3 line record with summed amounts (even if zero)
$combined_amounts = array(
'base_amount' => $line_total_base,
'vat_amount' => $line_total_vat,
'total_amount' => $line_total_amount
);
$combined_label = !empty($account_labels) ? implode(', ', $account_labels) : 'No accounts mapped';
// Truncate label if too long to prevent database issues (keep some buffer)
if (strlen($combined_label) > 1000) {
$combined_label = substr($combined_label, 0, 997) . '...';
}
$this->createCA3Line($declaration_id, $ca3_line, $combined_label, $combined_amounts);
// Update totals - only VAT amounts from sections B and C
if (in_array($ca3_line, ['08', '09', '9B'])) {
// Section B: VAT amounts only
$total_vat_collected += $line_total_vat;
} elseif (in_array($ca3_line, ['19', '20', '21', '22'])) {
// Section B sub-section: VAT deductible amounts
$total_vat_deductible += $line_total_vat;
}
}
// Calculate line 16: Subtotal of lines 08, 09, 9B (for user reference)
$this->calculateLine16($declaration_id);
// Calculate line 23: Subtotal of lines 20, 21, 22 (for user reference)
$this->calculateLine23($declaration_id);
// Calculate D-section result lines (25, 26, 28, 29)
$this->calculateDSectionLines($declaration_id, $total_vat_collected, $total_vat_deductible);
// Calculate net amounts
$net_vat_due = $total_vat_collected - $total_vat_deductible;
$vat_credit = $net_vat_due < 0 ? abs($net_vat_due) : 0;
$net_vat_due = $net_vat_due > 0 ? $net_vat_due : 0;
// Update declaration totals
$this->updateDeclarationTotals($declaration_id, $total_vat_collected, $total_vat_deductible, $net_vat_due, $vat_credit);
return true;
}
/**
* Calculate line 16: Subtotal of lines 08, 09, 9B (for user reference)
*
* @param int $declaration_id Declaration ID
* @return bool Success
*/
private function calculateLine16($declaration_id)
{
// Get the amounts from lines 08, 09, 9B
$sql = "SELECT ca3_line, vat_amount FROM " . MAIN_DB_PREFIX . "declarationtva_ca3_lines
WHERE declaration_id = " . (int)$declaration_id . "
AND ca3_line IN ('08', '09', '9B')";
$result = $this->db->query($sql);
$line_16_total = 0;
$account_labels = array();
if ($result) {
while ($obj = $this->db->fetch_object($result)) {
$line_16_total += $obj->vat_amount;
$account_labels[] = "Line " . $obj->ca3_line . ": " . number_format($obj->vat_amount, 2);
}
}
// Create line 16 record
$this->createCA3Line($declaration_id, '16', 'Subtotal: ' . implode(', ', $account_labels), array(
'base_amount' => 0,
'vat_amount' => $line_16_total,
'total_amount' => $line_16_total
));
return true;
}
/**
* Round VAT amount to whole number and format with original amount in brackets
*
* @param float $amount Original amount
* @return array Array with 'rounded' and 'formatted' values
*/
private function roundVATAmount($amount)
{
$rounded = round($amount);
$formatted = $rounded;
if ($rounded != $amount) {
$formatted = $rounded . ' (' . number_format($amount, 2) . ')';
}
return array(
'rounded' => $rounded,
'formatted' => $formatted
);
}
/**
* Calculate line 23: Subtotal of lines 20, 21, 22 (for user reference)
*
* @param int $declaration_id Declaration ID
* @return bool Success
*/
private function calculateLine23($declaration_id)
{
// Get the amounts from lines 20, 21, 22
$sql = "SELECT ca3_line, vat_amount FROM " . MAIN_DB_PREFIX . "declarationtva_ca3_lines
WHERE declaration_id = " . (int)$declaration_id . "
AND ca3_line IN ('20', '21', '22')";
$result = $this->db->query($sql);
$line_23_total = 0;
$account_labels = array();
if ($result) {
while ($obj = $this->db->fetch_object($result)) {
$line_23_total += $obj->vat_amount;
$account_labels[] = "Line " . $obj->ca3_line . ": " . number_format($obj->vat_amount, 2);
}
}
// Create line 23 record
$this->createCA3Line($declaration_id, '23', 'Subtotal: ' . implode(', ', $account_labels), array(
'base_amount' => 0,
'vat_amount' => $line_23_total,
'total_amount' => $line_23_total
));
return true;
}
/**
* Get amount for a specific CA-3 line
*
* @param int $declaration_id Declaration ID
* @param string $ca3_line CA-3 line code
* @return float Line amount
*/
private function getLineAmount($declaration_id, $ca3_line)
{
$sql = "SELECT vat_amount FROM " . MAIN_DB_PREFIX . "declarationtva_ca3_lines
WHERE declaration_id = " . (int)$declaration_id . "
AND ca3_line = '" . $this->db->escape($ca3_line) . "'";
$result = $this->db->query($sql);
if ($result && $this->db->num_rows($result) > 0) {
$obj = $this->db->fetch_object($result);
return (float)$obj->vat_amount;
}
return 0.0;
}
/**
* Calculate D-section result lines (25, 26, 28, 29)
*
* @param int $declaration_id Declaration ID
* @param float $total_vat_collected Total VAT collected
* @param float $total_vat_deductible Total VAT deductible
* @return bool Success
*/
private function calculateDSectionLines($declaration_id, $total_vat_collected, $total_vat_deductible)
{
// Get line 16 and 23 amounts for line 25 calculation
$line_16_amount = $this->getLineAmount($declaration_id, '16');
$line_23_amount = $this->getLineAmount($declaration_id, '23');
// Calculate net VAT due
$net_vat_due = $total_vat_collected - $total_vat_deductible;
// Line 25: Crédit de TVA (ligne 23 - ligne16) - only if > 0
$line_25_amount = $line_23_amount - $line_16_amount;
if ($line_25_amount > 0) {
$this->createCA3Line($declaration_id, '25', 'Crédit de TVA (ligne 23 - ligne16)', array(
'base_amount' => 0,
'vat_amount' => $line_25_amount,
'total_amount' => $line_25_amount
));
} else {
$this->createCA3Line($declaration_id, '25', 'Crédit de TVA (ligne 23 - ligne16)', array(
'base_amount' => 0,
'vat_amount' => 0,
'total_amount' => 0
));
}
// Line 27: Crédit de TVA à reporter (ligne 25 ligne 26) - same value as line 25, only if > 0 and < 760
$line_27_amount = $line_25_amount; // Same value as line 25
if ($line_27_amount > 0 && $line_27_amount < 760) {
$this->createCA3Line($declaration_id, '27', 'Crédit de TVA à reporter (ligne 25 ligne 26) (Cette somme est à reporter ligne 22 de la prochaine déclaration)', array(
'base_amount' => 0,
'vat_amount' => $line_27_amount,
'total_amount' => $line_27_amount
));
} else {
$this->createCA3Line($declaration_id, '27', 'Crédit de TVA à reporter (ligne 25 ligne 26) (Cette somme est à reporter ligne 22 de la prochaine déclaration)', array(
'base_amount' => 0,
'vat_amount' => 0,
'total_amount' => 0
));
}
// Line 26: Remboursement de crédit de TVA demandé sur formulaire n°3519 - same value as line 25, only if >= 760
$line_26_amount = $line_25_amount; // Same value as line 25
if ($line_26_amount >= 760) {
$this->createCA3Line($declaration_id, '26', 'Remboursement de crédit de TVA demandé sur formulaire n°3519', array(
'base_amount' => 0,
'vat_amount' => $line_26_amount,
'total_amount' => $line_26_amount
));
} else {
$this->createCA3Line($declaration_id, '26', 'Remboursement de crédit de TVA demandé sur formulaire n°3519', array(
'base_amount' => 0,
'vat_amount' => 0,
'total_amount' => 0
));
}
// Line TD: TVA due (ligne 16 ligne 23) - only if > 0
$line_td_amount = $line_16_amount - $line_23_amount;
if ($line_td_amount > 0) {
$this->createCA3Line($declaration_id, 'TD', 'TVA due (ligne 16 ligne 23)', array(
'base_amount' => 0,
'vat_amount' => $line_td_amount,
'total_amount' => $line_td_amount
));
} else {
$this->createCA3Line($declaration_id, 'TD', 'TVA due (ligne 16 ligne 23)', array(
'base_amount' => 0,
'vat_amount' => 0,
'total_amount' => 0
));
}
// Line 28: TVA nette due (ligne TD ligne X5) - same value as line TD, only if > 0
$line_28_amount = $line_td_amount; // Same value as line TD
if ($line_28_amount > 0) {
$this->createCA3Line($declaration_id, '28', 'TVA nette due (ligne TD ligne X5)', array(
'base_amount' => 0,
'vat_amount' => $line_28_amount,
'total_amount' => $line_28_amount
));
} else {
$this->createCA3Line($declaration_id, '28', 'TVA nette due (ligne TD ligne X5)', array(
'base_amount' => 0,
'vat_amount' => 0,
'total_amount' => 0
));
}
// Line 32: Total à payer (lignes 28 + 29 + Z5 AB) - same value as line 28, only if > 0
$line_32_amount = $line_28_amount; // Same value as line 28
if ($line_32_amount > 0) {
$this->createCA3Line($declaration_id, '32', 'Total à payer (lignes 28 + 29 + Z5 AB) (N\'oubliez pas d\'effectuer le règlement correspondant)', array(
'base_amount' => 0,
'vat_amount' => $line_32_amount,
'total_amount' => $line_32_amount
));
} else {
$this->createCA3Line($declaration_id, '32', 'Total à payer (lignes 28 + 29 + Z5 AB) (N\'oubliez pas d\'effectuer le règlement correspondant)', array(
'base_amount' => 0,
'vat_amount' => 0,
'total_amount' => 0
));
}
return true;
}
/**
* Get account amounts for a period
*
* @param string $account_code Account code
* @param string $start_date Start date
* @param string $end_date End date
* @return array Amounts (base_amount, vat_amount, total_amount)
*/
public function getAccountAmounts($account_code, $start_date, $end_date)
{
// Use the correct Dolibarr accounting table structure
$possible_queries = array(
// Correct table and column names based on your Dolibarr structure
"SELECT SUM(debit) as total_debit, SUM(credit) as total_credit
FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping
WHERE numero_compte = '" . $this->db->escape($account_code) . "'
AND doc_date >= '" . $this->db->escape($start_date) . "'
AND doc_date <= '" . $this->db->escape($end_date) . "'
AND entity = " . $this->entity,
// Without entity filter (in case entity is not set correctly)
"SELECT SUM(debit) as total_debit, SUM(credit) as total_credit
FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping
WHERE numero_compte = '" . $this->db->escape($account_code) . "'
AND doc_date >= '" . $this->db->escape($start_date) . "'
AND doc_date <= '" . $this->db->escape($end_date) . "'"
);
foreach ($possible_queries as $sql) {
$result = $this->db->query($sql);
if ($result && $this->db->num_rows($result) > 0) {
$obj = $this->db->fetch_object($result);
// For VAT accounts, we need to use the credit side (VAT collected) or debit side (VAT paid)
// If debit = credit, the account is balanced, so we use the credit amount (VAT collected)
if ($obj->total_debit == $obj->total_credit) {
// Account is balanced, use the credit amount (VAT collected)
$total_amount = $obj->total_credit;
} else {
// Account has imbalance, use the absolute difference
$total_amount = abs($obj->total_debit - $obj->total_credit);
}
return array(
'base_amount' => $total_amount,
'vat_amount' => $total_amount,
'total_amount' => $total_amount
);
}
}
return array('base_amount' => 0, 'vat_amount' => 0, 'total_amount' => 0);
}
/**
* Create CA-3 line record
*
* @param int $declaration_id Declaration ID
* @param string $ca3_line CA-3 line code
* @param string $line_label Line label
* @param array $amounts Amounts array
* @return bool Success
*/
public function createCA3Line($declaration_id, $ca3_line, $line_label, $amounts)
{
// Round amounts to whole numbers
$rounded_base = round($amounts['base_amount']);
$rounded_vat = round($amounts['vat_amount']);
$rounded_total = round($amounts['total_amount']);
// Store original amounts in the line_label for now (we'll need to modify the database schema later)
$original_base = $amounts['base_amount'];
$original_vat = $amounts['vat_amount'];
$original_total = $amounts['total_amount'];
$sql = "INSERT INTO " . MAIN_DB_PREFIX . "declarationtva_ca3_lines
(declaration_id, ca3_line, line_label, base_amount, vat_amount, total_amount, created_date)
VALUES (" . $declaration_id . ", '" . $this->db->escape($ca3_line) . "',
'" . $this->db->escape($line_label) . "', " . $rounded_base . ",
" . $rounded_vat . ", " . $rounded_total . ", NOW())";
$result = $this->db->query($sql);
// Store original amounts in a separate way - we'll use the line_label to store them temporarily
if ($result && ($rounded_vat != $original_vat || $rounded_base != $original_base)) {
$original_info = "ORIGINAL_BASE:" . $original_base . "_ORIGINAL_VAT:" . $original_vat . "_ORIGINAL_TOTAL:" . $original_total;
$update_sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_ca3_lines
SET line_label = CONCAT(line_label, '|', '" . $this->db->escape($original_info) . "')
WHERE declaration_id = " . $declaration_id . " AND ca3_line = '" . $this->db->escape($ca3_line) . "'";
$this->db->query($update_sql);
}
return $result !== false;
}
/**
* Update declaration totals
*
* @param int $declaration_id Declaration ID
* @param float $total_vat_collected Total VAT collected
* @param float $total_vat_deductible Total VAT deductible
* @param float $net_vat_due Net VAT due
* @param float $vat_credit VAT credit
* @return bool Success
*/
public function updateDeclarationTotals($declaration_id, $total_vat_collected, $total_vat_deductible, $net_vat_due, $vat_credit)
{
// Round totals to whole numbers
$rounded_collected = round($total_vat_collected);
$rounded_deductible = round($total_vat_deductible);
$rounded_net_due = round($net_vat_due);
$rounded_credit = round($vat_credit);
$sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
SET total_vat_collected = " . $rounded_collected . ",
total_vat_deductible = " . $rounded_deductible . ",
net_vat_due = " . $rounded_net_due . ",
vat_credit = " . $rounded_credit . "
WHERE rowid = " . $declaration_id;
$result = $this->db->query($sql);
return $result !== false;
}
/**
* Get period information
*
* @param int $period_id Period ID
* @return array|false Period information or false if not found
*/
public function getPeriod($period_id)
{
$sql = "SELECT * FROM " . MAIN_DB_PREFIX . "declarationtva_periods
WHERE rowid = " . $period_id . " AND entity = " . $this->entity;
$result = $this->db->query($sql);
if ($result && $this->db->num_rows($result) > 0) {
return $this->db->fetch_array($result);
}
return false;
}
/**
* Generate declaration number
*
* @param array $period Period information
* @return string Declaration number
*/
public function generateDeclarationNumber($period)
{
$year = date('Y', strtotime($period['start_date']));
$start_month = date('m', strtotime($period['start_date']));
$end_month = date('m', strtotime($period['end_date']));
if ($start_month == $end_month) {
$month_part = $start_month;
} else {
$month_part = $start_month . '-' . $end_month;
}
return 'CA3-' . $year . '-' . $month_part . '-' . date('YmdHis');
}
/**
* Generate declaration number from dates
*
* @param string $start_date Start date
* @param string $end_date End date
* @return string Declaration number
*/
public function generateDeclarationNumberFromDates($start_date, $end_date)
{
$year = date('Y', strtotime($start_date));
$start_month = date('m', strtotime($start_date));
$end_month = date('m', strtotime($end_date));
if ($start_month == $end_month) {
$month_part = $start_month;
} else {
$month_part = $start_month . '-' . $end_month;
}
return 'CA3-' . $year . '-' . $month_part . '-' . date('YmdHis');
}
/**
* Get declaration information
*
* @param int $declaration_id Declaration ID
* @return array|false Declaration information or false if not found
*/
public function getDeclaration($declaration_id)
{
$sql = "SELECT d.*, p.period_name, p.start_date, p.end_date
FROM " . MAIN_DB_PREFIX . "declarationtva_declarations d
LEFT JOIN " . MAIN_DB_PREFIX . "declarationtva_periods p ON d.period_id = p.rowid
WHERE d.rowid = " . $declaration_id . " AND d.entity = " . $this->entity;
$result = $this->db->query($sql);
if ($result && $this->db->num_rows($result) > 0) {
return $this->db->fetch_array($result);
}
return false;
}
/**
* Get CA-3 lines for a declaration
*
* @param int $declaration_id Declaration ID
* @return array CA-3 lines
*/
public function getCA3Lines($declaration_id)
{
$sql = "SELECT * FROM " . MAIN_DB_PREFIX . "declarationtva_ca3_lines
WHERE declaration_id = " . $declaration_id . "
ORDER BY ca3_line";
$result = $this->db->query($sql);
$lines = array();
if ($result) {
while ($obj = $this->db->fetch_object($result)) {
$lines[] = array(
'ca3_line' => $obj->ca3_line,
'line_label' => $obj->line_label,
'base_amount' => $obj->base_amount,
'vat_amount' => $obj->vat_amount,
'total_amount' => $obj->total_amount
);
}
}
return $lines;
}
/**
* Validate declaration
*
* @param int $declaration_id Declaration ID
* @return bool Success
*/
public function validateDeclaration($declaration_id)
{
$sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
SET status = 'validated'
WHERE rowid = " . $declaration_id . " AND entity = " . $this->entity;
$result = $this->db->query($sql);
return $result !== false;
}
/**
* Submit declaration
*
* @param int $declaration_id Declaration ID
* @return bool Success
*/
public function submitDeclaration($declaration_id)
{
$sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
SET status = 'submitted', submission_date = NOW()
WHERE rowid = " . $declaration_id . " AND entity = " . $this->entity;
$result = $this->db->query($sql);
return $result !== false;
}
/**
* Delete a declaration
*
* @param int $declaration_id Declaration ID
* @return bool Success
*/
public function deleteDeclaration($declaration_id)
{
$this->db->begin();
// Check if declaration exists and is in draft status
$sql = "SELECT status FROM " . MAIN_DB_PREFIX . "declarationtva_declarations
WHERE rowid = " . (int)$declaration_id . " AND entity = " . $this->entity;
$result = $this->db->query($sql);
if ($result) {
$obj = $this->db->fetch_object($result);
if ($obj && $obj->status == 'draft') {
// Delete CA-3 lines first
$sql_lines = "DELETE FROM " . MAIN_DB_PREFIX . "declarationtva_ca3_lines
WHERE declaration_id = " . (int)$declaration_id;
$this->db->query($sql_lines);
// Delete declaration
$sql_declaration = "DELETE FROM " . MAIN_DB_PREFIX . "declarationtva_declarations
WHERE rowid = " . (int)$declaration_id . " AND entity = " . $this->entity;
$result = $this->db->query($sql_declaration);
if ($result) {
$this->db->commit();
return true;
}
}
}
$this->db->rollback();
return false;
}
/**
* Recalculate CA-3 amounts for a declaration
*
* @param int $declaration_id Declaration ID
* @return bool Success
*/
public function recalculateCA3Amounts($declaration_id)
{
// Get declaration info directly from database
$sql = "SELECT start_date, end_date FROM " . MAIN_DB_PREFIX . "declarationtva_declarations
WHERE rowid = " . $declaration_id . " AND entity = " . $this->entity;
$result = $this->db->query($sql);
if (!$result || $this->db->num_rows($result) == 0) {
return false;
}
$obj = $this->db->fetch_object($result);
// Clear existing CA-3 lines
$sql = "DELETE FROM " . MAIN_DB_PREFIX . "declarationtva_ca3_lines
WHERE declaration_id = " . $declaration_id;
$this->db->query($sql);
// Recalculate using declaration dates
$period = array(
'start_date' => $obj->start_date,
'end_date' => $obj->end_date
);
return $this->calculateCA3Amounts($declaration_id, $period);
}
/**
* Get account mappings with labels from chart of accounts
*
* @return array Array of account mappings with labels
*/
public function getAccountMappings()
{
$sql = "SELECT m.rowid, m.ca3_line, m.account_code, m.account_label, m.vat_rate, m.is_active,
a.label as account_label_pcg
FROM " . MAIN_DB_PREFIX . "declarationtva_account_mappings m
LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account a ON a.account_number = m.account_code AND a.entity = m.entity
WHERE m.entity = " . $this->entity . " AND m.is_active = 1
ORDER BY m.ca3_line, m.account_code";
$result = $this->db->query($sql);
$mappings = array();
if ($result) {
while ($obj = $this->db->fetch_object($result)) {
// Use the label from chart of accounts if available, otherwise use the stored label
$account_label = !empty($obj->account_label_pcg) ? $obj->account_label_pcg : $obj->account_label;
$mappings[] = array(
'rowid' => $obj->rowid,
'ca3_line' => $obj->ca3_line,
'account_code' => $obj->account_code,
'account_label' => $account_label,
'vat_rate' => $obj->vat_rate,
'is_active' => $obj->is_active
);
}
}
return $mappings;
}
/**
* Get detailed account breakdown for a specific CA-3 line
*
* @param int $declaration_id Declaration ID
* @param string $ca3_line CA-3 line code (e.g., 'A1', '08', '09', etc.)
* @return array Detailed breakdown with accounts and amounts
*/
public function getCA3LineDetails($declaration_id, $ca3_line)
{
// Get declaration dates
$sql = "SELECT start_date, end_date FROM " . MAIN_DB_PREFIX . "declarationtva_declarations
WHERE rowid = " . (int)$declaration_id . " AND entity = " . $this->entity;
$result = $this->db->query($sql);
if (!$result || $this->db->num_rows($result) == 0) {
return array();
}
$obj = $this->db->fetch_object($result);
$start_date = $obj->start_date;
$end_date = $obj->end_date;
// Get account mappings for this CA-3 line
$mappings = $this->getAccountMappings();
$line_mappings = array();
// Find mappings for this specific line
foreach ($mappings as $mapping) {
// Handle special cases for lines 08, 09, 9B which have _BASE and _VAT suffixes
if (in_array($ca3_line, array('08', '09', '9B'))) {
if ($mapping['ca3_line'] == $ca3_line . '_BASE' || $mapping['ca3_line'] == $ca3_line . '_VAT') {
$line_mappings[] = $mapping;
}
} else {
// Normal matching for other lines
if ($mapping['ca3_line'] == $ca3_line) {
$line_mappings[] = $mapping;
}
}
}
$details = array();
$total_base = 0;
$total_vat = 0;
$total_amount = 0;
// Process each mapped account
foreach ($line_mappings as $mapping) {
$account_code = $mapping['account_code'];
$account_label = $mapping['account_label'];
// Get account amounts for this period
$amounts = $this->getAccountAmounts($account_code, $start_date, $end_date);
$account_detail = array(
'account_code' => $account_code,
'account_label' => $account_label,
'base_amount' => $amounts['base_amount'],
'vat_amount' => $amounts['vat_amount'],
'total_amount' => $amounts['total_amount'],
'mapping_type' => $mapping['ca3_line'] // Will be 'A1', '08_BASE', '08_VAT', etc.
);
$details[] = $account_detail;
// Accumulate totals
$total_base += $amounts['base_amount'];
$total_vat += $amounts['vat_amount'];
$total_amount += $amounts['total_amount'];
}
// Get the calculated line total from CA-3 lines table
$sql_line = "SELECT base_amount, vat_amount, total_amount, line_label
FROM " . MAIN_DB_PREFIX . "declarationtva_ca3_lines
WHERE declaration_id = " . (int)$declaration_id . "
AND ca3_line = '" . $this->db->escape($ca3_line) . "'";
$result_line = $this->db->query($sql_line);
$calculated_line = null;
if ($result_line && $this->db->num_rows($result_line) > 0) {
$calculated_line = $this->db->fetch_object($result_line);
}
return array(
'ca3_line' => $ca3_line,
'declaration_id' => $declaration_id,
'start_date' => $start_date,
'end_date' => $end_date,
'account_details' => $details,
'calculated_line' => $calculated_line,
'totals' => array(
'base_amount' => $total_base,
'vat_amount' => $total_vat,
'total_amount' => $total_amount
),
'account_count' => count($details)
);
}
}