Files
QB-Import-from-Excel/get_account_ids.py
T
2026-02-13 10:38:45 -05:00

280 lines
9.4 KiB
Python

#!/usr/bin/env python3
"""
QBO Account ID Lookup Script
============================
This script connects to QuickBooks Online and retrieves all accounts
with their IDs, names, types, and other details.
Usage:
python get_account_ids.py [--type TYPE] [--search NAME] [--export FILE]
Examples:
python get_account_ids.py # List all accounts
python get_account_ids.py --type Bank # List only Bank accounts
python get_account_ids.py --search Checking # Search by name
python get_account_ids.py --export accounts.csv # Export to CSV
"""
import os
import sys
import json
import argparse
from pathlib import Path
from datetime import datetime
# Add parent directory to path to import from src
script_dir = Path(__file__).parent
sys.path.insert(0, str(script_dir))
from src.config.settings import Settings
from src.api.qbo_client import QBOClient
def get_accounts(client, account_type=None, search_term=None):
"""
Fetch accounts from QBO with optional filtering.
Args:
client: QBOClient instance
account_type: Filter by account type (Bank, Expense, Income, etc.)
search_term: Search accounts by name
Returns:
List of account dictionaries
"""
# Build query
query = "SELECT * FROM Account"
conditions = []
if account_type:
conditions.append(f"AccountType = '{account_type}'")
if search_term:
conditions.append(f"Name LIKE '%{search_term}%'")
if conditions:
query += " WHERE " + " AND ".join(conditions)
query += " ORDERBY Name"
# Execute query
response = client._make_request('GET', 'query', params={'query': query})
if response and 'QueryResponse' in response:
return response['QueryResponse'].get('Account', [])
return []
def format_account_table(accounts):
"""Format accounts as a readable table."""
if not accounts:
return "No accounts found."
# Define columns
headers = ['ID', 'Name', 'Type', 'SubType', 'AcctNum', 'Balance', 'Active']
# Calculate column widths
widths = {
'ID': max(len('ID'), max(len(str(a.get('Id', ''))) for a in accounts)),
'Name': max(len('Name'), min(40, max(len(str(a.get('Name', ''))) for a in accounts))),
'Type': max(len('Type'), max(len(str(a.get('AccountType', ''))) for a in accounts)),
'SubType': max(len('SubType'), max(len(str(a.get('AccountSubType', ''))) for a in accounts)),
'AcctNum': max(len('AcctNum'), max(len(str(a.get('AcctNum', ''))) for a in accounts)),
'Balance': max(len('Balance'), 12),
'Active': max(len('Active'), 6),
}
# Build header
header_row = " | ".join(h.ljust(widths[h]) for h in headers)
separator = "-+-".join("-" * widths[h] for h in headers)
lines = [header_row, separator]
# Build data rows
for account in accounts:
name = str(account.get('Name', ''))[:40]
balance = account.get('CurrentBalance', 0)
balance_str = f"${balance:,.2f}" if balance else "-"
row = [
str(account.get('Id', '')).ljust(widths['ID']),
name.ljust(widths['Name']),
str(account.get('AccountType', '')).ljust(widths['Type']),
str(account.get('AccountSubType', '')).ljust(widths['SubType']),
str(account.get('AcctNum', '')).ljust(widths['AcctNum']),
balance_str.rjust(widths['Balance']),
('Yes' if account.get('Active', True) else 'No').ljust(widths['Active']),
]
lines.append(" | ".join(row))
return "\n".join(lines)
def export_to_csv(accounts, filepath):
"""Export accounts to CSV file."""
import csv
headers = ['Id', 'Name', 'FullyQualifiedName', 'AccountType', 'AccountSubType',
'AcctNum', 'CurrentBalance', 'Active', 'Classification', 'Description']
with open(filepath, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=headers, extrasaction='ignore')
writer.writeheader()
for account in accounts:
writer.writerow(account)
print(f"Exported {len(accounts)} accounts to {filepath}")
def export_to_json(accounts, filepath):
"""Export accounts to JSON file."""
with open(filepath, 'w', encoding='utf-8') as f:
json.dump(accounts, f, indent=2)
print(f"Exported {len(accounts)} accounts to {filepath}")
def print_account_types(accounts):
"""Print summary of account types."""
type_counts = {}
for account in accounts:
acct_type = account.get('AccountType', 'Unknown')
type_counts[acct_type] = type_counts.get(acct_type, 0) + 1
print("\nAccount Types Summary:")
print("-" * 30)
for acct_type, count in sorted(type_counts.items()):
print(f" {acct_type}: {count}")
print("-" * 30)
print(f" Total: {len(accounts)}")
def main():
parser = argparse.ArgumentParser(
description='Fetch Account IDs from QuickBooks Online',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Account Types:
Bank - Bank accounts (checking, savings)
Accounts Receivable - Customer receivables
Other Current Asset - Other current assets
Fixed Asset - Property, equipment, etc.
Other Asset - Other long-term assets
Accounts Payable - Vendor payables
Credit Card - Credit card accounts
Other Current Liability - Other current liabilities
Long Term Liability - Long-term debt
Equity - Owner's equity accounts
Income - Revenue accounts
Cost of Goods Sold - COGS accounts
Expense - Expense accounts
Other Income - Other income
Other Expense - Other expenses
Examples:
%(prog)s --type Bank
%(prog)s --type Expense --search Office
%(prog)s --export accounts.csv
%(prog)s --type "Accounts Payable"
"""
)
parser.add_argument('--type', '-t', dest='account_type',
help='Filter by account type (e.g., Bank, Expense, Income)')
parser.add_argument('--search', '-s', dest='search_term',
help='Search accounts by name')
parser.add_argument('--export', '-e', dest='export_file',
help='Export to file (CSV or JSON based on extension)')
parser.add_argument('--summary', action='store_true',
help='Show account type summary')
parser.add_argument('--json', action='store_true',
help='Output as JSON')
parser.add_argument('--verbose', '-v', action='store_true',
help='Show detailed account information')
args = parser.parse_args()
# Initialize settings and client
print("=" * 60)
print("QBO Account ID Lookup")
print("=" * 60)
try:
settings = Settings()
credentials = settings.get_credentials()
if not credentials.access_token:
print("\nError: Not connected to QuickBooks Online.")
print("Please connect via the web application first.")
sys.exit(1)
client = QBOClient(credentials)
if not client.is_authenticated:
print("\nError: Authentication failed or token expired.")
print("Please reconnect via the web application.")
sys.exit(1)
# Get company info
company_info = client.get_company_info()
print(f"\nConnected to: {company_info.get('CompanyName', 'Unknown')}")
print(f"Environment: {credentials.environment}")
print("-" * 60)
# Fetch accounts
print(f"\nFetching accounts...")
if args.account_type:
print(f" Filter by type: {args.account_type}")
if args.search_term:
print(f" Search term: {args.search_term}")
accounts = get_accounts(client, args.account_type, args.search_term)
print(f"\nFound {len(accounts)} account(s)")
print("-" * 60)
if not accounts:
print("No accounts match your criteria.")
sys.exit(0)
# Output results
if args.json:
print(json.dumps(accounts, indent=2))
elif args.verbose:
for i, account in enumerate(accounts, 1):
print(f"\n[{i}] {account.get('Name')}")
print(f" ID: {account.get('Id')}")
print(f" Type: {account.get('AccountType')} / {account.get('AccountSubType', '-')}")
print(f" Number: {account.get('AcctNum', '-')}")
print(f" Balance: ${account.get('CurrentBalance', 0):,.2f}")
print(f" Active: {account.get('Active', True)}")
if account.get('Description'):
print(f" Description: {account.get('Description')}")
else:
print(format_account_table(accounts))
# Show summary if requested
if args.summary:
print_account_types(accounts)
# Export if requested
if args.export_file:
filepath = args.export_file
if filepath.endswith('.json'):
export_to_json(accounts, filepath)
else:
export_to_csv(accounts, filepath)
print("\n" + "=" * 60)
print("Done!")
except Exception as e:
print(f"\nError: {str(e)}")
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == '__main__':
main()