"""Report run handlers.""" from decimal import Decimal from http import HTTPStatus from typing import Optional from flask.typing import ResponseReturnValue from flask_pydantic import validate from pydantic import Field, model_validator from collaborator.api import app from collaborator.constants import error from collaborator.constants.header import ABACUS_PROFILE from collaborator.logic import report_run from collaborator.schemas import BaseSchema, PaginatedRequestMixin, SortableRequestMixin from collaborator.utils import api as api_utils from collaborator.utils import handlers as handler_utils from collaborator.utils import handlers as utils from collaborator.utils.error import OwsError from collaborator.utils.helpers import check_vendors_authorization class ReportRunItem(BaseSchema): """Report run item for dataloader.""" report_run_id: int class ReportRunDataloaderBody(BaseSchema): """Request body model for report run dataloader.""" report_runs: list[ReportRunItem] @app.route("/report-runs/dataloader", methods=["POST"]) @validate() @handler_utils.fetch_authorized_resources def get_report_runs_dataloader( authorized_resources, user, body: ReportRunDataloaderBody ) -> ResponseReturnValue: """Get report runs (dataloader). Args: params (dict): Body parameters authorized_resources: List of resources to which the requestor has access user (User): User who made the request Returns: flask.Response """ report_run_ids = [run.report_run_id for run in body.report_runs] report_runs = report_run.report_runs_dataloader(report_run_ids) return [ { "data": ( { "report_run_uuid": run.uuid, "report_run_name": run.name, "period_ids": run.period_ids, "period_name": run.period_name, "requested_datetime": run.requested_datetime.isoformat(), "trigger_type": run.trigger_type, } if run else None ) } for run in report_runs ] class TriggerAutoReportRunBody(BaseSchema): """Request body model for triggering automatic report run creation.""" statement_period_id: int = Field(gt=0) @app.route("/report-runs/auto-report-run", methods=["POST"]) @validate() @utils.fetch_authorized_resources def trigger_auto_report_run( authorized_resources, user, body: TriggerAutoReportRunBody, ) -> ResponseReturnValue: """Trigger automatic report run creation.""" result = report_run.trigger_auto_report_run(body.statement_period_id, user) return result class ReportRunParticipationsQuery( BaseSchema, PaginatedRequestMixin, SortableRequestMixin ): """Request model for report run participations.""" vendor_id: Optional[int] = None report_run_id: Optional[int] = None @model_validator(mode="after") def validate_at_least_one_id(self): """Validate that at least one of vendor_id or report_run_id is provided.""" if not self.vendor_id and not self.report_run_id: raise ValueError( "Either 'vendor_id' or 'report_run_id' must be provided.", ) return self @app.route("/report-run-participations", methods=["GET"]) @validate() @utils.fetch_authorized_resources @utils.fetch_profile_type def get_report_run_participations( authorized_resources, profile_type, user, query: ReportRunParticipationsQuery, ) -> ResponseReturnValue: """Get report run participations. Args: authorized_resources (List[Dict]): Resources to which the requestor has access user: Unused Returns: flask.Response: Paginated report run participations response """ vendor_id = query.vendor_id if not vendor_id: if profile_type != ABACUS_PROFILE: raise OwsError( code=error.ERROR_CODE_UNEXPECTED_PROFILE_TYPE, message=error.ERROR_MESSAGE_UNEXPECTED_PROFILE_TYPE, status=HTTPStatus.FORBIDDEN, ) else: check_vendors_authorization(authorized_resources, [vendor_id]) report_runs, total_count = report_run.get_report_run_participations( account_id=vendor_id, **query.model_dump(exclude={"vendor_id"}), ) return api_utils.create_paginated_response( [ { "report_run_id": run.report_run_id, "vendor_id": run.vendor_id, "currency": run.currency, "amount": ( float(run.amount) if isinstance(run.amount, Decimal) else None ), "reports_total_count": run.total_count, "reports_status_error_count": run.error_count, "reports_status_requested_count": run.requested_count, "reports_status_generated_count": run.generated_count, "reports_with_transaction_count": run.transaction_count, } for run in report_runs ], total_count, ).message