BEGIN;

CREATE TABLE IF NOT EXISTS fiscal_tax_codes (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT REFERENCES companies (id) ON DELETE CASCADE,
  code VARCHAR(10) NOT NULL,
  label TEXT NOT NULL,
  cadre INTEGER NOT NULL,
  sub_cadre VARCHAR(10),
  tax_category VARCHAR(50),
  rate NUMERIC(8, 4),
  rate_type VARCHAR(20),
  base_formula TEXT,
  legal_reference VARCHAR(100),
  is_deduction BOOLEAN NOT NULL DEFAULT FALSE,
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  sort_order INTEGER,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  CONSTRAINT chk_fiscal_tax_codes_cadre CHECK (cadre BETWEEN 1 AND 8),
  CONSTRAINT chk_fiscal_tax_codes_tax_category CHECK (
    tax_category IS NULL
    OR tax_category IN ('TVA', 'IRG', 'IBS', 'TLS', 'TIMBRE', 'AUTRE')
  ),
  CONSTRAINT chk_fiscal_tax_codes_rate_type CHECK (
    rate_type IS NULL
    OR rate_type IN ('fixed', 'bareme', 'variable')
  )
);

ALTER TABLE fiscal_tax_codes
  ADD COLUMN IF NOT EXISTS legal_reference VARCHAR(100);

CREATE UNIQUE INDEX IF NOT EXISTS uq_fiscal_tax_codes_company_code
  ON fiscal_tax_codes (company_id, code)
  WHERE company_id IS NOT NULL;

CREATE UNIQUE INDEX IF NOT EXISTS uq_fiscal_tax_codes_global_code
  ON fiscal_tax_codes (code)
  WHERE company_id IS NULL;

CREATE INDEX IF NOT EXISTS idx_fiscal_tax_codes_company_id
  ON fiscal_tax_codes (company_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_tax_codes_cadre
  ON fiscal_tax_codes (cadre, sort_order);
CREATE INDEX IF NOT EXISTS idx_fiscal_tax_codes_tax_category
  ON fiscal_tax_codes (tax_category);
CREATE INDEX IF NOT EXISTS idx_fiscal_tax_codes_active
  ON fiscal_tax_codes (is_active);

CREATE TABLE IF NOT EXISTS fiscal_rules (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT REFERENCES companies (id) ON DELETE CASCADE,
  tax_code_id BIGINT NOT NULL REFERENCES fiscal_tax_codes (id) ON DELETE CASCADE,
  version_group_key VARCHAR(120),
  version_number INTEGER NOT NULL DEFAULT 1,
  rule_name VARCHAR(200) NOT NULL,
  rule_type VARCHAR(30) NOT NULL,
  account_code_from VARCHAR(20),
  account_code_to VARCHAR(20),
  account_code_exact VARCHAR(20),
  account_code_exact_list JSONB,
  journal_type VARCHAR(30),
  journal_type_list JSONB,
  entry_label_pattern VARCHAR(200),
  auxiliary_type VARCHAR(20),
  amount_side VARCHAR(10),
  sign INTEGER NOT NULL DEFAULT 1,
  effective_from DATE NOT NULL,
  effective_to DATE,
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  description TEXT,
  legal_reference VARCHAR(100),
  created_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  CONSTRAINT chk_fiscal_rules_type CHECK (
    rule_type IN (
      'account_range',
      'account_exact',
      'journal_type',
      'entry_label_pattern',
      'auxiliary_type'
    )
  ),
  CONSTRAINT chk_fiscal_rules_amount_side CHECK (
    amount_side IS NULL
    OR amount_side IN ('debit', 'credit', 'net', 'absolute')
  ),
  CONSTRAINT chk_fiscal_rules_sign CHECK (sign IN (-1, 1)),
  CONSTRAINT chk_fiscal_rules_auxiliary_type CHECK (
    auxiliary_type IS NULL
    OR auxiliary_type IN ('client', 'supplier')
  ),
  CONSTRAINT chk_fiscal_rules_period CHECK (
    effective_to IS NULL OR effective_to >= effective_from
  ),
  CONSTRAINT chk_fiscal_rules_version_number CHECK (version_number >= 1),
  CONSTRAINT chk_fiscal_rules_account_code_exact_list_json CHECK (
    account_code_exact_list IS NULL
    OR jsonb_typeof(account_code_exact_list) = 'array'
  ),
  CONSTRAINT chk_fiscal_rules_journal_type_list_json CHECK (
    journal_type_list IS NULL
    OR jsonb_typeof(journal_type_list) = 'array'
  )
);

ALTER TABLE fiscal_rules
  ADD COLUMN IF NOT EXISTS version_group_key VARCHAR(120);

ALTER TABLE fiscal_rules
  ADD COLUMN IF NOT EXISTS version_number INTEGER NOT NULL DEFAULT 1;

ALTER TABLE fiscal_rules
  ADD COLUMN IF NOT EXISTS account_code_exact_list JSONB;

ALTER TABLE fiscal_rules
  ADD COLUMN IF NOT EXISTS journal_type_list JSONB;

DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1
    FROM pg_constraint
    WHERE conname = 'chk_fiscal_rules_account_code_exact_list_json'
  ) THEN
    ALTER TABLE fiscal_rules
      ADD CONSTRAINT chk_fiscal_rules_account_code_exact_list_json CHECK (
        account_code_exact_list IS NULL
        OR jsonb_typeof(account_code_exact_list) = 'array'
      );
  END IF;
END $$;

DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1
    FROM pg_constraint
    WHERE conname = 'chk_fiscal_rules_journal_type_list_json'
  ) THEN
    ALTER TABLE fiscal_rules
      ADD CONSTRAINT chk_fiscal_rules_journal_type_list_json CHECK (
        journal_type_list IS NULL
        OR jsonb_typeof(journal_type_list) = 'array'
      );
  END IF;
END $$;

DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1
    FROM pg_constraint
    WHERE conname = 'chk_fiscal_rules_version_number'
  ) THEN
    ALTER TABLE fiscal_rules
      ADD CONSTRAINT chk_fiscal_rules_version_number CHECK (version_number >= 1);
  END IF;
END $$;

CREATE INDEX IF NOT EXISTS idx_fiscal_rules_company_id
  ON fiscal_rules (company_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_rules_tax_code_id
  ON fiscal_rules (tax_code_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_rules_status
  ON fiscal_rules (is_active, effective_from, effective_to);
CREATE INDEX IF NOT EXISTS idx_fiscal_rules_type
  ON fiscal_rules (rule_type);
CREATE INDEX IF NOT EXISTS idx_fiscal_rules_version_group
  ON fiscal_rules (company_id, version_group_key, version_number);
CREATE INDEX IF NOT EXISTS idx_fiscal_rules_effective_dates
  ON fiscal_rules (company_id, effective_from, effective_to);

CREATE TABLE IF NOT EXISTS fiscal_account_mapping (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
  account_id BIGINT NOT NULL REFERENCES accounts (id) ON DELETE CASCADE,
  tax_code_id BIGINT NOT NULL REFERENCES fiscal_tax_codes (id) ON DELETE CASCADE,
  amount_side VARCHAR(10) NOT NULL DEFAULT 'credit',
  sign INTEGER NOT NULL DEFAULT 1,
  applies_to_tva_collected BOOLEAN NOT NULL DEFAULT FALSE,
  applies_to_tva_deductible BOOLEAN NOT NULL DEFAULT FALSE,
  effective_from DATE NOT NULL,
  effective_to DATE,
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  notes TEXT,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  CONSTRAINT chk_fiscal_account_mapping_amount_side CHECK (
    amount_side IN ('debit', 'credit', 'net', 'absolute')
  ),
  CONSTRAINT chk_fiscal_account_mapping_sign CHECK (sign IN (-1, 1)),
  CONSTRAINT chk_fiscal_account_mapping_period CHECK (
    effective_to IS NULL OR effective_to >= effective_from
  )
);

DO $$
BEGIN
  IF EXISTS (
    SELECT 1
    FROM pg_constraint
    WHERE conname = 'chk_fiscal_account_mapping_amount_side'
  ) THEN
    ALTER TABLE fiscal_account_mapping
      DROP CONSTRAINT chk_fiscal_account_mapping_amount_side;
  END IF;
END $$;

ALTER TABLE fiscal_account_mapping
  ADD CONSTRAINT chk_fiscal_account_mapping_amount_side CHECK (
    amount_side IN ('debit', 'credit', 'net', 'absolute')
  );

CREATE UNIQUE INDEX IF NOT EXISTS uq_fiscal_account_mapping_period
  ON fiscal_account_mapping (company_id, account_id, tax_code_id, effective_from);

CREATE INDEX IF NOT EXISTS idx_fiscal_account_mapping_company_id
  ON fiscal_account_mapping (company_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_account_mapping_account_id
  ON fiscal_account_mapping (account_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_account_mapping_tax_code_id
  ON fiscal_account_mapping (tax_code_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_account_mapping_status
  ON fiscal_account_mapping (is_active, effective_from, effective_to);

CREATE TABLE IF NOT EXISTS fiscal_journal_mapping (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
  journal_id BIGINT NOT NULL REFERENCES journals (id) ON DELETE CASCADE,
  tax_code_id BIGINT NOT NULL REFERENCES fiscal_tax_codes (id) ON DELETE CASCADE,
  mapping_type VARCHAR(30) NOT NULL,
  amount_side VARCHAR(10) NOT NULL DEFAULT 'credit',
  sign INTEGER NOT NULL DEFAULT 1,
  effective_from DATE NOT NULL,
  effective_to DATE,
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  CONSTRAINT chk_fiscal_journal_mapping_type CHECK (
    mapping_type IN ('include', 'exclude')
  ),
  CONSTRAINT chk_fiscal_journal_mapping_amount_side CHECK (
    amount_side IN ('debit', 'credit', 'net')
  ),
  CONSTRAINT chk_fiscal_journal_mapping_sign CHECK (sign IN (-1, 1)),
  CONSTRAINT chk_fiscal_journal_mapping_period CHECK (
    effective_to IS NULL OR effective_to >= effective_from
  )
);

CREATE UNIQUE INDEX IF NOT EXISTS uq_fiscal_journal_mapping_period
  ON fiscal_journal_mapping (company_id, journal_id, tax_code_id, effective_from);

CREATE INDEX IF NOT EXISTS idx_fiscal_journal_mapping_company_id
  ON fiscal_journal_mapping (company_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_journal_mapping_journal_id
  ON fiscal_journal_mapping (journal_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_journal_mapping_tax_code_id
  ON fiscal_journal_mapping (tax_code_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_journal_mapping_status
  ON fiscal_journal_mapping (is_active, effective_from, effective_to);

CREATE TABLE IF NOT EXISTS fiscal_periods (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
  fiscal_year_id BIGINT NOT NULL REFERENCES fiscal_years (id) ON DELETE CASCADE,
  period_type VARCHAR(20) NOT NULL,
  mois INTEGER,
  trimestre INTEGER,
  annee INTEGER NOT NULL,
  date_from DATE NOT NULL,
  date_to DATE NOT NULL,
  deadline_g50 DATE,
  is_locked BOOLEAN NOT NULL DEFAULT FALSE,
  locked_at TIMESTAMPTZ,
  locked_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  CONSTRAINT chk_fiscal_periods_type CHECK (
    period_type IN ('monthly', 'quarterly')
  ),
  CONSTRAINT chk_fiscal_periods_month CHECK (mois IS NULL OR mois BETWEEN 1 AND 12),
  CONSTRAINT chk_fiscal_periods_quarter CHECK (
    trimestre IS NULL OR trimestre BETWEEN 1 AND 4
  ),
  CONSTRAINT chk_fiscal_periods_dates CHECK (date_to >= date_from),
  CONSTRAINT chk_fiscal_periods_shape CHECK (
    (
      period_type = 'monthly'
      AND mois IS NOT NULL
      AND trimestre IS NULL
    )
    OR (
      period_type = 'quarterly'
      AND trimestre IS NOT NULL
      AND mois IS NULL
    )
  )
);

CREATE UNIQUE INDEX IF NOT EXISTS uq_fiscal_periods_company_period
  ON fiscal_periods (
    company_id,
    fiscal_year_id,
    period_type,
    annee,
    COALESCE(mois, 0),
    COALESCE(trimestre, 0)
  );

CREATE INDEX IF NOT EXISTS idx_fiscal_periods_company_id
  ON fiscal_periods (company_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_periods_fiscal_year_id
  ON fiscal_periods (fiscal_year_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_periods_annee
  ON fiscal_periods (annee);
CREATE INDEX IF NOT EXISTS idx_fiscal_periods_mois
  ON fiscal_periods (mois);
CREATE INDEX IF NOT EXISTS idx_fiscal_periods_trimestre
  ON fiscal_periods (trimestre);
CREATE INDEX IF NOT EXISTS idx_fiscal_periods_locked
  ON fiscal_periods (is_locked);

CREATE TABLE IF NOT EXISTS g50_headers (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
  fiscal_period_id BIGINT NOT NULL REFERENCES fiscal_periods (id) ON DELETE CASCADE,
  version INTEGER NOT NULL DEFAULT 1,
  status VARCHAR(20) NOT NULL DEFAULT 'draft',
  total_cadre1 NUMERIC(15, 2) NOT NULL DEFAULT 0,
  total_cadre2 NUMERIC(15, 2) NOT NULL DEFAULT 0,
  total_cadre3 NUMERIC(15, 2) NOT NULL DEFAULT 0,
  total_cadre4 NUMERIC(15, 2) NOT NULL DEFAULT 0,
  total_cadre5 NUMERIC(15, 2) NOT NULL DEFAULT 0,
  total_cadre6 NUMERIC(15, 2) NOT NULL DEFAULT 0,
  total_cadre7 NUMERIC(15, 2) NOT NULL DEFAULT 0,
  total_tva_collectee NUMERIC(15, 2) NOT NULL DEFAULT 0,
  total_tva_deductible NUMERIC(15, 2) NOT NULL DEFAULT 0,
  tva_a_payer NUMERIC(15, 2) NOT NULL DEFAULT 0,
  tva_precompte_reporter NUMERIC(15, 2) NOT NULL DEFAULT 0,
  total_a_payer NUMERIC(15, 2) NOT NULL DEFAULT 0,
  calculated_at TIMESTAMPTZ,
  calculated_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
  entries_count INTEGER NOT NULL DEFAULT 0,
  entries_sum_debit NUMERIC(15, 2) NOT NULL DEFAULT 0,
  entries_sum_credit NUMERIC(15, 2) NOT NULL DEFAULT 0,
  validated_at TIMESTAMPTZ,
  validated_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
  quittance_numero VARCHAR(50),
  quittance_date DATE,
  montant_paye NUMERIC(15, 2) NOT NULL DEFAULT 0,
  g50_declaration_id BIGINT REFERENCES g50_declarations (id) ON DELETE SET NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  CONSTRAINT chk_g50_headers_status CHECK (
    status IN ('draft', 'adjusted', 'validated', 'locked')
  ),
  CONSTRAINT chk_g50_headers_version CHECK (version >= 1)
);

CREATE UNIQUE INDEX IF NOT EXISTS uq_g50_headers_period_version
  ON g50_headers (fiscal_period_id, version);

CREATE INDEX IF NOT EXISTS idx_g50_headers_company_id
  ON g50_headers (company_id);
CREATE INDEX IF NOT EXISTS idx_g50_headers_fiscal_period_id
  ON g50_headers (fiscal_period_id);
CREATE INDEX IF NOT EXISTS idx_g50_headers_status
  ON g50_headers (status);

CREATE TABLE IF NOT EXISTS g50_lines (
  id BIGSERIAL PRIMARY KEY,
  g50_header_id BIGINT NOT NULL REFERENCES g50_headers (id) ON DELETE CASCADE,
  tax_code_id BIGINT NOT NULL REFERENCES fiscal_tax_codes (id) ON DELETE RESTRICT,
  code VARCHAR(10) NOT NULL,
  cadre INTEGER NOT NULL,
  label TEXT NOT NULL,
  ca_global NUMERIC(15, 2) NOT NULL DEFAULT 0,
  ca_imposable NUMERIC(15, 2) NOT NULL DEFAULT 0,
  ca_exonere NUMERIC(15, 2) NOT NULL DEFAULT 0,
  base_imposable NUMERIC(15, 2) NOT NULL DEFAULT 0,
  taux NUMERIC(8, 4),
  montant_calcule NUMERIC(15, 2) NOT NULL DEFAULT 0,
  montant_ajuste NUMERIC(15, 2),
  montant_final NUMERIC(15, 2) NOT NULL DEFAULT 0,
  source_entry_ids BIGINT[],
  source_entry_count INTEGER NOT NULL DEFAULT 0,
  is_manually_adjusted BOOLEAN NOT NULL DEFAULT FALSE,
  adjustment_reason TEXT,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  CONSTRAINT chk_g50_lines_cadre CHECK (cadre BETWEEN 1 AND 8)
);

CREATE UNIQUE INDEX IF NOT EXISTS uq_g50_lines_header_code
  ON g50_lines (g50_header_id, code);

CREATE INDEX IF NOT EXISTS idx_g50_lines_g50_header_id
  ON g50_lines (g50_header_id);
CREATE INDEX IF NOT EXISTS idx_g50_lines_tax_code_id
  ON g50_lines (tax_code_id);
CREATE INDEX IF NOT EXISTS idx_g50_lines_cadre
  ON g50_lines (cadre, code);

CREATE TABLE IF NOT EXISTS g50_adjustments (
  id BIGSERIAL PRIMARY KEY,
  g50_header_id BIGINT NOT NULL REFERENCES g50_headers (id) ON DELETE CASCADE,
  g50_line_id BIGINT NOT NULL REFERENCES g50_lines (id) ON DELETE CASCADE,
  tax_code_id BIGINT REFERENCES fiscal_tax_codes (id) ON DELETE SET NULL,
  code VARCHAR(10),
  montant_avant NUMERIC(15, 2),
  montant_apres NUMERIC(15, 2),
  difference NUMERIC(15, 2),
  reason_type VARCHAR(50),
  justification TEXT NOT NULL,
  supporting_document_url VARCHAR(500),
  adjusted_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
  adjusted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  requires_approval BOOLEAN NOT NULL DEFAULT FALSE,
  approved_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
  approved_at TIMESTAMPTZ,
  CONSTRAINT chk_g50_adjustments_reason_type CHECK (
    reason_type IS NULL
    OR reason_type IN (
      'facturation_error',
      'missing_entry',
      'rate_correction',
      'credit_note_missing',
      'other'
    )
  )
);

CREATE INDEX IF NOT EXISTS idx_g50_adjustments_g50_header_id
  ON g50_adjustments (g50_header_id);
CREATE INDEX IF NOT EXISTS idx_g50_adjustments_g50_line_id
  ON g50_adjustments (g50_line_id);
CREATE INDEX IF NOT EXISTS idx_g50_adjustments_tax_code_id
  ON g50_adjustments (tax_code_id);

CREATE TABLE IF NOT EXISTS g50_audit_log (
  id BIGSERIAL PRIMARY KEY,
  g50_header_id BIGINT NOT NULL REFERENCES g50_headers (id) ON DELETE CASCADE,
  action VARCHAR(50) NOT NULL,
  actor_id BIGINT REFERENCES users (id) ON DELETE SET NULL,
  details JSONB NOT NULL DEFAULT '{}'::jsonb,
  ip_address INET,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  CONSTRAINT chk_g50_audit_log_action CHECK (
    action IN ('calculated', 'line_adjusted', 'validated', 'locked', 'reopened', 'exported')
  )
);

CREATE INDEX IF NOT EXISTS idx_g50_audit_log_g50_header_id
  ON g50_audit_log (g50_header_id);
CREATE INDEX IF NOT EXISTS idx_g50_audit_log_action
  ON g50_audit_log (action);
CREATE INDEX IF NOT EXISTS idx_g50_audit_log_created_at
  ON g50_audit_log (created_at DESC);

INSERT INTO fiscal_tax_codes (
  company_id,
  code,
  label,
  cadre,
  sub_cadre,
  tax_category,
  rate,
  rate_type,
  base_formula,
  legal_reference,
  is_deduction,
  is_active,
  sort_order
)
VALUES
  (NULL, 'E1M10', 'Acompte provisionnel IBS', 1, NULL, 'IBS', NULL, 'variable', 'Montant d''acompte IBS determine par liquidation fiscale', 'art. 356 CIDTA', FALSE, TRUE, 110),
  (NULL, 'E1M11', 'Solde de liquidation IBS', 1, NULL, 'IBS', NULL, 'variable', 'Solde IBS restant a payer', 'art. 356 CIDTA', FALSE, TRUE, 111),
  (NULL, 'E1M12', 'Acompte provisionnel ICBS', 1, NULL, 'IBS', NULL, 'variable', 'Montant d''acompte ICBS determine par liquidation fiscale', 'art. 356 CIDTA', FALSE, TRUE, 112),
  (NULL, 'E1M13', 'Solde de liquidation ICBS', 1, NULL, 'IBS', NULL, 'variable', 'Solde ICBS restant a payer', 'art. 356 CIDTA', FALSE, TRUE, 113),
  (NULL, 'E1M30', 'IBS / Revenus entreprises etrangeres (prestations services)', 2, NULL, 'IBS', NULL, 'variable', 'Base imposable des prestations d''entreprises etrangeres', 'art. 156 CIDTA', FALSE, TRUE, 210),
  (NULL, 'E1M40', 'IBS / Autres retenues a la source', 2, NULL, 'IBS', NULL, 'variable', 'Base imposable des autres retenues IBS', 'art. 156 CIDTA', FALSE, TRUE, 220),
  (NULL, 'E1N10', 'IRG BIC/BNC acompte provisionnel', 3, NULL, 'IRG', NULL, 'variable', 'Acompte provisionnel IRG BIC/BNC/RA', 'art. 356 CIDTA', FALSE, TRUE, 310),
  (NULL, 'E1N20', 'IRG BIC/BNC solde de liquidation', 3, NULL, 'IRG', NULL, 'variable', 'Solde de liquidation IRG BIC/BNC/RA', 'art. 356 CIDTA', FALSE, TRUE, 320),
  (NULL, 'E1L20', 'IRG / Traitements, salaires, pensions et rentes viageres', 4, NULL, 'IRG', NULL, 'bareme', 'Base salariale imposable soumise au bareme IRG', 'bareme IRG', FALSE, TRUE, 410),
  (NULL, 'E1L30', 'IRG / Revenus des creances, depots et cautionnements', 4, NULL, 'IRG', 10.0000, 'fixed', 'Base imposable des revenus de creances', 'art. 104 CIDTA', FALSE, TRUE, 420),
  (NULL, 'E1L40', 'IRG / Benefices distribues par societes de capitaux', 4, NULL, 'IRG', 15.0000, 'fixed', 'Base imposable des benefices distribues', 'art. 104 CIDTA', FALSE, TRUE, 430),
  (NULL, 'E1L60', 'IRG / Produits des titres anonymes ou au porteur', 4, NULL, 'IRG', 50.0000, 'fixed', 'Base imposable des titres anonymes ou au porteur', 'art. 104 CIDTA', FALSE, TRUE, 440),
  (NULL, 'E1L70', 'IRG / Revenus entreprises etrangeres (prestations)', 4, NULL, 'IRG', NULL, 'variable', 'Base imposable des retenues IRG sur entreprises etrangeres', 'art. 156 CIDTA', FALSE, TRUE, 450),
  (NULL, 'E1L80', 'IRG / Autres retenues a la source', 4, NULL, 'IRG', NULL, 'variable', 'Autres bases soumises a retenue IRG', 'CIDTA', FALSE, TRUE, 460),
  (NULL, 'E2A10', 'TLS / Transport par canalisation hydrocarbures', 5, NULL, 'TLS', 3.0000, 'fixed', 'Base TLS mensuelle sur transport par canalisation', 'art. 364 octies CIDTA', FALSE, TRUE, 510),
  (NULL, 'E2A20', 'TLS / Activites minieres sans refaction', 5, NULL, 'TLS', 1.5000, 'fixed', 'Base TLS mensuelle sur activites minieres sans refaction', 'art. 364 octies CIDTA', FALSE, TRUE, 520),
  (NULL, 'E2A21', 'TLS / Activites minieres avec refaction 30%', 5, NULL, 'TLS', 1.5000, 'fixed', 'Base TLS mensuelle apres refaction de 30%', 'art. 364 octies CIDTA', FALSE, TRUE, 521),
  (NULL, 'E2E00', 'Droit de timbre sur etat', 6, NULL, 'TIMBRE', NULL, 'variable', 'Base declaree pour paiement du droit de timbre sur etat', 'Code du timbre', FALSE, TRUE, 610),
  (NULL, 'E2E01', 'Taxe de formation professionnelle', 7, NULL, 'AUTRE', NULL, 'variable', 'Base d''imposition de la taxe de formation professionnelle', 'G50 officiel', FALSE, TRUE, 701),
  (NULL, 'E2E02', 'Taxe d''apprentissage', 7, NULL, 'AUTRE', NULL, 'variable', 'Base d''imposition de la taxe d''apprentissage', 'G50 officiel', FALSE, TRUE, 702),
  (NULL, 'E2E03', 'Taxe habitat', 7, NULL, 'AUTRE', NULL, 'variable', 'Base d''imposition de la taxe habitat', 'G50 officiel', FALSE, TRUE, 703),
  (NULL, 'E2E04', 'Taxe sur vehicules', 7, NULL, 'AUTRE', NULL, 'variable', 'Base d''imposition de la taxe sur vehicules', 'G50 officiel', FALSE, TRUE, 704),
  (NULL, 'E2E05', 'Taxe sur pneus', 7, NULL, 'AUTRE', NULL, 'variable', 'Base d''imposition de la taxe sur pneus', 'G50 officiel', FALSE, TRUE, 705),
  (NULL, 'E2E06', 'Autres taxes diverses 06', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E06', 'G50 officiel', FALSE, TRUE, 706),
  (NULL, 'E2E07', 'Autres taxes diverses 07', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E07', 'G50 officiel', FALSE, TRUE, 707),
  (NULL, 'E2E08', 'Autres taxes diverses 08', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E08', 'G50 officiel', FALSE, TRUE, 708),
  (NULL, 'E2E09', 'Autres taxes diverses 09', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E09', 'G50 officiel', FALSE, TRUE, 709),
  (NULL, 'E2E10', 'Autres taxes diverses 10', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E10', 'G50 officiel', FALSE, TRUE, 710),
  (NULL, 'E2E11', 'Autres taxes diverses 11', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E11', 'G50 officiel', FALSE, TRUE, 711),
  (NULL, 'E2E12', 'Autres taxes diverses 12', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E12', 'G50 officiel', FALSE, TRUE, 712),
  (NULL, 'E2E13', 'Autres taxes diverses 13', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E13', 'G50 officiel', FALSE, TRUE, 713),
  (NULL, 'E2E14', 'Autres taxes diverses 14', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E14', 'G50 officiel', FALSE, TRUE, 714),
  (NULL, 'E2E15', 'Autres taxes diverses 15', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E15', 'G50 officiel', FALSE, TRUE, 715),
  (NULL, 'E2E16', 'Autres taxes diverses 16', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E16', 'G50 officiel', FALSE, TRUE, 716),
  (NULL, 'E2E17', 'Autres taxes diverses 17', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E17', 'G50 officiel', FALSE, TRUE, 717),
  (NULL, 'E2E18', 'Autres taxes diverses 18', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E18', 'G50 officiel', FALSE, TRUE, 718),
  (NULL, 'E2E19', 'Autres taxes diverses 19', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E19', 'G50 officiel', FALSE, TRUE, 719),
  (NULL, 'E2E20', 'Autres taxes diverses 20', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E20', 'G50 officiel', FALSE, TRUE, 720),
  (NULL, 'E2E21', 'Autres taxes diverses 21', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E21', 'G50 officiel', FALSE, TRUE, 721),
  (NULL, 'E2E22', 'Autres taxes diverses 22', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E22', 'G50 officiel', FALSE, TRUE, 722),
  (NULL, 'E2E23', 'Autres taxes diverses 23', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E23', 'G50 officiel', FALSE, TRUE, 723),
  (NULL, 'E2E24', 'Autres taxes diverses 24', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E24', 'G50 officiel', FALSE, TRUE, 724),
  (NULL, 'E2E25', 'Autres taxes diverses 25', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E25', 'G50 officiel', FALSE, TRUE, 725),
  (NULL, 'E2E26', 'Autres taxes diverses 26', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E26', 'G50 officiel', FALSE, TRUE, 726),
  (NULL, 'E2E27', 'Autres taxes diverses 27', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E27', 'G50 officiel', FALSE, TRUE, 727),
  (NULL, 'E2E28', 'Autres taxes diverses 28', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E28', 'G50 officiel', FALSE, TRUE, 728),
  (NULL, 'E2E29', 'Autres taxes diverses 29', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E29', 'G50 officiel', FALSE, TRUE, 729),
  (NULL, 'E2E30', 'Autres taxes diverses 30', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E30', 'G50 officiel', FALSE, TRUE, 730),
  (NULL, 'E2E31', 'Autres taxes diverses 31', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E31', 'G50 officiel', FALSE, TRUE, 731),
  (NULL, 'E2E32', 'Autres taxes diverses 32', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E32', 'G50 officiel', FALSE, TRUE, 732),
  (NULL, 'E2E33', 'Autres taxes diverses 33', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E33', 'G50 officiel', FALSE, TRUE, 733),
  (NULL, 'E2E34', 'Autres taxes diverses 34', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E34', 'G50 officiel', FALSE, TRUE, 734),
  (NULL, 'E2E35', 'Autres taxes diverses 35', 7, NULL, 'AUTRE', NULL, 'variable', 'Autre base d''imposition fiscale code E2E35', 'G50 officiel', FALSE, TRUE, 735),
  (NULL, 'E3B11', 'Biens, produits et denrees (art. 23 CTCA)', 8, 'A', 'TVA', 9.0000, 'fixed', 'CA total a 9% - CA exonere', 'art. 23 CTCA', FALSE, TRUE, 811),
  (NULL, 'E3B12', 'Prestations de services (art. 23 CTCA)', 8, 'A', 'TVA', 9.0000, 'fixed', 'CA total a 9% - CA exonere', 'art. 23 CTCA', FALSE, TRUE, 812),
  (NULL, 'E3B13', 'Operations immobilieres (art. 23 CTCA)', 8, 'A', 'TVA', 9.0000, 'fixed', 'CA total a 9% - CA exonere', 'art. 23 CTCA', FALSE, TRUE, 813),
  (NULL, 'E3B14', 'Actes medicaux', 8, 'A', 'TVA', 9.0000, 'fixed', 'CA total a 9% - CA exonere', 'art. 23 CTCA', FALSE, TRUE, 814),
  (NULL, 'E3B15', 'Commissionnaires et courtiers', 8, 'A', 'TVA', 9.0000, 'fixed', 'CA total a 9% - CA exonere', 'art. 23 CTCA', FALSE, TRUE, 815),
  (NULL, 'E3B16', 'Fourniture d''energie', 8, 'A', 'TVA', 9.0000, 'fixed', 'CA total a 9% - CA exonere', 'art. 23 CTCA', FALSE, TRUE, 816),
  (NULL, 'E3B21', 'Productions: biens, produits (art. 21 CTCA)', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 821),
  (NULL, 'E3B22', 'Revente en l''etat (art. 21 CTCA)', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 822),
  (NULL, 'E3B23', 'Travaux immobiliers (autres que 9%)', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 823),
  (NULL, 'E3B24', 'Professions liberales', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 824),
  (NULL, 'E3B25', 'Operations de banques et assurances', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 825),
  (NULL, 'E3B26', 'Prestations telephones et telex', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 826),
  (NULL, 'E3B27', 'Operations diverses taux 19% - rubrique 27', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 827),
  (NULL, 'E3B28', 'Autres prestations de services', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 828),
  (NULL, 'E3B29', 'Operations diverses taux 19% - rubrique 29', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 829),
  (NULL, 'E3B30', 'Operations diverses taux 19% - rubrique 30', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 830),
  (NULL, 'E3B31', 'Debits de boissons', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 831),
  (NULL, 'E3B32', 'Operations diverses taux 19% - rubrique 32', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 832),
  (NULL, 'E3B33', 'Operations diverses taux 19% - rubrique 33', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 833),
  (NULL, 'E3B34', 'Tabacs et allumettes', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 834),
  (NULL, 'E3B35', 'Spectacles, jeux et divertissements', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 835),
  (NULL, 'E3B36', 'Autres prestations (art. 21 CTCA)', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 836),
  (NULL, 'E3B37', 'Consommations sur place', 8, 'A', 'TVA', 19.0000, 'fixed', 'CA total a 19% - CA exonere', 'art. 21 CTCA', FALSE, TRUE, 837),
  (NULL, 'E3B91', 'Precompte anterieur (mois precedent)', 8, 'B', 'TVA', NULL, 'variable', 'Precompte TVA a reporter depuis la declaration precedente', 'art. 29 CTCA', TRUE, TRUE, 891),
  (NULL, 'E3B92', 'TVA sur achats biens, matieres et services', 8, 'B', 'TVA', NULL, 'variable', 'TVA deductible sur achats courants', 'art. 29 CTCA', TRUE, TRUE, 892),
  (NULL, 'E3B93', 'TVA sur achats biens amortissables (art. 38)', 8, 'B', 'TVA', NULL, 'variable', 'TVA deductible sur immobilisations', 'art. 38 CTCA', TRUE, TRUE, 893),
  (NULL, 'E3B94', 'Regularisation prorata - deduction complementaire', 8, 'B', 'TVA', NULL, 'variable', 'Regularisation de prorata en deduction', 'art. 40 CTCA', TRUE, TRUE, 894),
  (NULL, 'E3B95', 'TVA a recuperer sur factures annulees ou impayees', 8, 'B', 'TVA', NULL, 'variable', 'TVA recuperable sur annulation ou impayes', 'art. 18 CTCA', TRUE, TRUE, 895),
  (NULL, 'E3B96', 'Autres deductions', 8, 'B', 'TVA', NULL, 'variable', 'Autres deductions TVA autorisees', 'CTCA', TRUE, TRUE, 896),
  (NULL, 'E3B97', 'Regularisation prorata (+)', 8, 'C', 'TVA', NULL, 'variable', 'Regularisation positive du prorata', 'art. 40 CTCA', FALSE, TRUE, 897),
  (NULL, 'E3B98', 'Reversement deduction article 38 (+)', 8, 'C', 'TVA', NULL, 'variable', 'Reversement de deduction sur immobilisations', 'art. 38 CTCA', FALSE, TRUE, 898),
  (NULL, 'E3B99', 'TVA a payer du mois', 8, 'C', 'TVA', NULL, 'variable', 'TVA nette due apres deductions', 'CTCA', FALSE, TRUE, 899),
  (NULL, 'E3B00', 'Precompte a reporter sur le mois suivant', 8, 'C', 'TVA', NULL, 'variable', 'Credit TVA a reporter', 'CTCA', FALSE, TRUE, 900)
ON CONFLICT (code) WHERE company_id IS NULL
DO UPDATE SET
  label = EXCLUDED.label,
  cadre = EXCLUDED.cadre,
  sub_cadre = EXCLUDED.sub_cadre,
  tax_category = EXCLUDED.tax_category,
  rate = EXCLUDED.rate,
  rate_type = EXCLUDED.rate_type,
  base_formula = EXCLUDED.base_formula,
  legal_reference = EXCLUDED.legal_reference,
  is_deduction = EXCLUDED.is_deduction,
  is_active = EXCLUDED.is_active,
  sort_order = EXCLUDED.sort_order,
  updated_at = NOW();

COMMIT;
