Simplify: O2M batch, domain dedup, db.go split, constants

Performance:
- O2M formatO2MFields: N+1 → single batched query per O2M field
  (collect parent IDs, WHERE inverse IN (...), group by parent)

Code dedup:
- domain.go compileSimpleCondition: 80 lines → 12 lines by delegating
  to compileQualifiedCondition (eliminates duplicate operator handling)
- db.go SeedWithSetup: 170-line monolith → 5 focused sub-functions
  (seedCurrencyAndCountry, seedCompanyAndAdmin, seedJournalsAndSequences,
  seedChartOfAccounts, resetSequences)

Quality:
- Magic numbers (80, 200, 8) replaced with named constants
- Net -34 lines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc
2026-04-03 13:11:37 +02:00
parent 70320b6b29
commit 6fd9cdea1b
4 changed files with 132 additions and 166 deletions

View File

@@ -307,8 +307,46 @@ func SeedWithSetup(ctx context.Context, pool *pgxpool.Pool, cfg SetupConfig) err
log.Printf("db: seeding database for %q...", cfg.CompanyName)
// 1. Currency (EUR)
_, err = tx.Exec(ctx, `
if err := seedCurrencyAndCountry(ctx, tx, cfg); err != nil {
return err
}
if err := seedCompanyAndAdmin(ctx, tx, cfg); err != nil {
return err
}
if err := seedJournalsAndSequences(ctx, tx); err != nil {
return err
}
seedChartOfAccounts(ctx, tx, cfg)
seedStockData(ctx, tx)
seedViews(ctx, tx)
seedActions(ctx, tx)
seedMenus(ctx, tx)
// Settings record (res.config.settings needs at least one record to display)
tx.Exec(ctx, `INSERT INTO res_config_settings (id, company_id, show_effect, create_uid, write_uid)
VALUES (1, 1, true, 1, 1) ON CONFLICT (id) DO NOTHING`)
seedSystemParams(ctx, tx)
seedLanguages(ctx, tx)
seedTranslations(ctx, tx)
if cfg.DemoData {
seedDemoData(ctx, tx)
}
resetSequences(ctx, tx)
if err := tx.Commit(ctx); err != nil {
return fmt.Errorf("db: commit seed: %w", err)
}
log.Printf("db: database seeded successfully for %q", cfg.CompanyName)
return nil
}
// seedCurrencyAndCountry seeds the default currency (EUR) and country.
func seedCurrencyAndCountry(ctx context.Context, tx pgx.Tx, cfg SetupConfig) error {
_, err := tx.Exec(ctx, `
INSERT INTO res_currency (id, name, symbol, decimal_places, rounding, active, "position")
VALUES (1, 'EUR', '€', 2, 0.01, true, 'after')
ON CONFLICT (id) DO NOTHING`)
@@ -316,7 +354,6 @@ func SeedWithSetup(ctx context.Context, pool *pgxpool.Pool, cfg SetupConfig) err
return fmt.Errorf("db: seed currency: %w", err)
}
// 2. Country
_, err = tx.Exec(ctx, `
INSERT INTO res_country (id, name, code, phone_code)
VALUES (1, $1, $2, $3)
@@ -324,9 +361,12 @@ func SeedWithSetup(ctx context.Context, pool *pgxpool.Pool, cfg SetupConfig) err
if err != nil {
return fmt.Errorf("db: seed country: %w", err)
}
return nil
}
// 3. Company partner
_, err = tx.Exec(ctx, `
// seedCompanyAndAdmin seeds the company partner, company, admin partner, and admin user.
func seedCompanyAndAdmin(ctx context.Context, tx pgx.Tx, cfg SetupConfig) error {
_, err := tx.Exec(ctx, `
INSERT INTO res_partner (id, name, is_company, active, type, lang, email, phone, street, zip, city, country_id, vat)
VALUES (1, $1, true, true, 'contact', 'de_DE', $2, $3, $4, $5, $6, 1, $7)
ON CONFLICT (id) DO NOTHING`,
@@ -335,7 +375,6 @@ func SeedWithSetup(ctx context.Context, pool *pgxpool.Pool, cfg SetupConfig) err
return fmt.Errorf("db: seed company partner: %w", err)
}
// 4. Company
_, err = tx.Exec(ctx, `
INSERT INTO res_company (id, name, partner_id, currency_id, country_id, active, sequence, street, zip, city, email, phone, vat)
VALUES (1, $1, 1, 1, 1, true, 10, $2, $3, $4, $5, $6, $7)
@@ -345,7 +384,6 @@ func SeedWithSetup(ctx context.Context, pool *pgxpool.Pool, cfg SetupConfig) err
return fmt.Errorf("db: seed company: %w", err)
}
// 5. Admin partner
adminName := "Administrator"
_, err = tx.Exec(ctx, `
INSERT INTO res_partner (id, name, is_company, active, type, email, lang)
@@ -355,7 +393,6 @@ func SeedWithSetup(ctx context.Context, pool *pgxpool.Pool, cfg SetupConfig) err
return fmt.Errorf("db: seed admin partner: %w", err)
}
// 6. Admin user
_, err = tx.Exec(ctx, `
INSERT INTO res_users (id, login, password, active, partner_id, company_id)
VALUES (1, $1, $2, true, 2, 1)
@@ -363,9 +400,12 @@ func SeedWithSetup(ctx context.Context, pool *pgxpool.Pool, cfg SetupConfig) err
if err != nil {
return fmt.Errorf("db: seed admin user: %w", err)
}
return nil
}
// 7. Journals
_, err = tx.Exec(ctx, `
// seedJournalsAndSequences seeds accounting journals and IR sequences.
func seedJournalsAndSequences(ctx context.Context, tx pgx.Tx) error {
_, err := tx.Exec(ctx, `
INSERT INTO account_journal (id, name, code, type, company_id, active, sequence) VALUES
(1, 'Ausgangsrechnungen', 'INV', 'sale', 1, true, 10),
(2, 'Eingangsrechnungen', 'BILL', 'purchase', 1, true, 20),
@@ -377,7 +417,6 @@ func SeedWithSetup(ctx context.Context, pool *pgxpool.Pool, cfg SetupConfig) err
return fmt.Errorf("db: seed journals: %w", err)
}
// 8. Sequences
_, err = tx.Exec(ctx, `
INSERT INTO ir_sequence (id, name, code, prefix, padding, number_next, number_increment, active, implementation) VALUES
(1, 'Buchungssatz', 'account.move', 'MISC/', 4, 1, 1, true, 'standard'),
@@ -389,59 +428,34 @@ func SeedWithSetup(ctx context.Context, pool *pgxpool.Pool, cfg SetupConfig) err
if err != nil {
return fmt.Errorf("db: seed sequences: %w", err)
}
return nil
}
// 9. Chart of Accounts (if selected)
if cfg.Chart == "skr03" || cfg.Chart == "skr04" {
// Currently only SKR03 is implemented
for _, acc := range l10n_de.SKR03Accounts {
tx.Exec(ctx, `
INSERT INTO account_account (code, name, account_type, company_id, reconcile)
VALUES ($1, $2, $3, 1, $4) ON CONFLICT DO NOTHING`,
acc.Code, acc.Name, acc.AccountType, acc.Reconcile)
}
log.Printf("db: seeded %d SKR03 accounts", len(l10n_de.SKR03Accounts))
// Taxes
for _, tax := range l10n_de.SKR03Taxes {
tx.Exec(ctx, `
INSERT INTO account_tax (name, amount, type_tax_use, amount_type, company_id, active, sequence, is_base_affected)
VALUES ($1, $2, $3, 'percent', 1, true, 1, true) ON CONFLICT DO NOTHING`,
tax.Name, tax.Amount, tax.TypeUse)
}
log.Printf("db: seeded %d German tax definitions", len(l10n_de.SKR03Taxes))
// seedChartOfAccounts seeds the chart of accounts and tax definitions if configured.
func seedChartOfAccounts(ctx context.Context, tx pgx.Tx, cfg SetupConfig) {
if cfg.Chart != "skr03" && cfg.Chart != "skr04" {
return
}
// 10. Stock reference data (locations, picking types, warehouse)
seedStockData(ctx, tx)
// 11. UI Views for key models
seedViews(ctx, tx)
// 12. Actions (ir_act_window + ir_model_data for XML IDs)
seedActions(ctx, tx)
// 13. Menus (ir_ui_menu + ir_model_data for XML IDs)
seedMenus(ctx, tx)
// 14. Settings record (res.config.settings needs at least one record to display)
tx.Exec(ctx, `INSERT INTO res_config_settings (id, company_id, show_effect, create_uid, write_uid)
VALUES (1, 1, true, 1, 1) ON CONFLICT (id) DO NOTHING`)
// 14b. System parameters (ir.config_parameter)
seedSystemParams(ctx, tx)
// 14c. Languages (res.lang — seed German alongside English)
seedLanguages(ctx, tx)
// 14d. Translations (ir.translation — German translations for core UI terms)
seedTranslations(ctx, tx)
// 15. Demo data
if cfg.DemoData {
seedDemoData(ctx, tx)
// Currently only SKR03 is implemented
for _, acc := range l10n_de.SKR03Accounts {
tx.Exec(ctx, `
INSERT INTO account_account (code, name, account_type, company_id, reconcile)
VALUES ($1, $2, $3, 1, $4) ON CONFLICT DO NOTHING`,
acc.Code, acc.Name, acc.AccountType, acc.Reconcile)
}
log.Printf("db: seeded %d SKR03 accounts", len(l10n_de.SKR03Accounts))
// 15. Reset sequences (each individually — pgx doesn't support multi-statement)
for _, tax := range l10n_de.SKR03Taxes {
tx.Exec(ctx, `
INSERT INTO account_tax (name, amount, type_tax_use, amount_type, company_id, active, sequence, is_base_affected)
VALUES ($1, $2, $3, 'percent', 1, true, 1, true) ON CONFLICT DO NOTHING`,
tax.Name, tax.Amount, tax.TypeUse)
}
log.Printf("db: seeded %d German tax definitions", len(l10n_de.SKR03Taxes))
}
// resetSequences resets all auto-increment sequences to their current max values.
func resetSequences(ctx context.Context, tx pgx.Tx) {
seqs := []string{
"res_currency", "res_country", "res_partner", "res_company",
"res_users", "ir_sequence", "account_journal", "account_account",
@@ -460,13 +474,6 @@ func SeedWithSetup(ctx context.Context, pool *pgxpool.Pool, cfg SetupConfig) err
`SELECT setval('%s_id_seq', GREATEST((SELECT COALESCE(MAX(id),0) FROM %q), 1))`,
table, table))
}
if err := tx.Commit(ctx); err != nil {
return fmt.Errorf("db: commit seed: %w", err)
}
log.Printf("db: database seeded successfully for %q", cfg.CompanyName)
return nil
}
// seedStockData creates stock locations, picking types, and a default warehouse.