oca-financial/odoo-bringout-oca-account-analytic-account_analytic_distribution_manual/account_analytic_distribution_manual/hooks.py
2025-08-29 15:43:04 +02:00

196 lines
7.3 KiB
Python

# Copyright 2024 Tecnativa - Carlos Lopez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import SUPERUSER_ID, api, tools
# metadata for all models related to account_analytic_tag(m2m)
# add more models if needed
RELATION_M2M_INFO = {
"account_analytic_tag_account_asset_profile_rel": {
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
"table2": "account_asset_profile",
"column2": "account_asset_profile_id",
},
"account_analytic_tag_hr_expense_rel": {
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
"table2": "hr_expense",
"column2": "hr_expense_id",
},
"account_reconcile_model_second_analytic_tag_rel": {
"table2": "account_reconcile_model",
"column2": "account_reconcile_model_id",
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
},
"hr_timesheet_switch_line_tag_rel": {
"table2": "hr_timesheet_switch",
"column2": "line_id",
"table1": "account_analytic_tag",
"column1": "tag_id",
},
"account_analytic_tag_sale_order_line_rel": {
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
"table2": "sale_order_line",
"column2": "sale_order_line_id",
},
"account_reconcile_model_analytic_tag_rel": {
"table2": "account_reconcile_model_line",
"column2": "account_reconcile_model_line_id",
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
},
"account_analytic_tag_mis_report_instance_rel": {
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
"table2": "mis_report_instance",
"column2": "mis_report_instance_id",
},
"account_analytic_tag_account_move_line_rel": {
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
"table2": "account_move_line",
"column2": "account_move_line_id",
},
"account_analytic_tag_mis_report_instance_period_rel": {
"table2": "mis_report_instance_period",
"column2": "mis_report_instance_period_id",
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
},
"account_analytic_tag_general_ledger_report_wizard_rel": {
"table2": "general_ledger_report_wizard",
"column2": "general_ledger_report_wizard_id",
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
},
"account_analytic_default_account_analytic_tag_rel": {
"table2": "account_analytic_default",
"column2": "account_analytic_default_id",
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
},
"account_analytic_tag_purchase_order_line_rel": {
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
"table2": "purchase_order_line",
"column2": "purchase_order_line_id",
},
"account_analytic_tag_account_asset_rel": {
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
"table2": "account_asset",
"column2": "account_asset_id",
},
"account_analytic_tag_project_task_stock_rel": {
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
"table2": "project_task",
"column2": "project_task_id",
},
"account_analytic_tag_project_task_rel": {
"table1": "account_analytic_tag",
"column1": "account_analytic_tag_id",
"table2": "project_task",
"column2": "project_task_id",
},
"account_analytic_line_tag_rel": {
"table2": "account_analytic_line",
"column2": "line_id",
"table1": "account_analytic_tag",
"column1": "tag_id",
},
}
def post_init_hook(cr, registry):
if tools.table_exists(cr, "account_analytic_tag"):
env = api.Environment(cr, SUPERUSER_ID, {})
DistributionManual = env["account.analytic.distribution.manual"]
sql = """
WITH counted_tags AS (
SELECT
tag.id,
tag.name,
tag.active,
tag.company_id,
ROW_NUMBER() OVER (PARTITION BY tag.name ORDER BY tag.id) AS row_count
FROM account_analytic_tag tag
WHERE tag.active_analytic_distribution = true
)
SELECT
CASE
WHEN row_count = 1 THEN tag.name
ELSE CONCAT(tag.name, ' (', tag.id, ')')
END AS name,
tag.id,
tag.active,
tag.company_id,
distribution.account_id,
distribution.percentage
FROM
counted_tags tag
INNER JOIN
account_analytic_distribution distribution ON tag.id = distribution.tag_id;
"""
env.cr.execute(sql)
distribution_by_tag = {}
for data in env.cr.dictfetchall():
tag_key = (data["id"], data["name"], data["active"], data["company_id"])
distribution_by_tag.setdefault(tag_key, []).append(data)
distribution_map = {}
all_tag_ids = []
for tag_key, distributions in distribution_by_tag.items():
tag_id, tag_name, tag_active, company_id = tag_key
distribution_manual_val = {
"name": tag_name,
"active": tag_active,
"company_id": company_id or env.company.id,
"analytic_distribution": {
distribution["account_id"]: distribution["percentage"]
for distribution in distributions
},
}
new_distribution = DistributionManual.create(distribution_manual_val)
distribution_map[tag_id] = new_distribution
all_tag_ids.append(tag_id)
# Update references in all models related to account_analytic_tag(m2m)
for table_m2m, info in RELATION_M2M_INFO.items():
column1 = info["column1"]
table2 = info["table2"]
column2 = info["column2"]
res_model_name = table2.replace("_", ".")
if (
res_model_name in env
and "manual_distribution_id" in env[res_model_name]._fields
and all_tag_ids
):
sql = f"""
SELECT {column1}, {column2}
FROM {table_m2m}
WHERE {column1} IN %s
"""
env.cr.execute(sql, (tuple(all_tag_ids),))
for tag_id, res_id in env.cr.fetchall():
env.cr.execute(
f"""
UPDATE {table2}
SET manual_distribution_id = %s
WHERE id = %s
""",
(distribution_map[tag_id].id, res_id),
)
# Define the value of manual_distribution_id in the line items
env.cr.execute(
"""
UPDATE account_analytic_line AS aal
SET manual_distribution_id = aml.manual_distribution_id
FROM account_move_line AS aml
WHERE aal.move_line_id = aml.id
AND aml.manual_distribution_id IS NOT NULL
AND aal.manual_distribution_id IS NULL
""",
)