1893 lines
72 KiB
PHP
1893 lines
72 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', '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
|
||
));
|
||
}
|
||
|
||
// Get VAT refund threshold configuration
|
||
require_once DOL_DOCUMENT_ROOT . '/custom/declarationtva/core/class/declarationtva_config.class.php';
|
||
$config = new DeclarationTVA_Config($this->db, $this->entity);
|
||
$threshold_config = $config->getVATRefundThresholdConfiguration();
|
||
$refund_threshold = $threshold_config['refund_threshold'];
|
||
$threshold_enabled = $threshold_config['refund_threshold_enabled'];
|
||
|
||
// Line 26: Crédit de TVA à rembourser (≥ threshold)
|
||
if ($line_25_amount > 0 && (!$threshold_enabled || $line_25_amount >= $refund_threshold)) {
|
||
$this->createCA3Line($declaration_id, '26', 'Crédit de TVA à rembourser (ligne 25 – ligne 26)', array(
|
||
'base_amount' => 0,
|
||
'vat_amount' => $line_25_amount,
|
||
'total_amount' => $line_25_amount
|
||
));
|
||
} else {
|
||
$this->createCA3Line($declaration_id, '26', 'Crédit de TVA à rembourser (ligne 25 – ligne 26)', array(
|
||
'base_amount' => 0,
|
||
'vat_amount' => 0,
|
||
'total_amount' => 0
|
||
));
|
||
}
|
||
|
||
// Line 27: Crédit de TVA à reporter (< threshold)
|
||
$line_27_amount = $line_25_amount; // Same value as line 25
|
||
if ($line_25_amount > 0 && $threshold_enabled && $line_25_amount < $refund_threshold) {
|
||
$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 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)
|
||
{
|
||
// Get amount calculation configuration
|
||
require_once DOL_DOCUMENT_ROOT . '/custom/declarationtva/core/class/declarationtva_config.class.php';
|
||
$config = new DeclarationTVA_Config($this->db, $this->entity);
|
||
$calc_config = $config->getAmountCalculationConfiguration();
|
||
|
||
// Apply calculation method (round or truncate)
|
||
if ($calc_config['amount_calculation_method'] == 'truncate') {
|
||
$rounded_base = floor($amounts['base_amount']);
|
||
$rounded_vat = floor($amounts['vat_amount']);
|
||
$rounded_total = floor($amounts['total_amount']);
|
||
} else {
|
||
// Default to rounding
|
||
$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;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* 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 VAT credit carry-forward from previous periods
|
||
*/
|
||
public function getVATCreditCarryForward($declaration_start_date)
|
||
{
|
||
// Get journal configuration to use the correct account
|
||
require_once DOL_DOCUMENT_ROOT . '/custom/declarationtva/core/class/declarationtva_config.class.php';
|
||
$config = new DeclarationTVA_Config($this->db, $this->entity);
|
||
$journal_config = $config->getJournalConfiguration();
|
||
$vat_to_receive_account = $journal_config['vat_to_receive'];
|
||
|
||
// Check VAT credit account balance at declaration start date
|
||
$sql = "SELECT SUM(debit - credit) as balance
|
||
FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping
|
||
WHERE account_number = '" . $this->db->escape($vat_to_receive_account) . "'
|
||
AND doc_date < '" . $declaration_start_date . "'";
|
||
|
||
$result = $this->db->query($sql);
|
||
if ($result && $this->db->num_rows($result) > 0) {
|
||
$obj = $this->db->fetch_object($result);
|
||
return max(0, $obj->balance); // Only positive balances (credits)
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* Create accounting entries for declaration submission
|
||
*
|
||
* @param int $declaration_id Declaration ID
|
||
* @return bool Success
|
||
*/
|
||
public function createAccountingEntries($declaration_id)
|
||
{
|
||
global $user;
|
||
|
||
// Get declaration data
|
||
$fetch_result = $this->fetch($declaration_id);
|
||
if (!$fetch_result) {
|
||
$this->error = 'Declaration not found';
|
||
return false;
|
||
}
|
||
|
||
// Create a declaration object with the fetched data
|
||
$declaration = new stdClass();
|
||
$declaration->rowid = $this->rowid;
|
||
$declaration->declaration_name = $this->declaration_name;
|
||
$declaration->start_date = $this->start_date;
|
||
$declaration->end_date = $this->end_date;
|
||
|
||
// Get CA-3 lines data
|
||
$ca3_lines = $this->getCA3Lines($declaration_id);
|
||
if (empty($ca3_lines)) {
|
||
$this->error = 'No CA-3 lines found for declaration';
|
||
return false;
|
||
}
|
||
|
||
// Debug: Log CA-3 lines found
|
||
error_log("DEBUG: Found " . count($ca3_lines) . " CA-3 lines for declaration " . $declaration_id);
|
||
|
||
// Create lookup array for CA-3 data
|
||
$ca3_lookup = array();
|
||
foreach ($ca3_lines as $line) {
|
||
$ca3_lookup[$line['ca3_line']] = $line;
|
||
}
|
||
|
||
// Get journal configuration
|
||
require_once DOL_DOCUMENT_ROOT . '/custom/declarationtva/core/class/declarationtva_config.class.php';
|
||
$config = new DeclarationTVA_Config($this->db, $this->entity);
|
||
$journal_config = $config->getJournalConfiguration();
|
||
|
||
// Create OD journal entries
|
||
$od_entries = $this->createODJournalEntries($declaration, $ca3_lookup, $journal_config);
|
||
error_log("DEBUG: OD entries result: " . ($od_entries ? "SUCCESS" : "FAILED"));
|
||
if (!$od_entries) {
|
||
return false;
|
||
}
|
||
|
||
// Create bank journal entries
|
||
$bank_entries = $this->createBankJournalEntries($declaration, $ca3_lookup, $journal_config, $user);
|
||
if (!$bank_entries) {
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Create OD journal entries for VAT accounts
|
||
*
|
||
* @param object $declaration Declaration object
|
||
* @param array $ca3_lookup CA-3 data lookup array
|
||
* @param array $journal_config Journal configuration
|
||
* @return bool Success
|
||
*/
|
||
private function createODJournalEntries($declaration, $ca3_lookup, $journal_config)
|
||
{
|
||
$entries = array();
|
||
|
||
// Get line 8 VAT accounts (debit side)
|
||
$line8_entries = $this->getLine8VATAccountsForAccounting($declaration, $ca3_lookup);
|
||
error_log("DEBUG: Line 8 entries: " . count($line8_entries));
|
||
$entries = array_merge($entries, $line8_entries);
|
||
|
||
// Get line 20 accounts (credit side)
|
||
$line20_entries = $this->getLine20AccountsForAccounting($declaration, $ca3_lookup);
|
||
error_log("DEBUG: Line 20 entries: " . count($line20_entries));
|
||
$entries = array_merge($entries, $line20_entries);
|
||
|
||
// Add balancing entry
|
||
$balancing_entry = $this->getVATResultEntryForAccounting($declaration, $ca3_lookup, $journal_config);
|
||
error_log("DEBUG: Balancing entry: " . ($balancing_entry ? "FOUND" : "NONE"));
|
||
if ($balancing_entry) {
|
||
$entries[] = $balancing_entry;
|
||
}
|
||
|
||
error_log("DEBUG: Total OD entries to create: " . count($entries));
|
||
|
||
// Create accounting entries in Dolibarr
|
||
return $this->saveAccountingEntries($entries, $declaration, $user);
|
||
}
|
||
|
||
/**
|
||
* Create bank journal entries for payments/refunds
|
||
*
|
||
* @param object $declaration Declaration object
|
||
* @param array $ca3_lookup CA-3 data lookup array
|
||
* @param array $journal_config Journal configuration
|
||
* @param object $user User object
|
||
* @return bool Success
|
||
*/
|
||
private function createBankJournalEntries($declaration, $ca3_lookup, $journal_config, $user)
|
||
{
|
||
// Get bank account configuration
|
||
require_once DOL_DOCUMENT_ROOT . '/custom/declarationtva/core/class/declarationtva_config.class.php';
|
||
$config = new DeclarationTVA_Config($this->db, $this->entity);
|
||
$bank_config = $config->getBankAccountConfiguration();
|
||
$bank_account_id = $bank_config['bank_account'];
|
||
|
||
if (empty($bank_account_id) || $bank_account_id == 0) {
|
||
// No bank account configured - skip bank entries
|
||
return true;
|
||
}
|
||
|
||
// Get bank account details
|
||
$bank_account = $this->getBankAccountDetails($bank_account_id);
|
||
if (!$bank_account) {
|
||
$this->error = 'Bank account not found';
|
||
return false;
|
||
}
|
||
|
||
// Calculate VAT amounts
|
||
$line_16_amount = $this->getLineAmount($declaration->rowid, '16');
|
||
$line_23_amount = $this->getLineAmount($declaration->rowid, '23');
|
||
$td_amount = $line_16_amount - $line_23_amount;
|
||
|
||
$entries = array();
|
||
|
||
if ($td_amount > 0) {
|
||
// VAT payment case - money going out
|
||
$entries[] = array(
|
||
'account_code' => $bank_account['account_code'],
|
||
'account_label' => $bank_account['account_label'],
|
||
'entry_label' => 'Paiement TVA - ' . $declaration->declaration_name,
|
||
'debit' => '',
|
||
'credit' => $td_amount
|
||
);
|
||
|
||
$entries[] = array(
|
||
'account_code' => $journal_config['vat_to_pay'],
|
||
'account_label' => $this->getAccountLabel($journal_config['vat_to_pay']),
|
||
'entry_label' => 'Paiement TVA - ' . $declaration->declaration_name,
|
||
'debit' => $td_amount,
|
||
'credit' => ''
|
||
);
|
||
} elseif ($td_amount < 0) {
|
||
// VAT refund case - money coming in
|
||
$vat_credit = abs($td_amount);
|
||
|
||
// Determine which credit account to use based on threshold
|
||
$threshold_config = $config->getVATRefundThresholdConfiguration();
|
||
$refund_threshold = $threshold_config['refund_threshold'];
|
||
$threshold_enabled = $threshold_config['refund_threshold_enabled'];
|
||
|
||
if ($threshold_enabled && $vat_credit < $refund_threshold) {
|
||
// Use carry-forward account
|
||
$vat_account = $journal_config['vat_to_receive'];
|
||
} else {
|
||
// Use immediate refund account
|
||
$vat_account = $journal_config['vat_refund'];
|
||
}
|
||
|
||
$entries[] = array(
|
||
'account_code' => $bank_account['account_code'],
|
||
'account_label' => $bank_account['account_label'],
|
||
'entry_label' => 'Remboursement TVA - ' . $declaration->declaration_name,
|
||
'debit' => $vat_credit,
|
||
'credit' => ''
|
||
);
|
||
|
||
$entries[] = array(
|
||
'account_code' => $vat_account,
|
||
'account_label' => $this->getAccountLabel($vat_account),
|
||
'entry_label' => 'Remboursement TVA - ' . $declaration->declaration_name,
|
||
'debit' => '',
|
||
'credit' => $vat_credit
|
||
);
|
||
}
|
||
|
||
// Create accounting entries in Dolibarr
|
||
return $this->saveAccountingEntries($entries, $declaration, $user);
|
||
}
|
||
|
||
/**
|
||
* Get line 8 VAT accounts for accounting entries
|
||
*
|
||
* @param object $declaration Declaration object
|
||
* @param array $ca3_lookup CA-3 data lookup array
|
||
* @return array Accounting entries
|
||
*/
|
||
private function getLine8VATAccountsForAccounting($declaration, $ca3_lookup)
|
||
{
|
||
$entries = array();
|
||
|
||
if (!isset($ca3_lookup['08'])) {
|
||
return $entries;
|
||
}
|
||
|
||
error_log("DEBUG: Declaration object rowid: " . ($declaration->rowid ?? 'NULL'));
|
||
$line8_details = $this->getCA3LineDetails($declaration->rowid, '08');
|
||
|
||
if (empty($line8_details) || empty($line8_details['account_details'])) {
|
||
return $entries;
|
||
}
|
||
|
||
foreach ($line8_details['account_details'] as $account) {
|
||
// Only include 445 accounts (VAT accounts) with non-zero amounts
|
||
if (strpos($account['account_code'], '445') === 0 && $account['vat_amount'] > 0) {
|
||
$entries[] = array(
|
||
'account_code' => $account['account_code'],
|
||
'account_label' => $account['account_label'],
|
||
'entry_label' => $declaration->declaration_name,
|
||
'debit' => $account['vat_amount'],
|
||
'credit' => 0
|
||
);
|
||
}
|
||
}
|
||
|
||
return $entries;
|
||
}
|
||
|
||
/**
|
||
* Get line 20 accounts for accounting entries
|
||
*
|
||
* @param object $declaration Declaration object
|
||
* @param array $ca3_lookup CA-3 data lookup array
|
||
* @return array Accounting entries
|
||
*/
|
||
private function getLine20AccountsForAccounting($declaration, $ca3_lookup)
|
||
{
|
||
$entries = array();
|
||
|
||
if (!isset($ca3_lookup['20'])) {
|
||
return $entries;
|
||
}
|
||
|
||
$line20_details = $this->getCA3LineDetails($declaration->rowid, '20');
|
||
|
||
if (empty($line20_details) || empty($line20_details['account_details'])) {
|
||
return $entries;
|
||
}
|
||
|
||
foreach ($line20_details['account_details'] as $account) {
|
||
// Only include 445 accounts (VAT accounts) with non-zero amounts
|
||
if (strpos($account['account_code'], '445') === 0 && $account['vat_amount'] > 0) {
|
||
$entries[] = array(
|
||
'account_code' => $account['account_code'],
|
||
'account_label' => $account['account_label'],
|
||
'entry_label' => $declaration->declaration_name,
|
||
'debit' => 0,
|
||
'credit' => $account['vat_amount']
|
||
);
|
||
}
|
||
}
|
||
|
||
return $entries;
|
||
}
|
||
|
||
/**
|
||
* Get VAT result entry for accounting
|
||
*
|
||
* @param object $declaration Declaration object
|
||
* @param array $ca3_lookup CA-3 data lookup array
|
||
* @param array $journal_config Journal configuration
|
||
* @return array|null Accounting entry
|
||
*/
|
||
private function getVATResultEntryForAccounting($declaration, $ca3_lookup, $journal_config)
|
||
{
|
||
// Get TD line amount (Line 16 - Line 23)
|
||
$line_16_amount = $this->getLineAmount($declaration->rowid, '16');
|
||
$line_23_amount = $this->getLineAmount($declaration->rowid, '23');
|
||
$td_amount = $line_16_amount - $line_23_amount;
|
||
|
||
if ($td_amount > 0) {
|
||
// VAT due case
|
||
return array(
|
||
'account_code' => $journal_config['vat_to_pay'],
|
||
'account_label' => $this->getAccountLabel($journal_config['vat_to_pay']),
|
||
'entry_label' => $declaration->declaration_name,
|
||
'debit' => 0,
|
||
'credit' => $td_amount
|
||
);
|
||
} elseif ($td_amount < 0) {
|
||
// VAT credit case
|
||
$vat_credit = abs($td_amount);
|
||
|
||
// Determine which credit account to use based on threshold
|
||
require_once DOL_DOCUMENT_ROOT . '/custom/declarationtva/core/class/declarationtva_config.class.php';
|
||
$config = new DeclarationTVA_Config($this->db, $this->entity);
|
||
$threshold_config = $config->getVATRefundThresholdConfiguration();
|
||
$refund_threshold = $threshold_config['refund_threshold'];
|
||
$threshold_enabled = $threshold_config['refund_threshold_enabled'];
|
||
|
||
if ($threshold_enabled && $vat_credit < $refund_threshold) {
|
||
// Use carry-forward account
|
||
$vat_account = $journal_config['vat_to_receive'];
|
||
} else {
|
||
// Use immediate refund account
|
||
$vat_account = $journal_config['vat_refund'];
|
||
}
|
||
|
||
return array(
|
||
'account_code' => $vat_account,
|
||
'account_label' => $this->getAccountLabel($vat_account),
|
||
'entry_label' => $declaration->declaration_name,
|
||
'debit' => $vat_credit,
|
||
'credit' => 0
|
||
);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Save accounting entries to Dolibarr
|
||
*
|
||
* @param array $entries Accounting entries
|
||
* @param object $declaration Declaration object
|
||
* @param object $user User object
|
||
* @return bool Success
|
||
*/
|
||
private function saveAccountingEntries($entries, $declaration, $user)
|
||
{
|
||
if (empty($entries)) {
|
||
return true; // No entries to save
|
||
}
|
||
|
||
// Use Dolibarr's bookkeeping class
|
||
require_once DOL_DOCUMENT_ROOT . '/accountancy/class/bookkeeping.class.php';
|
||
|
||
$bookkeeping = new Bookkeeping($this->db);
|
||
|
||
foreach ($entries as $entry) {
|
||
// Create accounting entry
|
||
$bookkeeping->doc_type = 'declarationtva';
|
||
$bookkeeping->doc_ref = $declaration->declaration_name;
|
||
$bookkeeping->doc_date = $declaration->end_date; // Use declaration end date for OD entries
|
||
$bookkeeping->account_number = $entry['account_code'];
|
||
$bookkeeping->account_label = $entry['account_label'];
|
||
$bookkeeping->debit = $entry['debit'];
|
||
$bookkeeping->credit = $entry['credit'];
|
||
$bookkeeping->label = $entry['entry_label'];
|
||
$bookkeeping->entity = $this->entity;
|
||
|
||
$result = $bookkeeping->create($user);
|
||
if (!$result) {
|
||
$this->error = 'Failed to create accounting entry: ' . $bookkeeping->error;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Get bank account details
|
||
*
|
||
* @param int $bank_account_id Bank account ID
|
||
* @return array|false Bank account details
|
||
*/
|
||
private function getBankAccountDetails($bank_account_id)
|
||
{
|
||
$sql = "SELECT ba.rowid, ba.label, ba.number, a.account_number as account_code, a.label as account_label
|
||
FROM " . MAIN_DB_PREFIX . "bank_account ba
|
||
LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account a ON a.rowid = ba.account_number
|
||
WHERE ba.rowid = " . (int)$bank_account_id . " AND ba.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 account label from account code
|
||
*
|
||
* @param string $account_code Account code
|
||
* @return string Account label
|
||
*/
|
||
private function getAccountLabel($account_code)
|
||
{
|
||
$sql = "SELECT label FROM " . MAIN_DB_PREFIX . "accounting_account
|
||
WHERE account_number = '" . $this->db->escape($account_code) . "'
|
||
AND entity = " . $this->entity;
|
||
|
||
$result = $this->db->query($sql);
|
||
if ($result && $this->db->num_rows($result) > 0) {
|
||
$obj = $this->db->fetch_object($result);
|
||
return $obj->label;
|
||
}
|
||
|
||
return $account_code; // Fallback to account code
|
||
}
|
||
|
||
/**
|
||
* Submit declaration (create accounting entries and update status)
|
||
*
|
||
* @param int $declaration_id Declaration ID
|
||
* @return bool Success
|
||
*/
|
||
public function submitDeclaration($declaration_id)
|
||
{
|
||
global $user;
|
||
|
||
// Get declaration data
|
||
$declaration = $this->fetch($declaration_id);
|
||
if (!$declaration) {
|
||
$this->error = 'Declaration not found';
|
||
return false;
|
||
}
|
||
|
||
// Check if declaration is validated
|
||
// TEMPORARILY DISABLED FOR TESTING - allows re-submission
|
||
/*
|
||
if ($declaration->status !== 'validated') {
|
||
$this->error = 'Declaration must be validated before submission';
|
||
return false;
|
||
}
|
||
*/
|
||
|
||
// Check if accounting entries are enabled
|
||
require_once DOL_DOCUMENT_ROOT . '/custom/declarationtva/core/class/declarationtva_config.class.php';
|
||
$config = new DeclarationTVA_Config($this->db, $this->entity);
|
||
$auto_create_config = $config->getAutoCreateAccountingConfiguration();
|
||
|
||
if (!isset($auto_create_config['auto_create_accounting']) || !$auto_create_config['auto_create_accounting']) {
|
||
// Accounting entries disabled - just update status
|
||
return $this->updateDeclarationStatus($declaration_id, 'submitted');
|
||
}
|
||
|
||
// Create accounting entries
|
||
$accounting_result = $this->createAccountingEntries($declaration_id);
|
||
if (!$accounting_result) {
|
||
$this->error = 'Failed to create accounting entries: ' . $this->error;
|
||
return false;
|
||
}
|
||
|
||
// Update declaration status to submitted
|
||
$status_result = $this->updateDeclarationStatus($declaration_id, 'submitted');
|
||
if (!$status_result) {
|
||
$this->error = 'Failed to update declaration status: ' . $this->error;
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Reset declaration status to validated (for testing purposes)
|
||
*
|
||
* @param int $declaration_id Declaration ID
|
||
* @return bool Success
|
||
*/
|
||
public function resetDeclarationStatus($declaration_id)
|
||
{
|
||
$sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
|
||
SET status = 'validated'
|
||
WHERE rowid = " . (int)$declaration_id . " AND entity = " . $this->entity;
|
||
|
||
$result = $this->db->query($sql);
|
||
if (!$result) {
|
||
$this->error = 'Database error: ' . $this->db->lasterror();
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Update declaration status
|
||
*
|
||
* @param int $declaration_id Declaration ID
|
||
* @param string $status New status
|
||
* @return bool Success
|
||
*/
|
||
private function updateDeclarationStatus($declaration_id, $status)
|
||
{
|
||
$sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
|
||
SET status = '" . $this->db->escape($status) . "'
|
||
WHERE rowid = " . (int)$declaration_id;
|
||
|
||
$result = $this->db->query($sql);
|
||
if (!$result) {
|
||
$this->error = 'Database error: ' . $this->db->lasterror();
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Validate accounting entries balance
|
||
*
|
||
* @param array $entries Accounting entries
|
||
* @return bool Is balanced
|
||
*/
|
||
private function validateAccountingBalance($entries)
|
||
{
|
||
$total_debit = 0;
|
||
$total_credit = 0;
|
||
|
||
foreach ($entries as $entry) {
|
||
$total_debit += (float)$entry['debit'];
|
||
$total_credit += (float)$entry['credit'];
|
||
}
|
||
|
||
// Allow for small rounding differences (0.01)
|
||
return abs($total_debit - $total_credit) < 0.01;
|
||
}
|
||
|
||
/**
|
||
* 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)
|
||
{
|
||
error_log("DEBUG: getCA3LineDetails called for declaration $declaration_id, line $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) {
|
||
error_log("DEBUG: No declaration dates found for declaration $declaration_id");
|
||
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);
|
||
}
|
||
|
||
$result = 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)
|
||
);
|
||
|
||
error_log("DEBUG: getCA3LineDetails returning " . count($details) . " account details for line $ca3_line");
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* Validate a declaration
|
||
*
|
||
* @param int $declaration_id Declaration ID
|
||
* @return bool Success
|
||
*/
|
||
public function validateDeclaration($declaration_id)
|
||
{
|
||
// First, check if the validated_date and validated_by columns exist
|
||
$sql_check_columns = "SHOW COLUMNS FROM " . MAIN_DB_PREFIX . "declarationtva_declarations LIKE 'validated_date'";
|
||
$result_check = $this->db->query($sql_check_columns);
|
||
$has_validated_columns = ($result_check && $this->db->num_rows($result_check) > 0);
|
||
|
||
if ($has_validated_columns) {
|
||
// Use the enhanced version with validated_date and validated_by
|
||
$sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
|
||
SET status = 'validated',
|
||
validated_date = NOW(),
|
||
validated_by = " . $this->db->escape($GLOBALS['user']->id) . "
|
||
WHERE rowid = " . (int)$declaration_id . "
|
||
AND entity = " . $this->entity;
|
||
} else {
|
||
// Use the basic version without the additional columns
|
||
$sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
|
||
SET status = 'validated'
|
||
WHERE rowid = " . (int)$declaration_id . "
|
||
AND entity = " . $this->entity;
|
||
}
|
||
|
||
$result = $this->db->query($sql);
|
||
if (!$result) {
|
||
$this->error = "Database error updating declaration: " . $this->db->lasterror();
|
||
return false;
|
||
}
|
||
|
||
// Check if the update actually affected any rows
|
||
if ($this->db->affected_rows($result) == 0) {
|
||
$this->error = "No declaration found with ID " . $declaration_id . " or insufficient permissions";
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Unvalidate a declaration (for testing purposes)
|
||
*
|
||
* @param int $declaration_id Declaration ID
|
||
* @return bool Success
|
||
*/
|
||
public function unvalidateDeclaration($declaration_id)
|
||
{
|
||
// Check if the validated_date and validated_by columns exist
|
||
$sql_check_columns = "SHOW COLUMNS FROM " . MAIN_DB_PREFIX . "declarationtva_declarations LIKE 'validated_date'";
|
||
$result_check = $this->db->query($sql_check_columns);
|
||
$has_validated_columns = ($result_check && $this->db->num_rows($result_check) > 0);
|
||
|
||
if ($has_validated_columns) {
|
||
// Use the enhanced version with validated_date and validated_by
|
||
$sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
|
||
SET status = 'draft',
|
||
validated_date = NULL,
|
||
validated_by = NULL
|
||
WHERE rowid = " . (int)$declaration_id . "
|
||
AND entity = " . $this->entity;
|
||
} else {
|
||
// Use the basic version without the additional columns
|
||
$sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
|
||
SET status = 'draft'
|
||
WHERE rowid = " . (int)$declaration_id . "
|
||
AND entity = " . $this->entity;
|
||
}
|
||
|
||
$result = $this->db->query($sql);
|
||
if (!$result) {
|
||
$this->error = "Database error updating declaration: " . $this->db->lasterror();
|
||
return false;
|
||
}
|
||
|
||
// Check if the update actually affected any rows
|
||
if ($this->db->affected_rows($result) == 0) {
|
||
$this->error = "No declaration found with ID " . $declaration_id . " or insufficient permissions";
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Save validated PDF to Dolibarr documents
|
||
*
|
||
* @param int $declaration_id Declaration ID
|
||
* @param string $pdf_path Path to the PDF file
|
||
* @return bool Success
|
||
*/
|
||
public function saveValidatedPDF($declaration_id, $pdf_path)
|
||
{
|
||
global $conf, $user;
|
||
|
||
try {
|
||
// Create VAT declarations validated directory structure
|
||
$vat_declarations_dir = DOL_DATA_ROOT . '/declarationtva/validated/';
|
||
|
||
// Create directory if it doesn't exist
|
||
if (!is_dir($vat_declarations_dir)) {
|
||
if (!dol_mkdir($vat_declarations_dir)) {
|
||
$this->error = "Failed to create VAT declarations directory: " . $vat_declarations_dir;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// Check if PDF is already in the correct location
|
||
if (strpos($pdf_path, $vat_declarations_dir) === 0) {
|
||
// PDF is already in the correct location, no need to copy
|
||
$dest_path = $pdf_path;
|
||
} else {
|
||
// Generate filename with proper structure
|
||
$filename = 'CA3_' . $this->declaration_number . '_' . date('Y-m-d') . '.pdf';
|
||
$dest_path = $vat_declarations_dir . $filename;
|
||
|
||
// Copy PDF to validated directory
|
||
if (!copy($pdf_path, $dest_path)) {
|
||
$this->error = "Failed to copy PDF to validated directory";
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// Try to add document record to Dolibarr (optional feature)
|
||
// Skip ECM integration if there are any issues to prevent fatal errors
|
||
$ecm_integration_enabled = false; // Temporarily disabled to prevent fatal errors
|
||
|
||
if ($ecm_integration_enabled) {
|
||
// Try multiple possible paths for ecmfiles.class.php
|
||
$ecmfiles_paths = array(
|
||
DOL_DOCUMENT_ROOT . '/ecm/class/ecmfiles.class.php',
|
||
dirname(__FILE__) . '/../../../ecm/class/ecmfiles.class.php',
|
||
dirname(__FILE__) . '/../../../../ecm/class/ecmfiles.class.php',
|
||
DOL_DOCUMENT_ROOT . '/core/class/ecmfiles.class.php',
|
||
dirname(__FILE__) . '/../../../../core/class/ecmfiles.class.php'
|
||
);
|
||
|
||
$ecmfiles_path = null;
|
||
foreach ($ecmfiles_paths as $path) {
|
||
if (file_exists($path)) {
|
||
$ecmfiles_path = $path;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if ($ecmfiles_path && file_exists($ecmfiles_path)) {
|
||
try {
|
||
// Log the path being used for debugging
|
||
require_once $ecmfiles_path;
|
||
$ecmfile = new EcmFiles($this->db);
|
||
|
||
$ecmfile->filepath = 'declarationtva/' . date('Y') . '/' . date('m') . '/';
|
||
$ecmfile->filename = $filename;
|
||
$ecmfile->label = 'CA-3 Déclaration TVA - ' . $this->declaration_number;
|
||
$ecmfile->description = 'Déclaration TVA CA-3 validée avec détail des comptes pour la période ' . date('Y-m');
|
||
$ecmfile->entity = $this->entity;
|
||
$ecmfile->fk_user_author = $user->id;
|
||
$ecmfile->fk_user_modif = $user->id;
|
||
$ecmfile->datec = dol_now();
|
||
$ecmfile->tms = dol_now();
|
||
$ecmfile->mimetype = 'application/pdf';
|
||
$ecmfile->filesize = filesize($dest_path);
|
||
$ecmfile->checksum = md5_file($dest_path);
|
||
|
||
$result = $ecmfile->create($user);
|
||
if ($result > 0) {
|
||
// Try to link document to declaration (this might fail if table doesn't exist)
|
||
$link_result = $this->linkDocumentToDeclaration($declaration_id, $ecmfile->id);
|
||
if (!$link_result) {
|
||
// Log the error but don't fail the whole process
|
||
}
|
||
} else {
|
||
// Log the error but don't fail the whole process
|
||
}
|
||
} catch (Exception $e) {
|
||
// Log the error but don't fail the whole process
|
||
}
|
||
} else {
|
||
// Log that ECM files class is not available
|
||
}
|
||
}
|
||
|
||
// Return true even if ECM file creation failed - the PDF is still saved to disk
|
||
return true;
|
||
} catch (Exception $e) {
|
||
$this->error = "Exception in saveValidatedPDF: " . $e->getMessage();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Link document to declaration
|
||
*
|
||
* @param int $declaration_id Declaration ID
|
||
* @param int $document_id Document ID
|
||
* @return bool Success
|
||
*/
|
||
private function linkDocumentToDeclaration($declaration_id, $document_id)
|
||
{
|
||
// First check if the table exists
|
||
$sql_check = "SHOW TABLES LIKE '" . MAIN_DB_PREFIX . "declarationtva_documents'";
|
||
$result_check = $this->db->query($sql_check);
|
||
|
||
if (!$result_check || $this->db->num_rows($result_check) == 0) {
|
||
$this->error = "Documents table does not exist. Please run the database migration.";
|
||
return false;
|
||
}
|
||
|
||
$sql = "INSERT INTO " . MAIN_DB_PREFIX . "declarationtva_documents
|
||
(declaration_id, document_id, created_date, entity)
|
||
VALUES (" . (int)$declaration_id . ", " . (int)$document_id . ", NOW(), " . $this->entity . ")";
|
||
|
||
$result = $this->db->query($sql);
|
||
if (!$result) {
|
||
$this->error = "Database error linking document: " . $this->db->lasterror();
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Check if declaration has a validated document
|
||
*
|
||
* @param int $declaration_id Declaration ID
|
||
* @return bool Has document
|
||
*/
|
||
public function hasValidatedDocument($declaration_id)
|
||
{
|
||
// Get declaration details
|
||
$sql = "SELECT declaration_number, status 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 false;
|
||
}
|
||
|
||
$obj = $this->db->fetch_object($result);
|
||
|
||
// Only check for documents if declaration is validated
|
||
if ($obj->status != 'validated') {
|
||
return false;
|
||
}
|
||
|
||
// Check if PDF file exists in the VAT declarations validated directory
|
||
$vat_declarations_dir = DOL_DATA_ROOT . '/declarationtva/validated/';
|
||
|
||
// Look for PDF files with the declaration ID (not declaration number)
|
||
$pattern = $vat_declarations_dir . 'CA3_' . $declaration_id . '_*.pdf';
|
||
$files = glob($pattern);
|
||
|
||
// If no files found with the exact pattern, try a more flexible search
|
||
if (empty($files)) {
|
||
$pattern = $vat_declarations_dir . 'CA3_*' . $declaration_id . '*.pdf';
|
||
$files = glob($pattern);
|
||
}
|
||
|
||
return !empty($files) && file_exists($files[0]);
|
||
}
|
||
|
||
/**
|
||
* Get the PDF file path for a validated declaration
|
||
*
|
||
* @param int $declaration_id Declaration ID
|
||
* @return string|false PDF file path or false if not found
|
||
*/
|
||
public function getValidatedPDFPath($declaration_id)
|
||
{
|
||
// Get declaration details
|
||
$sql = "SELECT declaration_number, status 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 false;
|
||
}
|
||
|
||
$obj = $this->db->fetch_object($result);
|
||
|
||
// Only return path if declaration is validated
|
||
if ($obj->status != 'validated') {
|
||
return false;
|
||
}
|
||
|
||
// Check if PDF file exists in the VAT declarations validated directory
|
||
$vat_declarations_dir = DOL_DATA_ROOT . '/declarationtva/validated/';
|
||
|
||
// Look for PDF files with the declaration ID (not declaration number)
|
||
$pattern = $vat_declarations_dir . 'CA3_' . $declaration_id . '_*.pdf';
|
||
$files = glob($pattern);
|
||
|
||
// If no files found with the exact pattern, try a more flexible search
|
||
if (empty($files)) {
|
||
$pattern = $vat_declarations_dir . 'CA3_*' . $declaration_id . '*.pdf';
|
||
$files = glob($pattern);
|
||
}
|
||
|
||
if (!empty($files) && file_exists($files[0])) {
|
||
return $files[0];
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Get the VAT declarations documents directory path
|
||
*
|
||
* @param string $year Year (optional, defaults to current year)
|
||
* @param string $month Month (optional, defaults to current month)
|
||
* @return string Directory path
|
||
*/
|
||
public function getVATDeclarationsDirectory($year = null, $month = null)
|
||
{
|
||
if ($year === null) {
|
||
$year = date('Y');
|
||
}
|
||
if ($month === null) {
|
||
$month = date('m');
|
||
}
|
||
|
||
return DOL_DATA_ROOT . '/documents/declarationtva/' . $year . '/' . $month . '/';
|
||
}
|
||
|
||
/**
|
||
* Get the relative path for ECM files
|
||
*
|
||
* @param string $year Year (optional, defaults to current year)
|
||
* @param string $month Month (optional, defaults to current month)
|
||
* @return string Relative path
|
||
*/
|
||
public function getVATDeclarationsRelativePath($year = null, $month = null)
|
||
{
|
||
if ($year === null) {
|
||
$year = date('Y');
|
||
}
|
||
if ($month === null) {
|
||
$month = date('m');
|
||
}
|
||
|
||
return 'declarationtva/' . $year . '/' . $month . '/';
|
||
}
|
||
}
|