19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:30:07 +01:00
parent ba20ce7443
commit 768b70e05e
2357 changed files with 1057103 additions and 712486 deletions

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import date
@ -6,11 +5,11 @@ import calendar
from dateutil.relativedelta import relativedelta
from odoo import models, api, _
from odoo.osv import expression
from odoo.fields import Domain
from odoo.tools import date_utils
class AccountMove(models.Model):
class AccountAccount(models.Model):
_inherit = "account.account"
@api.model
@ -42,48 +41,59 @@ class AccountMove(models.Model):
start, _ = date_utils.get_fiscal_year(end, fiscal_day, fiscal_month)
return start, end
def _build_spreadsheet_formula_domain(self, formula_params):
codes = [code for code in formula_params["codes"] if code]
if not codes:
return expression.FALSE_DOMAIN
company_id = formula_params["company_id"] or self.env.company.id
def _build_spreadsheet_formula_domain(self, formula_params, default_accounts=False):
company_id = formula_params.get("company_id") or self.env.company.id
company = self.env["res.company"].browse(company_id)
start, end = self._get_date_period_boundaries(
formula_params["date_range"], company
)
balance_domain = [
start, end = self._get_date_period_boundaries(formula_params["date_range"], company)
balance_domain = Domain([
("account_id.include_initial_balance", "=", True),
("date", "<=", end),
]
pnl_domain = [
])
pnl_domain = Domain([
("account_id.include_initial_balance", "=", False),
("date", ">=", start),
("date", "<=", end),
]
# It is more optimized to (like) search for code directly in account.account than in account_move_line
code_domain = expression.OR(
[
("code", "=like", f"{code}%"),
]
for code in codes
)
account_ids = self.env["account.account"].with_company(company_id).search(code_domain).ids
code_domain = [("account_id", "in", account_ids)]
period_domain = expression.OR([balance_domain, pnl_domain])
domain = expression.AND([code_domain, period_domain, [("company_id", "=", company_id)]])
if formula_params["include_unposted"]:
domain = expression.AND(
[domain, [("move_id.state", "!=", "cancel")]]
])
period_domain = balance_domain | pnl_domain
# Determine account domain based on tags or codes
if 'account_tag_ids' in formula_params:
tag_ids = [int(tag_id) for tag_id in formula_params["account_tag_ids"]]
account_id_domain = Domain('account_id.tag_ids', 'in', tag_ids) if tag_ids else Domain.FALSE
elif 'codes' in formula_params:
codes = [code for code in formula_params.get("codes", []) if code]
default_domain = Domain.FALSE
if not codes:
if not default_accounts:
return default_domain
default_domain = Domain('account_type', 'in', ['liability_payable', 'asset_receivable'])
# It is more optimized to (like) search for code directly in account.account than in account_move_line
code_domain = Domain.OR(
Domain("code", "=like", f"{code}%")
for code in codes
)
account_domain = code_domain | default_domain
account_ids = self.env["account.account"].with_company(company_id).search(account_domain).ids
account_id_domain = [("account_id", "in", account_ids)]
else:
domain = expression.AND(
[domain, [("move_id.state", "=", "posted")]]
)
account_id_domain = Domain.FALSE
posted_domain = [("move_id.state", "!=", "cancel")] if formula_params.get("include_unposted") else [("move_id.state", "=", "posted")]
domain = Domain.AND([account_id_domain, period_domain, [("company_id", "=", company_id)], posted_domain])
partner_ids = [int(partner_id) for partner_id in formula_params.get('partner_ids', []) if partner_id]
if partner_ids:
domain &= Domain("partner_id", "in", partner_ids)
return domain
@api.readonly
@api.model
def spreadsheet_move_line_action(self, args):
domain = self._build_spreadsheet_formula_domain(args)
domain = self._build_spreadsheet_formula_domain(args, default_accounts=True)
return {
"type": "ir.actions.act_window",
"res_model": "account.move.line",
@ -91,45 +101,89 @@ class AccountMove(models.Model):
"views": [[False, "list"]],
"target": "current",
"domain": domain,
"name": _("Journal items for account prefix %s", ", ".join(args["codes"])),
"name": _("Cell Audit"),
}
@api.readonly
@api.model
def spreadsheet_fetch_debit_credit(self, args_list):
"""Fetch data for ODOO.CREDIT, ODOO.DEBIT and ODOO.BALANCE formulas
The input list looks like this:
[{
date_range: {
range_type: "year"
year: int
},
company_id: int
codes: str[]
include_unposted: bool
}]
The input list looks like this::
[{
date_range: {
range_type: "year"
year: int
},
company_id: int
codes: str[]
include_unposted: bool
}]
"""
results = []
for args in args_list:
company_id = args["company_id"] or self.env.company.id
domain = self._build_spreadsheet_formula_domain(args)
# remove this when _search always returns a Query object
if expression.is_false(self.env["account.move.line"], domain):
results.append({"credit": 0, "debit": 0})
continue
MoveLines = self.env["account.move.line"].with_company(company_id)
query = MoveLines._search(domain)
query.order = None
query_str, params = query.select(
"SUM(debit) AS debit", "SUM(credit) AS credit"
)
self.env.cr.execute(query_str, params)
line_values = self.env.cr.dictfetchone()
results.append(
{
"credit": line_values["credit"] or 0,
"debit": line_values["debit"] or 0,
}
)
[(debit, credit)] = MoveLines._read_group(domain, aggregates=['debit:sum', 'credit:sum'])
results.append({'debit': debit or 0, 'credit': credit or 0})
return results
@api.readonly
@api.model
def spreadsheet_fetch_residual_amount(self, args_list):
"""Fetch data for ODOO.RESUDUAL formulas
The input list looks like this::
[{
date_range: {
range_type: "year"
year: int
},
company_id: int
codes: str[]
include_unposted: bool
}]
"""
results = []
for args in args_list:
company_id = args["company_id"] or self.env.company.id
domain = self._build_spreadsheet_formula_domain(args, default_accounts=True)
MoveLines = self.env["account.move.line"].with_company(company_id)
[(amount_residual,)] = MoveLines._read_group(domain, aggregates=['amount_residual:sum'])
results.append({'amount_residual': amount_residual or 0})
return results
@api.model
def spreadsheet_fetch_partner_balance(self, args_list):
"""Fetch data for ODOO.PARTNER.BALANCE formulas
The input list looks like this::
[{
date_range: {
range_type: "year"
year: int
},
company_id: int
codes: str[]
include_unposted: bool
partner_ids: int[]
}]
"""
results = []
for args in args_list:
partner_ids = [partner_id for partner_id in args.get('partner_ids', []) if partner_id]
if not partner_ids:
results.append({'balance': 0})
continue
company_id = args["company_id"] or self.env.company.id
domain = self._build_spreadsheet_formula_domain(args, default_accounts=True)
MoveLines = self.env["account.move.line"].with_company(company_id)
[(balance,)] = MoveLines._read_group(domain, aggregates=['balance:sum'])
results.append({'balance': balance or 0})
return results
@ -137,11 +191,41 @@ class AccountMove(models.Model):
def get_account_group(self, account_types):
data = self._read_group(
[
*self._check_company_domain(self.env.company),
("account_type", "in", account_types),
("company_id", "=", self.env.company.id),
],
["code:array_agg"],
["account_type"],
['account_type'],
['code:array_agg'],
)
mapped = {group["account_type"]: group["code"] for group in data}
mapped = dict(data)
return [mapped.get(account_type, []) for account_type in account_types]
@api.model
def spreadsheet_fetch_balance_tag(self, args_list):
"""Fetch data for ODOO.BALANCE.TAG formulas
The input list looks like this::
[{
account_tag_ids: str[]
date_range: {
range_type: "year"
year: int
},
company_id: int
include_unposted: bool
}]
"""
results = []
for args in args_list:
account_tag_ids = [tag_id for tag_id in args.get('account_tag_ids', []) if tag_id]
if not account_tag_ids:
results.append({'balance': 0})
continue
company_id = args["company_id"] or self.env.company.id
domain = self._build_spreadsheet_formula_domain(args)
MoveLines = self.env["account.move.line"].with_company(company_id)
[(balance,)] = MoveLines._read_group(domain, aggregates=['balance:sum'])
results.append({'balance': balance or 0.0})
return results

View file

@ -6,6 +6,7 @@ from odoo.tools import date_utils
class ResCompany(models.Model):
_inherit = "res.company"
@api.readonly
@api.model
def get_fiscal_dates(self, payload):
companies = self.env["res.company"].browse(
@ -13,7 +14,7 @@ class ResCompany(models.Model):
)
existing_companies = companies.exists()
# prefetch both fields
existing_companies.read(["fiscalyear_last_day", "fiscalyear_last_month"])
existing_companies.fetch(["fiscalyear_last_day", "fiscalyear_last_month"])
results = []
for data, company in zip(payload, companies):