diff --git a/fusion_claims/models/dashboard.py b/fusion_claims/models/dashboard.py index dabf506c..84f41c2c 100644 --- a/fusion_claims/models/dashboard.py +++ b/fusion_claims/models/dashboard.py @@ -149,3 +149,61 @@ class FusionClaimsDashboard(models.TransientModel): ar_invoices = Move.search(ar_domain) rec.kpi_ar_count = len(ar_invoices) rec.kpi_ar_amount = sum(ar_invoices.mapped('amount_total')) + + # ========================================================================= + # Activities (left column) + # ========================================================================= + my_activities_count = fields.Integer(compute='_compute_activities') + my_activities_html = fields.Html(compute='_compute_activities', sanitize=False) + + def _compute_activities(self): + Activity = self.env['mail.activity'].sudo() + domain = [ + ('user_id', '=', self.env.user.id), + ('res_model', 'in', ['sale.order', 'account.move', 'fusion.technician.task']), + ] + for rec in self: + activities = Activity.search(domain, order='date_deadline asc', limit=10) + rec.my_activities_count = Activity.search_count(domain) + if not activities: + rec.my_activities_html = ( + '

No activities assigned.

' + ) + continue + from datetime import date + today = date.today() + rows = [] + for act in activities: + overdue = act.date_deadline and act.date_deadline < today + row_class = 'o_fc_activity_row o_fc_activity_overdue' if overdue else 'o_fc_activity_row' + deadline_text = act.date_deadline.strftime('%b %d') if act.date_deadline else '—' + url = f'/odoo/{act.res_model.replace(".", "_")}/{act.res_id}' + rows.append( + f'
' + f'{act.summary or act.activity_type_id.name or "Activity"}' + f'{deadline_text}' + f'
' + ) + rec.my_activities_html = '\n'.join(rows) + + # ========================================================================= + # Bottlenecks (left column) + # ========================================================================= + bottleneck_no_pod_count = fields.Integer(compute='_compute_secondary_counts') + bottleneck_no_response_count = fields.Integer(compute='_compute_secondary_counts') + + def _compute_secondary_counts(self): + from datetime import date, timedelta + SO = self.env['sale.order'].sudo() + cutoff_14d_ago = date.today() - timedelta(days=14) + for rec in self: + base = rec._role_filter_domain() + + rec.bottleneck_no_pod_count = SO.search_count(base + [ + ('x_fc_adp_application_status', 'in', ['approved', 'approved_deduction']), + ('x_fc_proof_of_delivery', '=', False), + ]) + rec.bottleneck_no_response_count = SO.search_count(base + [ + ('x_fc_adp_application_status', 'in', ['submitted', 'resubmitted']), + ('x_fc_claim_submission_date', '<', cutoff_14d_ago), + ]) diff --git a/fusion_claims/tests/test_dashboard.py b/fusion_claims/tests/test_dashboard.py index 278d63bf..589687e9 100644 --- a/fusion_claims/tests/test_dashboard.py +++ b/fusion_claims/tests/test_dashboard.py @@ -160,3 +160,51 @@ class TestFusionClaimsDashboard(TransactionCase): dashboard_rep = self.Dashboard.with_user(self.salesrep).create({}) self.assertEqual(dashboard_rep.kpi_ready_count, 0, "Salesrep must not see manager's invoice") + + # ------------------------------------------------------------------------- + # Task 4 — Activities + bottlenecks + # ------------------------------------------------------------------------- + def test_my_activities_count_zero_when_none(self): + dashboard = self.Dashboard.with_user(self.manager).create({}) + self.assertEqual(dashboard.my_activities_count, 0) + + def test_my_activities_count_picks_up_user_activity(self): + so = self.env['sale.order'].with_context(skip_status_validation=True).create({ + 'partner_id': self.partner.id, + 'user_id': self.manager.id, + 'x_fc_sale_type': 'adp', + }) + self.env['mail.activity'].create({ + 'res_model_id': self.env['ir.model']._get('sale.order').id, + 'res_id': so.id, + 'res_model': 'sale.order', + 'user_id': self.manager.id, + 'activity_type_id': self.env.ref('mail.mail_activity_data_todo').id, + 'summary': 'Test activity', + }) + dashboard = self.Dashboard.with_user(self.manager).create({}) + self.assertEqual(dashboard.my_activities_count, 1) + self.assertIn('Test activity', dashboard.my_activities_html or '') + + def test_bottleneck_no_pod_count(self): + self.env['sale.order'].with_context(skip_status_validation=True).create({ + 'partner_id': self.partner.id, + 'user_id': self.manager.id, + 'x_fc_sale_type': 'adp', + 'x_fc_adp_application_status': 'approved', + }) + dashboard = self.Dashboard.with_user(self.manager).create({}) + self.assertEqual(dashboard.bottleneck_no_pod_count, 1) + + def test_bottleneck_no_response_count(self): + from datetime import date, timedelta + old_date = date.today() - timedelta(days=20) + self.env['sale.order'].with_context(skip_status_validation=True).create({ + 'partner_id': self.partner.id, + 'user_id': self.manager.id, + 'x_fc_sale_type': 'adp', + 'x_fc_adp_application_status': 'submitted', + 'x_fc_claim_submission_date': old_date, + }) + dashboard = self.Dashboard.with_user(self.manager).create({}) + self.assertEqual(dashboard.bottleneck_no_response_count, 1)