"""Blueprint for statement period adjustment file API.""" from http import HTTPStatus from abacus_common_logic.views.create_view import CreateView from abacus_common_logic.views.item_view import ItemView from abacus_common_logic.views.list_view import ListView from common_apispec import doc, marshal_with, use_kwargs from flask import Blueprint, g, request from owsrequest import flask_request from owsresponse import response from owsresponse.adaptors.flask import flaskify from royalties.constants import error from royalties.constants.error import ERROR_CODE_AUTHORIZATION from royalties.logic import statement_period_adjustment_file as logic from royalties.models import StatementPeriodAdjustmentFile from royalties.schemas import ( AutoGenerationInProgressOrErrorSchema, StatementPeriodAdjustmentFileDetailSchema, StatementPeriodAdjustmentFilePostSchema, StatementPeriodAdjustmentFilePutSchema, ValidateAdjustmentsPostSchema, ValidateAdjustmentsResponseSchema, ) statement_period_adjustment_file_api = Blueprint( 'statement_period_adjustment_file_api', __name__ ) class StatementPeriodAdjustmentFileCreateView(CreateView): """Handles statement period adjustment file creation.""" post_schema = StatementPeriodAdjustmentFilePostSchema() def post(self, **kwargs): """Create statement period adjustment file.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) return super().post(**kwargs) def create_handler(self, **params): """Create statement period adjustment file.""" return logic.create_statement_period_adjustment_file(**params) class StatementPeriodAdjustmentFileItemView(ItemView): """View for finding an accounting period by ID.""" model_class = StatementPeriodAdjustmentFile object_detail_schema = StatementPeriodAdjustmentFileDetailSchema() put_schema = StatementPeriodAdjustmentFilePutSchema(partial=True) def get(self, object_id, **kwargs): """Get accounting period by id.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) return super().get(object_id, **kwargs) def put(self, object_id, **kwargs): """Update statement period adjustment file.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) return super().put(object_id, **kwargs) def update_handler(self, obj, **params): """Handle statement period adjustment file updates.""" return logic.update_statement_period_adjustment_file(obj, **params) def delete(self, object_id, **kwargs): """Delete object by id.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) obj = self.model_class.get_by_id_or_error(object_id, 404) return flaskify(logic.delete_statement_period_adjustment_file(obj)) class StatementPeriodAdjustmentFileListView(ListView): """Returns list of the statement period adjustment files.""" model_class = StatementPeriodAdjustmentFile list_entry_schema = StatementPeriodAdjustmentFileDetailSchema() def get(self, statement_period_id): """Get response with a list of objects.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) self.statement_period_id = statement_period_id offset = max(request.args.get('offset', default=0, type=int), 0) limit = max(request.args.get('limit', default=100, type=int), 1) query = request.args.get('query') results = self.list_entry_schema.dump( self.get_page( offset=offset, limit=limit, query=query, custom_order=self.custom_order(), ), many=True, ) count = ( self.base_list_query().filter(*self.model_class.filter_for(query)).count() ) return flaskify(response.Response({'items': results, 'total_count': count})) def base_list_query(self): """Get customized query.""" return self.model_class.filter_deleted_records().filter_by( statement_period_id=self.statement_period_id ) statement_period_adjustment_file_api.add_url_rule( '/statement-period//adjustment-file', methods=['POST'], view_func=StatementPeriodAdjustmentFileCreateView.as_view( 'create_statement_period_adjustment_file' ), ) statement_period_adjustment_file_api.add_url_rule( '/statement-period//adjustment-file/', methods=['GET', 'PUT', 'DELETE'], view_func=StatementPeriodAdjustmentFileItemView.as_view( 'statement_period_adjustment_file' ), ) statement_period_adjustment_file_api.add_url_rule( '/statement-period-adjustment-file/', methods=['GET', 'PUT', 'DELETE'], view_func=StatementPeriodAdjustmentFileItemView.as_view( 'statement_period_adjustment_file_by_id' ), ) statement_period_adjustment_file_api.add_url_rule( '/statement-period//adjustment-files', methods=['GET'], view_func=StatementPeriodAdjustmentFileListView.as_view( 'list_statement_period_adjustment_files' ), ) @statement_period_adjustment_file_api.route( '/abacus-adjustments/download/template', methods=['GET'] ) def downloadAbacusAdjustmentsTemplate(): """Get pre-signed url for abacus adjustments file template.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) resp = logic.get_adjustments_template_xlsx() return flaskify(response.Response({'template_url': resp.message})) @statement_period_adjustment_file_api.route( '/statement-period-adjustment-file/by-source-file-key/', methods=['GET'], ) @doc( summary='Get adjustment file by source file upload key.', params={ 'source_file_key': { 'description': 'The source file key of the adjustment file.', }, }, ) @marshal_with( StatementPeriodAdjustmentFileDetailSchema(), code=HTTPStatus.OK, description=HTTPStatus.OK.phrase, ) @marshal_with( None, code=HTTPStatus.NOT_FOUND, description=HTTPStatus.NOT_FOUND.phrase, ) def get_statement_period_adjustment_file_by_file_upload_key(source_file_key: str): """Get adjustment file by source file upload key.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) return flaskify(logic.get_adjustment_file_by_source_file_key(source_file_key)) @statement_period_adjustment_file_api.route( '/statement-period-adjustment-file//download/error', methods=['GET'], ) def downloadAbacusAdjustmentFileInvalidReport(adjustment_file_id: int): """Get pre-signed url for adjustment file report.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) resp = logic.get_adjustment_file_invalid_report(adjustment_file_id) if resp is None: return flaskify( ( response.create_error_response( code='error', status=400, message=error.ERROR_STATEMENT_PERIOD_INVALID_REPORT_NOT_FOUND.format( statement_period_adjustment_file_id=adjustment_file_id ), ) ) ) return flaskify(response.Response({'invalid_report_url': resp.message})) @statement_period_adjustment_file_api.route( '/statement-period-adjustment-file//download/report', methods=['GET'], ) def downloadAbacusAdjustmentFileValidReport(adjustment_file_id: int): """Get pre-signed url for adjustment file report.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) resp = logic.get_adjustment_file_valid_report(adjustment_file_id) if resp is None: return flaskify( ( response.create_error_response( code='error', status=400, message=error.ERROR_STATEMENT_PERIOD_VALID_REPORT_NOT_FOUND.format( statement_period_adjustment_file_id=adjustment_file_id ), ) ) ) return flaskify(response.Response({'valid_report_url': resp.message})) @statement_period_adjustment_file_api.route( '/statement-period-adjustment-files', methods=['GET'] ) def get_statement_period_adjustment_files(): """Get a list of statement period adjustment files.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) return flaskify(logic.get_statement_period_adjustment_files(request.args)) @statement_period_adjustment_file_api.route( '/statement-period-adjustment-file/users/', methods=['GET'] ) def get_statement_period_adjustment_file_users(user_action: str): """Get a list of statement period adjustment file users.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) return flaskify(logic.get_statement_period_adjustment_file_users(user_action)) @statement_period_adjustment_file_api.route( '/statement-period-adjustment-file/validate-adjustments', methods=['POST'] ) @doc( summary='Validate a list of manual adjustments', ) @marshal_with( ValidateAdjustmentsResponseSchema(), code=HTTPStatus.OK, description=HTTPStatus.OK.phrase, ) @marshal_with( None, code=HTTPStatus.UNAUTHORIZED, description=HTTPStatus.UNAUTHORIZED.phrase, ) @use_kwargs(ValidateAdjustmentsPostSchema, location='json', required=True, apply=True) def validate_adjustments(**kwargs): """Validate a list of manual adjustments.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) adjustments = kwargs['adjustments'] statement_period_id = kwargs['statement_period_id'] return flaskify(logic.validate_adjustments(adjustments, statement_period_id)) @statement_period_adjustment_file_api.route( '/statement-period//adjustments/auto-generation/progress', methods=['GET'], ) @doc( summary='Get the auto-generated adjustment files that are currently being processed or have encountered an error', params={ 'statement_period_id': { 'description': 'ID of the statement_period', }, }, ) @marshal_with( AutoGenerationInProgressOrErrorSchema, code=HTTPStatus.OK, description='Returns auto generated file record which is in progress', ) @marshal_with( None, code=HTTPStatus.UNAUTHORIZED, description=HTTPStatus.UNAUTHORIZED.phrase, ) @marshal_with( None, code=HTTPStatus.NOT_FOUND, description='Statement period not found', ) @marshal_with( None, code=HTTPStatus.BAD_REQUEST, description='Selected statement period status must be current', ) @marshal_with( None, code=HTTPStatus.INTERNAL_SERVER_ERROR, description='Internal server error', ) def get_in_progress_auto_generated_adjustments(statement_period_id: int): """Get the auto-generated adjustment files that are currently being processed or have encountered an error. Args: statement_period_id (int): id of the statement period Returns: in progress/error adjustment file """ access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code='authorization_error', message='Unauthorized', status=401, ) ) identity_id = g.request_context.identity_id return flaskify( logic.get_in_progress_auto_generated_adjustments( statement_period_id, identity_id ) )