diff --git a/mhr_api/src/mhr_api/models/db2/utils.py b/mhr_api/src/mhr_api/models/db2/utils.py index fad7f2c2a..5dbe6fb9b 100755 --- a/mhr_api/src/mhr_api/models/db2/utils.py +++ b/mhr_api/src/mhr_api/models/db2/utils.py @@ -17,7 +17,8 @@ from sqlalchemy.sql import text from mhr_api.exceptions import DatabaseException -from mhr_api.models import Db2Manuhome, Db2Document, utils as model_utils +from mhr_api.models import Db2Manuhome, Db2Document, utils as model_utils, registration_utils as reg_utils +from mhr_api.models.registration_utils import AccountRegistrationParams from mhr_api.models.type_tables import MhrDocumentType, MhrRegistrationTypes from mhr_api.models.db import db @@ -89,7 +90,7 @@ WHERE o2.manhomid = mh.manhomid AND og2.manhomid = mh.manhomid AND og2.owngrpid = o2.owngrpid - AND og2.status IN ('3', '4')) as owner_names, + AND og2.status IN ('3')) as owner_names, TRIM(d.affirmby), d.documtid as document_id, d.docuregi as doc_reg_number @@ -111,8 +112,66 @@ FROM manuhome mh, document d WHERE mh.mhregnum IN (?) AND mh.mhregnum = d.mhregnum -ORDER BY mh.updateda DESC, mh.updateti DESC, d.regidate DESC + ORDER BY mh.updateda DESC, mh.updateti DESC, d.regidate DESC """ +QUERY_ACCOUNT_REGISTRATIONS_SORT = """ +SELECT mh.mhregnum, mh.mhstatus, d.regidate, TRIM(d.name), TRIM(d.olbcfoli), TRIM(d.docutype), + (SELECT XMLSERIALIZE(XMLAGG ( XMLELEMENT ( NAME "owner", o2.ownrtype || TRIM(o2.ownrname))) AS CLOB) + FROM owner o2, owngroup og2 + WHERE o2.manhomid = mh.manhomid + AND og2.manhomid = mh.manhomid + AND og2.owngrpid = o2.owngrpid + AND og2.regdocid = d.documtid) as owner_names, + TRIM(d.affirmby), + d.documtid as document_id, + d.docuregi as doc_reg_number, + (SELECT TRIM(o2.ownrname) + FROM owner o2, owngroup og2 + WHERE o2.manhomid = mh.manhomid + AND og2.manhomid = mh.manhomid + AND og2.owngrpid = o2.owngrpid + AND og2.regdocid = d.documtid + FETCH FIRST 1 ROWS ONLY) as owner_name_sort + FROM manuhome mh, document d + WHERE mh.mhregnum IN (?) + AND mh.mhregnum = d.mhregnum +""" +REG_ORDER_BY_DATE = ' ORDER BY mh.updateda DESC, mh.updateti DESC, d.regidate DESC' +REG_ORDER_BY_MHR_NUMBER = ' ORDER BY mh.mhregnum' +REG_ORDER_BY_REG_TYPE = ' ORDER BY TRIM(d.docutype)' +REG_ORDER_BY_STATUS = ' ORDER BY mh.mhstatus' +REG_ORDER_BY_SUBMITTING_NAME = ' ORDER BY TRIM(d.name)' +REG_ORDER_BY_CLIENT_REF = ' ORDER BY TRIM(d.olbcfoli)' +REG_ORDER_BY_USERNAME = ' ORDER BY TRIM(d.affirmby)' +REG_ORDER_BY_OWNER_NAME = ' ORDER BY owner_name_sort' +REG_ORDER_BY_EXPIRY_DAYS = ' ORDER BY mh.mhregnum' +REG_FILTER_REG_TYPE = " AND TRIM(d.docutype) = '?'" +REG_FILTER_STATUS = " AND mh.mhstatus = '?'" +REG_FILTER_SUBMITTING_NAME = " AND TRIM(d.name) LIKE '?%'" +REG_FILTER_CLIENT_REF = " AND TRIM(d.olbcfoli) LIKE '?%'" +REG_FILTER_USERNAME = " AND TRIM(d.affirmby) LIKE '?%'" + +SORT_DESCENDING = ' DESC' +SORT_ASCENDING = ' ASC' + +QUERY_ACCOUNT_FILTER_BY = { + reg_utils.STATUS_PARAM: REG_FILTER_STATUS, + reg_utils.REG_TYPE_PARAM: REG_FILTER_REG_TYPE, + reg_utils.SUBMITTING_NAME_PARAM: REG_FILTER_SUBMITTING_NAME, + reg_utils.CLIENT_REF_PARAM: REG_FILTER_CLIENT_REF, + reg_utils.USER_NAME_PARAM: REG_FILTER_USERNAME +} +QUERY_ACCOUNT_ORDER_BY = { + reg_utils.REG_TS_PARAM: REG_ORDER_BY_DATE, + reg_utils.MHR_NUMBER_PARAM: REG_ORDER_BY_MHR_NUMBER, + reg_utils.STATUS_PARAM: REG_ORDER_BY_STATUS, + reg_utils.REG_TYPE_PARAM: REG_ORDER_BY_REG_TYPE, + reg_utils.SUBMITTING_NAME_PARAM: REG_ORDER_BY_SUBMITTING_NAME, + reg_utils.CLIENT_REF_PARAM: REG_ORDER_BY_CLIENT_REF, + reg_utils.OWNER_NAME_PARAM: REG_ORDER_BY_OWNER_NAME, + reg_utils.EXPIRY_DAYS_PARAM: REG_ORDER_BY_EXPIRY_DAYS, + reg_utils.USER_NAME_PARAM: REG_ORDER_BY_USERNAME +} REGISTRATION_DESC_NEW = 'REGISTER NEW UNIT' LEGACY_STATUS_DESCRIPTION = { 'R': 'ACTIVE', @@ -181,13 +240,13 @@ def find_summary_by_mhr_number(account_id: str, mhr_number: str, staff: bool): return registrations -def find_all_by_account_id(account_id: str, staff: bool, collapse: bool = False): +def find_all_by_account_id(params: AccountRegistrationParams): """Return a summary list of recent MHR registrations belonging to an account.""" results = [] # 1. get account and extra registrations from the Posgres table, then query DB2 by set of mhr numbers. - mhr_list = __get_mhr_list(account_id) + mhr_list = __get_mhr_list(params.account_id) # 2 Get summary list of new application registrations. - reg_summary_list = __get_reg_summary_list(account_id) + reg_summary_list = __get_reg_summary_list(params.account_id) doc_types = MhrDocumentType.find_all() if mhr_list: # 3. Get the summary info from DB2. @@ -200,19 +259,19 @@ def find_all_by_account_id(account_id: str, staff: bool, collapse: bool = False) if count > 1: mhr_numbers += ',' mhr_numbers += f"'{mhr_number}'" - query_text = QUERY_ACCOUNT_REGISTRATIONS.replace('?', mhr_numbers) - current_app.logger.info('Executing query for mhr numbers=' + mhr_numbers) - query = text(query_text) + query = text(build_account_query(params, mhr_numbers)) + # query_text = QUERY_ACCOUNT_REGISTRATIONS.replace('?', mhr_numbers) + # query = text(query_text) result = db.get_engine(current_app, 'db2').execute(query) rows = result.fetchall() if rows is not None: for row in rows: results.append(__build_summary(row, False)) for result in results: - __update_summary_info(result, results, reg_summary_list, doc_types, staff, account_id) - if not collapse: + __update_summary_info(result, results, reg_summary_list, doc_types, params.sbc_staff, params.account_id) + if not params.collapse: del result['documentType'] # Not in the schema. - if results and collapse: + if results and params.collapse: results = __collapse_results(results) except Exception as db_exception: # noqa: B902; return nicer error current_app.logger.error('DB2 find_all_by_account_id exception: ' + str(db_exception)) @@ -249,6 +308,51 @@ def find_by_document_id(document_id: str): return Db2Manuhome.find_by_document_id(document_id) +def build_account_query(params: AccountRegistrationParams, mhr_numbers: str) -> str: + """Build the account registration summary query.""" + query_text: str = QUERY_ACCOUNT_REGISTRATIONS + if not params.has_filter() and not params.has_sort(): + query_text = query_text.replace('?', mhr_numbers) + current_app.logger.info('Executing query for mhr numbers=' + mhr_numbers) + else: + query_text = QUERY_ACCOUNT_REGISTRATIONS_SORT + order_clause: str = '' + if params.has_filter(): + query_text = build_account_query_filter(query_text, params, mhr_numbers) + else: + query_text = query_text.replace('?', mhr_numbers) + if params.has_sort(): + order_clause = QUERY_ACCOUNT_ORDER_BY.get(params.sort_criteria) + if params.sort_criteria == reg_utils.REG_TS_PARAM: + if params.sort_direction and params.sort_direction == reg_utils.SORT_ASCENDING: + order_clause = order_clause.replace(SORT_DESCENDING, SORT_ASCENDING) + elif params.sort_direction and params.sort_direction == reg_utils.SORT_ASCENDING: + order_clause += SORT_ASCENDING + else: + order_clause += SORT_DESCENDING + query_text += order_clause + # current_app.logger.info(query_text) + return query_text + + +def build_account_query_filter(query_text: str, params: AccountRegistrationParams, mhr_numbers: str) -> str: + """Build the account registration summary query filter clause.""" + filter_clause: str = '' + filter_type, filter_value = params.get_filter_values() + if filter_type and filter_value: + if filter_type == reg_utils.MHR_NUMBER_PARAM: + query_text = query_text.replace('?', f"'{filter_value}'") + else: + query_text = query_text.replace('?', mhr_numbers) + if filter_type != reg_utils.REG_TS_PARAM: + filter_clause = QUERY_ACCOUNT_FILTER_BY.get(filter_type) + if filter_clause: + filter_clause = filter_clause.replace('?', filter_value) + if filter_clause: + query_text += filter_clause + return query_text + + def __get_mhr_list(account_id: str) -> dict: """Build a list of mhr numbers associated with the account.""" mhr_list = [] @@ -257,7 +361,7 @@ def __get_mhr_list(account_id: str) -> dict: result = db.session.execute(query, {'query_value': account_id}) rows = result.fetchall() except Exception as db_exception: # noqa: B902; return nicer error - current_app.logger.error('__get_mhr_list db exception: ' + str(db_exception)) + current_app.logger.error('get_mhr_list db exception: ' + str(db_exception)) raise DatabaseException(db_exception) if rows is not None: for row in rows: diff --git a/mhr_api/src/mhr_api/models/mhr_party.py b/mhr_api/src/mhr_api/models/mhr_party.py index b2d263d2a..c74756a7e 100755 --- a/mhr_api/src/mhr_api/models/mhr_party.py +++ b/mhr_api/src/mhr_api/models/mhr_party.py @@ -85,7 +85,7 @@ def json(self) -> dict: } if self.middle_name: person_name['middle'] = self.middle_name - party['individualName'] = person_name + party['personName'] = person_name if self.address: cp_address = self.address.json diff --git a/mhr_api/src/mhr_api/models/mhr_registration.py b/mhr_api/src/mhr_api/models/mhr_registration.py index d24f67934..27149e797 100755 --- a/mhr_api/src/mhr_api/models/mhr_registration.py +++ b/mhr_api/src/mhr_api/models/mhr_registration.py @@ -24,6 +24,7 @@ from mhr_api.models import utils as model_utils, Db2Manuhome from mhr_api.models.mhr_extra_registration import MhrExtraRegistration from mhr_api.models.db2 import utils as legacy_utils +from mhr_api.models.registration_utils import AccountRegistrationParams from mhr_api.services.authz import MANUFACTURER_GROUP, QUALIFIED_USER_GROUP, GOV_ACCOUNT_ROLE from .db import db @@ -292,11 +293,11 @@ def find_summary_by_mhr_number(cls, account_id: str, mhr_number: str, staff: boo raise DatabaseException('MhrRegistration.find_summary_by_mhr_number PosgreSQL not yet implemented.') @classmethod - def find_all_by_account_id(cls, account_id: str, staff: bool = False, collapse: bool = False): + def find_all_by_account_id(cls, params: AccountRegistrationParams): """Return a summary list of recent MHR registrations belonging to an account.""" - current_app.logger.debug(f'Account_id={account_id}') + current_app.logger.debug(f'Account_id={params.account_id}') if model_utils.is_legacy(): - return legacy_utils.find_all_by_account_id(account_id, staff, collapse) + return legacy_utils.find_all_by_account_id(params) raise DatabaseException('MhrRegistration.find_all_by_account_id PosgreSQL not yet implemented.') diff --git a/mhr_api/src/mhr_api/models/registration_utils.py b/mhr_api/src/mhr_api/models/registration_utils.py new file mode 100644 index 000000000..62a940e2e --- /dev/null +++ b/mhr_api/src/mhr_api/models/registration_utils.py @@ -0,0 +1,115 @@ +# Copyright © 2019 Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pylint: disable=too-few-public-methods + +"""This module holds methods to support registration model updates - mostly account registration summary.""" +# from flask import current_app +from mhr_api.models import utils as model_utils + + +# Account registration request parameters to support sorting and filtering. +CLIENT_REF_PARAM = 'clientReferenceId' +PAGE_NUM_PARAM = 'pageNumber' +SORT_DIRECTION_PARAM = 'sortDirection' +SORT_CRITERIA_PARAM = 'sortCriteriaName' +MHR_NUMBER_PARAM = 'mhrNumber' +DOC_REG_NUMBER_PARAM = 'documentRegistrationNumber' +REG_TYPE_PARAM = 'registrationType' +REG_TS_PARAM = 'createDateTime' +START_TS_PARAM = 'startDateTime' +END_TS_PARAM = 'endDateTime' +STATUS_PARAM = 'statusType' +SUBMITTING_NAME_PARAM = 'submittingName' +OWNER_NAME_PARAM = 'ownerName' +USER_NAME_PARAM = 'username' +EXPIRY_DAYS_PARAM = 'expiryDays' +SORT_ASCENDING = 'ascending' +SORT_DESCENDING = 'descending' + + +class AccountRegistrationParams(): + """Contains parameter values to use when sorting and filtering account summary registration information.""" + + account_id: str + collapse: bool = False + sbc_staff: bool = False + from_ui: bool = False + sort_direction: str = SORT_DESCENDING + page_number: int = 1 + sort_criteria: str = None + filter_mhr_number: str = None + filter_registration_type: str = None + filter_registration_date: str = None + # start_date_time: str = None + # end_date_time: str = None + filter_status_type: str = None + filter_client_reference_id: str = None + filter_submitting_name: str = None + filter_username: str = None + + def __init__(self, account_id, collapse: bool = False, sbc_staff: bool = False): + """Set common base initialization.""" + self.account_id = account_id + self.collapse = collapse + self.sbc_staff = sbc_staff + + def has_sort(self) -> bool: + """Check if sort criteria provided.""" + if self.sort_criteria: + if self.sort_criteria == MHR_NUMBER_PARAM or self.sort_criteria == REG_TYPE_PARAM or \ + self.sort_criteria == REG_TS_PARAM or self.sort_criteria == CLIENT_REF_PARAM: + return True + if self.sort_criteria == SUBMITTING_NAME_PARAM or self.sort_criteria == OWNER_NAME_PARAM or \ + self.sort_criteria == USER_NAME_PARAM or self.sort_criteria == STATUS_PARAM or \ + self.sort_criteria == EXPIRY_DAYS_PARAM: + return True + return False + + def has_filter(self) -> bool: + """Check if filter criteria provided.""" + return self.filter_client_reference_id or self.filter_mhr_number or self.filter_registration_type or \ + self.filter_registration_date or self.filter_status_type or self.filter_submitting_name or \ + self.filter_username + + def get_filter_values(self): # pylint: disable=too-many-return-statements + """Provide optional filter name and value if available.""" + if self.filter_mhr_number: + return MHR_NUMBER_PARAM, self.filter_mhr_number + if self.filter_registration_type: + return REG_TYPE_PARAM, self.filter_registration_type + if self.filter_registration_date: + return REG_TS_PARAM, self.filter_registration_date + if self.filter_status_type: + return STATUS_PARAM, self.filter_status_type + if self.filter_client_reference_id: + return CLIENT_REF_PARAM, self.filter_client_reference_id + if self.filter_submitting_name: + return SUBMITTING_NAME_PARAM, self.filter_submitting_name + if self.filter_username: + return USER_NAME_PARAM, self.filter_username + return None, None + + def get_page_size(self) -> int: + """Provide account registrations query page size.""" + if self.has_filter(): + return model_utils.MAX_ACCOUNT_REGISTRATIONS_DEFAULT + return model_utils.get_max_registrations_size() + + def get_page_offset(self) -> int: + """Provide account registrations query page offset.""" + page_offset: int = self.page_number + if page_offset <= 1: + return 0 + return (page_offset - 1) * self.get_page_size() diff --git a/mhr_api/src/mhr_api/resources/utils.py b/mhr_api/src/mhr_api/resources/utils.py index fab652b72..c93fa51b2 100644 --- a/mhr_api/src/mhr_api/resources/utils.py +++ b/mhr_api/src/mhr_api/resources/utils.py @@ -15,10 +15,11 @@ from enum import Enum from http import HTTPStatus -from flask import jsonify, current_app +from flask import jsonify, current_app, request from mhr_api.exceptions import ResourceErrorCodes -# from mhr_api.models import utils as model_utils +from mhr_api.models import utils as model_utils, registration_utils as reg_utils +from mhr_api.models.registration_utils import AccountRegistrationParams from mhr_api.services.authz import user_orgs, is_reg_staff_account, is_sbc_office_account, is_bcol_help from mhr_api.services.payment.exceptions import SBCPaymentException from mhr_api.utils import registration_validator @@ -252,12 +253,46 @@ def validate_exemption(registration, json_data, is_staff: bool = False): return registration_validator.validate_exemption(registration, json_data, is_staff) -def valid_api_key(request) -> bool: +def valid_api_key(req) -> bool: """Verify the callback request api key is valid.""" - key = get_apikey(request) + key = get_apikey(req) if not key: return False apikey = current_app.config.get('SUBSCRIPTION_API_KEY') if not apikey: return True return key == apikey + + +def get_account_registration_params(req: request, params: AccountRegistrationParams) -> AccountRegistrationParams: + """Extract account registration query parameters from the request.""" + params.from_ui = req.args.get(FROM_UI_PARAM, False) + params.page_number = int(req.args.get(reg_utils.PAGE_NUM_PARAM, -1)) + params.sort_direction = req.args.get(reg_utils.SORT_DIRECTION_PARAM, reg_utils.SORT_DESCENDING) + params.sort_criteria = req.args.get(reg_utils.SORT_CRITERIA_PARAM, None) + params.filter_mhr_number = req.args.get(reg_utils.MHR_NUMBER_PARAM, None) + params.filter_registration_type = req.args.get(reg_utils.REG_TYPE_PARAM, None) + params.filter_status_type = req.args.get(reg_utils.STATUS_PARAM, None) + params.filter_client_reference_id = req.args.get(reg_utils.CLIENT_REF_PARAM, None) + params.filter_submitting_name = req.args.get(reg_utils.SUBMITTING_NAME_PARAM, None) + params.filter_username = req.args.get(reg_utils.USER_NAME_PARAM, None) + # start_ts = req.args.get(reg_utils.START_TS_PARAM, None) + # end_ts = req.args.get(reg_utils.END_TS_PARAM, None) + # if start_ts and end_ts: + # params.start_date_time = start_ts + # params.end_date_time = end_ts + if params.sort_direction: + params.sort_direction = params.sort_direction.lower() + if params.sort_direction == 'asc': + params.sort_direction = reg_utils.SORT_ASCENDING + elif params.sort_direction == 'desc': + params.sort_direction = reg_utils.SORT_DESCENDING + if params.filter_mhr_number: + params.filter_mhr_number = model_utils.format_mhr_number(params.filter_mhr_number) + if params.filter_submitting_name: + params.filter_submitting_name = params.filter_submitting_name.strip().upper() + if params.filter_username: + params.filter_username = params.filter_username.strip().upper() + if params.filter_client_reference_id: + params.filter_client_reference_id = params.filter_client_reference_id.strip() + return params diff --git a/mhr_api/src/mhr_api/resources/v1/registrations.py b/mhr_api/src/mhr_api/resources/v1/registrations.py index dc27017f8..2c35170a8 100755 --- a/mhr_api/src/mhr_api/resources/v1/registrations.py +++ b/mhr_api/src/mhr_api/resources/v1/registrations.py @@ -24,6 +24,7 @@ from mhr_api.exceptions import BusinessException, DatabaseException from mhr_api.services.authz import authorized, authorized_role, is_staff, is_all_staff_account, REGISTER_MH from mhr_api.models import MhrRegistration +from mhr_api.models.registration_utils import AccountRegistrationParams from mhr_api.reports.v2.report_utils import ReportTypes from mhr_api.resources import utils as resource_utils, registration_utils as reg_utils from mhr_api.services.payment import TransactionTypes @@ -60,7 +61,12 @@ def get_account_registrations(): collapse_param = True elif isinstance(collapse_param, str): collapse_param = False - statement_list = MhrRegistration.find_all_by_account_id(account_id, is_staff(jwt), collapse_param) + + params: AccountRegistrationParams = AccountRegistrationParams(account_id=account_id, + collapse=collapse_param, + sbc_staff=is_staff(jwt)) + params = resource_utils.get_account_registration_params(request, params) + statement_list = MhrRegistration.find_all_by_account_id(params) return jsonify(statement_list), HTTPStatus.OK except DatabaseException as db_exception: diff --git a/mhr_api/tests/unit/api/test_registrations.py b/mhr_api/tests/unit/api/test_registrations.py index 9ee99ab7a..df0c6b4cc 100644 --- a/mhr_api/tests/unit/api/test_registrations.py +++ b/mhr_api/tests/unit/api/test_registrations.py @@ -23,8 +23,8 @@ from flask import current_app from registry_schemas.example_data.mhr import REGISTRATION -from mhr_api.models import MhrRegistration -from mhr_api.services.authz import COLIN_ROLE, MHR_ROLE, STAFF_ROLE, BCOL_HELP +from mhr_api.models import MhrRegistration, registration_utils as reg_utils +from mhr_api.services.authz import COLIN_ROLE, MHR_ROLE, STAFF_ROLE, BCOL_HELP, ASSETS_HELP from tests.unit.services.utils import create_header, create_header_account @@ -53,11 +53,25 @@ ('Invalid role', [COLIN_ROLE], HTTPStatus.UNAUTHORIZED, '2523', '150062'), ('Valid Request', [MHR_ROLE], HTTPStatus.OK, '2523', '150062'), ('Valid Request reg staff', [MHR_ROLE, STAFF_ROLE], HTTPStatus.OK, STAFF_ROLE, '150062'), - ('Valid Request bcol helpdesk', [MHR_ROLE, BCOL_HELP], HTTPStatus.OK, BCOL_HELP, '150062'), + ('Valid Request bcol helpdesk', [MHR_ROLE, BCOL_HELP], HTTPStatus.OK, ASSETS_HELP, '150062'), ('Valid Request other account', [MHR_ROLE], HTTPStatus.OK, 'PS12345', '150062'), ('Invalid MHR Number', [MHR_ROLE], HTTPStatus.NOT_FOUND, '2523', 'TESTXXXX'), ('Invalid request Staff no account', [MHR_ROLE, STAFF_ROLE], HTTPStatus.BAD_REQUEST, None, '150062') ] +# testdata pattern is ({desc}, {roles}, {status}, {sort_criteria}, {sort_direction}) +TEST_GET_ACCOUNT_DATA_SORT2 = [ + ('Sort mhr number', [MHR_ROLE, STAFF_ROLE], HTTPStatus.OK, reg_utils.MHR_NUMBER_PARAM, None) +] +TEST_GET_ACCOUNT_DATA_SORT = [ + ('Sort mhr number', [MHR_ROLE, STAFF_ROLE], HTTPStatus.OK, reg_utils.MHR_NUMBER_PARAM, None), + ('Sort reg type asc', [MHR_ROLE, STAFF_ROLE], HTTPStatus.OK, reg_utils.REG_TYPE_PARAM, reg_utils.SORT_ASCENDING), + ('Sort reg status desc', [MHR_ROLE, STAFF_ROLE], HTTPStatus.OK, reg_utils.STATUS_PARAM, reg_utils.SORT_DESCENDING), + ('Sort reg ts asc', [MHR_ROLE, STAFF_ROLE], HTTPStatus.OK, reg_utils.REG_TS_PARAM, reg_utils.SORT_ASCENDING), + ('Sort client ref', [MHR_ROLE, STAFF_ROLE], HTTPStatus.OK, reg_utils.CLIENT_REF_PARAM, None), + ('Sort user name', [MHR_ROLE, STAFF_ROLE], HTTPStatus.OK, reg_utils.USER_NAME_PARAM, None), + ('Sort submitting name', [MHR_ROLE, STAFF_ROLE], HTTPStatus.OK, reg_utils.SUBMITTING_NAME_PARAM, None), + ('Sort owner name', [MHR_ROLE, STAFF_ROLE], HTTPStatus.OK, reg_utils.OWNER_NAME_PARAM, None) +] @pytest.mark.parametrize('desc,roles,status,has_account,results_size', TEST_GET_ACCOUNT_DATA) @@ -141,3 +155,31 @@ def test_get_registration(session, client, jwt, desc, roles, status, account_id, assert response.status_code in (status, HTTPStatus.UNAUTHORIZED) else: assert response.status_code == status + + +@pytest.mark.parametrize('desc,roles,status,sort_criteria,sort_direction', TEST_GET_ACCOUNT_DATA_SORT) +def test_get_account_registrations_sort(session, client, jwt, desc, roles, status, sort_criteria, sort_direction): + """Assert that a get account registrations summary list endpoint with sorting works as expected.""" + headers = None + # setup + headers = create_header_account(jwt, roles) + params = f'?sortCriteriaName={sort_criteria}' + if sort_direction: + params += f'&sortDirection={sort_direction}' + # test + current_app.logger.debug('params=' + params) + rv = client.get('/api/v1/registrations' + params, + headers=headers) + # check + assert rv.status_code == status + assert rv.json + for registration in rv.json: + assert registration['mhrNumber'] + assert registration['registrationDescription'] + assert registration['statusType'] is not None + assert registration['createDateTime'] is not None + assert registration['username'] is not None + assert registration['submittingParty'] is not None + assert registration['clientReferenceId'] is not None + assert registration['ownerNames'] is not None + assert registration['path'] is not None diff --git a/mhr_api/tests/unit/models/db2/test_db2_utils.py b/mhr_api/tests/unit/models/db2/test_db2_utils.py new file mode 100644 index 000000000..2d3171874 --- /dev/null +++ b/mhr_api/tests/unit/models/db2/test_db2_utils.py @@ -0,0 +1,122 @@ +# Copyright © 2019 Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests to assure the MHR Registration DB2 Model utils. + +Test-Suite to ensure that the MH Registration DB2 Model helper methods are working as expected. +""" +from flask import current_app + +import pytest +from flask import current_app + +from mhr_api.models import registration_utils as reg_utils, utils as model_utils +from mhr_api.models.registration_utils import AccountRegistrationParams +from mhr_api.models.db2 import utils as db2_utils + + +# testdata pattern is ({account_id}, {has_results}) +TEST_ACCOUNT_REG_DATA = [ + ('2523', True), + ('999999', False) +] +# testdata pattern is ({account_id}, {sort_criteria}, {sort_order}, {mhr_numbers}, {expected_clause}) +TEST_QUERY_ORDER_DATA = [ + ('2523', None, None, "'098487'", db2_utils.REG_ORDER_BY_DATE), + ('2523', 'invalid', None, "'098487'", db2_utils.REG_ORDER_BY_DATE), + ('2523',reg_utils, None, "'098487'", db2_utils.REG_ORDER_BY_DATE), + ('2523', reg_utils.MHR_NUMBER_PARAM, reg_utils.SORT_ASCENDING, "'098487'", db2_utils.REG_ORDER_BY_MHR_NUMBER), + ('2523', reg_utils.REG_TYPE_PARAM, reg_utils.SORT_ASCENDING, "'098487'", db2_utils.REG_ORDER_BY_REG_TYPE), + ('2523', reg_utils.SUBMITTING_NAME_PARAM, reg_utils.SORT_DESCENDING, "'098487'", + db2_utils.REG_ORDER_BY_SUBMITTING_NAME), + ('2523', reg_utils.CLIENT_REF_PARAM, reg_utils.SORT_ASCENDING, "'098487'", db2_utils.REG_ORDER_BY_CLIENT_REF), + ('2523', reg_utils.REG_TS_PARAM, reg_utils.SORT_ASCENDING, "'098487'", db2_utils.REG_ORDER_BY_DATE), + ('2523', reg_utils.STATUS_PARAM, reg_utils.SORT_ASCENDING, "'098487'", db2_utils.REG_ORDER_BY_STATUS), + ('2523', reg_utils.USER_NAME_PARAM, reg_utils.SORT_DESCENDING, "'098487'", db2_utils.REG_ORDER_BY_USERNAME), + ('2523', reg_utils.OWNER_NAME_PARAM, reg_utils.SORT_DESCENDING, "'098487'", db2_utils.REG_ORDER_BY_OWNER_NAME), + ('2523', reg_utils.EXPIRY_DAYS_PARAM, reg_utils.SORT_DESCENDING, "'098487'", db2_utils.REG_ORDER_BY_EXPIRY_DAYS) +] + + +@pytest.mark.parametrize('account_id, has_results', TEST_ACCOUNT_REG_DATA) +def test_find_account_registrations(session, account_id, has_results): + """Assert that finding account summary MHR registration information works as expected.""" + params: AccountRegistrationParams = AccountRegistrationParams(account_id=account_id, + collapse=True, + sbc_staff=False) + + reg_list = db2_utils.find_all_by_account_id(params) + if has_results: + for registration in reg_list: + assert registration['mhrNumber'] + assert registration['registrationDescription'] + assert registration['statusType'] is not None + assert registration['createDateTime'] is not None + assert registration['username'] is not None + assert registration['submittingParty'] is not None + assert registration['clientReferenceId'] is not None + assert registration['ownerNames'] is not None + assert registration['path'] is not None + assert registration['documentId'] is not None + assert not registration.get('inUserList') + else: + assert not reg_list + + +@pytest.mark.parametrize('account_id,sort_criteria,sort_order,mhr_numbers,expected_clause', TEST_QUERY_ORDER_DATA) +def test_account_reg_order(session, account_id, sort_criteria, sort_order, mhr_numbers, expected_clause): + """Assert that account registration query order by clause is as expected.""" + params: AccountRegistrationParams = AccountRegistrationParams(account_id=account_id, + collapse=True, + sbc_staff=False) + params.sort_criteria = sort_criteria + params.sort_direction = sort_order + order_clause = expected_clause + if params.has_sort() and params.sort_criteria == reg_utils.REG_TS_PARAM: + if params.sort_direction and params.sort_direction == reg_utils.SORT_ASCENDING: + order_clause = order_clause.replace(db2_utils.SORT_DESCENDING, db2_utils.SORT_ASCENDING) + elif params.has_sort(): + if params.sort_direction and params.sort_direction == reg_utils.SORT_ASCENDING: + order_clause += db2_utils.SORT_ASCENDING + else: + order_clause += db2_utils.SORT_DESCENDING + + query: str = db2_utils.build_account_query(params, mhr_numbers) + current_app.logger.debug(query) + # current_app.logger.debug(order_clause) + assert query.endswith(order_clause) or query.endswith((order_clause + '\n')) + + +@pytest.mark.parametrize('account_id,sort_criteria,sort_order,mhr_numbers,expected_clause', TEST_QUERY_ORDER_DATA) +def test_find_account_sort_order(session, account_id, sort_criteria, sort_order, mhr_numbers, expected_clause): + """Assert that account registration query with an order by clause is as expected.""" + params: AccountRegistrationParams = AccountRegistrationParams(account_id=account_id, + collapse=True, + sbc_staff=False) + params.sort_criteria = sort_criteria + params.sort_direction = sort_order + reg_list = db2_utils.find_all_by_account_id(params) + assert reg_list + for registration in reg_list: + assert registration['mhrNumber'] + assert registration['registrationDescription'] + assert registration['statusType'] is not None + assert registration['createDateTime'] is not None + assert registration['username'] is not None + assert registration['submittingParty'] is not None + assert registration['clientReferenceId'] is not None + assert registration['ownerNames'] is not None + assert registration['path'] is not None + assert registration['documentId'] is not None + assert not registration.get('inUserList') diff --git a/mhr_api/tests/unit/models/test_mhr_registration.py b/mhr_api/tests/unit/models/test_mhr_registration.py index e2947bd69..a413eaa3e 100755 --- a/mhr_api/tests/unit/models/test_mhr_registration.py +++ b/mhr_api/tests/unit/models/test_mhr_registration.py @@ -26,6 +26,7 @@ from mhr_api.exceptions import BusinessException from mhr_api.models import MhrRegistration, MhrDraft, MhrDocument, MhrNote, utils as model_utils +from mhr_api.models.registration_utils import AccountRegistrationParams from mhr_api.models.type_tables import MhrLocationTypes, MhrPartyTypes, MhrOwnerStatusTypes, MhrStatusTypes from mhr_api.models.type_tables import MhrRegistrationTypes, MhrRegistrationStatusTypes, MhrDocumentTypes from mhr_api.models.type_tables import MhrTenancyTypes @@ -222,7 +223,11 @@ def test_find_summary_by_mhr_number(session, account_id, mhr_num, exists, reg_de @pytest.mark.parametrize('account_id, has_results', TEST_ACCOUNT_REG_DATA) def test_find_account_registrations(session, account_id, has_results): """Assert that finding account summary MHR registration information works as expected.""" - reg_list = MhrRegistration.find_all_by_account_id(account_id) + params: AccountRegistrationParams = AccountRegistrationParams(account_id=account_id, + collapse=True, + sbc_staff=False) + + reg_list = MhrRegistration.find_all_by_account_id(params) if has_results: for registration in reg_list: assert registration['mhrNumber']