diff --git a/admin/setup_mvp.php b/admin/setup_mvp.php
new file mode 100644
index 0000000..b3450b9
--- /dev/null
+++ b/admin/setup_mvp.php
@@ -0,0 +1,154 @@
+rights->declarationtva->admin) {
+ accessforbidden();
+}
+
+// Load language files
+$langs->load("declarationtva@declarationtva");
+
+// Initialize objects
+$config = new DeclarationTVA_Config($db, $conf->entity);
+
+// Handle form submission
+$action = GETPOST('action', 'alpha');
+if ($action == 'update_mappings') {
+ $ca3_lines = array('A1', 'A2', 'B1', 'B2', 'B3', 'B4', '17', '20', '21', '22', '28', '29');
+
+ foreach ($ca3_lines as $line) {
+ $account_code = GETPOST('account_code_' . $line, 'alpha');
+ $account_label = GETPOST('account_label_' . $line, 'alpha');
+ $vat_rate = GETPOST('vat_rate_' . $line, 'alpha');
+
+ if (!empty($account_code)) {
+ $config->updateAccountMapping($line, $account_code, $account_label, $vat_rate);
+ }
+ }
+
+ setEventMessages($langs->trans("ConfigurationUpdated"), null, 'mesgs');
+}
+
+// Get current mappings
+$mappings = $config->getAllAccountMappings();
+$account_mappings = array();
+foreach ($mappings as $mapping) {
+ $account_mappings[$mapping['ca3_line']] = $mapping;
+}
+
+// Get available accounting accounts
+$accounts = $config->getAccountingAccounts();
+$vat_rates = $config->getVATRates();
+$ca3_definitions = $config->getCA3LineDefinitions();
+
+// Page title
+$title = $langs->trans("DeclarationTVASetup");
+llxHeader('', $title);
+
+// Print page header
+print load_fiche_titre($title, '', 'title_accountancy');
+
+// Print configuration form
+print '
';
+
+// Print current configuration
+print '';
+print '
' . $langs->trans("CurrentConfiguration") . '
';
+
+if (empty($mappings)) {
+ print '
' . $langs->trans("NoConfigurationFound") . '
';
+} else {
+ print '
';
+ print '';
+ print '| ' . $langs->trans("CA3Line") . ' | ';
+ print '' . $langs->trans("AccountCode") . ' | ';
+ print '' . $langs->trans("AccountLabel") . ' | ';
+ print '' . $langs->trans("VATRate") . ' | ';
+ print '' . $langs->trans("Status") . ' | ';
+ print '
';
+
+ foreach ($mappings as $mapping) {
+ print '';
+ print '| ' . $mapping['ca3_line'] . ' | ';
+ print '' . $mapping['account_code'] . ' | ';
+ print '' . $mapping['account_label'] . ' | ';
+ print '' . $mapping['vat_rate'] . '% | ';
+ print '' . ($mapping['is_active'] ? $langs->trans("Active") : $langs->trans("Inactive")) . ' | ';
+ print '
';
+ }
+ print '
';
+}
+
+print '
';
+
+// Print footer
+llxFooter();
+?>
diff --git a/core/class/declarationtva.class.php b/core/class/declarationtva.class.php
new file mode 100644
index 0000000..758d22f
--- /dev/null
+++ b/core/class/declarationtva.class.php
@@ -0,0 +1,342 @@
+db = $db;
+ $this->entity = $entity;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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
+ $mappings = $this->getAccountMappings();
+
+ $total_vat_collected = 0;
+ $total_vat_deductible = 0;
+
+ // Process each CA-3 line
+ foreach ($mappings as $mapping) {
+ $amounts = $this->getAccountAmounts($mapping['account_code'], $period['start_date'], $period['end_date']);
+
+ // Create CA-3 line record
+ $this->createCA3Line($declaration_id, $mapping['ca3_line'], $mapping['account_label'], $amounts);
+
+ // Update totals
+ if (in_array($mapping['ca3_line'], ['A1', 'A2', 'B1', 'B2', 'B3', 'B4', '17'])) {
+ $total_vat_collected += $amounts['vat_amount'];
+ } elseif (in_array($mapping['ca3_line'], ['20', '21'])) {
+ $total_vat_deductible += $amounts['vat_amount'];
+ }
+ }
+
+ // Calculate net amounts
+ $net_vat_due = $total_vat_collected - $total_vat_deductible;
+ $vat_credit = $net_vat_due < 0 ? abs($net_vat_due) : 0;
+ $net_vat_due = $net_vat_due > 0 ? $net_vat_due : 0;
+
+ // Update declaration totals
+ $this->updateDeclarationTotals($declaration_id, $total_vat_collected, $total_vat_deductible, $net_vat_due, $vat_credit);
+
+ return true;
+ }
+
+ /**
+ * Get account amounts for a period
+ *
+ * @param string $account_code Account code
+ * @param string $start_date Start date
+ * @param string $end_date End date
+ * @return array Amounts (base_amount, vat_amount, total_amount)
+ */
+ public function getAccountAmounts($account_code, $start_date, $end_date)
+ {
+ // Query Dolibarr accounting entries
+ $sql = "SELECT SUM(debit) as total_debit, SUM(credit) as total_credit
+ FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping
+ WHERE account_number = '" . $this->db->escape($account_code) . "'
+ AND doc_date >= '" . $this->db->escape($start_date) . "'
+ AND doc_date <= '" . $this->db->escape($end_date) . "'";
+
+ $result = $this->db->query($sql);
+ if ($result && $this->db->num_rows($result) > 0) {
+ $obj = $this->db->fetch_object($result);
+ $total_amount = $obj->total_debit - $obj->total_credit;
+
+ 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)
+ {
+ $sql = "INSERT INTO " . MAIN_DB_PREFIX . "declarationtva_ca3_lines
+ (declaration_id, ca3_line, line_label, base_amount, vat_amount, total_amount, created_date)
+ VALUES (" . $declaration_id . ", '" . $this->db->escape($ca3_line) . "',
+ '" . $this->db->escape($line_label) . "', " . $amounts['base_amount'] . ",
+ " . $amounts['vat_amount'] . ", " . $amounts['total_amount'] . ", NOW())";
+
+ $result = $this->db->query($sql);
+ return $result !== false;
+ }
+
+ /**
+ * Update declaration totals
+ *
+ * @param int $declaration_id Declaration ID
+ * @param float $total_vat_collected Total VAT collected
+ * @param float $total_vat_deductible Total VAT deductible
+ * @param float $net_vat_due Net VAT due
+ * @param float $vat_credit VAT credit
+ * @return bool Success
+ */
+ public function updateDeclarationTotals($declaration_id, $total_vat_collected, $total_vat_deductible, $net_vat_due, $vat_credit)
+ {
+ $sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
+ SET total_vat_collected = " . $total_vat_collected . ",
+ total_vat_deductible = " . $total_vat_deductible . ",
+ net_vat_due = " . $net_vat_due . ",
+ vat_credit = " . $vat_credit . "
+ WHERE rowid = " . $declaration_id;
+
+ $result = $this->db->query($sql);
+ return $result !== false;
+ }
+
+ /**
+ * Get account mappings
+ *
+ * @return array Account mappings
+ */
+ public function getAccountMappings()
+ {
+ $sql = "SELECT ca3_line, account_code, account_label, vat_rate
+ FROM " . MAIN_DB_PREFIX . "declarationtva_account_mappings
+ WHERE entity = " . $this->entity . " AND is_active = 1
+ ORDER BY ca3_line";
+
+ $result = $this->db->query($sql);
+ $mappings = array();
+
+ if ($result) {
+ while ($obj = $this->db->fetch_object($result)) {
+ $mappings[] = array(
+ 'ca3_line' => $obj->ca3_line,
+ 'account_code' => $obj->account_code,
+ 'account_label' => $obj->account_label,
+ 'vat_rate' => $obj->vat_rate
+ );
+ }
+ }
+
+ return $mappings;
+ }
+
+ /**
+ * Get period information
+ *
+ * @param int $period_id Period ID
+ * @return array|false Period information or false if not found
+ */
+ public function getPeriod($period_id)
+ {
+ $sql = "SELECT * FROM " . MAIN_DB_PREFIX . "declarationtva_periods
+ WHERE rowid = " . $period_id . " AND entity = " . $this->entity;
+
+ $result = $this->db->query($sql);
+ if ($result && $this->db->num_rows($result) > 0) {
+ return $this->db->fetch_array($result);
+ }
+
+ return false;
+ }
+
+ /**
+ * Generate declaration number
+ *
+ * @param array $period Period information
+ * @return string Declaration number
+ */
+ public function generateDeclarationNumber($period)
+ {
+ $year = date('Y', strtotime($period['start_date']));
+ $quarter = ceil(date('n', strtotime($period['start_date'])) / 3);
+
+ return 'CA3-' . $year . '-Q' . $quarter . '-' . date('YmdHis');
+ }
+
+ /**
+ * Get declaration information
+ *
+ * @param int $declaration_id Declaration ID
+ * @return array|false Declaration information or false if not found
+ */
+ public function getDeclaration($declaration_id)
+ {
+ $sql = "SELECT d.*, p.period_name, p.start_date, p.end_date
+ FROM " . MAIN_DB_PREFIX . "declarationtva_declarations d
+ LEFT JOIN " . MAIN_DB_PREFIX . "declarationtva_periods p ON d.period_id = p.rowid
+ WHERE d.rowid = " . $declaration_id . " AND d.entity = " . $this->entity;
+
+ $result = $this->db->query($sql);
+ if ($result && $this->db->num_rows($result) > 0) {
+ return $this->db->fetch_array($result);
+ }
+
+ return false;
+ }
+
+ /**
+ * Get CA-3 lines for a declaration
+ *
+ * @param int $declaration_id Declaration ID
+ * @return array CA-3 lines
+ */
+ public function getCA3Lines($declaration_id)
+ {
+ $sql = "SELECT * FROM " . MAIN_DB_PREFIX . "declarationtva_ca3_lines
+ WHERE declaration_id = " . $declaration_id . "
+ ORDER BY ca3_line";
+
+ $result = $this->db->query($sql);
+ $lines = array();
+
+ if ($result) {
+ while ($obj = $this->db->fetch_object($result)) {
+ $lines[] = array(
+ 'ca3_line' => $obj->ca3_line,
+ 'line_label' => $obj->line_label,
+ 'base_amount' => $obj->base_amount,
+ 'vat_amount' => $obj->vat_amount,
+ 'total_amount' => $obj->total_amount
+ );
+ }
+ }
+
+ return $lines;
+ }
+
+ /**
+ * Validate declaration
+ *
+ * @param int $declaration_id Declaration ID
+ * @return bool Success
+ */
+ public function validateDeclaration($declaration_id)
+ {
+ $sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
+ SET status = 'validated'
+ WHERE rowid = " . $declaration_id . " AND entity = " . $this->entity;
+
+ $result = $this->db->query($sql);
+ return $result !== false;
+ }
+
+ /**
+ * Submit declaration
+ *
+ * @param int $declaration_id Declaration ID
+ * @return bool Success
+ */
+ public function submitDeclaration($declaration_id)
+ {
+ $sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
+ SET status = 'submitted', submission_date = NOW()
+ WHERE rowid = " . $declaration_id . " AND entity = " . $this->entity;
+
+ $result = $this->db->query($sql);
+ return $result !== false;
+ }
+}
diff --git a/core/class/declarationtva_config.class.php b/core/class/declarationtva_config.class.php
new file mode 100644
index 0000000..e748a4a
--- /dev/null
+++ b/core/class/declarationtva_config.class.php
@@ -0,0 +1,237 @@
+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
+ *
+ * @param string $ca3_line CA-3 line code
+ * @param string $account_code Account code
+ * @param string $account_label Account label
+ * @param float $vat_rate VAT rate
+ * @return bool Success
+ */
+ public function updateAccountMapping($ca3_line, $account_code, $account_label, $vat_rate)
+ {
+ $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) . "', '" . $this->db->escape($account_label) . "',
+ " . $vat_rate . ", 1, NOW())
+ ON DUPLICATE KEY UPDATE
+ account_code = '" . $this->db->escape($account_code) . "',
+ account_label = '" . $this->db->escape($account_label) . "',
+ vat_rate = " . $vat_rate;
+
+ $result = $this->db->query($sql);
+ return $result !== false;
+ }
+
+ /**
+ * 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 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
+ *
+ * @return array CA-3 line definitions
+ */
+ public function getCA3LineDefinitions()
+ {
+ return array(
+ 'A1' => array('label' => 'Montant hors TVA des opérations imposables', 'type' => 'base'),
+ 'A2' => array('label' => 'Opérations imposables mais ne relevant pas du CA courant', 'type' => 'base'),
+ 'B1' => array('label' => 'Répartition 20% (base + taxe)', 'type' => 'vat'),
+ 'B2' => array('label' => 'Répartition 10% (base + taxe)', 'type' => 'vat'),
+ 'B3' => array('label' => 'Répartition 5,5% (base + taxe)', 'type' => 'vat'),
+ 'B4' => array('label' => 'Répartition 2,1% (base + taxe)', 'type' => 'vat'),
+ '17' => array('label' => 'TVA due au titre des acquisitions intracommunautaires', 'type' => 'vat'),
+ '20' => array('label' => 'TVA déductible sur immobilisations', 'type' => 'vat'),
+ '21' => array('label' => 'TVA déductible sur autres biens et services', 'type' => 'vat'),
+ '22' => array('label' => 'Crédit de TVA reportable', 'type' => 'vat'),
+ '28' => array('label' => 'TVA nette à payer', 'type' => 'vat'),
+ '29' => array('label' => 'Crédit de TVA à reporter ou remboursement', 'type' => 'vat')
+ );
+ }
+
+ /**
+ * 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/core/class/declarationtva_period.class.php b/core/class/declarationtva_period.class.php
new file mode 100644
index 0000000..23acd5b
--- /dev/null
+++ b/core/class/declarationtva_period.class.php
@@ -0,0 +1,292 @@
+db = $db;
+ $this->entity = $entity;
+ }
+
+ /**
+ * Create a new period
+ *
+ * @param string $period_name Period name (e.g., Q1-2024)
+ * @param string $start_date Start date (YYYY-MM-DD)
+ * @param string $end_date End date (YYYY-MM-DD)
+ * @return int Period ID or -1 if error
+ */
+ public function createPeriod($period_name, $start_date, $end_date)
+ {
+ $this->db->begin();
+
+ // Check if period already exists
+ if ($this->periodExists($period_name)) {
+ $this->error = "Period already exists";
+ $this->db->rollback();
+ return -1;
+ }
+
+ // Create period
+ $sql = "INSERT INTO " . MAIN_DB_PREFIX . "declarationtva_periods
+ (entity, period_name, start_date, end_date, status, created_date)
+ VALUES (" . $this->entity . ", '" . $this->db->escape($period_name) . "',
+ '" . $this->db->escape($start_date) . "', '" . $this->db->escape($end_date) . "',
+ 'draft', NOW())";
+
+ $result = $this->db->query($sql);
+ if (!$result) {
+ $this->error = "Error creating period: " . $this->db->lasterror();
+ $this->db->rollback();
+ return -1;
+ }
+
+ $period_id = $this->db->last_insert_id(MAIN_DB_PREFIX . "declarationtva_periods");
+
+ $this->db->commit();
+ return $period_id;
+ }
+
+ /**
+ * Check if period exists
+ *
+ * @param string $period_name Period name
+ * @return bool Exists
+ */
+ public function periodExists($period_name)
+ {
+ $sql = "SELECT COUNT(*) as count FROM " . MAIN_DB_PREFIX . "declarationtva_periods
+ WHERE entity = " . $this->entity . " AND period_name = '" . $this->db->escape($period_name) . "'";
+
+ $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;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Get all periods
+ *
+ * @return array Periods
+ */
+ public function getAllPeriods()
+ {
+ $sql = "SELECT * FROM " . MAIN_DB_PREFIX . "declarationtva_periods
+ WHERE entity = " . $this->entity . "
+ ORDER BY start_date DESC";
+
+ $result = $this->db->query($sql);
+ $periods = array();
+
+ if ($result) {
+ while ($obj = $this->db->fetch_object($result)) {
+ $periods[] = array(
+ 'rowid' => $obj->rowid,
+ 'period_name' => $obj->period_name,
+ 'start_date' => $obj->start_date,
+ 'end_date' => $obj->end_date,
+ 'status' => $obj->status,
+ 'created_date' => $obj->created_date
+ );
+ }
+ }
+
+ return $periods;
+ }
+
+ /**
+ * Update period status
+ *
+ * @param int $period_id Period ID
+ * @param string $status New status
+ * @return bool Success
+ */
+ public function updatePeriodStatus($period_id, $status)
+ {
+ $sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_periods
+ SET status = '" . $this->db->escape($status) . "'
+ WHERE rowid = " . $period_id . " AND entity = " . $this->entity;
+
+ $result = $this->db->query($sql);
+ return $result !== false;
+ }
+
+ /**
+ * Generate quarterly periods for a year
+ *
+ * @param int $year Year
+ * @return array Period IDs
+ */
+ public function generateYearlyPeriods($year)
+ {
+ $periods = array();
+ $quarters = array(
+ 'Q1' => array('start' => $year . '-01-01', 'end' => $year . '-03-31'),
+ 'Q2' => array('start' => $year . '-04-01', 'end' => $year . '-06-30'),
+ 'Q3' => array('start' => $year . '-07-01', 'end' => $year . '-09-30'),
+ 'Q4' => array('start' => $year . '-10-01', 'end' => $year . '-12-31')
+ );
+
+ foreach ($quarters as $quarter => $dates) {
+ $period_name = $quarter . '-' . $year;
+
+ if (!$this->periodExists($period_name)) {
+ $period_id = $this->createPeriod($period_name, $dates['start'], $dates['end']);
+ if ($period_id > 0) {
+ $periods[] = $period_id;
+ }
+ }
+ }
+
+ return $periods;
+ }
+
+ /**
+ * Get current period (based on today's date)
+ *
+ * @return array|false Current period or false if not found
+ */
+ public function getCurrentPeriod()
+ {
+ $today = date('Y-m-d');
+
+ $sql = "SELECT * FROM " . MAIN_DB_PREFIX . "declarationtva_periods
+ WHERE entity = " . $this->entity . "
+ AND start_date <= '" . $today . "'
+ AND end_date >= '" . $today . "'
+ ORDER BY start_date DESC
+ LIMIT 1";
+
+ $result = $this->db->query($sql);
+ if ($result && $this->db->num_rows($result) > 0) {
+ return $this->db->fetch_array($result);
+ }
+
+ return false;
+ }
+
+ /**
+ * Get period by name
+ *
+ * @param string $period_name Period name
+ * @return array|false Period information or false if not found
+ */
+ public function getPeriodByName($period_name)
+ {
+ $sql = "SELECT * FROM " . MAIN_DB_PREFIX . "declarationtva_periods
+ WHERE entity = " . $this->entity . " AND period_name = '" . $this->db->escape($period_name) . "'";
+
+ $result = $this->db->query($sql);
+ if ($result && $this->db->num_rows($result) > 0) {
+ return $this->db->fetch_array($result);
+ }
+
+ return false;
+ }
+
+ /**
+ * Delete period (only if no declarations exist)
+ *
+ * @param int $period_id Period ID
+ * @return bool Success
+ */
+ public function deletePeriod($period_id)
+ {
+ // Check if declarations exist for this period
+ $sql = "SELECT COUNT(*) as count FROM " . MAIN_DB_PREFIX . "declarationtva_declarations
+ WHERE period_id = " . $period_id . " AND entity = " . $this->entity;
+
+ $result = $this->db->query($sql);
+ if ($result && $this->db->num_rows($result) > 0) {
+ $obj = $this->db->fetch_object($result);
+ if ($obj->count > 0) {
+ $this->error = "Cannot delete period with existing declarations";
+ return false;
+ }
+ }
+
+ $sql = "DELETE FROM " . MAIN_DB_PREFIX . "declarationtva_periods
+ WHERE rowid = " . $period_id . " AND entity = " . $this->entity;
+
+ $result = $this->db->query($sql);
+ return $result !== false;
+ }
+
+ /**
+ * Get period statistics
+ *
+ * @param int $period_id Period ID
+ * @return array Statistics
+ */
+ public function getPeriodStatistics($period_id)
+ {
+ $sql = "SELECT COUNT(*) as declaration_count,
+ SUM(total_vat_collected) as total_vat_collected,
+ SUM(total_vat_deductible) as total_vat_deductible,
+ SUM(net_vat_due) as net_vat_due,
+ SUM(vat_credit) as vat_credit
+ FROM " . MAIN_DB_PREFIX . "declarationtva_declarations
+ WHERE period_id = " . $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 array(
+ 'declaration_count' => 0,
+ 'total_vat_collected' => 0,
+ 'total_vat_deductible' => 0,
+ 'net_vat_due' => 0,
+ 'vat_credit' => 0
+ );
+ }
+}
diff --git a/declarationtvaindex.php b/declarationtvaindex.php
index b7b5a7e..a43538c 100644
--- a/declarationtvaindex.php
+++ b/declarationtvaindex.php
@@ -1,259 +1,186 @@
- * Copyright (C) 2004-2015 Laurent Destailleur
- * Copyright (C) 2005-2012 Regis Houssin
- * Copyright (C) 2015 Jean-François Ferry
- * Copyright (C) 2024 Frédéric France
- * Copyright (C) 2025 Frank Cools
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
/**
- * \file declarationtva/declarationtvaindex.php
- * \ingroup declarationtva
- * \brief Home page of declarationtva top menu
+ * DeclarationTVA Main Interface
+ * French CA-3 VAT Declaration Module for Dolibarr
+ * MVP Version - Phase 1
*/
// Load Dolibarr environment
-$res = 0;
-// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
-if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
- $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
-}
-// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
-$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
-$tmp2 = realpath(__FILE__);
-$i = strlen($tmp) - 1;
-$j = strlen($tmp2) - 1;
-while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
- $i--;
- $j--;
-}
-if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
- $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
-}
-if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
- $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
-}
-// Try main.inc.php using relative path
-if (!$res && file_exists("../main.inc.php")) {
- $res = @include "../main.inc.php";
-}
-if (!$res && file_exists("../../main.inc.php")) {
- $res = @include "../../main.inc.php";
-}
-if (!$res && file_exists("../../../main.inc.php")) {
- $res = @include "../../../main.inc.php";
+if (file_exists('../main.inc.php')) {
+ $res = @include '../main.inc.php';
+} elseif (file_exists('../../main.inc.php')) {
+ $res = @include '../../main.inc.php';
+} else {
+ $res = 0;
}
+
if (!$res) {
- die("Include of main fails");
+ die("Include of main fails");
}
-require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
+// Load module classes
+require_once DOL_DOCUMENT_ROOT . '/custom/declarationtva/core/class/declarationtva.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/declarationtva/core/class/declarationtva_config.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/declarationtva/core/class/declarationtva_period.class.php';
-/**
- * @var Conf $conf
- * @var DoliDB $db
- * @var HookManager $hookmanager
- * @var Translate $langs
- * @var User $user
- */
-
-// Load translation files required by the page
-$langs->loadLangs(array("declarationtva@declarationtva"));
-
-$action = GETPOST('action', 'aZ09');
-
-$now = dol_now();
-$max = getDolGlobalInt('MAIN_SIZE_SHORTLIST_LIMIT', 5);
-
-// Security check - Protection if external user
-$socid = GETPOSTINT('socid');
-if (!empty($user->socid) && $user->socid > 0) {
- $action = '';
- $socid = $user->socid;
+// Access control
+if (!$user->rights->declarationtva->read) {
+ accessforbidden();
}
-// Initialize a technical object to manage hooks. Note that conf->hooks_modules contains array
-//$hookmanager->initHooks(array($object->element.'index'));
+// Load language files
+$langs->load("declarationtva@declarationtva");
-// Security check (enable the most restrictive one)
-//if ($user->socid > 0) accessforbidden();
-//if ($user->socid > 0) $socid = $user->socid;
-//if (!isModEnabled('declarationtva')) {
-// accessforbidden('Module not enabled');
-//}
-//if (! $user->hasRight('declarationtva', 'myobject', 'read')) {
-// accessforbidden();
-//}
-//restrictedArea($user, 'declarationtva', 0, 'declarationtva_myobject', 'myobject', '', 'rowid');
-//if (empty($user->admin)) {
-// accessforbidden('Must be admin');
-//}
+// Initialize objects
+$declarationtva = new DeclarationTVA($db, $conf->entity);
+$config = new DeclarationTVA_Config($db, $conf->entity);
+$period = new DeclarationTVA_Period($db, $conf->entity);
+// Handle actions
+$action = GETPOST('action', 'alpha');
+$declaration_id = GETPOST('declaration_id', 'int');
+$period_id = GETPOST('period_id', 'int');
-/*
- * Actions
- */
-
-// None
-
-
-/*
- * View
- */
-
-$form = new Form($db);
-$formfile = new FormFile($db);
-
-llxHeader("", $langs->trans("DeclarationTVAArea"), '', '', 0, 0, '', '', '', 'mod-declarationtva page-index');
-
-print load_fiche_titre($langs->trans("DeclarationTVAArea"), '', 'declarationtva.png@declarationtva');
-
-print '';
-
-
-/* BEGIN MODULEBUILDER DRAFT MYOBJECT
-// Draft MyObject
-if (isModEnabled('declarationtva') && $user->hasRight('declarationtva', 'read')) {
- $langs->load("orders");
-
- $sql = "SELECT c.rowid, c.ref, c.ref_client, c.total_ht, c.tva as total_tva, c.total_ttc, s.rowid as socid, s.nom as name, s.client, s.canvas";
- $sql.= ", s.code_client";
- $sql.= " FROM ".$db->prefix()."commande as c";
- $sql.= ", ".$db->prefix()."societe as s";
- $sql.= " WHERE c.fk_soc = s.rowid";
- $sql.= " AND c.fk_statut = 0";
- $sql.= " AND c.entity IN (".getEntity('commande').")";
- if ($socid) $sql.= " AND c.fk_soc = ".((int) $socid);
-
- $resql = $db->query($sql);
- if ($resql)
- {
- $total = 0;
- $num = $db->num_rows($resql);
-
- print '
';
- print '';
- print '| '.$langs->trans("DraftMyObjects").($num?''.$num.'':'').' |
';
-
- $var = true;
- if ($num > 0)
- {
- $i = 0;
- while ($i < $num)
- {
-
- $obj = $db->fetch_object($resql);
- print '| ';
-
- $myobjectstatic->id=$obj->rowid;
- $myobjectstatic->ref=$obj->ref;
- $myobjectstatic->ref_client=$obj->ref_client;
- $myobjectstatic->total_ht = $obj->total_ht;
- $myobjectstatic->total_tva = $obj->total_tva;
- $myobjectstatic->total_ttc = $obj->total_ttc;
-
- print $myobjectstatic->getNomUrl(1);
- print ' | ';
- print '';
- print ' | ';
- print ''.price($obj->total_ttc).' |
';
- $i++;
- $total += $obj->total_ttc;
- }
- if ($total>0)
- {
-
- print '| '.$langs->trans("Total").' | '.price($total)." |
";
- }
- }
- else
- {
-
- print '| '.$langs->trans("NoOrder").' |
';
- }
- print "
";
-
- $db->free($resql);
- }
- else
- {
- dol_print_error($db);
- }
+// Process actions
+if ($action == 'create_declaration' && $period_id > 0) {
+ $declaration_id = $declarationtva->createDeclaration($period_id);
+ if ($declaration_id > 0) {
+ setEventMessages($langs->trans("DeclarationCreated"), null, 'mesgs');
+ } else {
+ setEventMessages($langs->trans("ErrorCreatingDeclaration") . ": " . $declarationtva->error, null, 'errors');
+ }
+} elseif ($action == 'validate_declaration' && $declaration_id > 0) {
+ if ($declarationtva->validateDeclaration($declaration_id)) {
+ setEventMessages($langs->trans("DeclarationValidated"), null, 'mesgs');
+ } else {
+ setEventMessages($langs->trans("ErrorValidatingDeclaration"), null, 'errors');
+ }
+} elseif ($action == 'submit_declaration' && $declaration_id > 0) {
+ if ($declarationtva->submitDeclaration($declaration_id)) {
+ setEventMessages($langs->trans("DeclarationSubmitted"), null, 'mesgs');
+ } else {
+ setEventMessages($langs->trans("ErrorSubmittingDeclaration"), null, 'errors');
+ }
}
-END MODULEBUILDER DRAFT MYOBJECT */
+// Get data for display
+$periods = $period->getAllPeriods();
+$declarations = array();
-print '
';
-
-
-/* BEGIN MODULEBUILDER LASTMODIFIED MYOBJECT
-// Last modified myobject
-if (isModEnabled('declarationtva') && $user->hasRight('declarationtva', 'read')) {
- $sql = "SELECT s.rowid, s.ref, s.label, s.date_creation, s.tms";
- $sql.= " FROM ".$db->prefix()."declarationtva_myobject as s";
- $sql.= " WHERE s.entity IN (".getEntity($myobjectstatic->element).")";
- //if ($socid) $sql.= " AND s.rowid = $socid";
- $sql .= " ORDER BY s.tms DESC";
- $sql .= $db->plimit($max, 0);
-
- $resql = $db->query($sql);
- if ($resql)
- {
- $num = $db->num_rows($resql);
- $i = 0;
-
- print '
';
- print '';
- print '| ';
- print $langs->trans("BoxTitleLatestModifiedMyObjects", $max);
- print ' | ';
- print ''.$langs->trans("DateModificationShort").' | ';
- print '
';
- if ($num)
- {
- while ($i < $num)
- {
- $objp = $db->fetch_object($resql);
-
- $myobjectstatic->id=$objp->rowid;
- $myobjectstatic->ref=$objp->ref;
- $myobjectstatic->label=$objp->label;
- $myobjectstatic->status = $objp->status;
-
- print '';
- print '| '.$myobjectstatic->getNomUrl(1).' | ';
- print '';
- print " | ";
- print ''.dol_print_date($db->jdate($objp->tms), 'day')." | ";
- print '
';
- $i++;
- }
-
- $db->free($resql);
- } else {
- print '| '.$langs->trans("None").' |
';
- }
- print "
";
- }
+// Get declarations for each period
+foreach ($periods as $p) {
+ $sql = "SELECT * FROM " . MAIN_DB_PREFIX . "declarationtva_declarations
+ WHERE period_id = " . $p['rowid'] . " AND entity = " . $conf->entity . "
+ ORDER BY created_date DESC";
+
+ $result = $db->query($sql);
+ if ($result) {
+ while ($obj = $db->fetch_object($result)) {
+ $declarations[] = array(
+ 'rowid' => $obj->rowid,
+ 'declaration_number' => $obj->declaration_number,
+ 'status' => $obj->status,
+ 'total_vat_collected' => $obj->total_vat_collected,
+ 'total_vat_deductible' => $obj->total_vat_deductible,
+ 'net_vat_due' => $obj->net_vat_due,
+ 'vat_credit' => $obj->vat_credit,
+ 'created_date' => $obj->created_date,
+ 'period_name' => $p['period_name']
+ );
+ }
+ }
}
-*/
-print '
';
+// Page title
+$title = $langs->trans("DeclarationTVAMainInterface");
+llxHeader('', $title);
-// End of page
+// Print page header
+print load_fiche_titre($title, '', 'title_accountancy');
+
+// Print periods section
+print '';
+print '
';
+print '
' . $langs->trans("DeclarationTVAPeriods") . '
';
+
+if (empty($periods)) {
+ print '
' . $langs->trans("NoPeriodsFound") . '
';
+} else {
+ print '
';
+ print '';
+ print '| ' . $langs->trans("PeriodName") . ' | ';
+ print '' . $langs->trans("StartDate") . ' | ';
+ print '' . $langs->trans("EndDate") . ' | ';
+ print '' . $langs->trans("Status") . ' | ';
+ print '' . $langs->trans("Actions") . ' | ';
+ print '
';
+
+ foreach ($periods as $p) {
+ print '';
+ print '| ' . $p['period_name'] . ' | ';
+ print '' . dol_print_date($p['start_date'], 'day') . ' | ';
+ print '' . dol_print_date($p['end_date'], 'day') . ' | ';
+ print '' . $langs->trans("Status" . ucfirst($p['status'])) . ' | ';
+ print '';
+ print '' . $langs->trans("CreateDeclaration") . '';
+ print ' | ';
+ print '
';
+ }
+ print '
';
+}
+
+print '
';
+print '
';
+
+// Print declarations section
+print '';
+print '
';
+print '
' . $langs->trans("DeclarationTVADeclarations") . '
';
+
+if (empty($declarations)) {
+ print '
' . $langs->trans("NoDeclarationsFound") . '
';
+} else {
+ print '
';
+ print '';
+ print '| ' . $langs->trans("DeclarationNumber") . ' | ';
+ print '' . $langs->trans("Period") . ' | ';
+ print '' . $langs->trans("Status") . ' | ';
+ print '' . $langs->trans("NetVATDue") . ' | ';
+ print '' . $langs->trans("Actions") . ' | ';
+ print '
';
+
+ foreach ($declarations as $d) {
+ print '';
+ print '| ' . $d['declaration_number'] . ' | ';
+ print '' . $d['period_name'] . ' | ';
+ print '' . $langs->trans("Status" . ucfirst($d['status'])) . ' | ';
+ print '' . price($d['net_vat_due']) . ' | ';
+ print '';
+
+ if ($d['status'] == 'draft') {
+ print '' . $langs->trans("Validate") . '';
+ } elseif ($d['status'] == 'validated') {
+ print '' . $langs->trans("Submit") . '';
+ }
+
+ print '' . $langs->trans("View") . '';
+ print ' | ';
+ print '
';
+ }
+ print '
';
+}
+
+print '
';
+print '
';
+
+// Print configuration section
+print '';
+print '
' . $langs->trans("DeclarationTVAConfiguration") . '
';
+print '
';
+print '
';
+
+// Print footer
llxFooter();
-$db->close();
+?>
\ No newline at end of file
diff --git a/sql/mvp_schema.sql b/sql/mvp_schema.sql
new file mode 100644
index 0000000..3fccde3
--- /dev/null
+++ b/sql/mvp_schema.sql
@@ -0,0 +1,121 @@
+--
+-- DeclarationTVA MVP Database Schema
+-- Phase 1 - Basic CA-3 Declaration System
+-- Simplified for MVP development
+--
+
+-- =====================================================
+-- 1. CORE MVP TABLES (Simplified)
+-- =====================================================
+
+-- Basic configuration table
+CREATE TABLE IF NOT EXISTS `llx_declarationtva_config` (
+ `rowid` int(11) NOT NULL AUTO_INCREMENT,
+ `entity` int(11) NOT NULL DEFAULT 1,
+ `config_key` varchar(64) NOT NULL,
+ `config_value` text,
+ `created_date` datetime DEFAULT NULL,
+ PRIMARY KEY (`rowid`),
+ UNIQUE KEY `uk_config_entity_key` (`entity`, `config_key`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+-- Simplified PCG account mappings (one account per CA-3 line for MVP)
+CREATE TABLE IF NOT EXISTS `llx_declarationtva_account_mappings` (
+ `rowid` int(11) NOT NULL AUTO_INCREMENT,
+ `entity` int(11) NOT NULL DEFAULT 1,
+ `ca3_line` varchar(8) NOT NULL COMMENT 'A1, A2, B1, B2, B3, B4, 17, 20, 21, 22, 28, 29',
+ `account_code` varchar(32) NOT NULL COMMENT 'PCG account code',
+ `account_label` varchar(255) DEFAULT NULL,
+ `vat_rate` decimal(5,2) DEFAULT NULL,
+ `is_active` tinyint(1) DEFAULT 1,
+ `created_date` datetime DEFAULT NULL,
+ PRIMARY KEY (`rowid`),
+ UNIQUE KEY `uk_mapping_entity_line` (`entity`, `ca3_line`),
+ KEY `idx_ca3_line` (`ca3_line`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+-- Declaration periods (quarterly only for MVP)
+CREATE TABLE IF NOT EXISTS `llx_declarationtva_periods` (
+ `rowid` int(11) NOT NULL AUTO_INCREMENT,
+ `entity` int(11) NOT NULL DEFAULT 1,
+ `period_name` varchar(32) NOT NULL COMMENT 'Q1-2024, Q2-2024, etc.',
+ `start_date` date NOT NULL,
+ `end_date` date NOT NULL,
+ `status` varchar(32) DEFAULT 'draft' COMMENT 'draft, validated, submitted',
+ `created_date` datetime DEFAULT NULL,
+ PRIMARY KEY (`rowid`),
+ UNIQUE KEY `uk_period_entity_name` (`entity`, `period_name`),
+ KEY `idx_period_dates` (`start_date`, `end_date`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+-- Main declarations table (simplified)
+CREATE TABLE IF NOT EXISTS `llx_declarationtva_declarations` (
+ `rowid` int(11) NOT NULL AUTO_INCREMENT,
+ `entity` int(11) NOT NULL DEFAULT 1,
+ `period_id` int(11) NOT NULL,
+ `declaration_number` varchar(32) NOT NULL,
+ `status` varchar(32) DEFAULT 'draft' COMMENT 'draft, validated, submitted',
+ `total_vat_collected` decimal(15,2) DEFAULT 0.00,
+ `total_vat_deductible` decimal(15,2) DEFAULT 0.00,
+ `net_vat_due` decimal(15,2) DEFAULT 0.00,
+ `vat_credit` decimal(15,2) DEFAULT 0.00,
+ `submission_date` datetime DEFAULT NULL,
+ `created_date` datetime DEFAULT NULL,
+ PRIMARY KEY (`rowid`),
+ UNIQUE KEY `uk_declaration_entity_number` (`entity`, `declaration_number`),
+ KEY `idx_period_id` (`period_id`),
+ CONSTRAINT `fk_declaration_period` FOREIGN KEY (`period_id`) REFERENCES `llx_declarationtva_periods` (`rowid`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+-- CA-3 form lines (simplified)
+CREATE TABLE IF NOT EXISTS `llx_declarationtva_ca3_lines` (
+ `rowid` int(11) NOT NULL AUTO_INCREMENT,
+ `declaration_id` int(11) NOT NULL,
+ `ca3_line` varchar(8) NOT NULL,
+ `line_label` varchar(255) DEFAULT NULL,
+ `base_amount` decimal(15,2) DEFAULT 0.00,
+ `vat_amount` decimal(15,2) DEFAULT 0.00,
+ `total_amount` decimal(15,2) DEFAULT 0.00,
+ `created_date` datetime DEFAULT NULL,
+ PRIMARY KEY (`rowid`),
+ UNIQUE KEY `uk_declaration_line` (`declaration_id`, `ca3_line`),
+ CONSTRAINT `fk_ca3_declaration` FOREIGN KEY (`declaration_id`) REFERENCES `llx_declarationtva_declarations` (`rowid`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+-- =====================================================
+-- 2. INITIAL DATA FOR MVP
+-- =====================================================
+
+-- Insert default configuration
+INSERT INTO `llx_declarationtva_config` (`entity`, `config_key`, `config_value`, `created_date`) VALUES
+(1, 'module_version', '1.0.0-mvp', NOW()),
+(1, 'default_period_type', 'quarterly', NOW()),
+(1, 'vat_rates', '20.00,10.00,5.50,2.10,0.00', NOW()),
+(1, 'declaration_language', 'fr', NOW());
+
+-- Insert default CA-3 line mappings (simplified)
+INSERT INTO `llx_declarationtva_account_mappings` (`entity`, `ca3_line`, `account_code`, `account_label`, `vat_rate`, `created_date`) VALUES
+(1, 'A1', '701000', 'Ventes HT 20%', 20.00, NOW()),
+(1, 'A2', '701000', 'Opérations spéciales', 20.00, NOW()),
+(1, 'B1', '445710', 'TVA collectée 20%', 20.00, NOW()),
+(1, 'B2', '445720', 'TVA collectée 10%', 10.00, NOW()),
+(1, 'B3', '445730', 'TVA collectée 5.5%', 5.50, NOW()),
+(1, 'B4', '445740', 'TVA collectée 2.1%', 2.10, NOW()),
+(1, '17', '445200', 'TVA due intra-EU', 20.00, NOW()),
+(1, '20', '445620', 'TVA déductible immobilisations', 20.00, NOW()),
+(1, '21', '445660', 'TVA déductible autres', 20.00, NOW()),
+(1, '22', '445670', 'Crédit TVA', 0.00, NOW()),
+(1, '28', '445510', 'TVA nette à payer', 0.00, NOW()),
+(1, '29', '445670', 'Crédit TVA à reporter', 0.00, NOW());
+
+-- =====================================================
+-- 3. BASIC INDEXES FOR PERFORMANCE
+-- =====================================================
+
+CREATE INDEX `idx_declarationtva_periods_dates` ON `llx_declarationtva_periods` (`start_date`, `end_date`);
+CREATE INDEX `idx_declarationtva_declarations_period` ON `llx_declarationtva_declarations` (`period_id`);
+CREATE INDEX `idx_declarationtva_account_mappings_line` ON `llx_declarationtva_account_mappings` (`ca3_line`);
+
+-- =====================================================
+-- END OF MVP SCHEMA
+-- =====================================================