diff --git a/admin/setup_mvp.php b/admin/setup_mvp.php
index d7c59ae..3421f0e 100644
--- a/admin/setup_mvp.php
+++ b/admin/setup_mvp.php
@@ -156,9 +156,6 @@ foreach ($lines_by_section as $section_code => $lines) {
// Use Dolibarr's native multi-select with search functionality
print $form->multiselectarray('account_codes_' . $line, $account_options, $selected_accounts, 0, 0, '', 0, '200px');
-
- // Add helper text
- print '
' . $langs->trans("MultiSelectHelp") . '';
print '';
print '';
}
diff --git a/core/class/declarationtva_config.class.php b/core/class/declarationtva_config.class.php
index e69de29..583ae01 100644
--- a/core/class/declarationtva_config.class.php
+++ b/core/class/declarationtva_config.class.php
@@ -0,0 +1,425 @@
+db = $db;
+ $this->entity = $entity;
+ }
+
+ /**
+ * Get configuration value
+ *
+ * @param string $key Configuration key
+ * @param mixed $default Default value
+ * @return mixed Configuration value
+ */
+ public function get($key, $default = null)
+ {
+ $sql = "SELECT config_value FROM " . MAIN_DB_PREFIX . "declarationtva_config
+ WHERE entity = " . $this->entity . " AND config_key = '" . $this->db->escape($key) . "'";
+
+ $result = $this->db->query($sql);
+ if ($result && $this->db->num_rows($result) > 0) {
+ $obj = $this->db->fetch_object($result);
+ return $obj->config_value;
+ }
+
+ return $default;
+ }
+
+ /**
+ * Set configuration value
+ *
+ * @param string $key Configuration key
+ * @param mixed $value Configuration value
+ * @return bool Success
+ */
+ public function set($key, $value)
+ {
+ $sql = "INSERT INTO " . MAIN_DB_PREFIX . "declarationtva_config
+ (entity, config_key, config_value, created_date)
+ VALUES (" . $this->entity . ", '" . $this->db->escape($key) . "',
+ '" . $this->db->escape($value) . "', NOW())
+ ON DUPLICATE KEY UPDATE config_value = '" . $this->db->escape($value) . "'";
+
+ $result = $this->db->query($sql);
+ return $result !== false;
+ }
+
+ /**
+ * Get account mapping for a CA-3 line
+ *
+ * @param string $ca3_line CA-3 line code
+ * @return array|false Account mapping or false if not found
+ */
+ public function getAccountMapping($ca3_line)
+ {
+ $sql = "SELECT * FROM " . MAIN_DB_PREFIX . "declarationtva_account_mappings
+ WHERE entity = " . $this->entity . " AND ca3_line = '" . $this->db->escape($ca3_line) . "'";
+
+ $result = $this->db->query($sql);
+ if ($result && $this->db->num_rows($result) > 0) {
+ return $this->db->fetch_array($result);
+ }
+
+ return false;
+ }
+
+ /**
+ * Update account mapping for multiple accounts
+ *
+ * @param string $ca3_line CA-3 line code
+ * @param array $account_codes Array of account codes
+ * @return bool Success
+ */
+ public function updateAccountMapping($ca3_line, $account_codes)
+ {
+ // First, deactivate all existing mappings for this CA-3 line
+ $sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_account_mappings
+ SET is_active = 0
+ WHERE entity = " . $this->entity . " AND ca3_line = '" . $this->db->escape($ca3_line) . "'";
+ $this->db->query($sql);
+
+ // Then insert/activate new mappings
+ if (!empty($account_codes)) {
+ foreach ($account_codes as $account_code) {
+ if (!empty($account_code)) {
+ // Check if mapping already exists
+ $check_sql = "SELECT id FROM " . MAIN_DB_PREFIX . "declarationtva_account_mappings
+ WHERE entity = " . $this->entity . "
+ AND ca3_line = '" . $this->db->escape($ca3_line) . "'
+ AND account_code = '" . $this->db->escape($account_code) . "'";
+ $check_result = $this->db->query($check_sql);
+
+ if ($check_result && $this->db->num_rows($check_result) > 0) {
+ // Update existing mapping
+ $sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_account_mappings
+ SET is_active = 1
+ WHERE entity = " . $this->entity . "
+ AND ca3_line = '" . $this->db->escape($ca3_line) . "'
+ AND account_code = '" . $this->db->escape($account_code) . "'";
+ $this->db->query($sql);
+ } else {
+ // Insert new mapping
+ $sql = "INSERT INTO " . MAIN_DB_PREFIX . "declarationtva_account_mappings
+ (entity, ca3_line, account_code, account_label, vat_rate, is_active, created_date)
+ VALUES (" . $this->entity . ", '" . $this->db->escape($ca3_line) . "',
+ '" . $this->db->escape($account_code) . "', '', 0, 1, NOW())";
+ $this->db->query($sql);
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Get all account mappings
+ *
+ * @return array Account mappings
+ */
+ public function getAllAccountMappings()
+ {
+ $sql = "SELECT * 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(
+ 'rowid' => $obj->rowid,
+ 'ca3_line' => $obj->ca3_line,
+ 'account_code' => $obj->account_code,
+ 'account_label' => $obj->account_label,
+ 'vat_rate' => $obj->vat_rate,
+ 'is_active' => $obj->is_active
+ );
+ }
+ }
+
+ return $mappings;
+ }
+
+ /**
+ * Get account mappings grouped by CA-3 line
+ *
+ * @return array Account mappings grouped by CA-3 line
+ */
+ public function getAccountMappingsByLine()
+ {
+ $sql = "SELECT ca3_line, account_code FROM " . MAIN_DB_PREFIX . "declarationtva_account_mappings
+ WHERE entity = " . $this->entity . " AND is_active = 1
+ ORDER BY ca3_line, account_code";
+
+ $result = $this->db->query($sql);
+ $mappings = array();
+
+ if ($result) {
+ while ($obj = $this->db->fetch_object($result)) {
+ if (!isset($mappings[$obj->ca3_line])) {
+ $mappings[$obj->ca3_line] = array();
+ }
+ $mappings[$obj->ca3_line][] = $obj->account_code;
+ }
+ }
+
+ return $mappings;
+ }
+
+ /**
+ * Get available accounting accounts from Dolibarr
+ *
+ * @return array Accounting accounts
+ */
+ public function getAccountingAccounts()
+ {
+ $sql = "SELECT account_number, label FROM " . MAIN_DB_PREFIX . "accounting_account
+ WHERE active = 1
+ ORDER BY account_number";
+
+ $result = $this->db->query($sql);
+ $accounts = array();
+
+ if ($result) {
+ while ($obj = $this->db->fetch_object($result)) {
+ $accounts[] = array(
+ 'account_number' => $obj->account_number,
+ 'label' => $obj->label
+ );
+ }
+ }
+
+ return $accounts;
+ }
+
+ /**
+ * Get CA-3 line definitions (Notice 4722 - Latest Official Structure)
+ *
+ * @return array CA-3 line definitions
+ */
+ public function getCA3LineDefinitions()
+ {
+ return array(
+ // A. Opérations imposables (Taxable Operations) - Notice 4722
+ 'A1' => array(
+ 'label' => 'Montant HT des opérations imposables normales (biens + services imposables en France à 20%, 10%, 5,5%, 2,1%)',
+ 'type' => 'base',
+ 'section' => 'A',
+ 'description' => 'HT amount of all taxable operations that form normal sales (goods + services taxable in France at 20%, 10%, 5,5%, 2,1%)',
+ 'pcg_accounts' => 'Sales: 7xxxx; VAT: 44571x / 44572x / 44573x / 44574x'
+ ),
+ 'A2' => array(
+ 'label' => 'Montant HT des opérations imposables spéciales ne relevant pas du CA courant (cessions d\'immobilisations, livraisons à soi-même)',
+ 'type' => 'base',
+ 'section' => 'A',
+ 'description' => 'HT amount of special taxable operations not part of ordinary turnover (e.g. cessions d\'immobilisations, livraisons à soi-même)',
+ 'pcg_accounts' => '775xxx (gains on disposal), 72xxx (production immobilisée), VAT: 44571x'
+ ),
+ 'A3' => array(
+ 'label' => 'Montant HT des services achetés à des prestataires non établis en France mais imposables en France (autoliquidation services étrangers)',
+ 'type' => 'base',
+ 'section' => 'A',
+ 'description' => 'HT amount of services purchased from providers not established in France but taxable in France (reverse charge for foreign services)',
+ 'pcg_accounts' => '6xxxx (services purchased), 4452xxx (TVA due autoliquidée)'
+ ),
+ 'A4' => array(
+ 'label' => 'Montant HT des importations imposables en France (hors UE), à l\'exclusion des produits pétroliers',
+ 'type' => 'base',
+ 'section' => 'A',
+ 'description' => 'HT amount of imports taxable in France (non-EU), excluding petroleum products',
+ 'pcg_accounts' => '6xxxx / 2xxxx purchases or assets; VAT: 4452xxx (import VAT)'
+ ),
+ 'A5' => array(
+ 'label' => 'Montant HT des opérations imposables à la sortie d\'un régime fiscal suspensif (régimes douaniers, zones franches, etc.)',
+ 'type' => 'base',
+ 'section' => 'A',
+ 'description' => 'HT amount of taxable operations at exit from a suspensive fiscal regime (customs regimes, free zones, etc.)',
+ 'pcg_accounts' => 'Specific 6xxxx/2xxxx depending on goods; VAT: 4452xxx'
+ ),
+
+ // B. Décompte de la TVA due (VAT Due Calculation) - Notice 4722
+ '08' => array(
+ 'label' => 'TVA due au taux de 20%',
+ 'type' => 'vat',
+ 'section' => 'B',
+ 'description' => 'VAT amounts due, calculated on A1/A2 bases at 20% rate',
+ 'pcg_accounts' => '44571x (TVA collectée à 20%)'
+ ),
+ '09' => array(
+ 'label' => 'TVA due au taux de 10%',
+ 'type' => 'vat',
+ 'section' => 'B',
+ 'description' => 'VAT amounts due, calculated on A1/A2 bases at 10% rate',
+ 'pcg_accounts' => '44572x (TVA collectée à 10%)'
+ ),
+ '9B' => array(
+ 'label' => 'TVA due aux taux réduits (5,5% et 2,1%)',
+ 'type' => 'vat',
+ 'section' => 'B',
+ 'description' => 'VAT amounts due, calculated on A1/A2 bases at reduced rates (5,5% and 2,1%)',
+ 'pcg_accounts' => '44573x (5,5%) / 44574x (2,1%) (TVA collectée aux taux réduits)'
+ ),
+ '17' => array(
+ 'label' => 'TVA due au titre des acquisitions intracommunautaires (autoliquidation)',
+ 'type' => 'vat',
+ 'section' => 'B',
+ 'description' => 'VAT due on intra-EU acquisitions (autoliquidation)',
+ 'pcg_accounts' => '4452xxx (TVA due intracommunautaire)'
+ ),
+
+ // C. Décompte de la TVA déductible (Deductible VAT Calculation) - Notice 4722
+ '20' => array(
+ 'label' => 'TVA déductible sur immobilisations',
+ 'type' => 'vat',
+ 'section' => 'C',
+ 'description' => 'Deductible VAT on capital goods (fixed assets)',
+ 'pcg_accounts' => '44562x (TVA déductible sur immobilisations)'
+ ),
+ '21' => array(
+ 'label' => 'TVA déductible sur autres biens et services',
+ 'type' => 'vat',
+ 'section' => 'C',
+ 'description' => 'Deductible VAT on other goods and services (operating expenses)',
+ 'pcg_accounts' => '44566x (TVA déductible sur autres biens et services)'
+ ),
+ '22' => array(
+ 'label' => 'TVA déductible sur importations',
+ 'type' => 'vat',
+ 'section' => 'C',
+ 'description' => 'Deductible VAT on imports',
+ 'pcg_accounts' => '44566x / 44562x (TVA déductible sur importations)'
+ ),
+
+ // D. Résultat (Result) - Notice 4722
+ '25' => array(
+ 'label' => 'TVA brute due (Total TVA due)',
+ 'type' => 'vat',
+ 'section' => 'D',
+ 'description' => 'Total VAT due (sum of all VAT due amounts)',
+ 'pcg_accounts' => 'Sum of 08 + 09 + 9B + 17'
+ ),
+ '26' => array(
+ 'label' => 'TVA déductible totale (Total deductible VAT)',
+ 'type' => 'vat',
+ 'section' => 'D',
+ 'description' => 'Total deductible VAT (sum of all deductible VAT amounts)',
+ 'pcg_accounts' => 'Sum of 20 + 21 + 22'
+ ),
+ '28' => array(
+ 'label' => 'TVA nette à payer',
+ 'type' => 'vat',
+ 'section' => 'D',
+ 'description' => 'Net VAT to pay (if total due > total deductible)',
+ 'pcg_accounts' => '445510 (État - TVA à décaisser)'
+ ),
+ '29' => array(
+ 'label' => 'Crédit de TVA à reporter ou remboursement',
+ 'type' => 'vat',
+ 'section' => 'D',
+ 'description' => 'VAT credit to carry forward or refund (if total deductible > total due)',
+ 'pcg_accounts' => '445670 (État - Crédit de TVA à reporter ou rembourser)'
+ )
+ );
+ }
+
+ /**
+ * Get CA-3 section headers (Notice 4722)
+ *
+ * @return array Section headers
+ */
+ public function getCA3SectionHeaders()
+ {
+ return array(
+ 'A' => array(
+ 'title' => 'A. Opérations imposables (Taxable Operations)',
+ 'description' => 'HT amounts of all taxable operations according to Notice 4722 (3310-CA3-SD)',
+ 'notice' => 'Notice 4722 - Summary Table CA3 (3310-CA3-SD)'
+ ),
+ 'B' => array(
+ 'title' => 'B. Décompte de la TVA due (VAT Due Calculation)',
+ 'description' => 'VAT amounts due, calculated on A1/A2 bases per applicable rate',
+ 'notice' => 'Notice 4722 - VAT Due Calculation'
+ ),
+ 'C' => array(
+ 'title' => 'C. Décompte de la TVA déductible (Deductible VAT Calculation)',
+ 'description' => 'VAT amounts that can be deducted from purchases and expenses',
+ 'notice' => 'Notice 4722 - Deductible VAT Calculation'
+ ),
+ 'D' => array(
+ 'title' => 'D. Résultat (Result)',
+ 'description' => 'Final calculation: net VAT to pay or credit to carry forward',
+ 'notice' => 'Notice 4722 - Final Result'
+ )
+ );
+ }
+
+ /**
+ * Get supported VAT rates
+ *
+ * @return array VAT rates
+ */
+ public function getVATRates()
+ {
+ return array(
+ '20.00' => '20%',
+ '10.00' => '10%',
+ '5.50' => '5.5%',
+ '2.10' => '2.1%',
+ '0.00' => '0%'
+ );
+ }
+
+ /**
+ * Validate account mapping
+ *
+ * @param string $ca3_line CA-3 line code
+ * @param string $account_code Account code
+ * @return bool Valid
+ */
+ public function validateAccountMapping($ca3_line, $account_code)
+ {
+ // Check if account exists in Dolibarr
+ $sql = "SELECT COUNT(*) as count FROM " . MAIN_DB_PREFIX . "accounting_account
+ WHERE account_number = '" . $this->db->escape($account_code) . "' AND active = 1";
+
+ $result = $this->db->query($sql);
+ if ($result && $this->db->num_rows($result) > 0) {
+ $obj = $this->db->fetch_object($result);
+ return $obj->count > 0;
+ }
+
+ return false;
+ }
+}
diff --git a/langs/en_US/declarationtva.lang b/langs/en_US/declarationtva.lang
index 40f967e..05209a6 100644
--- a/langs/en_US/declarationtva.lang
+++ b/langs/en_US/declarationtva.lang
@@ -368,6 +368,5 @@ PCGAccounts = PCG Accounts
AccountSelection = Account Selection
SelectedAccounts = Selected Accounts
AccountCount = Account Count
-MultiSelectHelp = Hold Ctrl (or Cmd on Mac) to select multiple accounts
ErrorCSRFToken = Security token error. Please try again.
NoChangesDetected = No changes detected in the configuration.
diff --git a/langs/fr_FR/declarationtva.lang b/langs/fr_FR/declarationtva.lang
index 3318a9b..bf149e5 100644
--- a/langs/fr_FR/declarationtva.lang
+++ b/langs/fr_FR/declarationtva.lang
@@ -357,6 +357,5 @@ PCGAccounts = Comptes PCG
AccountSelection = Sélection de comptes
SelectedAccounts = Comptes sélectionnés
AccountCount = Nombre de comptes
-MultiSelectHelp = Maintenez Ctrl (ou Cmd sur Mac) pour sélectionner plusieurs comptes
ErrorCSRFToken = Erreur de jeton de sécurité. Veuillez réessayer.
NoChangesDetected = Aucun changement détecté dans la configuration.