Skip to content

Commit

Permalink
MHR API add account registration sorting. (#1077)
Browse files Browse the repository at this point in the history
- Account registration summary add sorting criteria and direction as new request parameters.
- Fix to Postgres submitting party JSON to return personName.
  • Loading branch information
doug-lovett authored Dec 6, 2022
1 parent ea69550 commit 3f89e00
Show file tree
Hide file tree
Showing 9 changed files with 456 additions and 26 deletions.
130 changes: 117 additions & 13 deletions mhr_api/src/mhr_api/models/db2/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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',
Expand Down Expand Up @@ -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.
Expand All @@ -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))
Expand Down Expand Up @@ -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 = []
Expand All @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion mhr_api/src/mhr_api/models/mhr_party.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions mhr_api/src/mhr_api/models/mhr_registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.')

Expand Down
115 changes: 115 additions & 0 deletions mhr_api/src/mhr_api/models/registration_utils.py
Original file line number Diff line number Diff line change
@@ -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()
Loading

0 comments on commit 3f89e00

Please sign in to comment.