Project accounting data mismatch occurs after cloud migration from on-premise

We recently completed a migration from Odoo 16 on-premise to Odoo 16 Enterprise cloud and are discovering significant data mismatches in our project accounting module. Project cost allocations, revenue recognition, and timesheet billing amounts don’t match between the old system and the new cloud instance.

The migration appeared successful with no errors reported, but when we started month-end close in the cloud system, we found discrepancies of $127,000 across 23 active projects. Some projects show inflated costs, others show missing revenue, and timesheet billable hours don’t match the original data.

We performed a data comparison query and found issues:

-- Comparison of project costs before/after migration
SELECT
    p.name as project_name,
    SUM(aal_old.amount) as old_cost,
    SUM(aal_new.amount) as new_cost,
    (SUM(aal_new.amount) - SUM(aal_old.amount)) as variance
FROM project_project p
LEFT JOIN account_analytic_line aal_old ON aal_old.project_id = p.id
LEFT JOIN account_analytic_line aal_new ON aal_new.project_id = p.id
WHERE p.active = true
GROUP BY p.name
HAVING ABS(SUM(aal_new.amount) - SUM(aal_old.amount)) > 1000;

Results show 23 projects with variances ranging from $2,400 to $18,500

Our auditors are flagging this as a critical issue. Has anyone dealt with project accounting data integrity issues after cloud migration? We need to understand what went wrong and how to correct it.

This is a common issue with project accounting migrations. The problem usually stems from how analytic account lines are linked to projects during the migration process. The migration tool might have correctly copied the data but failed to maintain the proper relationships between timesheet entries, expense lines, and revenue recognition records. Check if your analytic account IDs changed during migration - if they did, all the linked records need to be remapped.

I’ve handled multiple Odoo 16 cloud migrations with project accounting modules, and the issue you’re describing is almost always related to how the migration tool handles multi-currency transactions and analytic account line conversions. Here’s what’s happening and how to fix it:

The problem occurs when your project accounting data includes transactions in multiple currencies or when analytic lines have been modified after their initial creation (like adjustments, corrections, or reversals). During migration, the standard Odoo migration tool doesn’t always preserve the complete audit trail and modification history of analytic lines, which causes the aggregation calculations to produce different results.

Here’s a comprehensive diagnostic and correction approach:

-- Step 1: Identify specific discrepancy types
-- Check for missing analytic lines
SELECT
    'Missing Lines' as issue_type,
    COUNT(*) as count,
    SUM(amount) as total_amount
FROM account_analytic_line_backup  -- Your on-premise backup
WHERE id NOT IN (SELECT id FROM account_analytic_line);

-- Check for amount discrepancies in existing lines
SELECT
    'Amount Mismatch' as issue_type,
    COUNT(*) as count,
    SUM(ABS(new.amount - old.amount)) as total_variance
FROM account_analytic_line new
JOIN account_analytic_line_backup old ON new.id = old.id
WHERE ABS(new.amount - old.amount) > 0.01;

-- Check for incorrect project assignments
SELECT
    'Project Reassignment' as issue_type,
    COUNT(*) as count
FROM account_analytic_line new
JOIN account_analytic_line_backup old ON new.id = old.id
WHERE new.project_id != old.project_id;

-- Check for currency conversion issues
SELECT
    p.name as project_name,
    aal.currency_id,
    COUNT(*) as line_count,
    SUM(aal.amount) as amount,
    SUM(aal.amount * cr.rate) as converted_amount
FROM account_analytic_line aal
JOIN project_project p ON aal.project_id = p.id
LEFT JOIN res_currency_rate cr ON cr.currency_id = aal.currency_id
WHERE aal.currency_id IS NOT NULL
GROUP BY p.name, aal.currency_id;

Based on the diagnostic results, you’ll need to apply corrections. The most common issue is that timesheet entries and their corresponding invoice lines got disconnected during migration. Here’s the correction script:

# Run this through Odoo shell in your cloud instance
from odoo import api, SUPERUSER_ID

with api.Environment.manage():
    env = api.Environment(cr, SUPERUSER_ID, {})

    # Get all projects with discrepancies
    projects = env['project.project'].search([('active', '=', True)])

    for project in projects:
        print(f"Processing project: {project.name}")

        # Recalculate all analytic line amounts
        analytic_lines = env['account.analytic.line'].search([
            ('project_id', '=', project.id)
        ])

        for line in analytic_lines:
            # Verify currency conversion is correct
            if line.currency_id and line.currency_id != line.company_id.currency_id:
                # Recalculate with proper exchange rate
                rate = line.currency_id._get_conversion_rate(
                    line.currency_id,
                    line.company_id.currency_id,
                    line.company_id,
                    line.date
                )
                correct_amount = line.amount * rate
                if abs(line.amount_currency - correct_amount) > 0.01:
                    line.write({'amount_currency': correct_amount})

            # Reconnect timesheet entries to SO lines
            if line.timesheet_id and not line.so_line:
                # Find matching SO line based on project and task
                so_line = env['sale.order.line'].search([
                    ('order_id.project_id', '=', project.id),
                    ('product_id', '=', line.product_id.id),
                    ('state', 'in', ['sale', 'done'])
                ], limit=1)
                if so_line:
                    line.write({'so_line': so_line.id})

        # Force recalculation of project totals
        project._compute_analytic_line_ids()
        env.cr.commit()  # Commit after each project

    print("Correction complete")

After running the corrections, you need to verify the results:

  1. Re-run your variance query to confirm discrepancies are resolved
  2. Generate a reconciliation report comparing pre and post-migration totals
  3. Verify that revenue recognition schedules match between systems
  4. Confirm that timesheet billing amounts are correctly linked to sales orders

For the $127,000 discrepancy, you should also check if there are any analytic lines that were created in the on-premise system between the data extraction date and the cutover date - these would need to be manually migrated as a catch-up batch.

Finally, implement a validation script that runs daily to catch any future discrepancies early.

Check if the migration included all the accounting period data correctly. Sometimes migrations fail to properly transfer fiscal year and period configurations, which can cause revenue recognition and cost allocation to be calculated differently in the cloud system. Also verify that your project billing types (time and materials vs fixed price) were migrated correctly - if these got changed or reset to defaults, it would cause significant discrepancies in how revenue is calculated.

From an audit perspective, you need to identify whether this is a display issue (where the data is correct but aggregation queries are wrong) or an actual data integrity issue (where records were corrupted or lost during migration). Run record count comparisons for each table involved in project accounting: account_analytic_line, hr_timesheet, sale_order_line, project_task. If record counts match but amounts don’t, it’s likely a relationship mapping issue. If record counts don’t match, you have missing data that needs to be recovered from your on-premise backup.

Excellent analysis financial_systems_architect! We ran your diagnostic queries and found that we had both missing analytic lines (237 records) and currency conversion issues (18 projects with multi-currency transactions). The correction script resolved most of the discrepancies. We’re now down to $3,200 in variances which we traced to timesheet entries created during the migration cutover window. We’re manually migrating those final entries. The validation script is also set up to run daily. Thank you for the comprehensive solution!