Skip to content

Commit

Permalink
API transport permit updates. (#1610)
Browse files Browse the repository at this point in the history
* API transport permit updates.

Signed-off-by: Doug Lovett <[email protected]>

* Cancel existing permit note.

Signed-off-by: Doug Lovett <[email protected]>

* Update schema version.

Signed-off-by: Doug Lovett <[email protected]>

* Return the latest MH status for the registration report.

Signed-off-by: Doug Lovett <[email protected]>

---------

Signed-off-by: Doug Lovett <[email protected]>
  • Loading branch information
doug-lovett authored Nov 1, 2023
1 parent 92968ed commit abcdf27
Show file tree
Hide file tree
Showing 13 changed files with 143 additions and 145 deletions.
2 changes: 1 addition & 1 deletion mhr_api/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,4 @@ sentry-sdk==1.20.0
six==1.16.0
strict-rfc3339==0.7
urllib3==1.26.11
git+https://github.com/bcgov/[email protected].5#egg=registry_schemas
git+https://github.com/bcgov/[email protected].6#egg=registry_schemas
2 changes: 1 addition & 1 deletion mhr_api/requirements/bcregistry-libraries.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
git+https://github.com/bcgov/[email protected].5#egg=registry_schemas
git+https://github.com/bcgov/[email protected].6#egg=registry_schemas
10 changes: 10 additions & 0 deletions mhr_api/src/mhr_api/models/db2/manuhome.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,14 @@ def save_permit(self):
note: Db2Mhomnote = self.reg_notes[index]
if note.reg_document_id == doc.id:
note.save()
for note in self.reg_notes:
if note.reg_document_id != doc.id and \
note.document_type in (Db2Document.DocumentTypes.PERMIT,
Db2Document.DocumentTypes.PERMIT_TRIM) and \
note.status == Db2Mhomnote.StatusTypes.ACTIVE:
note.status = Db2Mhomnote.StatusTypes.CANCELLED
note.can_document_id = doc.id
note.save()
if self.new_location:
self.reg_location.save()
self.new_location.save()
Expand Down Expand Up @@ -764,6 +772,8 @@ def create_from_permit(registration, reg_json):
manuhome.new_location.location_id = (manuhome.reg_location.location_id + 1)
manuhome.reg_location.status = Db2Location.StatusTypes.HISTORICAL
manuhome.reg_location.can_document_id = doc.id
if manuhome.new_location.province and manuhome.new_location.province != model_utils.PROVINCE_BC:
manuhome.mh_status = Db2Manuhome.StatusTypes.EXEMPT
return manuhome

@staticmethod
Expand Down
11 changes: 10 additions & 1 deletion mhr_api/src/mhr_api/models/mhr_registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ def save_transfer(self, json_data, new_reg_id):
self.remove_groups(json_data, new_reg_id)
db.session.commit()

def save_permit(self, new_reg_id):
def save_permit(self, json_data, new_reg_id):
"""Update the existing location state to historical."""
if self.locations and self.locations[0].status_type == MhrStatusTypes.ACTIVE:
self.locations[0].status_type = MhrStatusTypes.HISTORICAL
Expand All @@ -320,6 +320,15 @@ def save_permit(self, new_reg_id):
if existing.status_type == MhrStatusTypes.ACTIVE and existing.registration_id != new_reg_id:
existing.status_type = MhrStatusTypes.HISTORICAL
existing.change_registration_id = new_reg_id
if reg.notes:
note: MhrNote = reg.notes[0]
if note.document_type == MhrDocumentTypes.REG_103 and note.status_type == MhrNoteStatusTypes.ACTIVE:
note.status_type = MhrNoteStatusTypes.CANCELLED
note.change_registration_id = new_reg_id
if json_data and json_data['newLocation']['address']['region'] != model_utils.PROVINCE_BC:
self.status_type = MhrRegistrationStatusTypes.EXEMPT
current_app.logger.info('Transport new location out of province, updating status to EXEMPT.')
db.session.commit()

def is_transfer(self) -> bool:
"""Determine if the registration is one of the transfer types."""
Expand Down
2 changes: 1 addition & 1 deletion mhr_api/src/mhr_api/resources/registration_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ def pay_and_save_permit(req: request, # pylint: disable=too-many-arguments
registration.pay_path = pay_ref['receipt']
registration.save()
if current_reg.id and current_reg.id > 0 and current_reg.locations:
current_reg.save_permit(registration.id)
current_reg.save_permit(request_json, registration.id)
return registration
except Exception as db_exception: # noqa: B902; handle all db related errors.
current_app.logger.error(SAVE_ERROR_MESSAGE.format(account_id, 'registration', str(db_exception)))
Expand Down
1 change: 1 addition & 0 deletions mhr_api/src/mhr_api/resources/v1/permits.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def post_permits(mhr_number: str): # pylint: disable=too-many-return-statements
current_reg.current_view = True
current_json = current_reg.new_registration_json
response_json['description'] = current_json.get('description')
response_json['status'] = current_json.get('status')
setup_report(registration, response_json, group, jwt)
return jsonify(response_json), HTTPStatus.CREATED
except DatabaseException as db_exception:
Expand Down
19 changes: 8 additions & 11 deletions mhr_api/src/mhr_api/utils/registration_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from mhr_api.models.type_tables import MhrDocumentTypes, MhrLocationTypes
from mhr_api.models.type_tables import MhrTenancyTypes, MhrPartyTypes, MhrRegistrationTypes
from mhr_api.models.utils import now_ts, ts_from_iso_format, valid_tax_cert_date
from mhr_api.services.authz import MANUFACTURER_GROUP, QUALIFIED_USER_GROUP
from mhr_api.services.authz import MANUFACTURER_GROUP, QUALIFIED_USER_GROUP, DEALERSHIP_GROUP
from mhr_api.utils import validator_utils


Expand Down Expand Up @@ -244,32 +244,29 @@ def validate_permit(registration: MhrRegistration, json_data, staff: bool = Fals
if registration and group_name and group_name == MANUFACTURER_GROUP:
error_msg += validate_manufacturer_permit(registration.mhr_number, json_data.get('submittingParty'),
current_location)
if registration and group_name and group_name == DEALERSHIP_GROUP and current_location and \
current_location.get('locationType', '') != MhrLocationTypes.MANUFACTURER:
error_msg += MANUFACTURER_DEALER_INVALID
error_msg += validator_utils.validate_submitting_party(json_data)
error_msg += validator_utils.validate_registration_state(registration, staff, MhrRegistrationTypes.PERMIT)
error_msg += validator_utils.validate_draft_state(json_data)
if json_data.get('newLocation'):
location = json_data.get('newLocation')
error_msg += validate_location(location)
error_msg += validator_utils.validate_location_different(current_location, location)
error_msg += validate_tax_certificate(location, current_location)
if not json_data.get('landStatusConfirmation'):
if location.get('locationType') and \
location['locationType'] in (MhrLocationTypes.STRATA,
MhrLocationTypes.RESERVE,
MhrLocationTypes.OTHER):
error_msg += STATUS_CONFIRMATION_REQUIRED
elif location.get('locationType') and location['locationType'] == MhrLocationTypes.MH_PARK and \
current_location and location.get('parkName'):
existing_name: str = current_location.get('parkName')
if not existing_name or location.get('parkName').strip().upper() != existing_name:
elif current_location and location.get('locationType', '') == MhrLocationTypes.MH_PARK:
if current_location.get('locationType', '') != MhrLocationTypes.MH_PARK or \
current_location.get('parkName', '') != location.get('parkName'):
error_msg += STATUS_CONFIRMATION_REQUIRED
if location.get('pidNumber'):
error_msg += validator_utils.validate_pid(location.get('pidNumber'))
if current_location and json_data.get('existingLocation') and \
not location_address_match(current_location, json_data.get('existingLocation')):
error_msg += LOCATION_ADDRESS_MISMATCH
if registration and json_data.get('owner') and \
not validator_utils.owner_name_match(registration, json_data.get('owner')):
error_msg += OWNER_NAME_MISMATCH
except Exception as validation_exception: # noqa: B902; eat all errors
current_app.logger.error('validate_transfer exception: ' + str(validation_exception))
error_msg += VALIDATOR_ERROR
Expand Down
34 changes: 31 additions & 3 deletions mhr_api/src/mhr_api/utils/validator_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
Refactored from registration_validator.
"""
import copy

from flask import current_app

from mhr_api.models import MhrRegistration, MhrDraft
Expand Down Expand Up @@ -60,6 +62,7 @@
DELETE_GROUP_TYPE_INVALID = 'The owner group tenancy type with ID {group_id} is invalid. '
GROUP_INTEREST_MISMATCH = 'The owner group interest numerator sum does not equal the interest common denominator. '
MHR_NUMBER_INVALID = 'MHR nubmer {mhr_num} either is greater than the existng maximum MHR number or already exists. '
LOCATION_INVALID_IDENTICAL = 'The new location cannot be identical to the existing location. '

PPR_REG_TYPE_ALL = ' SA_TAX TA_TAX TM_TAX '
PPR_REG_TYPE_GOV = ' SA_GOV TA_GOV TM_GOV '
Expand Down Expand Up @@ -151,7 +154,7 @@ def validate_registration_state(registration: MhrRegistration, staff: bool, reg_
(not reg_type or reg_type != MhrRegistrationTypes.TRANS):
error_msg += STATE_NOT_ALLOWED
error_msg += STATE_FROZEN_AFFIDAVIT
return check_state_note(registration, staff, error_msg)
return check_state_note(registration, staff, error_msg, reg_type)


def validate_registration_state_exre(registration: MhrRegistration):
Expand All @@ -169,7 +172,7 @@ def validate_registration_state_exemption(registration: MhrRegistration, reg_typ
error_msg = ''
if registration.status_type:
if registration.status_type == MhrRegistrationStatusTypes.ACTIVE:
return check_state_note(registration, staff, error_msg)
return check_state_note(registration, staff, error_msg, reg_type)
if registration.status_type == MhrRegistrationStatusTypes.CANCELLED:
error_msg += STATE_NOT_ALLOWED
elif reg_type == MhrRegistrationTypes.EXEMPTION_RES:
Expand Down Expand Up @@ -299,7 +302,7 @@ def get_existing_group_count(registration: MhrRegistration) -> int:
return group_count


def check_state_note(registration: MhrRegistration, staff: bool, error_msg: str) -> str:
def check_state_note(registration: MhrRegistration, staff: bool, error_msg: str, reg_type: str) -> str:
"""Check registration state for non-staff: frozen if active TAXN, NCON, or REST unit note."""
if not registration or staff:
return error_msg
Expand All @@ -312,6 +315,7 @@ def check_state_note(registration: MhrRegistration, staff: bool, error_msg: str)
reg.notes[0].status_type == MhrNoteStatusTypes.ACTIVE:
error_msg += STATE_FROZEN_NOTE
elif reg.registration_type in (MhrRegistrationTypes.PERMIT, MhrRegistrationTypes.PERMIT_EXTENSION) and \
reg_type not in (MhrRegistrationTypes.PERMIT, MhrRegistrationTypes.PERMIT_EXTENSION) and \
reg.notes and reg.notes[0].status_type == MhrNoteStatusTypes.ACTIVE and \
not reg.notes[0].is_expired():
error_msg += STATE_FROZEN_PERMIT
Expand Down Expand Up @@ -545,3 +549,27 @@ def validate_mhr_number(mhr_number: str, staff: bool) -> str:
if not reg_utils.validate_mhr_number(mhr_number):
error_msg += MHR_NUMBER_INVALID.format(mhr_num=mhr_number)
return error_msg


def validate_location_different(current_loc: dict, new_loc: dict) -> str:
"""Verify the new location is not identical to the existing location."""
error_msg = ''
if not current_loc or not new_loc:
return error_msg
loc_1 = copy.deepcopy(current_loc)
loc_2 = copy.deepcopy(new_loc)
loc_1['status'] = ''
loc_1['locationId'] = ''
loc_1['leaveProvince'] = False
loc_2['status'] = ''
loc_2['locationId'] = ''
loc_2['leaveProvince'] = False
if loc_1.get('address') and loc_1['address'].get('postalCode') and \
str(loc_1['address']['postalCode']).strip() == '':
del loc_1['address']['postalCode']
if loc_2.get('address') and loc_2['address'].get('postalCode') and \
str(loc_2['address']['postalCode']).strip() == '':
del loc_2['address']['postalCode']
if loc_1 == loc_2:
error_msg += LOCATION_INVALID_IDENTICAL
return error_msg
19 changes: 15 additions & 4 deletions mhr_api/src/mhr_api/utils/validator_utils_legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from flask import current_app

from mhr_api.models import Db2Manuhome, Db2Owngroup, Db2Document, Db2Mhomnote, Db2Owner, utils as model_utils
from mhr_api.models.type_tables import MhrDocumentTypes, MhrRegistrationTypes, MhrTenancyTypes
from mhr_api.models.type_tables import MhrDocumentTypes, MhrRegistrationTypes, MhrTenancyTypes, MhrStatusTypes
from mhr_api.models.db2.owngroup import NEW_TENANCY_LEGACY
from mhr_api.models.db2.utils import get_db2_permit_count
from mhr_api.models.utils import to_db2_ind_name
Expand Down Expand Up @@ -61,7 +61,7 @@ def validate_registration_state(registration, staff: bool, reg_type: str, doc_ty
reg_type != MhrRegistrationTypes.TRANS:
error_msg += STATE_NOT_ALLOWED
error_msg += STATE_FROZEN_AFFIDAVIT
return check_state_note(manuhome, staff, error_msg)
return check_state_note(manuhome, staff, error_msg, reg_type)


def validate_registration_state_exre(manuhome: Db2Manuhome):
Expand All @@ -76,7 +76,7 @@ def validate_registration_state_exemption(manuhome: Db2Manuhome, reg_type: str,
"""Validate registration state for residential/non-residential exemption requests."""
error_msg = ''
if manuhome.mh_status == manuhome.StatusTypes.REGISTERED:
return check_state_note(manuhome, staff, error_msg)
return check_state_note(manuhome, staff, error_msg, reg_type)
if manuhome.mh_status == manuhome.StatusTypes.CANCELLED:
error_msg += STATE_NOT_ALLOWED
elif reg_type == MhrRegistrationTypes.EXEMPTION_RES:
Expand All @@ -94,6 +94,16 @@ def get_existing_location(registration):
return {}
manuhome: Db2Manuhome = registration.manuhome
if manuhome and manuhome.reg_location:
# Use modernized if exists.
doc_id: str = manuhome.reg_location.reg_document_id
if registration.locations and registration.locations[0].status_type == MhrStatusTypes.ACTIVE and \
registration.documents and registration.documents[0].document_id == doc_id:
return registration.locations[0].json
if registration.change_registrations:
for reg in registration.change_registrations:
if reg.locations and reg.locations[0].status_type == MhrStatusTypes.ACTIVE and \
reg.documents and reg.documents[0].document_id == doc_id:
return reg.locations[0].json
return manuhome.reg_location.registration_json
return {}

Expand All @@ -115,7 +125,7 @@ def get_existing_group_count(registration) -> int:
return group_count


def check_state_note(manuhome: Db2Manuhome, staff: bool, error_msg: str) -> str:
def check_state_note(manuhome: Db2Manuhome, staff: bool, error_msg: str, reg_type: str) -> str:
"""Check registration state for non-staff: frozen if active TAXN, NCON, or REST unit note."""
if staff:
return error_msg
Expand All @@ -127,6 +137,7 @@ def check_state_note(manuhome: Db2Manuhome, staff: bool, error_msg: str) -> str:
elif note.document_type in (Db2Document.DocumentTypes.PERMIT,
Db2Document.DocumentTypes.PERMIT_TRIM,
Db2Document.DocumentTypes.PERMIT_EXTENSION) and \
reg_type not in (MhrRegistrationTypes.PERMIT, MhrRegistrationTypes.PERMIT_EXTENSION) and \
note.status == Db2Mhomnote.StatusTypes.ACTIVE and note.expiry_date and \
note.expiry_date > model_utils.today_local().date():
error_msg += STATE_FROZEN_PERMIT
Expand Down
2 changes: 1 addition & 1 deletion mhr_api/src/mhr_api/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@
Development release segment: .devN
"""

__version__ = '1.6.2' # pylint: disable=invalid-name
__version__ = '1.6.3' # pylint: disable=invalid-name
2 changes: 1 addition & 1 deletion mhr_api/test_data/postgres_data_files/test0004.sql
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ INSERT INTO mhr_sections(id, registration_id, status_type, compressed_key, seria
;
INSERT INTO mhr_documents(id, document_type, registration_id, document_id, document_registration_number, attention_reference,
declared_value, consideration_value, own_land, transfer_date, consent, owner_x_reference, change_registration_id)
VALUES(200000016, 'REG_101', 200000016, '40583993', '90499016', 'attn', NULL, NULL, 'Y', null, null, null, 200000016)
VALUES(200000016, 'REG_101', 200000016, 'UT000016', '90499016', 'attn', NULL, NULL, 'Y', null, null, null, 200000016)
;
INSERT INTO mhr_owner_groups(id, sequence_number, registration_id, status_type, tenancy_type, interest,
tenancy_specified, interest_numerator, interest_denominator, change_registration_id)
Expand Down
Loading

0 comments on commit abcdf27

Please sign in to comment.