Fixed: - Grouped BASE and VAT accounts separately for lines 08, 09, 9B - Added clear section headers: 'Base Accounts (Sales)' and 'VAT Accounts' - Improved visual organization of account breakdown - Removed debugging code - Added translations for new section headers This ensures users can clearly see which accounts contribute to base amounts vs VAT amounts for the special lines.
958 lines
35 KiB
PHP
958 lines
35 KiB
PHP
<?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', '08', '09', '9B', '17', '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])) {
|
|
error_log("DeclarationTVA: Processing CA-3 line $ca3_line with " . count($grouped_mappings[$ca3_line]) . " mapped accounts");
|
|
foreach ($grouped_mappings[$ca3_line] as $mapping) {
|
|
error_log("DeclarationTVA: Processing account " . $mapping['account_code'] . " for line $ca3_line");
|
|
$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'];
|
|
|
|
error_log("DeclarationTVA: Account " . $mapping['account_code'] . " amounts: base=" . $amounts['base_amount'] . ", vat=" . $amounts['vat_amount']);
|
|
}
|
|
} else {
|
|
error_log("DeclarationTVA: No mappings found for CA-3 line $ca3_line");
|
|
}
|
|
}
|
|
|
|
// 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';
|
|
$this->createCA3Line($declaration_id, $ca3_line, $combined_label, $combined_amounts);
|
|
|
|
// Log the final amounts for debugging
|
|
error_log("DeclarationTVA: Final amounts for line $ca3_line: base=$line_total_base, vat=$line_total_vat, total=$line_total_amount");
|
|
|
|
// Update totals - only VAT amounts from sections B and C
|
|
if (in_array($ca3_line, ['08', '09', '9B'])) {
|
|
// Section B: VAT amounts only (line 17 is manual entry)
|
|
$total_vat_collected += $line_total_vat;
|
|
} elseif (in_array($ca3_line, ['20', '21', '22'])) {
|
|
// Section C: VAT amounts only
|
|
$total_vat_deductible += $line_total_vat;
|
|
}
|
|
}
|
|
|
|
// Debug totals
|
|
error_log("DeclarationTVA: Total VAT collected: $total_vat_collected, Total VAT deductible: $total_vat_deductible");
|
|
|
|
// 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;
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
// Calculate net VAT due
|
|
$net_vat_due = $total_vat_collected - $total_vat_deductible;
|
|
|
|
// Line 25: TVA brute due (Total VAT due) - only if negative (VAT credit - we receive money)
|
|
if ($net_vat_due < 0) {
|
|
$line_25_amount = $total_vat_collected;
|
|
$this->createCA3Line($declaration_id, '25', 'Calculated from sections A and B', array(
|
|
'base_amount' => 0,
|
|
'vat_amount' => $line_25_amount,
|
|
'total_amount' => $line_25_amount
|
|
));
|
|
} else {
|
|
$this->createCA3Line($declaration_id, '25', 'Calculated from sections A and B', array(
|
|
'base_amount' => 0,
|
|
'vat_amount' => 0,
|
|
'total_amount' => 0
|
|
));
|
|
}
|
|
|
|
// Line 26: TVA déductible totale (Total deductible VAT)
|
|
$line_26_amount = $total_vat_deductible;
|
|
$this->createCA3Line($declaration_id, '26', 'Calculated from section C', array(
|
|
'base_amount' => 0,
|
|
'vat_amount' => $line_26_amount,
|
|
'total_amount' => $line_26_amount
|
|
));
|
|
|
|
// Line TD: TVA due (VAT due) - only if positive (we need to pay)
|
|
if ($net_vat_due > 0) {
|
|
$line_td_amount = $net_vat_due;
|
|
$this->createCA3Line($declaration_id, 'TD', 'TVA due (amount to pay)', array(
|
|
'base_amount' => 0,
|
|
'vat_amount' => $line_td_amount,
|
|
'total_amount' => $line_td_amount
|
|
));
|
|
} else {
|
|
$this->createCA3Line($declaration_id, 'TD', 'TVA due (amount to pay)', array(
|
|
'base_amount' => 0,
|
|
'vat_amount' => 0,
|
|
'total_amount' => 0
|
|
));
|
|
}
|
|
|
|
// Line 28: TVA nette due (Net VAT due) - if positive
|
|
if ($net_vat_due > 0) {
|
|
$this->createCA3Line($declaration_id, '28', 'Calculated: 25 - 26', array(
|
|
'base_amount' => 0,
|
|
'vat_amount' => $net_vat_due,
|
|
'total_amount' => $net_vat_due
|
|
));
|
|
} else {
|
|
$this->createCA3Line($declaration_id, '28', 'Calculated: 25 - 26', array(
|
|
'base_amount' => 0,
|
|
'vat_amount' => 0,
|
|
'total_amount' => 0
|
|
));
|
|
}
|
|
|
|
// Line 29: Crédit de TVA (VAT Credit) - if negative
|
|
if ($net_vat_due < 0) {
|
|
$vat_credit = abs($net_vat_due);
|
|
$this->createCA3Line($declaration_id, '29', 'Calculated: 26 - 25', array(
|
|
'base_amount' => 0,
|
|
'vat_amount' => $vat_credit,
|
|
'total_amount' => $vat_credit
|
|
));
|
|
} else {
|
|
$this->createCA3Line($declaration_id, '29', 'Calculated: 26 - 25', 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);
|
|
}
|
|
|
|
// Log successful query for debugging
|
|
error_log("DeclarationTVA: Found data with query: " . substr($sql, 0, 100) . "... Debit: " . $obj->total_debit . ", Credit: " . $obj->total_credit . ", Amount: $total_amount");
|
|
|
|
return array(
|
|
'base_amount' => $total_amount,
|
|
'vat_amount' => $total_amount,
|
|
'total_amount' => $total_amount
|
|
);
|
|
}
|
|
}
|
|
|
|
// If no data found, log the account code for debugging
|
|
error_log("DeclarationTVA: No data found for account $account_code in any accounting table");
|
|
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 account mappings
|
|
*
|
|
* @return array Account mappings
|
|
*/
|
|
public function getAccountMappings()
|
|
{
|
|
$sql = "SELECT ca3_line, account_code, account_label, vat_rate
|
|
FROM " . MAIN_DB_PREFIX . "declarationtva_account_mappings
|
|
WHERE entity = " . $this->entity . " AND is_active = 1
|
|
ORDER BY ca3_line";
|
|
|
|
$result = $this->db->query($sql);
|
|
$mappings = array();
|
|
|
|
if ($result) {
|
|
while ($obj = $this->db->fetch_object($result)) {
|
|
$mappings[] = array(
|
|
'ca3_line' => $obj->ca3_line,
|
|
'account_code' => $obj->account_code,
|
|
'account_label' => $obj->account_label,
|
|
'vat_rate' => $obj->vat_rate
|
|
);
|
|
}
|
|
}
|
|
|
|
return $mappings;
|
|
}
|
|
|
|
/**
|
|
* 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 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)
|
|
);
|
|
}
|
|
}
|