import sys import os import argparse from datetime import datetime, date from dateutil.relativedelta import relativedelta def main(): parser = argparse.ArgumentParser(description="Deep Test Depreciation Logic") parser.add_argument("odoo_bin_path", help="Path to odoo-bin executable") parser.add_argument("conf_path", help="Path to odoo.conf") parser.add_argument("db_name", help="Database name") args = parser.parse_args() odoo_bin_path = os.path.abspath(args.odoo_bin_path) conf_path = os.path.abspath(args.conf_path) db_name = args.db_name # Add Odoo to sys.path odoo_root = os.path.dirname(odoo_bin_path) if odoo_root not in sys.path: sys.path.append(odoo_root) # Change CWD to config directory to handle relative paths in config (like addons_path) os.chdir(os.path.dirname(conf_path)) try: import odoo from odoo import api, SUPERUSER_ID except ImportError: print(f"Error: Could not import 'odoo' module from {odoo_root}. Make sure odoo-bin path is correct.") sys.exit(1) print(f"Initializing Odoo Environment for database: {db_name}...") try: odoo.tools.config.parse_config(['-c', conf_path]) registry = odoo.registry(db_name) except Exception as e: print(f"Error initializing Odoo: {e}") return with registry.cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, {}) print("Connected to Odoo.") try: test_different_scenarios(env) cr.commit() print("Test completed successfully.") except Exception as e: cr.rollback() print(f"Test failed: {e}") import traceback traceback.print_exc() def test_different_scenarios(env): # Find an asset model to use model = env['account.asset'].search([('state', '=', 'model')], limit=1) if not model: print("No asset model found!") return print(f"Using asset model: {model.name}") print(f"Model settings: method={model.method}, method_number={model.method_number}, method_period={model.method_period}") # Test different acquisition dates test_cases = [ { 'name': 'Future Acquisition (2025-11-01)', 'acquisition_date': date(2025, 11, 1), 'description': 'Asset acquired after cutoff date' }, { 'name': 'Recent Acquisition (2024-11-01)', 'acquisition_date': date(2024, 11, 1), 'description': 'Asset acquired before cutoff date' }, { 'name': 'Old Acquisition (2020-01-01)', 'acquisition_date': date(2020, 1, 1), 'description': 'Very old asset' } ] for i, test_case in enumerate(test_cases): print(f"\n{'='*60}") print(f"TEST {i+1}: {test_case['name']}") print(f"Description: {test_case['description']}") print(f"{'='*60}") acquisition_date = test_case['acquisition_date'] original_value = 48500000.0 vals = { 'name': f'TEST Asset - {test_case["name"]}', 'original_value': original_value, 'acquisition_date': acquisition_date, 'model_id': model.id, 'method': model.method, 'method_number': 60, # Force 60 months 'method_period': '1', # Force monthly 'prorata_computation_type': model.prorata_computation_type, 'state': 'draft', 'account_asset_id': model.account_asset_id.id, 'account_depreciation_id': model.account_depreciation_id.id, 'account_depreciation_expense_id': model.account_depreciation_expense_id.id, 'journal_id': model.journal_id.id, 'method_progress_factor': model.method_progress_factor, 'analytic_distribution': model.analytic_distribution, } asset = env['account.asset'].create(vals) print(f"Created asset: {asset.name}") print(f" Acquisition Date: {asset.acquisition_date}") print(f" Method Number: {asset.method_number}") print(f" Method Period: {asset.method_period}") # Compute depreciation board asset.compute_depreciation_board() moves = asset.depreciation_move_ids.sorted('date') print(f" Moves created: {len(moves)}") if moves: print(f" First move: {moves[0].date}") print(f" Last move: {moves[-1].date}") # Calculate expected end date expected_end = acquisition_date + relativedelta(months=59) # 60 months = 0 to 59 print(f" Expected last move around: {expected_end}") # Check if complete if len(moves) >= 60: print(f" ✅ Complete: {len(moves)} moves") else: print(f" ❌ Incomplete: Only {len(moves)} moves (expected 60)") # Show first few and last few moves print(f" First 3 moves:") for move in moves[:3]: amount = sum(line.debit for line in move.line_ids if line.account_id == asset.account_depreciation_expense_id) print(f" {move.date}: {amount:,.2f}") print(f" Last 3 moves:") for move in moves[-3:]: amount = sum(line.debit for line in move.line_ids if line.account_id == asset.account_depreciation_expense_id) print(f" {move.date}: {amount:,.2f}") # Cleanup asset.unlink() # Test with different prorata settings print(f"\n{'='*60}") print(f"TEST: Different Prorata Settings") print(f"{'='*60}") prorata_options = ['constant_periods', 'daily_computation', 'none'] for prorata in prorata_options: print(f"\nTesting prorata_computation_type: {prorata}") vals = { 'name': f'TEST Asset - Prorata {prorata}', 'original_value': 48500000.0, 'acquisition_date': date(2024, 11, 1), 'model_id': model.id, 'method': 'linear', 'method_number': 60, 'method_period': '1', 'prorata_computation_type': prorata, 'state': 'draft', 'account_asset_id': model.account_asset_id.id, 'account_depreciation_id': model.account_depreciation_id.id, 'account_depreciation_expense_id': model.account_depreciation_expense_id.id, 'journal_id': model.journal_id.id, 'method_progress_factor': model.method_progress_factor, 'analytic_distribution': model.analytic_distribution, } asset = env['account.asset'].create(vals) asset.compute_depreciation_board() moves = asset.depreciation_move_ids.sorted('date') print(f" Moves: {len(moves)}, Last: {moves[-1].date if moves else 'None'}, Prorata Date: {asset.prorata_date}") asset.unlink() # Manual Test for 'none' with forced date print(f"\nTesting prorata_computation_type: none (FORCED prorata_date)") vals = { 'name': f'TEST Asset - Forced None', 'original_value': 48500000.0, 'acquisition_date': date(2024, 11, 1), 'prorata_date': date(2024, 11, 1), # Explicitly set 'model_id': model.id, 'method': 'linear', 'method_number': 60, 'method_period': '1', 'prorata_computation_type': 'none', 'state': 'draft', 'account_asset_id': model.account_asset_id.id, 'account_depreciation_id': model.account_depreciation_id.id, 'account_depreciation_expense_id': model.account_depreciation_expense_id.id, 'journal_id': model.journal_id.id, } asset = env['account.asset'].create(vals) asset.compute_depreciation_board() moves = asset.depreciation_move_ids.sorted('date') print(f" Moves: {len(moves)}, Last: {moves[-1].date if moves else 'None'}, Prorata Date: {asset.prorata_date}") asset.unlink() if __name__ == "__main__": main()