"""Logic for statement periods.""" from typing import Type from marshmallow import ValidationError from owsresponse import response from royalties import models from royalties.connectors.ows_collaborators import close_bulk_dp_collaborator_statements from royalties.constants import constants, error from royalties.schemas.exchange_rate import ExchangeRateSchema from royalties.schemas.statement_period import StatementPeriodDetailSchema from royalties.utils.format_error import validation_error from royalties.utils.response import prepare_dataload_response def get_recent_statement_periods(): """Logic to get current and last closed periods.""" recent_periods = models.StatementPeriod.get_recent_periods() message = StatementPeriodDetailSchema(many=True).dump(recent_periods) return response.Response(message=message, status=200) def get_statement_period_exchange_rates( statement_period_id: int, output_format: str ) -> Type[response.Response]: """Get exchange rates by statement period in json format. Args: statement_period_id(int): ID of statement period output_format: Response format. preferred format is json Response: A List of exchange rates. """ statement_period = models.StatementPeriod.get_by_id_or_error(statement_period_id) if output_format == 'json': exchange_rates = statement_period.stream_all_fx_rates() return response.Response( ExchangeRateSchema(exclude=['statement_period_id'], many=True).dump( exchange_rates ) ) else: return response.create_error_response( code=error.ERROR_CODE_BAD_REQUEST, message=error.ERROR_INVALID_OUTPUT_FORMAT ) def get_upcoming_statement_periods(): """Logic to get open upcoming periods.""" upcoming_periods = models.StatementPeriod.get_upcoming_periods() message = StatementPeriodDetailSchema(many=True).dump(upcoming_periods) return response.Response(message=message, status=200) def get_current_statement_period(): """Logic to get current statement period.""" current_period = models.StatementPeriod.get_current_statement_period() message = StatementPeriodDetailSchema(many=False).dump(current_period) return response.Response(message=message, status=200) def close_statement_period(statement_period_id): """Logic to update current period to closed status.""" try: current_statement_period, next_statement_period = ( _validate_statement_period_can_close(statement_period_id) ) close_bulk_dp_collaborator_statements( current_statement_period.statement_period_name, next_statement_period.statement_period_id, ) current_statement_period.close_period() next_statement_period.update_attributes( statement_period_status=constants.STATEMENT_PERIOD_STATUSES.CURRENT ) models.StatementPeriod.commit_changes() message = StatementPeriodDetailSchema().dump(current_statement_period) except Exception as e: status_code = ( e.kwargs.get('status_code', 400) if isinstance(e, ValidationError) else 400 ) return validation_error(str(e), status_code=status_code) return response.Response(message=message, status=201) def _validate_statement_period_state(statement_period_id): """Validate statement period.""" statement_period = models.StatementPeriod.get_by_id_or_error(statement_period_id) if ( statement_period.statement_period_status != constants.STATEMENT_PERIOD_STATUSES.CURRENT ): raise Exception(error.ERROR_NO_CURRENT_STATEMENT_PERIOD) def _validate_statement_period_can_close(statement_period_id): """Validate if the statement period can be closed or not.""" current_statement_period = models.StatementPeriod.get_by_id_or_error( statement_period_id ) if ( current_statement_period.statement_period_status != constants.STATEMENT_PERIOD_STATUSES.CURRENT ): raise Exception(error.ERROR_STATEMENT_PERIOD_CURRENT_STATUS) if current_statement_period.has_active_accounting_periods(): raise Exception(error.ERROR_STATEMENT_PERIOD_HAS_ACC_PERIODS) if not current_statement_period.all_balances_closed: raise Exception(error.ERROR_BALANCES_ARE_NOT_CLOSED) payment_entities = current_statement_period.statement_period_payment_entities is_visible_customer_true = all( payment_entity.is_visible_to_customer for payment_entity in payment_entities ) if not is_visible_customer_true: raise Exception(error.ERROR_STATEMENT_PERIOD_PAYMENT_ENTITY) next_period = models.StatementPeriod.get_by_id(statement_period_id + 1) if not next_period: raise Exception( error.ERROR_NEXT_STATEMENT_PERIOD_NOT_FOUND.format( statement_period_id=statement_period_id ) ) return current_statement_period, next_period def get_statement_periods_by_ids(statement_period_ids: list) -> response.Response: """Get statement periods by a list of IDs. Args: statement_period_ids(list): a list of statement period IDs Returns: a list of statement periods. """ statement_periods = models.StatementPeriod.get_by_ids(statement_period_ids) statement_periods_list = StatementPeriodDetailSchema().dump( statement_periods, many=True ) message = prepare_dataload_response( statement_period_ids, statement_periods_list, 'statement_period_id' ) return response.Response(message=message, status=200) def get_statement_periods_by_years(statement_years: list) -> response.Response: """Get statement periods by a list of statement_years. Args: statement_years(list): a list of statement years Returns: a list of statement periods. """ statement_periods = models.StatementPeriod.get_by_statement_years(statement_years) message = StatementPeriodDetailSchema(many=True).dump(statement_periods) return response.Response(message=message, status=200)