diff --git a/admin/setup_mvp.php b/admin/setup_mvp.php
index 17d56d5..b979516 100644
--- a/admin/setup_mvp.php
+++ b/admin/setup_mvp.php
@@ -522,6 +522,15 @@ print '';
$account_options[$account['account_number']] = $account['account_number'] . ' - ' . $account['label'];
}
+ // Accounting entries toggle
+ print '
';
print '| ' . $langs->trans("VATToPayAccount") . ' | ';
print '';
diff --git a/core/class/declarationtva.class.php b/core/class/declarationtva.class.php
index e767aa9..ec664b2 100644
--- a/core/class/declarationtva.class.php
+++ b/core/class/declarationtva.class.php
@@ -784,21 +784,6 @@ class DeclarationTVA
}
- /**
- * 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
@@ -901,6 +886,480 @@ class DeclarationTVA
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
+ $declaration = $this->fetch($declaration_id);
+ if (!$declaration) {
+ $this->error = 'Declaration not found';
+ return false;
+ }
+
+ // 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;
+ }
+
+ // 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);
+ if (!$od_entries) {
+ return false;
+ }
+
+ // Create bank journal entries
+ $bank_entries = $this->createBankJournalEntries($declaration, $ca3_lookup, $journal_config);
+ 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);
+ $entries = array_merge($entries, $line8_entries);
+
+ // Get line 20 accounts (credit side)
+ $line20_entries = $this->getLine20AccountsForAccounting($declaration, $ca3_lookup);
+ $entries = array_merge($entries, $line20_entries);
+
+ // Add balancing entry
+ $balancing_entry = $this->getVATResultEntryForAccounting($declaration, $ca3_lookup, $journal_config);
+ if ($balancing_entry) {
+ $entries[] = $balancing_entry;
+ }
+
+ // Create accounting entries in Dolibarr
+ return $this->saveAccountingEntries($entries, $declaration);
+ }
+
+ /**
+ * 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
+ * @return bool Success
+ */
+ private function createBankJournalEntries($declaration, $ca3_lookup, $journal_config)
+ {
+ // 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);
+ }
+
+ /**
+ * 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;
+ }
+
+ $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
+ * @return bool Success
+ */
+ private function saveAccountingEntries($entries, $declaration)
+ {
+ if (empty($entries)) {
+ return true; // No entries to save
+ }
+
+ // Use Dolibarr's accounting integration
+ require_once DOL_DOCUMENT_ROOT . '/compta/accounting/class/accountingbookkeeping.class.php';
+
+ $bookkeeping = new AccountingBookkeeping($this->db);
+
+ foreach ($entries as $entry) {
+ // Create accounting entry
+ $bookkeeping->doc_type = 'declarationtva';
+ $bookkeeping->doc_ref = $declaration->declaration_number;
+ $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
+ 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);
+ $journal_config = $config->getJournalConfiguration();
+
+ if (!isset($journal_config['create_accounting_entries']) || !$journal_config['create_accounting_entries']) {
+ // 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;
+ }
+
+ /**
+ * 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) . "',
+ date_submitted = NOW()
+ 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
*
diff --git a/core/class/declarationtva_config.class.php b/core/class/declarationtva_config.class.php
index 2fabe45..6ae7809 100644
--- a/core/class/declarationtva_config.class.php
+++ b/core/class/declarationtva_config.class.php
@@ -720,7 +720,8 @@ class DeclarationTVA_Config
'vat_to_receive' => '44567', // TVA A PAYER (carry forward)
'vat_refund' => '445671', // TVA A REMBOURSER (immediate refund)
'other_charges' => '658', // AUTRES CHARGES DE GESTION COURANTE
- 'other_products' => '758' // AUTRES PRODUITS DE GESTION COURANT
+ 'other_products' => '758', // AUTRES PRODUITS DE GESTION COURANT
+ 'create_accounting_entries' => 1 // Enable accounting entries by default
);
$config = array();
diff --git a/declarationtva_view.php b/declarationtva_view.php
index c098a65..5b4eb2b 100644
--- a/declarationtva_view.php
+++ b/declarationtva_view.php
@@ -112,6 +112,15 @@ if ($action == 'unvalidate' && $token) {
}
}
+if ($action == 'submit' && $token) {
+ // Submit the declaration (create accounting entries and update status)
+ if ($declarationtva->submitDeclaration($id)) {
+ setEventMessages($langs->trans("DeclarationSubmitted"), null, 'mesgs');
+ } else {
+ setEventMessages($langs->trans("ErrorSubmittingDeclaration") . ": " . $declarationtva->error, null, 'errors');
+ }
+}
+
// Fetch declaration
if ($declarationtva->fetch($id) < 0) {
setEventMessages($langs->trans("DeclarationNotFound"), null, 'errors');
diff --git a/langs/fr_FR/declarationtva.lang b/langs/fr_FR/declarationtva.lang
index 32f857e..b829cb8 100644
--- a/langs/fr_FR/declarationtva.lang
+++ b/langs/fr_FR/declarationtva.lang
@@ -536,3 +536,8 @@ VATRefundAccountDescription = Compte pour les remboursements immédiats de TVA (
VATRefundThresholdConfiguration = Configuration du seuil de remboursement TVA
VATRefundThresholdConfigurationUpdated = Configuration du seuil de remboursement TVA mise à jour
VATRefundThresholdConfigurationUpdateFailed = Erreur lors de la mise à jour de la configuration du seuil de remboursement TVA
+CreateAccountingEntries = Créer les écritures comptables
+CreateAccountingEntriesDescription = Activer la création automatique d'écritures comptables lors de la soumission des déclarations
+DeclarationSubmitted = Déclaration soumise avec succès
+ErrorSubmittingDeclaration = Erreur lors de la soumission de la déclaration
+Submit = Soumettre
|