"""Contract search logic.""" from urllib.parse import unquote from marshmallow import ValidationError from owsresponse import response from abacus_contract.constants.constants import CONTRACT_LIFECYCLE_STATUSES from abacus_contract.constants.error import ERROR_INVALID_CONTRACT_STATUS from abacus_contract.models.contract import Contract from abacus_contract.schemas.contract import ContractDetailSchema from abacus_contract.utils.format_error import validation_error contract_detail_schema = ContractDetailSchema() contract_model = Contract() def get_contracts(params): """Search contracts by params.""" try: contracts_by_params, total_count = _execute_contract_query(params) contract_list = contract_detail_schema.dump(contracts_by_params, many=True) except Exception as e: return validation_error(str(e)) return response.Response({'items': contract_list, 'total_count': total_count}) def _execute_contract_query(params): """Search for contracts.""" contract_type = _get_search_term_from_params(params, key='contract_type') is_excluded_from_accounting_run = _get_search_term_from_params( params, key='is_excluded_from_accounting_run' ) contract_statuses = _get_search_term_from_params(params, key='contract_statuses') run_controller_ids = _get_search_term_from_params(params, key='run_controller_ids') if (contract_type): ContractDetailSchema().load({'contract_type': contract_type}, partial=True) if (is_excluded_from_accounting_run is not None and is_excluded_from_accounting_run != ''): # noqa:E501 ContractDetailSchema().load({ 'is_excluded_from_accounting_run': is_excluded_from_accounting_run }, partial=True) if isinstance(is_excluded_from_accounting_run, str): is_excluded_from_accounting_run = 1 \ if is_excluded_from_accounting_run.strip().lower() == 'true' \ or is_excluded_from_accounting_run.strip() == '1' else 0 if (contract_statuses): _validate_contract_statuses(contract_statuses) query_config = { 'contract_name': _get_search_term_from_params(params), 'search_term': _get_search_term_from_params(params, key='search_term'), 'account_ids': _get_account_ids_from_params(params), 'contract_type': contract_type, 'is_excluded_from_accounting_run': is_excluded_from_accounting_run, 'contract_statuses': contract_statuses, 'run_controller_ids': run_controller_ids } query_config = {k: v for k, v in query_config.items() if v not in [None, '']} query = Contract.get_filtered_query(**query_config) result = _execute_paged_query(query, params) return result, query.count() def _get_account_ids_from_params(params): """Get the correct account ids from the params.""" account_ids = params.get('account_ids') if account_ids: return [int(account_id) for account_id in account_ids.split(',')] return account_ids def _get_search_term_from_params(params, key='contract_name'): """Get the correct search term from the params.""" return unquote(params.get(key, '')) def _execute_paged_query(query, params): """Get the offset and limit from the params and execute the paged query.""" limit = max(int(params.get('limit', 100)), 1) offset = max(int(params.get('offset', 0)), 0) return query \ .order_by(contract_model.default_order()) \ .offset(offset) \ .limit(limit) \ .all() def _validate_contract_statuses(contract_statuses): """Validate contract status.""" contract_lifecycle_statuses = list(CONTRACT_LIFECYCLE_STATUSES) contract_lifecycle_statuses.remove('inactive') isValid = all( item in CONTRACT_LIFECYCLE_STATUSES for item in contract_statuses.split(',') ) if not isValid: raise ValidationError( ERROR_INVALID_CONTRACT_STATUS.format( contract_lifecycle_status=', '.join(contract_lifecycle_statuses) ) ) return True