Skip to content

Commit

Permalink
Miscellaneous MHR API permit updates. (#1906)
Browse files Browse the repository at this point in the history
Signed-off-by: Doug Lovett <[email protected]>
  • Loading branch information
doug-lovett authored May 31, 2024
1 parent 90ad85f commit a553f83
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 28 deletions.
4 changes: 2 additions & 2 deletions mhr_api/report-templates/adminRegistrationV2.html
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@
<div class="separator mt-5"></div>
<div class="section-title mt-5">Cancelled Transport Permit Information</div>
<div class="section-data mt-3">
Transport permit {{note.cancelledDocumentId}} that was registered on {{note.cancelledDateTime}} was cancelled under
document registration number {{note.cancelledDocumentRegistrationNumber}}.
Transport permit {{note.cancelledDocumentId}} issued on {{note.cancelledDateTime}} was cancelled by
document registration number {{note.cancelledDocumentRegistrationNumber}} effective {{createDateTime}}.
</div>
{% if previousLocation is defined %}
<div class="section-title mt-5">Location Change <span class="pl-2">&nbsp;</span><span class="section-label">CANCELLED</span> </div>
Expand Down
11 changes: 10 additions & 1 deletion mhr_api/src/mhr_api/resources/registration_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ def pay(req: request, request_json: dict, account_id: str, trans_type: str, tran
details: dict = get_pay_details(request_json.get('registrationType'), trans_id)
if request_json.get('transferDocumentType'):
details = get_pay_details_doc(request_json.get('transferDocumentType'), trans_id)
elif request_json.get('documentType'):
details = get_pay_details_doc(request_json.get('documentType'), trans_id)
elif request_json.get('registrationType') == MhrRegistrationTypes.PERMIT and request_json.get('amendment'):
details = get_pay_details_doc(MhrDocumentTypes.AMEND_PERMIT, trans_id)
if not is_reg_staff_account(account_id):
payment = Payment(jwt=jwt.get_token_auth_header(), account_id=account_id, details=details)
pay_ref = payment.create_payment(trans_type, 1, trans_id, client_ref, False)
Expand Down Expand Up @@ -342,7 +346,12 @@ def pay_and_save_admin(req: request, # pylint: disable=too-many-arguments
request_json['affirmByName'] = get_affirmby(token)
if not request_json.get('registrationType'):
request_json['registrationType'] = MhrRegistrationTypes.REG_STAFF_ADMIN
payment, pay_ref = pay_staff(req, request_json, trans_type, trans_id)
payment = None
pay_ref = None
if is_reg_staff_account(account_id):
payment, pay_ref = pay_staff(req, request_json, trans_type, trans_id)
else:
payment, pay_ref = pay(req, request_json, account_id, trans_type, trans_id)
invoice_id = pay_ref['invoiceId']
# Try to save the registration: failure throws an exception.
try:
Expand Down
24 changes: 13 additions & 11 deletions mhr_api/src/mhr_api/resources/v1/admin_registrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@

bp = Blueprint('ADMIN_REGISTRATIONS1', # pylint: disable=invalid-name
__name__, url_prefix='/api/v1/admin-registrations')
# Mapping from doc type to pay transaction type
DOC_TO_TRANSACTION_TYPE = {
MhrDocumentTypes.NRED: TransactionTypes.UNIT_NOTE.value,
MhrDocumentTypes.STAT: TransactionTypes.ADMIN_RLCHG.value,
MhrDocumentTypes.REGC_STAFF: TransactionTypes.CORRECTION.value,
MhrDocumentTypes.REGC_CLIENT: TransactionTypes.CORRECTION.value,
MhrDocumentTypes.PUBA: TransactionTypes.AMENDMENT.value,
MhrDocumentTypes.EXRE: TransactionTypes.REGISTRATION.value,
MhrDocumentTypes.CANCEL_PERMIT: TransactionTypes.CANCEL_PERMIT.value
}


@bp.route('/<string:mhr_number>', methods=['POST', 'OPTIONS'])
Expand Down Expand Up @@ -225,17 +235,9 @@ def get_report_groups(response_json: dict, current_json: dict, add_groups: dict)


def get_transaction_type(request_json: dict) -> str:
"""Try and obtain an optional boolean parameter value from the request parameters."""
if request_json.get('documentType', '') == MhrDocumentTypes.NRED:
return TransactionTypes.UNIT_NOTE
if request_json.get('documentType', '') == MhrDocumentTypes.STAT:
return TransactionTypes.ADMIN_RLCHG
if request_json.get('documentType') in (MhrDocumentTypes.REGC_STAFF, MhrDocumentTypes.REGC_CLIENT):
return TransactionTypes.CORRECTION
if request_json.get('documentType') == MhrDocumentTypes.PUBA:
return TransactionTypes.AMENDMENT
if request_json.get('documentType') == MhrDocumentTypes.EXRE:
return TransactionTypes.REGISTRATION
"""Map the admin registration document type to the pay transaction type."""
if DOC_TO_TRANSACTION_TYPE.get(request_json.get('documentType', '')):
return DOC_TO_TRANSACTION_TYPE.get(request_json.get('documentType'))
return TransactionTypes.UNIT_NOTE


Expand Down
1 change: 1 addition & 0 deletions mhr_api/src/mhr_api/services/payment/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ class TransactionTypes(str, Enum):
AMEND_PERMIT = 'AMEND_PERMIT'
AMENDMENT = 'AMENDMENT'
CORRECTION = 'CORRECTION'
CANCEL_PERMIT = 'CANCEL_PERMIT'
1 change: 1 addition & 0 deletions mhr_api/src/mhr_api/services/payment/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
'ADMIN_CORLC': 'CORLC',
'ADMIN_RLCHG': 'RLCHG',
'AMEND_PERMIT': 'MHROT',
'CANCEL_PERMIT': 'MHROT',
'AMENDMENT': 'MHROT',
'CORRECTION': 'MHROT'
}
Expand Down
26 changes: 24 additions & 2 deletions mhr_api/src/mhr_api/utils/registration_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
TRAN_DEATH_DATE_INVALID = 'A death date and time must be in the past. '
TRAN_DEATH_QS_JOINT = 'A lawyer/notary qualified supplier JOINT tenancy business owner is not allowed with this ' + \
'registration. '
TRAN_AFFIDAVIT_DECLARED_VALUE = 'Declared value must be cannot be greater than 25000 for this registration. '
TRAN_AFFIDAVIT_DECLARED_VALUE = 'Declared value cannot be greater than 25000 for this registration. '
TRAN_WILL_PROBATE = 'One (and only one) deceased owner must have a probate document (no death certificate). '
TRAN_WILL_DEATH_CERT = 'Deceased owners without a probate document must have a death certificate ' + \
'or corporation number. '
Expand All @@ -76,7 +76,7 @@
'dealer/manufacturer lot or manufactured home park. '
TRANS_DOC_TYPE_INVALID = 'The transferDocumentType is only allowed with a TRANS transfer due to sale or gift. '
AMEND_LOCATION_TYPE_QS = 'New location type cannot be different than the existing location type.'
AMEND_PERMIT_INVALID = 'Amend transport permit not allowed: no active tansport permit exists.'
AMEND_PERMIT_INVALID = 'Amend transport permit not allowed: no active tansport permit exists. '
TRAN_DEATH_QS_JOINT_REMOVE = 'A lawyer/notary qualified supplier JOINT tenancy business owner cannot be changed ' + \
'with this registration. '
PERMIT_QS_ADDRESS_MISSING = 'No existing qualified supplier lot address found. '
Expand All @@ -95,6 +95,8 @@
EXNR_CONVERTED_INVALID = 'Non-residential exemption converted reason (note nonResidentialReason) is invalid. ' + \
'Allowed values are OFFICE, STORAGE_SHED, BUNKHOUSE, or OTHER. '
TRANS_DOC_TYPE_NOT_ALLOWED = 'The transferDocumentType is only allowed with BC Registries staff TRANS registrations. '
AMEND_PERMIT_QS_ADDRESS_INVALID = 'Amend transport permit can only change the home location address street. ' + \
'City and province may not be modified. '

PPR_SECURITY_AGREEMENT = ' SA TA TG TM '

Expand Down Expand Up @@ -318,11 +320,31 @@ def validate_permit_location(json_data: dict, current_location: dict, staff: boo
if current_location.get('locationType', '') != MhrLocationTypes.MH_PARK or \
current_location.get('parkName', '') != location.get('parkName'):
error_msg += validator_utils.STATUS_CONFIRMATION_REQUIRED
if not staff and json_data.get('amendment'):
error_msg += validate_amend_location_address(json_data, current_location)
if location.get('pidNumber'):
error_msg += validator_utils.validate_pid(location.get('pidNumber'))
return error_msg


def validate_amend_location_address(json_data: dict, current_location: dict) -> str:
"""Check that amend transport permit only changes the location address street value."""
error_msg: str = ''
if not current_location or not current_location.get('address') or not json_data['newLocation'].get('address'):
return error_msg
addr_1 = json_data['newLocation'].get('address')
addr_2 = current_location.get('address')
if addr_1.get('city'):
addr_1['city'] = str(addr_1.get('city')).upper().strip()
if addr_1.get('city', '') != addr_2.get('city', '') or \
addr_1.get('region', '') != addr_2.get('region', '') or \
addr_1.get('country', '') != addr_2.get('country', ''):
error_msg = AMEND_PERMIT_QS_ADDRESS_INVALID
if addr_2.get('postalCode', '') != addr_1.get('postalCode', ''):
error_msg = AMEND_PERMIT_QS_ADDRESS_INVALID
return error_msg


def validate_permit_location_address(json_data: dict, current_location: dict) -> str:
"""Manufacturer check that current location address matches supplier lot address."""
error_msg: str = ''
Expand Down
15 changes: 8 additions & 7 deletions mhr_api/tests/unit/api/test_admin_registrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,13 +294,14 @@
]
# testdata pattern is ({doc_type}, {pay_trans_type})
TEST_TRANS_TYPE_DATA = [
(MhrDocumentTypes.EXRE, TransactionTypes.REGISTRATION),
(MhrDocumentTypes.NRED, TransactionTypes.UNIT_NOTE),
(MhrDocumentTypes.NCAN, TransactionTypes.UNIT_NOTE),
(MhrDocumentTypes.STAT, TransactionTypes.ADMIN_RLCHG),
(MhrDocumentTypes.REGC_CLIENT, TransactionTypes.CORRECTION),
(MhrDocumentTypes.REGC_STAFF, TransactionTypes.CORRECTION),
(MhrDocumentTypes.PUBA, TransactionTypes.AMENDMENT)
(MhrDocumentTypes.EXRE, TransactionTypes.REGISTRATION.value),
(MhrDocumentTypes.NRED, TransactionTypes.UNIT_NOTE.value),
(MhrDocumentTypes.NCAN, TransactionTypes.UNIT_NOTE.value),
(MhrDocumentTypes.STAT, TransactionTypes.ADMIN_RLCHG.value),
(MhrDocumentTypes.REGC_CLIENT, TransactionTypes.CORRECTION.value),
(MhrDocumentTypes.REGC_STAFF, TransactionTypes.CORRECTION.value),
(MhrDocumentTypes.PUBA, TransactionTypes.AMENDMENT.value),
(MhrDocumentTypes.CANCEL_PERMIT, TransactionTypes.CANCEL_PERMIT.value)
]
# testdata pattern is ({mhr_num}, {account_id}, {has_loc}, {has_desc}, {has_owners})
TEST_CREATE_DATA_EXRE= [
Expand Down
5 changes: 4 additions & 1 deletion mhr_api/tests/unit/services/test_payment.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,10 @@
(TransactionTypes.UNIT_NOTE_OTHER, 'MHROT'),
(TransactionTypes.ADMIN_RLCHG, 'RLCHG'),
(TransactionTypes.CORRECTION, 'MHROT'),
(TransactionTypes.AMENDMENT, 'MHROT')
(TransactionTypes.AMENDMENT, 'MHROT'),
(TransactionTypes.TRANSPORT_PERMIT, 'TRAPP'),
(TransactionTypes.CANCEL_PERMIT, 'MHROT'),
(TransactionTypes.AMEND_PERMIT, 'MHROT')
]


Expand Down
63 changes: 59 additions & 4 deletions mhr_api/tests/unit/utils/test_permit_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,22 @@
('Valid staff EXEMPT location', True, True, None, '000931', 'PS12345', STAFF_ROLE),
('Valid non-staff EXEMPT location', True, False, None, '000931', 'PS12345', QUALIFIED_USER_GROUP)
]
# test data pattern is ({desc}, {valid}, {staff}, {mhr_num}, {street}, {city}, {prov}, {pcode}, {message_content})
TEST_AMEND_LOCATION_DATA = [
('Valid staff no change', True, True, '000931', False, False, False, False, None),
('Valid staff change street', True, True, '000931', True, False, False, False, None),
('Valid staff change city', True, True, '000931', False, True, False, False, None),
('Valid staff change region', True, True, '000931', False, False, True, False, None),
('Valid staff change pcode', True, True, '000931', False, False, False, True, None),
('Valid non-staff no change', True, False, '000931', False, False, False, False, None),
('Valid non-staff change street', True, False, '000931', True, False, False, False, None),
('Invalid non-staff change city', False, False, '000931', False, True, False, False,
validator.AMEND_PERMIT_QS_ADDRESS_INVALID),
('Invalid non-staff change region', False, False, '000931', False, False, True, False,
validator.AMEND_PERMIT_QS_ADDRESS_INVALID),
('Invalid non-staff change pcode', False, False, '000931', False, False, False, True,
validator.AMEND_PERMIT_QS_ADDRESS_INVALID)
]
# test data pattern is ({description}, {valid}, {staff}, {add_days}, {message_content}, {mhr_num}, {account}, {group})
TEST_EXPIRY_DATE_DATA = [
('Valid staff future year', True, True, 365, None, '000900', 'PS12345', STAFF_ROLE),
Expand Down Expand Up @@ -445,11 +461,14 @@ def test_validate_amend_permit(session, desc, valid, staff, message_content, mhr
json_data['documentId'] = DOC_ID_VALID
json_data['amendment'] = True
if desc == 'Valid non-staff location type change':
json_data['newLocation'] = LOCATION_RESERVE
elif desc == 'Valid non-staff':
json_data['newLocation'] = LOCATION_OTHER
json_data['newLocation'] = copy.deepcopy(LOCATION_RESERVE)
json_data['newLocation']['address'] = LOCATION_OTHER.get('address')
elif desc in ('Valid non-staff', 'Valid non-staff EXEMPT location'):
json_data['newLocation'] = copy.deepcopy(LOCATION_OTHER)
if desc == 'Valid non-staff EXEMPT location':
json_data['newLocation']['address']['region'] = 'AB'
if desc == 'Valid staff tax cert':
json_data['newLocation']['taxExpiryDate'] = get_valid_tax_cert_dt()
json_data['newLocation']['taxExpiryDate'] = get_valid_tax_cert_dt()
else:
if 'taxExpiryDate' in json_data['newLocation']:
del json_data['newLocation']['taxExpiryDate']
Expand Down Expand Up @@ -493,6 +512,42 @@ def test_validate_amend_permit(session, desc, valid, staff, message_content, mhr
assert error_msg.find(message_content) != -1


@pytest.mark.parametrize('desc,valid,staff,mhr_num,street,city,prov,pcode,message_content', TEST_AMEND_LOCATION_DATA)
def test_validate_amend_location(session, desc, valid, staff, mhr_num, street, city, prov, pcode, message_content):
"""Assert that amend MH transport permit location change address validation works as expected."""
# setup
account = 'PS12345'
group = STAFF_ROLE if staff else QUALIFIED_USER_GROUP
json_data = get_valid_registration()
json_data['documentId'] = DOC_ID_VALID
json_data['amendment'] = True
address = copy.deepcopy(LOCATION_OTHER.get('address'))
if street:
address['street'] = 'DIFF STREET'
if city:
address['city'] = 'DIFF CITY'
if prov:
address['region'] = 'SK'
if pcode:
address['postalCode'] = 'X1X 3X3'
json_data['newLocation']['address'] = address

# current_app.logger.info(json_data)
valid_format, errors = schema_utils.validate(json_data, 'permit', 'mhr')
# Additional validation not covered by the schema.
registration: MhrRegistration = MhrRegistration.find_all_by_mhr_number(mhr_num, account)
error_msg = validator.validate_permit(registration, json_data, staff, group)
if errors:
for err in errors:
current_app.logger.debug(err.message)
if valid:
assert valid_format and error_msg == ''
else:
assert error_msg != ''
if message_content:
assert error_msg.find(message_content) != -1


@pytest.mark.parametrize('desc,valid,mhr_num,location,message_content,group', TEST_PERMIT_DATA_EXTRA)
def test_validate_permit_extra(session, desc, valid, mhr_num, location, message_content, group):
"""Assert that extra MH transport permit validation works as expected."""
Expand Down
1 change: 1 addition & 0 deletions mhr_api/tests/unit/utils/test_validator_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

INVALID_TEXT_CHARSET = 'TEST \U0001d5c4\U0001d5c6/\U0001d5c1 INVALID'


# testdata pattern is ({description}, {rebuilt}, {other}, {csa_num}, {eng_date}, {staff}, {message content})
TEST_DESCRIPTION_DATA = [
('Non utf-8 rebuilt remarks', INVALID_TEXT_CHARSET, None, None, None, True, None),
Expand Down

0 comments on commit a553f83

Please sign in to comment.