Skip to content

Account Model (account.account)

Overview

The Account model (account.account) represents the chart of accounts—the complete listing of all accounts in the general ledger. Each account is a container for journal entry lines and tracks specific types of assets, liabilities, equity, revenue, or expenses. Accounts form a hierarchical structure with parent accounts providing grouping and rollup capabilities. This model is fundamental to the accounting system, as every financial transaction ultimately posts to accounts, and all financial reports derive from account balances.


Model Information

Model Name: account.account
Display Name: Account
Key Fields: code, company_id
Source File: netforce_account/models/account_account.py

Features

  • ✅ Audit logging enabled (_audit_log = True)
  • ✅ Multi-company support (_multi_company = True)
  • ✅ Full-text content search (_content_search = True)
  • ✅ Unique key constraint per company (_key = ["code", "company_id"])
  • ✅ Export name field: code (_export_name_field = "code")
  • ✅ Indexed code field for performance

Understanding Key Fields

What are Key Fields?

For the account.account model, the key fields are:

_key = ["code", "company_id"]

This means the combination of these fields must be unique: - code - The account code (e.g., "101", "40100") - company_id - The company owning this account

Why Key Fields Matter

Uniqueness Guarantee - Key fields prevent duplicate accounts:

# Examples of valid combinations:
Company A, Code "101"   Valid (Cash account)
Company A, Code "401"   Valid (Revenue account)
Company B, Code "101"   Valid (different company)

# This would fail - duplicate key:
Company A, Code "101"   ERROR: Account code already exists!

Account Types

Accounts are organized into categories based on their financial statement classification:

Asset Types

Type Code Description Normal Balance
Cash cash Cash on hand Debit
Cheque cheque Cheque accounts Debit
Bank Account bank Bank accounts Debit
Receivable receivable Accounts receivable (AR) Debit
Current Asset cur_asset Other current assets Debit
Fixed Asset fixed_asset Property, plant, equipment Debit
Non-current Asset noncur_asset Long-term assets Debit
Supplier Deposit sup_deposit Deposits paid to suppliers Debit

Liability Types

Type Code Description Normal Balance
Payable payable Accounts payable (AP) Credit
Customer Deposit cust_deposit Deposits received from customers Credit
Current Liability cur_liability Short-term liabilities Credit
Non-current Liability noncur_liability Long-term liabilities Credit

Equity Types

Type Code Description Normal Balance
Equity equity Owner's equity, retained earnings Credit

Income Types

Type Code Description Normal Balance
Revenue revenue Operating revenue Credit
Other Income other_income Non-operating income Credit

Expense Types

Type Code Description Normal Balance
Cost of Sales cost_sales Direct costs (COGS) Debit
Expense expense Operating expenses Debit
Other Expense other_expense Non-operating expenses Debit

Special Types

Type Code Description
View view Parent/header account (no posting)
Other other Miscellaneous accounts

Bank Account Types

For accounts with type of cash, cheque, or bank, you can specify additional bank type:

Bank Type Code Description
Bank Account bank Standard bank account
Credit Card credit_card Credit card account
PayPal paypal PayPal account

Key Fields Reference

Core Fields

Field Type Required Description
code Char Account code (unique per company)
name Char(256) Account name
type Selection Account type (asset, liability, etc.)
parent_id Many2One Parent account (for hierarchy)
currency_id Many2One Account currency
company_id Many2One Owning company
active Boolean Whether account is active

Bank-Specific Fields

Field Type Description
bank_type Selection Bank account subtype
bank_name Char Name of bank
bank_no Char Bank account number
creditcard_no Char Credit card number

Configuration Fields

Field Type Description
tax_id Many2One Default tax rate for this account
fixed_asset_type_id Many2One Fixed asset type (for fixed asset accounts)
sequence_id Many2One Number sequence
description Text Account description/notes

Requirements/Validation Fields

Field Type Description
require_contact Boolean Line must have contact
require_tax_no Boolean Line must have tax number
require_track Boolean Line must have tracking category
require_track2 Boolean Line must have secondary tracking

Payment Configuration

Field Type Description
enable_payment Boolean Enable payments to this account
enable_adjust Boolean Enable adjustments to this account

Balance Fields (Computed)

Field Type Description
balance Decimal Current accounting balance
debit Decimal Total debits
credit Decimal Total credits
balance_cur Decimal Balance in account currency
balance_statement Decimal Latest bank statement balance
balance_90d Json Balance history for last 90 days

Relationship Fields

Field Type Description
move_lines One2Many Journal entry lines
statements One2Many Bank statements
comments One2Many Comments/messages

Analytics Fields

Field Type Description
unrec_num Integer Number of unreconciled items
company_currency_id Many2One Company currency (computed)
hide_details Boolean Hide from detail reports

API Methods

1. Create Account

Method: create(vals, context)

Creates a new account in the chart of accounts.

Parameters:

vals = {
    "code": "10100",                  # Required: Account code
    "name": "Petty Cash",             # Required: Account name
    "type": "cash",                   # Required: Account type
    "currency_id": 1,                 # Required: Currency ID
    "parent_id": 101,                 # Optional: Parent account
    "tax_id": 5,                      # Optional: Default tax
    "require_contact": False,         # Optional: Validation rules
    "active": True                    # Optional: Active status
}

Returns: int - New account ID

Example:

# Create cash account
account_id = get_model("account.account").create({
    "code": "10100",
    "name": "Petty Cash",
    "type": "cash",
    "currency_id": base_currency_id,
    "parent_id": cash_parent_id
})


2. Get Account Balance

Method: get_balance(ids, context)

Calculates account balance with flexible filtering options.

Parameters: - ids (list): Account IDs

Context Options:

context = {
    "date_from": "2025-01-01",        # Start date filter
    "date_to": "2025-01-31",          # End date filter
    "track_id": 10,                   # Filter by tracking category
    "track2_id": 20,                  # Filter by secondary tracking
    "currency_id": 2,                 # Convert to this currency
    "contact_id": 123,                # Filter by contact
    "contact_type": "customer",       # Filter by contact type
    "bank_rec_state": "reconciled",   # Filter by reconciliation
    "excl_date_to": True,             # Exclude date_to from range
    "journal_id": 5,                  # Filter by journal
    "no_close": True,                 # Exclude closing entries
    "nocache": True                   # Skip cache
}

Returns: dict - Account ID → balance data

Balance Data Structure:

{
    account_id: {
        "debit": 10000.00,            # Total debits
        "credit": 5000.00,            # Total credits
        "balance": 5000.00,           # Net balance (debit - credit)
        "balance_cur": 5000.00        # Balance in account currency
    }
}

Example:

# Get account balance for January 2025
balances = get_model("account.account").get_balance(
    [account_id],
    context={
        "date_from": "2025-01-01",
        "date_to": "2025-01-31"
    }
)
print(f"Balance: {balances[account_id]['balance']}")

# Get balance by department
balances = get_model("account.account").get_balance(
    [expense_account_id],
    context={
        "track_id": marketing_dept_id,
        "date_to": "2025-01-31"
    }
)

# Get customer receivables
balances = get_model("account.account").get_balance(
    [ar_account_id],
    context={
        "contact_type": "customer",
        "date_to": "2025-01-31"
    }
)


3. Get 90-Day Balance History

Method: get_balance_90d(ids, context)

Returns daily balance data for the last 90 days (for charting).

Parameters: - ids (list): Account IDs - nocache (bool): Skip cache (default False)

Returns: dict - Account ID → array of [timestamp, balance] pairs

Example:

# Get balance history for chart
history = get_model("account.account").get_balance_90d([account_id])
data = history[account_id]
# data = [[1704067200000, 5000.00], [1704153600000, 5250.00], ...]


4. Get Statement Balance

Method: get_balance_statement(ids, context)

Returns the latest bank statement balance for bank accounts.

Parameters: - ids (list): Account IDs

Returns: dict - Account ID → statement balance

Example:

# Get latest statement balance
stmt_bal = get_model("account.account").get_balance_statement([bank_account_id])
print(f"Statement balance: {stmt_bal[bank_account_id]}")


5. Auto Bank Reconcile

Method: auto_bank_reconcile(ids, context)

Automatically matches bank statement lines with journal entry lines.

Parameters: - ids (list): Bank account IDs

Behavior: - Finds unreconciled statement lines and move lines - Matches by amount and date (within max_days tolerance) - Links matching items - Returns count of matches found

Returns: dict with flash message

Example:

# Auto-match bank transactions
result = get_model("account.account").auto_bank_reconcile([bank_account_id])
print(result["flash"])  # "15 matches found"


6. Reconcile All Matched

Method: reconcile_all_matched(ids, context)

Reconciles all statement lines that have matching move lines.

Parameters: - ids (list): Account IDs

Behavior: - Finds unreconciled statement lines with move lines - Reconciles each matched line

Example:

get_model("account.account").reconcile_all_matched([bank_account_id])


7. Delete Account

Method: delete(ids, context)

Deletes accounts from the chart.

Parameters: - ids (list): Account IDs to delete

Behavior: - Validates account is not used in posted journal entries - Deletes draft journal entries using this account - Deletes account

Returns: None

Example:

# Can only delete unused accounts
get_model("account.account").delete([account_id])

Validation Errors: - "This account can't be deleted because it is used in some posted accounting transactions"


Method: name_search(name, condition, limit, context)

Searches accounts by code or name with smart matching.

Parameters: - name (str): Search term - condition (list): Additional search conditions - limit (int): Maximum results

Behavior: - If name is numeric: searches code starting with number - Otherwise: searches name (partial) or code (starts with)

Returns: List of (id, name) tuples

Example:

# Search by code
results = get_model("account.account").name_search("101")
# Returns accounts with codes starting with "101"

# Search by name
results = get_model("account.account").name_search("cash")
# Returns accounts with "cash" in name or code starting with "cash"


9. Name Get

Method: name_get(ids, context)

Returns formatted account names with codes.

Parameters: - ids (list): Account IDs

Returns: List of (id, "[code] name") tuples

Example:

names = get_model("account.account").name_get([account_id])
# Returns: [(123, "[10100] Petty Cash")]


Search Functions

Search by Code

# Find account by exact code
condition = [["code", "=", "10100"]]

# Find accounts with code starting with "101"
condition = [["code", "=ilike", "101%"]]

Search by Type

# Find all bank accounts
condition = [["type", "=", "bank"]]

# Find all asset accounts
condition = [["type", "in", ["cash", "bank", "receivable", "cur_asset"]]]

Search by Parent

# Find child accounts of specific parent
condition = [["parent_id", "=", parent_account_id]]

Search Active Accounts

# Find only active accounts
condition = [["active", "=", True]]

Computed Fields Functions

get_balance(ids, context)

Calculates account balances with comprehensive filtering: - Sums debits and credits from posted journal entry lines - Supports date ranges, tracking, contacts, reconciliation status - Handles currency conversion - Uses field cache for performance

get_balance_90d(ids, context)

Generates daily balance data for last 90 days: - Starts with balance from 90 days ago - Adds/subtracts each day's transactions - Returns time-series data for charting - Cached with daily refresh

get_balance_statement(ids, context)

Returns latest bank statement balance: - Queries most recent statement line - Used for bank reconciliation

get_unrec_num(ids, context)

Counts unreconciled bank statement lines per account.

get_company_currency(ids, context)

Returns the company's base currency for each account.


Account Hierarchy

Accounts can form a parent-child hierarchy using parent_id:

1000 - Assets (view)
  ├── 1010 - Current Assets (view)
  │   ├── 1011 - Cash on Hand
  │   ├── 1012 - Checking Account
  │   └── 1020 - Accounts Receivable (view)
  │       ├── 1021 - Domestic AR
  │       └── 1022 - Foreign AR
  └── 1100 - Fixed Assets (view)
      ├── 1110 - Equipment
      └── 1120 - Vehicles

View Accounts: - Type = "view" - Used for grouping and rollup - Cannot be posted to directly - Balance is sum of children

Detail Accounts: - Any type except "view" - Can be posted to - Leaf nodes in the hierarchy


Best Practices

1. Use Meaningful Account Codes

# Bad: Non-descriptive codes
{
    "code": "1",
    "name": "Cash"
}

# Good: Structured codes
{
    "code": "10100",  # Assets - Current - Cash - Petty Cash
    "name": "Petty Cash"
}

2. Set Appropriate Account Type

# Good: Correct type for usage
{
    "code": "12000",
    "name": "Accounts Receivable",
    "type": "receivable",  # Enables AR tracking
    "require_contact": True  # Enforce contact requirement
}

3. Use Hierarchy for Organization

# Create parent account
parent_id = get_model("account.account").create({
    "code": "4000",
    "name": "Revenue",
    "type": "view",  # View account (no posting)
    "currency_id": base_currency_id
})

# Create child accounts
get_model("account.account").create({
    "code": "4010",
    "name": "Product Sales",
    "type": "revenue",
    "parent_id": parent_id,
    "currency_id": base_currency_id
})

get_model("account.account").create({
    "code": "4020",
    "name": "Service Revenue",
    "type": "revenue",
    "parent_id": parent_id,
    "currency_id": base_currency_id
})

4. Set Default Taxes

# Good: Set default tax for common usage
{
    "code": "40100",
    "name": "Product Sales",
    "type": "revenue",
    "tax_id": vat_7_percent_id,  # Default tax
    "currency_id": base_currency_id
}

5. Use Validation Flags Appropriately

# Good: Enforce data quality
{
    "code": "12000",
    "name": "Accounts Receivable",
    "type": "receivable",
    "require_contact": True,      # Must have customer
    "require_track": True,        # Must have department
    "currency_id": base_currency_id
}

Model Relationship Description
account.move.line One2Many Journal entry lines posting to account
account.statement One2Many Bank statements (for bank accounts)
account.tax.rate Many2One Default tax rate
account.track.categ Many2One Tracking categories (via move lines)
account.fixed.asset.type Many2One Fixed asset type
currency Many2One Account currency
company Many2One Owning company
sequence Many2One Number sequence
message One2Many Comments

Common Use Cases

Use Case 1: Create Standard Chart of Accounts

# Create account hierarchy
accounts = [
    # Assets
    {"code": "1000", "name": "Assets", "type": "view", "parent": None},
    {"code": "1010", "name": "Current Assets", "type": "view", "parent": "1000"},
    {"code": "10100", "name": "Petty Cash", "type": "cash", "parent": "1010"},
    {"code": "10200", "name": "Bank Account", "type": "bank", "parent": "1010"},
    {"code": "12000", "name": "Accounts Receivable", "type": "receivable", "parent": "1010"},

    # Liabilities
    {"code": "2000", "name": "Liabilities", "type": "view", "parent": None},
    {"code": "2010", "name": "Current Liabilities", "type": "view", "parent": "2000"},
    {"code": "21000", "name": "Accounts Payable", "type": "payable", "parent": "2010"},

    # Equity
    {"code": "3000", "name": "Equity", "type": "view", "parent": None},
    {"code": "30000", "name": "Retained Earnings", "type": "equity", "parent": "3000"},

    # Revenue
    {"code": "4000", "name": "Revenue", "type": "view", "parent": None},
    {"code": "40100", "name": "Product Sales", "type": "revenue", "parent": "4000"},
    {"code": "40200", "name": "Service Revenue", "type": "revenue", "parent": "4000"},

    # Expenses
    {"code": "5000", "name": "Expenses", "type": "view", "parent": None},
    {"code": "50100", "name": "Cost of Goods Sold", "type": "cost_sales", "parent": "5000"},
    {"code": "51000", "name": "Salaries", "type": "expense", "parent": "5000"},
    {"code": "52000", "name": "Rent", "type": "expense", "parent": "5000"},
]

# Create accounts in order
account_map = {}
for acc_def in accounts:
    parent_id = account_map.get(acc_def["parent"]) if acc_def["parent"] else None

    acc_id = get_model("account.account").create({
        "code": acc_def["code"],
        "name": acc_def["name"],
        "type": acc_def["type"],
        "parent_id": parent_id,
        "currency_id": base_currency_id
    })

    account_map[acc_def["code"]] = acc_id

print(f"Created {len(accounts)} accounts")

Use Case 2: Generate Trial Balance Report

from datetime import datetime

# Get all detail accounts (non-view)
accounts = get_model("account.account").search_browse([
    ["type", "!=", "view"],
    ["active", "=", True]
], order="code")

# Calculate balances
end_date = "2025-01-31"
print("TRIAL BALANCE")
print(f"As of {end_date}")
print("=" * 80)
print(f"{'Code':<10} {'Account Name':<40} {'Debit':>15} {'Credit':>15}")
print("-" * 80)

total_debit = 0
total_credit = 0

for account in accounts:
    balance_data = get_model("account.account").get_balance(
        [account.id],
        context={"date_to": end_date}
    )[account.id]

    debit = balance_data["debit"]
    credit = balance_data["credit"]

    if debit != 0 or credit != 0:
        print(f"{account.code:<10} {account.name:<40} {debit:>15,.2f} {credit:>15,.2f}")
        total_debit += debit
        total_credit += credit

print("-" * 80)
print(f"{'TOTAL':<50} {total_debit:>15,.2f} {total_credit:>15,.2f}")
print("=" * 80)

# Verify balance
if abs(total_debit - total_credit) < 0.01:
    print("✓ Trial balance is balanced")
else:
    print(f"✗ Trial balance is OUT OF BALANCE by {abs(total_debit - total_credit):.2f}")

Use Case 3: Generate Balance Sheet

# Define balance sheet structure
bs_structure = {
    "Assets": ["cash", "cheque", "bank", "receivable", "cur_asset", "fixed_asset", "noncur_asset"],
    "Liabilities": ["payable", "cust_deposit", "cur_liability", "noncur_liability"],
    "Equity": ["equity"]
}

date = "2025-01-31"
print("BALANCE SHEET")
print(f"As of {date}")
print("=" * 80)

section_totals = {}

for section, types in bs_structure.items():
    print(f"\n{section.upper()}")
    print("-" * 80)

    accounts = get_model("account.account").search_browse([
        ["type", "in", types],
        ["active", "=", True]
    ], order="code")

    section_total = 0
    for account in accounts:
        balance_data = get_model("account.account").get_balance(
            [account.id],
            context={"date_to": date}
        )[account.id]

        balance = balance_data["balance"]
        if balance != 0:
            print(f"  {account.code} - {account.name:<50} {balance:>15,.2f}")
            section_total += balance

    print("-" * 80)
    print(f"  Total {section:<53} {section_total:>15,.2f}")
    section_totals[section] = section_total

# Calculate totals
total_assets = section_totals["Assets"]
total_liabilities = section_totals["Liabilities"]
total_equity = section_totals["Equity"]
total_liab_equity = total_liabilities + total_equity

print("\n" + "=" * 80)
print(f"TOTAL ASSETS{' '*50} {total_assets:>15,.2f}")
print(f"TOTAL LIABILITIES & EQUITY{' '*38} {total_liab_equity:>15,.2f}")
print("=" * 80)

if abs(total_assets - total_liab_equity) < 0.01:
    print("✓ Balance sheet is balanced")
else:
    print(f"✗ Balance sheet is OUT OF BALANCE by {abs(total_assets - total_liab_equity):.2f}")

Use Case 4: Bank Reconciliation Workflow

# 1. Import bank statement
bank_account_id = 102  # Bank account
statement_id = get_model("account.statement").create({
    "account_id": bank_account_id,
    "date": "2025-01-31",
    "balance_start": 10000.00,
    "balance_end": 12500.00
})

# Import statement lines (from CSV/API/etc.)
# ... (statement line import code)

# 2. Auto-reconcile matching transactions
result = get_model("account.account").auto_bank_reconcile([bank_account_id])
print(result["flash"])  # "25 matches found"

# 3. Manually review unmatched items
account = get_model("account.account").browse(bank_account_id)
print(f"Unreconciled items: {account.unrec_num}")

# 4. Reconcile all matched items
get_model("account.account").reconcile_all_matched([bank_account_id])

# 5. Check reconciliation status
accounting_bal = get_model("account.account").get_balance([bank_account_id])[bank_account_id]["balance"]
statement_bal = get_model("account.account").get_balance_statement([bank_account_id])[bank_account_id]

print(f"Accounting balance: {accounting_bal:,.2f}")
print(f"Statement balance: {statement_bal:,.2f}")
print(f"Difference: {abs(accounting_bal - statement_bal):,.2f}")

Use Case 5: Analyze Expenses by Department

# Get all expense accounts
expense_accounts = get_model("account.account").search_browse([
    ["type", "in", ["cost_sales", "expense", "other_expense"]],
    ["active", "=", True]
])

# Get all departments (tracking categories)
departments = get_model("account.track.categ").search_browse([
    ["type", "=", "1"]  # Type 1 = primary tracking (departments)
])

print("EXPENSE ANALYSIS BY DEPARTMENT")
print("Period: January 2025")
print("=" * 100)
print(f"{'Account':<50} {'Dept 1':>15} {'Dept 2':>15} {'Dept 3':>15} {'Total':>15}")
print("-" * 100)

for account in expense_accounts:
    row_data = [account.code + " - " + account.name]
    row_total = 0

    for dept in departments:
        balance_data = get_model("account.account").get_balance(
            [account.id],
            context={
                "date_from": "2025-01-01",
                "date_to": "2025-01-31",
                "track_id": dept.id
            }
        )[account.id]

        amount = balance_data["balance"]
        row_data.append(f"{amount:>15,.2f}")
        row_total += amount

    row_data.append(f"{row_total:>15,.2f}")

    if row_total != 0:
        print(f"{row_data[0]:<50} " + " ".join(row_data[1:]))

print("=" * 100)

Use Case 6: Currency Conversion for Foreign Accounts

# Get USD bank account balance in both USD and base currency (THB)
usd_account_id = 105

# Balance in account currency (USD)
balance_usd = get_model("account.account").get_balance([usd_account_id])[usd_account_id]
print(f"USD Account Balance (USD): {balance_usd['balance_cur']:,.2f}")

# Balance in base currency (THB)
settings = get_model("settings").browse(1)
base_currency_id = settings.currency_id.id

balance_thb = get_model("account.account").get_balance(
    [usd_account_id],
    context={"currency_id": base_currency_id}
)[usd_account_id]
print(f"USD Account Balance (THB): {balance_thb['balance']:,.2f}")

# Calculate effective exchange rate
if balance_usd['balance_cur'] != 0:
    effective_rate = balance_thb['balance'] / balance_usd['balance_cur']
    print(f"Effective exchange rate: {effective_rate:.4f}")

Performance Tips

1. Use Field Cache

Balance calculations are cached for performance:

# First call: queries database
balance1 = get_model("account.account").get_balance([account_id])

# Second call: uses cache (much faster)
balance2 = get_model("account.account").get_balance([account_id])

# Force refresh: use nocache
balance3 = get_model("account.account").get_balance(
    [account_id],
    context={"nocache": True}
)

2. Batch Balance Queries

# Good: Query multiple accounts at once
account_ids = [101, 102, 103, 104, 105]
balances = get_model("account.account").get_balance(account_ids)

# Bad: Query one at a time
for account_id in account_ids:
    balance = get_model("account.account").get_balance([account_id])

3. Use Indexed Fields

Code field is indexed for fast lookups:

# Good: Uses index
accounts = get_model("account.account").search([["code", "=", "10100"]])


Troubleshooting

"This account can't be deleted because it is used in some posted accounting transactions"

Cause: Account has posted journal entries
Solution: Cannot delete accounts with transaction history. Consider deactivating instead: active = False

Balance doesn't match expected value

Cause: Journal entries not posted, or filtering issue
Solution: Verify all entries are posted, check date filters in context

"Missing currency for account"

Cause: Account created without currency_id
Solution: Always set currency_id when creating accounts

Auto-reconcile not finding matches

Cause: Date tolerance too strict or amounts don't match exactly
Solution: Adjust bank_reconcile_max_days in settings, verify amounts match

View account appearing in trial balance

Cause: Incorrect query filter
Solution: Filter by type != "view" to exclude parent accounts


Testing Examples

Unit Test: Create Account and Check Balance

def test_account_balance():
    # Create account
    account_id = get_model("account.account").create({
        "code": "99999",
        "name": "Test Account",
        "type": "other",
        "currency_id": 1
    })

    # Initial balance should be zero
    balance = get_model("account.account").get_balance([account_id])
    assert balance[account_id]["balance"] == 0

    # Create journal entry
    move_id = get_model("account.move").create({
        "journal_id": 1,
        "date": "2025-01-15",
        "narration": "Test",
        "lines": [
            ("create", {"account_id": account_id, "debit": 1000, "credit": 0}),
            ("create", {"account_id": 401, "debit": 0, "credit": 1000})
        ]
    })
    get_model("account.move").post([move_id])

    # Check balance
    balance = get_model("account.account").get_balance(
        [account_id],
        context={"nocache": True}
    )
    assert balance[account_id]["balance"] == 1000
    assert balance[account_id]["debit"] == 1000
    assert balance[account_id]["credit"] == 0

    # Cleanup
    move = get_model("account.move").browse(move_id)
    move.void()
    get_model("account.account").delete([account_id])

Security Considerations

Permission Model

  • account_view: View accounts
  • account_create: Create accounts
  • account_edit: Edit accounts
  • account_delete: Delete accounts

Data Access

  • Multi-company: Users only see accounts for their company
  • Audit log: All changes tracked
  • Deletion restricted: Cannot delete accounts with history

Configuration Settings

Required Settings

Setting Location Description
currency_id Settings Base currency for all accounts

Optional Settings

Setting Default Description
bank_reconcile_max_days 30 Max days for auto-reconcile matching

Integration Points

Internal Modules

  • Journal Entries: All transactions post to accounts
  • Invoices: Use AR/AP accounts
  • Payments: Use bank/cash accounts
  • Fixed Assets: Use fixed asset accounts
  • Bank Statements: Reconcile with bank accounts
  • Tracking: Filter by tracking categories
  • Reports: Source for all financial reports

Version History

Last Updated: November 7, 2025
Model File: netforce_account/models/account_account.py
Framework: Netforce
Document Version: 1.0.0
Complexity: ⭐⭐⭐⭐⭐ (Very High - Core configuration)


Additional Resources


Support & Feedback

For issues or questions about this module: 1. Verify account type matches usage 2. Check currency is set 3. Use nocache for latest balances 4. Review account hierarchy 5. Test queries in development environment


This documentation is generated for developer onboarding and reference purposes.