Debug Features: - Added error_log statements to getAccountAmounts() method - Added debugging to calculateCA3Amounts() method - Logs account queries, mappings found, and calculation results - Helps diagnose why calculations show 0.00 values To debug: 1. Check if PCG accounts are configured 2. Check if accounting data exists in Dolibarr 3. Check error logs for calculation details
559 lines
18 KiB
PHP
559 lines
18 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)
|
|
{
|
|
error_log("DeclarationTVA: Starting calculation for declaration $declaration_id");
|
|
error_log("DeclarationTVA: Period: " . $period['start_date'] . " to " . $period['end_date']);
|
|
|
|
// Get account mappings
|
|
$mappings = $this->getAccountMappings();
|
|
error_log("DeclarationTVA: Found " . count($mappings) . " account mappings");
|
|
|
|
$total_vat_collected = 0;
|
|
$total_vat_deductible = 0;
|
|
|
|
// Process each CA-3 line
|
|
foreach ($mappings as $mapping) {
|
|
error_log("DeclarationTVA: Processing mapping: " . $mapping['ca3_line'] . " -> " . $mapping['account_code']);
|
|
$amounts = $this->getAccountAmounts($mapping['account_code'], $period['start_date'], $period['end_date']);
|
|
|
|
// Create CA-3 line record
|
|
$this->createCA3Line($declaration_id, $mapping['ca3_line'], $mapping['account_label'], $amounts);
|
|
|
|
// Update totals
|
|
if (in_array($mapping['ca3_line'], ['A1', 'A2', 'B1', 'B2', 'B3', 'B4', '17'])) {
|
|
$total_vat_collected += $amounts['vat_amount'];
|
|
} elseif (in_array($mapping['ca3_line'], ['20', '21'])) {
|
|
$total_vat_deductible += $amounts['vat_amount'];
|
|
}
|
|
}
|
|
|
|
error_log("DeclarationTVA: Totals - Collected: $total_vat_collected, Deductible: $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;
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
// Query Dolibarr accounting entries
|
|
$sql = "SELECT SUM(debit) as total_debit, SUM(credit) as total_credit
|
|
FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping
|
|
WHERE account_number = '" . $this->db->escape($account_code) . "'
|
|
AND doc_date >= '" . $this->db->escape($start_date) . "'
|
|
AND doc_date <= '" . $this->db->escape($end_date) . "'";
|
|
|
|
// Debug: Log the query
|
|
error_log("DeclarationTVA: Querying account $account_code from $start_date to $end_date");
|
|
error_log("DeclarationTVA: SQL: $sql");
|
|
|
|
$result = $this->db->query($sql);
|
|
if ($result && $this->db->num_rows($result) > 0) {
|
|
$obj = $this->db->fetch_object($result);
|
|
$total_amount = $obj->total_debit - $obj->total_credit;
|
|
|
|
error_log("DeclarationTVA: Found amounts for $account_code: debit=$obj->total_debit, credit=$obj->total_credit, net=$total_amount");
|
|
|
|
return array(
|
|
'base_amount' => $total_amount,
|
|
'vat_amount' => $total_amount,
|
|
'total_amount' => $total_amount
|
|
);
|
|
}
|
|
|
|
error_log("DeclarationTVA: No data found for account $account_code");
|
|
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)
|
|
{
|
|
$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) . "', " . $amounts['base_amount'] . ",
|
|
" . $amounts['vat_amount'] . ", " . $amounts['total_amount'] . ", NOW())";
|
|
|
|
$result = $this->db->query($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)
|
|
{
|
|
$sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
|
|
SET total_vat_collected = " . $total_vat_collected . ",
|
|
total_vat_deductible = " . $total_vat_deductible . ",
|
|
net_vat_due = " . $net_vat_due . ",
|
|
vat_credit = " . $vat_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
|
|
$declaration = $this->getDeclarationInfo($declaration_id);
|
|
if (!$declaration) {
|
|
return false;
|
|
}
|
|
|
|
// 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' => $declaration['start_date'],
|
|
'end_date' => $declaration['end_date']
|
|
);
|
|
|
|
return $this->calculateCA3Amounts($declaration_id, $period);
|
|
}
|
|
}
|