Coverage for functions \ flipdare \ task \ report_task_handler.py: 78%
77 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-05-08 12:22 +1000
« prev ^ index » next coverage.py v7.13.0, created at 2026-05-08 12:22 +1000
1#!/usr/bin/env python
2# Copyright (c) 2026 Flipdare Pty Ltd. All rights reserved.
3#
4# This file is part of Flipdare's proprietary software and contains
5# confidential and copyrighted material. Unauthorised copying,
6# modification, distribution, or use of this file is strictly
7# prohibited without prior written permission from Flipdare Pty Ltd.
8#
9# This software includes third-party components licensed under MIT,
10# BSD, and Apache 2.0 licences. See THIRD_PARTY_NOTICES for details.
11#
13from __future__ import annotations
15from typing import TYPE_CHECKING
16from collections.abc import Sequence
17from flipdare.app_log import LOG
18from flipdare.constants import IS_DEBUG
19from flipdare.mailer.admin.app_log_email import AppLogEmail
20from flipdare.generated.schema.email.body.admin.log_email_schema import LogEmailSchema
21from flipdare.generated.shared.backend.system_log_type import SystemLogType
22from flipdare.service._service_provider import ServiceProvider
23from flipdare.service.core.cron_processor import CronResultEntry
24from flipdare.task.report.stats_reporter import StatsReporter
25from flipdare.task.report.core.cron_table_report import CronTableReport
26from flipdare.task.report.dare_reporter import DareReporter
27from flipdare.task.report.flag_reporter import FlagReporter
28from flipdare.task.report.issue_reporter import IssueReporter
29from flipdare.task.report.log_reporter import LogReporter
30from flipdare.task.report.payment_issue_reporter import PaymentIssueReporter
31from flipdare.task.report.restriction_reporter import RestrictionReporter
32from flipdare.generated.shared.backend.app_job_type import AppJobType
33from flipdare.result.output_result import OutputResult
34from flipdare.job_types import CronWithResultType, ReportJobType
35from flipdare.util.time_util import TimeUtil
37if TYPE_CHECKING:
38 from flipdare.manager.db_manager import DbManager
39 from flipdare.manager.backend_manager import BackendManager
42__all__ = ["ReportTaskHandler"]
45class ReportTaskHandler(ServiceProvider):
46 # NOTE: we need access to everything, so we defy the standard
47 # NOTE: for a core admin class.
48 def __init__(
49 self,
50 db_manager: DbManager | None = None,
51 system_manager: BackendManager | None = None,
52 ) -> None:
53 super().__init__(
54 db_manager=db_manager,
55 backend_manager=system_manager,
56 )
58 def run_report(self, job_type: ReportJobType) -> OutputResult: # noqa: PLR0912
59 db = self.db_manager
60 sys = self.backend_manager
61 result: OutputResult
63 match job_type:
64 case AppJobType.REPORT_DARE_REVIEW_REQUIRED:
65 result = DareReporter(db, sys).review_required()
66 case AppJobType.REPORT_DARE_AUTO_RESTRICTED:
67 result = DareReporter(db, sys).auto_restricted()
68 case AppJobType.REPORT_ISSUE_WAITING_ADMIN:
69 result = IssueReporter(db, sys).issue_waiting_admin()
70 case AppJobType.REPORT_PAYMENT_ISSUE_WAITING_ADMIN:
71 result = PaymentIssueReporter(db, sys).issue_waiting_admin()
72 case AppJobType.REPORT_FLAG_UNACKNOWLEDGED:
73 result = FlagReporter(db, sys).unacknowledged()
74 case AppJobType.REPORT_FLAG_DISPUTED_WAITING_ADMIN:
75 result = FlagReporter(db, sys).waiting_disputed()
76 case AppJobType.REPORT_RESTRICT_AUTO_PERMANENT:
77 result = RestrictionReporter(db, sys).auto_permanent()
78 case AppJobType.REPORT_RESTRICT_AUTO_NOT_PERMANENT:
79 result = RestrictionReporter(db, sys).auto_not_permanent()
80 case AppJobType.REPORT_RESTRICT_INACTIVE:
81 result = RestrictionReporter(db, sys).inactive()
82 case AppJobType.REPORT_PAYMENT_CRITICAL_ISSUES:
83 result = LogReporter(db, sys).payment_critical_issues()
84 case AppJobType.REPORT_JOB_TYPE_STATS:
85 result = StatsReporter(db, sys).job_stats()
86 case AppJobType.REPORT_LOG_STATS:
87 result = StatsReporter(db, sys).log_stats()
88 case AppJobType.REPORT_ERROR_STATS:
89 result = StatsReporter(db, sys).error_stats()
90 case AppJobType.REPORT_PAYMENT_STATS:
91 result = StatsReporter(db, sys).payment_stats()
93 if result.is_error:
94 self._log_report_error(job_type, result)
96 return result
98 def run_cron_with_result(
99 self,
100 job_type: CronWithResultType,
101 processed: Sequence[CronResultEntry],
102 ) -> OutputResult:
103 report = CronTableReport(
104 job_type=job_type,
105 processed=processed,
106 app_logger=self.app_logger,
107 mailer=self.admin_mailer,
108 )
110 result = report.create_and_send()
111 if result.is_error:
112 self._log_report_error(job_type, result)
114 return result
116 def _log_report_error(self, job_type: AppJobType, result: OutputResult) -> None:
117 if result.is_ok:
118 if IS_DEBUG:
119 LOG().debug(
120 f"Report {job_type.value} completed successfully with message: {result.message}"
121 )
122 return
124 msg = (
125 f"Report {job_type.value} failed to generate or send email. Message: {result.message}"
126 )
127 LOG().error(msg)
129 log_schema: LogEmailSchema = {
130 "log_type": SystemLogType.ERROR,
131 "called_from": f"ReportTaskHandler.run_report for {job_type.value}",
132 "source": job_type.value,
133 "message": msg,
134 "occurred_at": TimeUtil.formatted_user(TimeUtil.get_current_utc_dt()),
135 "job_type": job_type,
136 }
138 log_email = AppLogEmail(data=log_schema)
139 self.admin_mailer.send(log_email)