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)) { $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()) ON DUPLICATE KEY UPDATE is_active = 1, account_code = '" . $this->db->escape($account_code) . "'"; $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; } }