Scope CEO portfolio by active companies

This commit is contained in:
metatroncubeswdev 2026-08-30 11:25:42 -04:00
parent b17a5aaf7a
commit 462e91f00c

View File

@ -187,6 +187,7 @@ class McsOperatingDashboard(models.Model):
month_end = month_start + relativedelta(months=1, days=-1)
week_start = today - relativedelta(days=today.weekday())
week_end = week_start + relativedelta(days=6)
company_ids = self._dashboard_company_ids()
Lead = self.env["crm.lead"]
Project = self.env["project.project"]
@ -197,7 +198,10 @@ class McsOperatingDashboard(models.Model):
Partner = self.env["res.partner"]
CeoAction = self.env["mcs.ceo.action"]
active_projects = Project.search([("active", "=", True)])
active_projects = Project.search(
[("active", "=", True)]
+ self._company_domain(Project, company_ids, include_shared=True)
)
client_projects = active_projects.filtered(
lambda project: project.mcs_delivery_type
not in ("internal_product", "internal_r_and_d", "sales_initiative")
@ -207,7 +211,12 @@ class McsOperatingDashboard(models.Model):
in ("internal_product", "internal_r_and_d")
)
open_pipeline = Lead.search(
[("type", "=", "opportunity"), ("active", "=", True), ("probability", "<", 100)]
[
("type", "=", "opportunity"),
("active", "=", True),
("probability", "<", 100),
]
+ self._company_domain(Lead, company_ids, include_shared=True)
)
won_month = Lead.search(
[
@ -217,6 +226,7 @@ class McsOperatingDashboard(models.Model):
("date_closed", ">=", month_start),
("date_closed", "<=", month_end),
]
+ self._company_domain(Lead, company_ids, include_shared=True)
)
invoices_month = Invoice.search(
[
@ -225,6 +235,7 @@ class McsOperatingDashboard(models.Model):
("invoice_date", ">=", month_start),
("invoice_date", "<=", month_end),
]
+ self._company_domain(Invoice, company_ids, include_shared=False)
)
receivables = Invoice.search(
[
@ -232,18 +243,31 @@ class McsOperatingDashboard(models.Model):
("state", "=", "posted"),
("payment_state", "not in", ["paid", "in_payment", "reversed"]),
]
+ self._company_domain(Invoice, company_ids, include_shared=False)
)
posted_invoices = Invoice.search(
[("move_type", "=", "out_invoice"), ("state", "=", "posted")]
+ self._company_domain(Invoice, company_ids, include_shared=False)
)
overdue_receivables = receivables.filtered(
lambda invoice: invoice.invoice_date_due and invoice.invoice_date_due < today
)
timesheets_month = Timesheet.search(
[("date", ">=", month_start), ("date", "<=", month_end)]
+ self._company_domain(Timesheet, company_ids, include_shared=True)
)
timesheets_week = Timesheet.search(
[("date", ">=", week_start), ("date", "<=", week_end)]
+ self._company_domain(Timesheet, company_ids, include_shared=True)
)
active_employees = Employee.search(
[("active", "=", True)]
+ self._company_domain(Employee, company_ids, include_shared=True)
)
active_tasks = Task.search(
[("active", "=", True)]
+ self._company_domain(Task, company_ids, include_shared=True)
)
active_employees = Employee.search([("active", "=", True)])
active_tasks = Task.search([("active", "=", True)])
monthly_target = sum(active_projects.mapped("mcs_monthly_revenue_target"))
contracted_revenue = sum(client_projects.mapped("mcs_contracted_revenue"))
@ -293,6 +317,8 @@ class McsOperatingDashboard(models.Model):
"month_end": fields.Date.to_string(month_end),
"week_start": fields.Date.to_string(week_start),
"week_end": fields.Date.to_string(week_end),
"company_ids": company_ids,
"companies": self.env["res.company"].browse(company_ids).mapped("name"),
},
"company_pulse": {
"revenue_coverage": self._format_percent(revenue_coverage),
@ -336,19 +362,32 @@ class McsOperatingDashboard(models.Model):
"pipeline_coverage_status": self._coverage_status(pipeline_coverage),
"funnel": self._crm_funnel_data(open_pipeline),
},
"portfolio": self._portfolio_rows(Partner, client_projects),
"portfolio": self._portfolio_rows(Partner, client_projects, posted_invoices),
"project_health": self._project_health_distribution(active_projects),
"capacity": self._capacity_rows(active_employees, active_tasks, timesheets_week),
"time_distribution": self._time_distribution(timesheets_week),
"allocation_guardrail": self._allocation_guardrail(timesheets_week),
"ceo_actions": self._ceo_action_rows(CeoAction),
"internal_bets": self._internal_bet_rows(internal_projects, timesheets_month),
"actions": self._dashboard_actions(today, month_start, month_end, week_start, week_end),
"actions": self._dashboard_actions(
today, month_start, month_end, week_start, week_end, company_ids
),
}
def _format_percent(self, value):
return round(value or 0, 1)
def _dashboard_company_ids(self):
company_ids = self.env.context.get("allowed_company_ids") or self.env.companies.ids
return company_ids or [self.env.company.id]
def _company_domain(self, Model, company_ids, include_shared=True):
if "company_id" not in Model._fields:
return []
if include_shared:
return ["|", ("company_id", "=", False), ("company_id", "in", company_ids)]
return [("company_id", "in", company_ids)]
def _monthly_operating_cost(self):
try:
Contract = self.env["hr.contract"]
@ -356,6 +395,9 @@ class McsOperatingDashboard(models.Model):
return 0
contracts = Contract.sudo().search(
[("state", "=", "open"), ("employee_id.active", "=", True)]
+ self._company_domain(
Contract, self._dashboard_company_ids(), include_shared=True
)
)
return sum(contracts.mapped("wage"))
@ -435,32 +477,53 @@ class McsOperatingDashboard(models.Model):
)
return rows
def _portfolio_rows(self, Partner, client_projects):
partners = Partner.search([("mcs_is_client_account", "=", True)])
def _portfolio_rows(self, Partner, client_projects, posted_invoices):
partners = (
Partner.search([("mcs_is_client_account", "=", True)])
| client_projects.mapped("partner_id")
| posted_invoices.mapped("commercial_partner_id")
)
rows = []
for partner in partners:
projects = client_projects.filtered(lambda project: project.partner_id == partner)
invoices = posted_invoices.filtered(
lambda invoice: invoice.commercial_partner_id == partner.commercial_partner_id
)
unpaid_invoices = invoices.filtered(
lambda invoice: invoice.payment_state
not in ("paid", "in_payment", "reversed")
)
overdue_invoices = unpaid_invoices.filtered(
lambda invoice: invoice.invoice_date_due
and invoice.invoice_date_due < fields.Date.context_today(self)
)
if partner.parent_id and not projects:
continue
if (
not projects
and not partner.mcs_total_invoiced
and not partner.mcs_total_outstanding
and not invoices
):
continue
currencies = invoices.mapped("currency_id") or partner.mcs_currency_id
currency_name = (
currencies[0].name
if len(currencies) == 1
else "Mixed"
)
invoice_dates = [date for date in invoices.mapped("invoice_date") if date]
rows.append(
{
"id": partner.id,
"name": partner.display_name,
"currency": partner.mcs_currency_id.name or "",
"currency": currency_name,
"health": partner.mcs_account_health,
"active_workstreams": len(projects),
"revenue": sum(projects.mapped("mcs_monthly_revenue_target")),
"total_invoiced": partner.mcs_total_invoiced,
"outstanding": partner.mcs_total_outstanding,
"overdue": partner.mcs_total_overdue,
"last_invoice_date": fields.Date.to_string(partner.mcs_last_invoice_date)
if partner.mcs_last_invoice_date
"total_invoiced": sum(invoices.mapped("amount_total_signed")),
"outstanding": sum(unpaid_invoices.mapped("amount_residual_signed")),
"overdue": sum(overdue_invoices.mapped("amount_residual_signed")),
"last_invoice_date": fields.Date.to_string(max(invoice_dates))
if invoice_dates
else "",
"hours": sum(projects.mapped("mcs_actual_hours")),
"next_milestone": next(
@ -626,7 +689,11 @@ class McsOperatingDashboard(models.Model):
)
return rows
def _dashboard_actions(self, today, month_start, month_end, week_start, week_end):
def _dashboard_actions(self, today, month_start, month_end, week_start, week_end, company_ids):
Project = self.env["project.project"]
Lead = self.env["crm.lead"]
Invoice = self.env["account.move"]
Timesheet = self.env["account.analytic.line"]
return {
"monthly_revenue_projects": {
"type": "ir.actions.act_window",
@ -634,7 +701,8 @@ class McsOperatingDashboard(models.Model):
"res_model": "project.project",
"view_mode": "tree,form,kanban",
"views": self._action_views("tree", "form", "kanban"),
"domain": [("active", "=", True), ("mcs_monthly_revenue_target", ">", 0)],
"domain": [("active", "=", True), ("mcs_monthly_revenue_target", ">", 0)]
+ self._company_domain(Project, company_ids, include_shared=True),
},
"contracted_projects": {
"type": "ir.actions.act_window",
@ -642,7 +710,8 @@ class McsOperatingDashboard(models.Model):
"res_model": "project.project",
"view_mode": "tree,form,kanban",
"views": self._action_views("tree", "form", "kanban"),
"domain": [("active", "=", True), ("mcs_contracted_revenue", ">", 0)],
"domain": [("active", "=", True), ("mcs_contracted_revenue", ">", 0)]
+ self._company_domain(Project, company_ids, include_shared=True),
},
"pipeline": {
"type": "ir.actions.act_window",
@ -650,7 +719,12 @@ class McsOperatingDashboard(models.Model):
"res_model": "crm.lead",
"view_mode": "kanban,tree,form,pivot,graph",
"views": self._action_views("kanban", "tree", "form", "pivot", "graph"),
"domain": [("type", "=", "opportunity"), ("active", "=", True), ("probability", "<", 100)],
"domain": [
("type", "=", "opportunity"),
("active", "=", True),
("probability", "<", 100),
]
+ self._company_domain(Lead, company_ids, include_shared=True),
},
"overdue_receivables": {
"type": "ir.actions.act_window",
@ -663,7 +737,8 @@ class McsOperatingDashboard(models.Model):
("state", "=", "posted"),
("payment_state", "not in", ["paid", "in_payment", "reversed"]),
("invoice_date_due", "<", fields.Date.to_string(today)),
],
]
+ self._company_domain(Invoice, company_ids, include_shared=False),
},
"capacity": {
"type": "ir.actions.act_window",
@ -674,7 +749,8 @@ class McsOperatingDashboard(models.Model):
"domain": [
("date", ">=", fields.Date.to_string(week_start)),
("date", "<=", fields.Date.to_string(week_end)),
],
]
+ self._company_domain(Timesheet, company_ids, include_shared=True),
"context": {"group_by": "employee_id"},
},
"projects_at_risk": {
@ -683,7 +759,11 @@ class McsOperatingDashboard(models.Model):
"res_model": "project.project",
"view_mode": "tree,form,kanban",
"views": self._action_views("tree", "form", "kanban"),
"domain": [("active", "=", True), ("mcs_portfolio_health", "in", ["at_risk", "blocked"])],
"domain": [
("active", "=", True),
("mcs_portfolio_health", "in", ["at_risk", "blocked"]),
]
+ self._company_domain(Project, company_ids, include_shared=True),
},
"ceo_actions": {
"type": "ir.actions.act_window",
@ -699,7 +779,8 @@ class McsOperatingDashboard(models.Model):
"res_model": "project.project",
"view_mode": "tree,form,kanban",
"views": self._action_views("tree", "form", "kanban"),
"domain": [("mcs_delivery_type", "in", ["internal_product", "internal_r_and_d"])],
"domain": [("mcs_delivery_type", "in", ["internal_product", "internal_r_and_d"])]
+ self._company_domain(Project, company_ids, include_shared=True),
},
}