diff --git a/mhr_api/report-templates/adminRegistrationV2.html b/mhr_api/report-templates/adminRegistrationV2.html index 553beee85..79dffdd79 100644 --- a/mhr_api/report-templates/adminRegistrationV2.html +++ b/mhr_api/report-templates/adminRegistrationV2.html @@ -441,7 +441,7 @@ {% endif %} -
{{ documentDescription }} Applicatant Name:
+
{{ documentDescription }} Applicant Name:
{% if submittingParty.businessName is defined %} {{ submittingParty.businessName }} diff --git a/mhr_api/report-templates/registrationCoverV2.html b/mhr_api/report-templates/registrationCoverV2.html index 86828bd6e..760acf883 100644 --- a/mhr_api/report-templates/registrationCoverV2.html +++ b/mhr_api/report-templates/registrationCoverV2.html @@ -126,6 +126,10 @@
Transport Permit Number: {{ permitRegistrationNumber }}
+ {% elif extension is defined and extension and permitRegistrationNumber is defined %} +
Transport Permit Number: + {{ permitRegistrationNumber }} +
{% endif %}
{% if registrationType is defined and registrationType == 'PERMIT' %}Transport Permit Number:{% else %}Document Registration Number:{% endif %} diff --git a/mhr_api/report-templates/template-parts/v2/search-result/registration.html b/mhr_api/report-templates/template-parts/v2/search-result/registration.html index 88efb3bdb..d154461f7 100644 --- a/mhr_api/report-templates/template-parts/v2/search-result/registration.html +++ b/mhr_api/report-templates/template-parts/v2/search-result/registration.html @@ -29,17 +29,19 @@ Home Registration Status: {{detail.status|title}} - - Declared Value: - - {% if detail.declaredValue is defined and detail.declaredValue != '' %} - {{detail.declaredValue}} - {% if detail.declaredDateTime is defined and detail.declaredDateTime != '' %} as of {{detail.declaredDateTime}}{% endif %} - {% else %} - N/A - {% endif %} - - + {% if not detail.location.dealerName and detail.location.locationType != 'MANUFACTURER' %} + + Declared Value: + + {% if detail.declaredValue is defined and detail.declaredValue != '' %} + {{detail.declaredValue}} + {% if detail.declaredDateTime is defined and detail.declaredDateTime != '' %} as of {{detail.declaredDateTime}}{% endif %} + {% else %} + N/A + {% endif %} + + + {% endif %}
diff --git a/mhr_api/report-templates/template-parts/v2/style.html b/mhr_api/report-templates/template-parts/v2/style.html index df68a7204..3e773e416 100755 --- a/mhr_api/report-templates/template-parts/v2/style.html +++ b/mhr_api/report-templates/template-parts/v2/style.html @@ -1523,6 +1523,19 @@ background-color:#CBD5E0; /* #E2E7ED; */ } + .extended-label { + font-size: 7pt; + line-height: 13px !important; + font-family: 'BC Sans', sans-serif !important; + font-weight: bold; + color: #FFFFFF; + vertical-align: 15% !important; + padding: 3px 8px !important; + margin: 0px 3px 0px 0px !important; + border-radius: 4px; + background-color:#1669BB; + } + .tocpagenr { float:right; } diff --git a/mhr_api/report-templates/transportPermitV2.html b/mhr_api/report-templates/transportPermitV2.html index af816b6c3..c871f5721 100644 --- a/mhr_api/report-templates/transportPermitV2.html +++ b/mhr_api/report-templates/transportPermitV2.html @@ -39,6 +39,19 @@ Transport Permit Expiry Date: {{permitExpiryDateTime}} + {% elif extension is defined and extension %} + + Transport Permit Number: + {{permitRegistrationNumber}} + + + Transport Permit Date and Time of Issue: + {{permitDateTime}} + + + Transport Permit Expiry Date: + {{permitExpiryDateTime}}  EXTENDED + {% else %} Transport Permit Number: diff --git a/mhr_api/src/mhr_api/models/batch_utils.py b/mhr_api/src/mhr_api/models/batch_utils.py index 31b57aad0..334d40620 100644 --- a/mhr_api/src/mhr_api/models/batch_utils.py +++ b/mhr_api/src/mhr_api/models/batch_utils.py @@ -30,7 +30,7 @@ from mhr_registrations r, mhr_registration_reports rr, mhr_documents d where r.id = rr.registration_id and r.id = d.registration_id - and d.document_type in ('EXRE', 'REG_103', 'STAT', 'PUBA', 'REGC_STAFF', 'REGC_CLIENT', 'AMEND_PERMIT', + and d.document_type in ('EXRE', 'REG_103', 'REG_103E', 'STAT', 'PUBA', 'REGC_STAFF', 'REGC_CLIENT', 'AMEND_PERMIT', 'CANCEL_PERMIT') and rr.batch_report_data is not null and json_typeof(rr.batch_report_data) != 'null' @@ -42,7 +42,7 @@ from mhr_registrations r, mhr_registration_reports rr, mhr_documents d where r.id = rr.registration_id and r.id = d.registration_id - and d.document_type in ('EXRE', 'REG_103', 'STAT', 'PUBA', 'REGC_STAFF', 'REGC_CLIENT', 'AMEND_PERMIT', + and d.document_type in ('EXRE', 'REG_103', 'REG_103E', 'STAT', 'PUBA', 'REGC_STAFF', 'REGC_CLIENT', 'AMEND_PERMIT', 'CANCEL_PERMIT') and rr.batch_report_data is not null and json_typeof(rr.batch_report_data) != 'null' @@ -77,6 +77,7 @@ MhrDocumentTypes.ABAN.value, MhrDocumentTypes.REG_101.value, MhrDocumentTypes.REG_103.value, + MhrDocumentTypes.REG_103E.value, MhrDocumentTypes.REGC_CLIENT.value, MhrDocumentTypes.REGC_STAFF.value, MhrDocumentTypes.AFFE.value, @@ -156,6 +157,7 @@ PREVIOUS_LOCATION_DOC_TYPES = [ MhrDocumentTypes.EXRE.value, MhrDocumentTypes.REG_103.value, + MhrDocumentTypes.REG_103E.value, MhrDocumentTypes.AMEND_PERMIT.value, MhrDocumentTypes.CANCEL_PERMIT.value, MhrDocumentTypes.PUBA.value, @@ -432,7 +434,7 @@ def get_batch_registration_data(start_ts: str = None, end_ts: str = None): if start_ts and end_ts: start: str = get_query_ts(start_ts) end: str = get_query_ts(end_ts) - current_app.logger.debug(f'start={start} end={end}') + current_app.logger.debug(f'query parameters start={start} end={end}') result = db.session.execute(query, {'query_val1': start, 'query_val2': end}) else: result = db.session.execute(query) diff --git a/mhr_api/src/mhr_api/models/mhr_registration.py b/mhr_api/src/mhr_api/models/mhr_registration.py index f803937c2..8d5226000 100755 --- a/mhr_api/src/mhr_api/models/mhr_registration.py +++ b/mhr_api/src/mhr_api/models/mhr_registration.py @@ -22,6 +22,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 +import mhr_api.models.registration_change_utils as change_utils import mhr_api.models.registration_utils as reg_utils import mhr_api.models.registration_json_utils as reg_json_utils from mhr_api.services.authz import STAFF_ROLE @@ -42,7 +43,6 @@ MhrPartyTypes, MhrRegistrationTypes, MhrRegistrationStatusTypes, - MhrStatusTypes, MhrTenancyTypes ) @@ -150,6 +150,8 @@ def json(self) -> dict: reg_json = reg_json_utils.set_note_json(self, reg_json) if doc_json.get('documentType') == MhrDocumentTypes.AMEND_PERMIT: reg_json['amendment'] = True + elif doc_json.get('documentType') == MhrDocumentTypes.REG_103E: + reg_json['extension'] = True elif self.is_transfer(): if doc_json.get('transferDate'): reg_json['transferDate'] = doc_json.get('transferDate') @@ -320,7 +322,7 @@ def save_exemption(self, new_reg_id: int): self.status_type = MhrRegistrationStatusTypes.EXEMPT if self.change_registrations: # Close out active transport permit without reverting location. for reg in self.change_registrations: - if reg.notes and reg.notes[0].document_type in (MhrDocumentTypes.REG_103, + if reg.notes and reg.notes[0].document_type in (MhrDocumentTypes.REG_103, MhrDocumentTypes.REG_103E, MhrDocumentTypes.AMEND_PERMIT) and \ reg.notes[0].status_type == MhrNoteStatusTypes.ACTIVE: note: MhrNote = reg.notes[0] @@ -333,46 +335,6 @@ def save_transfer(self, json_data, new_reg_id): self.remove_groups(json_data, new_reg_id) db.session.commit() - 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 - self.locations[0].change_registration_id = new_reg_id - elif self.change_registrations: - for reg in self.change_registrations: # Updating a change registration location. - for existing in reg.locations: - 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 json_data.get('moveCompleted') and note.document_type == MhrDocumentTypes.REG_103 and \ - note.status_type == MhrNoteStatusTypes.ACTIVE and not note.is_expired(): - note.status_type = MhrNoteStatusTypes.COMPLETED - note.change_registration_id = new_reg_id - current_app.logger.debug(f'save_permit setting note status to completed reg id={new_reg_id}') - elif note.document_type in (MhrDocumentTypes.REG_103, - MhrDocumentTypes.REG_103E, - MhrDocumentTypes.AMEND_PERMIT) and \ - note.status_type == MhrNoteStatusTypes.ACTIVE and not note.is_expired(): - note.status_type = MhrNoteStatusTypes.CANCELLED - note.change_registration_id = new_reg_id - if json_data and json_data.get('documentType') == MhrDocumentTypes.CANCEL_PERMIT: - if self.status_type and self.status_type == MhrRegistrationStatusTypes.EXEMPT and \ - json_data.get('location') and json_data['location']['address']['region'] == model_utils.PROVINCE_BC: - self.status_type = MhrRegistrationStatusTypes.ACTIVE - current_app.logger.info('Cancel Transport Permit new location in BC, updating EXEMPT status to ACTIVE.') - elif json_data and json_data.get('amendment') and \ - self.status_type == MhrRegistrationStatusTypes.EXEMPT and \ - json_data['newLocation']['address']['region'] == model_utils.PROVINCE_BC: - self.status_type = MhrRegistrationStatusTypes.ACTIVE - current_app.logger.info('Amend Transport Permit new location in BC, updating EXEMPT status to ACTIVE.') - elif json_data and json_data['newLocation']['address']['region'] != model_utils.PROVINCE_BC and \ - json_data.get('documentType', '') != MhrDocumentTypes.CANCEL_PERMIT: - self.status_type = MhrRegistrationStatusTypes.EXEMPT - current_app.logger.info('Transport Permit 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.""" return self.registration_type in (MhrRegistrationTypes.TRANS, MhrRegistrationTypes.TRAND, @@ -791,6 +753,9 @@ def create_permit_from_json(base_reg, json_data['registrationType'] = MhrRegistrationTypes.AMENDMENT doc.document_type = MhrDocumentTypes.AMEND_PERMIT registration.registration_type = MhrRegistrationTypes.AMENDMENT + elif json_data.get('extension'): + doc.document_type = MhrDocumentTypes.REG_103E + registration.registration_type = MhrRegistrationTypes.PERMIT_EXTENSION # Save permit expiry date as a note. note: MhrNote = MhrNote(registration_id=base_reg.id, document_id=doc.id, @@ -805,11 +770,16 @@ def create_permit_from_json(base_reg, for reg in base_reg.change_registrations: # Updating a change registration location. if reg.notes and reg.notes[0] and reg.notes[0].status_type == MhrNoteStatusTypes.ACTIVE and \ reg.notes[0].expiry_date and \ - reg.notes[0].document_type in (MhrDocumentTypes.REG_103, MhrDocumentTypes.AMEND_PERMIT): + reg.notes[0].document_type in (MhrDocumentTypes.REG_103, MhrDocumentTypes.REG_103E, + MhrDocumentTypes.AMEND_PERMIT): note.expiry_date = reg.notes[0].expiry_date + if doc.document_type == MhrDocumentTypes.REG_103E: # Same location with optional updated tax info. + change_utils.setup_permit_extension_location(base_reg, registration, json_data.get('newLocation')) + if account_id == STAFF_ROLE and json_data.get('note') and json_data['note'].get('remarks'): + note.remarks = json_data['note'].get('remarks') + else: # New location + registration.locations.append(MhrLocation.create_from_json(json_data.get('newLocation'), registration.id)) registration.notes = [note] - # New location - registration.locations.append(MhrLocation.create_from_json(json_data.get('newLocation'), registration.id)) if base_reg: registration.manuhome = base_reg.manuhome return registration diff --git a/mhr_api/src/mhr_api/models/queries.py b/mhr_api/src/mhr_api/models/queries.py index 12d3fc3f0..8b8ab0bd9 100644 --- a/mhr_api/src/mhr_api/models/queries.py +++ b/mhr_api/src/mhr_api/models/queries.py @@ -105,7 +105,7 @@ FROM mhr_extra_registrations mer WHERE mer.mhr_number = arv.mhr_number AND mer.account_id = arv.account_id - AND (mer.removed_ind IS NULL OR mer.removed_ind != 'Y')) AS reg_count, + AND (mer.removed_ind IS NOT NULL AND mer.removed_ind = 'Y')) AS removed_count, (SELECT COUNT(mer.id) FROM mhr_extra_registrations mer WHERE mer.mhr_number = arv.mhr_number diff --git a/mhr_api/src/mhr_api/models/registration_change_utils.py b/mhr_api/src/mhr_api/models/registration_change_utils.py new file mode 100644 index 000000000..3947411ff --- /dev/null +++ b/mhr_api/src/mhr_api/models/registration_change_utils.py @@ -0,0 +1,111 @@ +# 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 additional methods to support registration model updates.""" +from flask import current_app +from mhr_api.models import utils as model_utils +from mhr_api.models import ( + MhrLocation +) +from mhr_api.models.db import db +from mhr_api.models.type_tables import ( + MhrDocumentTypes, + MhrNoteStatusTypes, + MhrRegistrationStatusTypes, + MhrStatusTypes +) + + +def save_exemption(registration, new_reg_id: int): + """Set the state of the original MH registration to exempt.""" + registration.status_type = MhrRegistrationStatusTypes.EXEMPT + if registration.change_registrations: # Close out active transport permit without reverting location. + for reg in registration.change_registrations: + if reg.notes and reg.notes[0].document_type in (MhrDocumentTypes.REG_103, MhrDocumentTypes.REG_103E, + MhrDocumentTypes.AMEND_PERMIT) and \ + reg.notes[0].status_type == MhrNoteStatusTypes.ACTIVE: + note = reg.notes[0] + note.status_type = MhrNoteStatusTypes.CANCELLED + note.change_registration_id = new_reg_id + db.session.commit() + + +def save_transfer(registration, json_data, new_reg_id): + """Update the original MH removed owner groups.""" + registration.remove_groups(json_data, new_reg_id) + db.session.commit() + + +def save_permit(registration, json_data, new_reg_id): + """Update the existing location state to historical.""" + if registration.locations and registration.locations[0].status_type == MhrStatusTypes.ACTIVE: + registration.locations[0].status_type = MhrStatusTypes.HISTORICAL + registration.locations[0].change_registration_id = new_reg_id + elif registration.change_registrations: + for reg in registration.change_registrations: # Updating a change registration location. + for existing in reg.locations: + 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 = reg.notes[0] + if json_data.get('moveCompleted') and note.document_type == MhrDocumentTypes.REG_103 and \ + note.status_type == MhrNoteStatusTypes.ACTIVE and not note.is_expired(): + note.status_type = MhrNoteStatusTypes.COMPLETED + note.change_registration_id = new_reg_id + current_app.logger.debug(f'save_permit setting note status to completed reg id={new_reg_id}') + elif note.document_type in (MhrDocumentTypes.REG_103, + MhrDocumentTypes.REG_103E, + MhrDocumentTypes.AMEND_PERMIT) and \ + note.status_type == MhrNoteStatusTypes.ACTIVE and not note.is_expired(): + note.status_type = MhrNoteStatusTypes.CANCELLED + note.change_registration_id = new_reg_id + if json_data and json_data.get('documentType') == MhrDocumentTypes.CANCEL_PERMIT: + if registration.status_type and registration.status_type == MhrRegistrationStatusTypes.EXEMPT and \ + json_data.get('location') and json_data['location']['address']['region'] == model_utils.PROVINCE_BC: + registration.status_type = MhrRegistrationStatusTypes.ACTIVE + current_app.logger.info('Cancel Transport Permit new location in BC, updating EXEMPT status to ACTIVE.') + elif json_data and json_data.get('amendment') and \ + registration.status_type == MhrRegistrationStatusTypes.EXEMPT and \ + json_data['newLocation']['address']['region'] == model_utils.PROVINCE_BC: + registration.status_type = MhrRegistrationStatusTypes.ACTIVE + current_app.logger.info('Amend Transport Permit new location in BC, updating EXEMPT status to ACTIVE.') + elif json_data and json_data['newLocation']['address']['region'] != model_utils.PROVINCE_BC and \ + json_data.get('documentType', '') != MhrDocumentTypes.CANCEL_PERMIT: + registration.status_type = MhrRegistrationStatusTypes.EXEMPT + current_app.logger.info('Transport Permit new location out of province, updating status to EXEMPT.') + db.session.commit() + + +def setup_permit_extension_location(base_reg, registration, new_loc_json: dict): + """REG_103E location does not change so clone the active location.""" + if not base_reg.change_registrations: + return + current_app.logger.info('Permit extension looking up existing location.') + for reg in base_reg.change_registrations: + if reg.locations and reg.locations[0].status_type == MhrStatusTypes.ACTIVE: + current_loc = reg.locations[0] + location: MhrLocation = MhrLocation.create_from_json(current_loc.json, registration.id) + location.registration_id = registration.id + location.change_registration_id = registration.id + current_app.logger.info('Permit extension cloned existing location.') + if new_loc_json: + if 'taxCertificate' in new_loc_json: + location.tax_certification = 'Y' if new_loc_json.get('taxCertificate') else 'N' + if new_loc_json.get('taxExpiryDate', None): + location.tax_certification_date = model_utils.ts_from_iso_format(new_loc_json.get('taxExpiryDate')) + registration.locations.append(location) + break diff --git a/mhr_api/src/mhr_api/models/registration_json_utils.py b/mhr_api/src/mhr_api/models/registration_json_utils.py index edae089bd..b341a9781 100644 --- a/mhr_api/src/mhr_api/models/registration_json_utils.py +++ b/mhr_api/src/mhr_api/models/registration_json_utils.py @@ -93,7 +93,8 @@ def set_permit_json(registration, reg_json: dict) -> dict: # pylint: disable=to permit_ts = reg.registration_ts # current_app.logger.debug(f'set_permit # {permit_number}') # Registrations are in chronological order: get the latest permit, use latest amendment status, expiry. - if reg.documents[0].document_type in (MhrDocumentTypes.REG_103, MhrDocumentTypes.AMEND_PERMIT): + if reg.documents[0].document_type in (MhrDocumentTypes.REG_103, MhrDocumentTypes.REG_103E, + MhrDocumentTypes.AMEND_PERMIT): if reg.notes: permit_status = reg.notes[0].status_type expiry_ts = reg.notes[0].expiry_date diff --git a/mhr_api/src/mhr_api/models/registration_utils.py b/mhr_api/src/mhr_api/models/registration_utils.py index 8623fc2d9..ed048a2f8 100644 --- a/mhr_api/src/mhr_api/models/registration_utils.py +++ b/mhr_api/src/mhr_api/models/registration_utils.py @@ -806,8 +806,10 @@ def __build_summary(row, account_id: str, staff: bool, add_in_user_list: bool = summary = __get_cancel_info(summary, row) elif doc_type in (MhrDocumentTypes.CAU, MhrDocumentTypes.CAUC, MhrDocumentTypes.CAUE): summary = __get_caution_info(summary, row, doc_type) - elif doc_type in (MhrDocumentTypes.REG_103, MhrDocumentTypes.AMEND_PERMIT) and row[12] and \ - (not row[11] or row[11] != MhrNoteStatusTypes.CANCELLED): + elif doc_type in (MhrDocumentTypes.REG_103, + MhrDocumentTypes.REG_103E, + MhrDocumentTypes.AMEND_PERMIT) and row[12] and \ + (not row[11] or row[11] not in (MhrNoteStatusTypes.CANCELLED, MhrNoteStatusTypes.COMPLETED)): expiry = row[12] summary['expireDays'] = model_utils.expiry_ts_days(expiry) summary = __set_frozen_status(summary, row, staff) @@ -906,11 +908,6 @@ def __collapse_results(results): has_caution = True changes.append(result) if changes: - # for change_reg in changes: - # if not change_reg.get('ownerNames'): - # change_reg['ownerNames'] = __get_previous_owner_names(changes, - # owner_names, - # change_reg.get('documentId')) reg['changes'] = changes reg['hasCaution'] = has_caution return registrations diff --git a/mhr_api/src/mhr_api/reports/v2/report.py b/mhr_api/src/mhr_api/reports/v2/report.py index 9dd84f442..2c8805479 100755 --- a/mhr_api/src/mhr_api/reports/v2/report.py +++ b/mhr_api/src/mhr_api/reports/v2/report.py @@ -178,7 +178,8 @@ def get_registration_staff_pdf(self): self._report_key = ReportTypes.MHR_EXEMPTION elif self._report_data.get('nocLocation'): self._report_key = ReportTypes.MHR_ADMIN_REGISTRATION - elif self._report_data.get('registrationType', '') == MhrRegistrationTypes.PERMIT: + elif self._report_data.get('registrationType', '') in (MhrRegistrationTypes.PERMIT, + MhrRegistrationTypes.PERMIT_EXTENSION): self._report_key = ReportTypes.MHR_TRANSPORT_PERMIT elif self._report_data.get('registrationType', '') == MhrRegistrationTypes.AMENDMENT and \ self._report_data.get('permitRegistrationNumber') and self._report_data.get('amendment'): @@ -725,7 +726,7 @@ def _set_date_times(self): # pylint: disable=too-many-statements, too-many-bran if reg.get('location') and reg['location'].get('taxExpiryDate'): reg['location']['taxExpiryDate'] = Report._to_report_datetime(reg['location']['taxExpiryDate'], False) - if self._report_key == ReportTypes.MHR_TRANSPORT_PERMIT and reg.get('amendment'): + if self._report_key == ReportTypes.MHR_TRANSPORT_PERMIT and (reg.get('amendment') or reg.get('extension')): if reg.get('permitDateTime'): reg['permitDateTime'] = Report._to_report_datetime(reg['permitDateTime']) reg['permitExpiryDateTime'] = Report._to_report_datetime(reg['permitExpiryDateTime'], False) diff --git a/mhr_api/src/mhr_api/resources/registration_utils.py b/mhr_api/src/mhr_api/resources/registration_utils.py index 43d10cfb2..2e4b695a0 100644 --- a/mhr_api/src/mhr_api/resources/registration_utils.py +++ b/mhr_api/src/mhr_api/resources/registration_utils.py @@ -20,6 +20,7 @@ from mhr_api.exceptions import DatabaseException from mhr_api.models import EventTracking, MhrRegistration, MhrRegistrationReport, SearchResult from mhr_api.models import utils as model_utils, batch_utils, registration_json_utils +import mhr_api.models.registration_change_utils as change_utils from mhr_api.models.registration_utils import ( save_admin, save_cancel_note, @@ -279,7 +280,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(request_json, registration.id) + change_utils.save_permit(current_reg, 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))) @@ -378,7 +379,7 @@ def pay_and_save_admin(req: request, # pylint: disable=too-many-arguments MhrDocumentTypes.PUBA): save_admin(current_reg, request_json, registration.id) elif request_json.get('documentType') == MhrDocumentTypes.CANCEL_PERMIT and current_reg: - current_reg.save_permit(request_json, registration.id) + change_utils.save_permit(current_reg, 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))) diff --git a/mhr_api/src/mhr_api/resources/v1/permits.py b/mhr_api/src/mhr_api/resources/v1/permits.py index 655a26704..1c955b1e5 100644 --- a/mhr_api/src/mhr_api/resources/v1/permits.py +++ b/mhr_api/src/mhr_api/resources/v1/permits.py @@ -106,7 +106,7 @@ def post_permits(mhr_number: str): # pylint: disable=too-many-return-statements response_json['description'] = current_json.get('description') response_json['status'] = current_json.get('status') response_json['ownerGroups'] = current_json.get('ownerGroups') - if response_json.get('amendment'): + if response_json.get('amendment') or response_json.get('extension'): response_json['permitRegistrationNumber'] = current_json.get('permitRegistrationNumber', '') response_json['permitDateTime'] = current_json.get('permitDateTime', '') response_json['permitExpiryDateTime'] = current_json.get('permitExpiryDateTime', '') @@ -155,6 +155,8 @@ def get_transaction_type(request_json) -> str: tran_type: str = TransactionTypes.TRANSPORT_PERMIT if 'amendment' in request_json and request_json.get('amendment'): tran_type = TransactionTypes.AMEND_PERMIT + elif 'extension' in request_json and request_json.get('extension'): + tran_type = TransactionTypes.TRANSPORT_PERMIT_EXT return tran_type @@ -181,7 +183,7 @@ def get_qs_location(request_json: dict, group: str, account_id: str) -> dict: return request_json qs_location: dict = None if group == MANUFACTURER_GROUP: - manufacturer = MhrManufacturer.find_by_account_id(account_id) + manufacturer: MhrManufacturer = MhrManufacturer.find_by_account_id(account_id) if manufacturer: man_json = manufacturer.json qs_location = man_json.get('location') diff --git a/mhr_api/src/mhr_api/utils/registration_validator.py b/mhr_api/src/mhr_api/utils/registration_validator.py index 5dc4c6659..e5598a4b6 100644 --- a/mhr_api/src/mhr_api/utils/registration_validator.py +++ b/mhr_api/src/mhr_api/utils/registration_validator.py @@ -110,6 +110,8 @@ DEALER_TRANSFER_OWNER_INVALID = 'QS dealer transfer invalid: either current owner group is not SOLE or the owner ' + \ 'name does not match the qualified supplier account name. ' TRANSFER_DATE_FUTURE = 'The transfer date of execution (transferDate) cannot be in the future. ' +EXTEND_PERMIT_EXISTS_INVALID = 'For qualified suppliers a transport permit can only be extended once. ' +EXTEND_PERMIT_INVALID = 'Extend transport permit not allowed: no active tansport permit exists. ' PPR_SECURITY_AGREEMENT = ' SA TA TG TM ' @@ -238,6 +240,11 @@ def validate_permit(registration: MhrRegistration, if json_data.get('amendment'): error_msg += validator_utils.validate_registration_state(registration, staff, MhrRegistrationTypes.PERMIT, MhrDocumentTypes.AMEND_PERMIT) + elif json_data.get('extension'): + error_msg += validator_utils.validate_registration_state(registration, + staff, + MhrRegistrationTypes.PERMIT_EXTENSION, + MhrDocumentTypes.REG_103E) else: error_msg += validator_utils.validate_registration_state(registration, staff, @@ -252,8 +259,12 @@ def validate_permit(registration: MhrRegistration, current_location.get('locationType', '') != MhrLocationTypes.MANUFACTURER: error_msg += MANUFACTURER_DEALER_INVALID error_msg += validator_utils.validate_draft_state(json_data) - error_msg += validate_permit_location(json_data, current_location, staff) - error_msg += validate_amend_permit(registration, json_data) + if json_data.get('extension'): + error_msg += validate_permit_extended_tax(json_data, staff) + error_msg += validate_extend_permit(registration, staff) + else: + error_msg += validate_permit_location(json_data, current_location, staff) + error_msg += validate_amend_permit(registration, json_data) if group_name and group_name == DEALERSHIP_GROUP and not json_data.get('qsLocation'): error_msg += PERMIT_QS_INFO_MISSING except Exception as validation_exception: # noqa: B902; eat all errors @@ -262,6 +273,20 @@ def validate_permit(registration: MhrRegistration, return error_msg +def validate_extend_permit(registration: MhrRegistration, staff): + """Perform all extra extend transport permit data validation checks.""" + error_msg = '' + if not validator_utils.has_active_permit(registration): + error_msg += EXTEND_PERMIT_INVALID + if registration.change_registrations and not staff: + for reg in registration.change_registrations: + if reg.notes and reg.notes[0] and reg.notes[0].status_type == MhrNoteStatusTypes.ACTIVE and \ + reg.notes[0].document_type == MhrDocumentTypes.REG_103E and not reg.notes[0].is_expired(): + error_msg += EXTEND_PERMIT_EXISTS_INVALID + break + return error_msg + + def validate_amend_permit(registration: MhrRegistration, json_data): """Perform all extra amend transport permit data validation checks.""" error_msg = '' @@ -321,6 +346,27 @@ def validate_exemption_note(json_data: dict, reg_type: str) -> str: # pylint: d return error_msg +def validate_permit_extended_tax(json_data: dict, staff: bool) -> str: + """Validate transport permit extension tax informaiton for non-staff.""" + error_msg = '' + if staff or not json_data.get('newLocation'): # Skip for staff. + return error_msg + location = json_data.get('newLocation') + if 'taxCertificate' not in location: + return error_msg + if location.get('taxCertificate'): + if location.get('taxExpiryDate'): + tax_ts = model_utils.ts_from_iso_format(location.get('taxExpiryDate')) + current_ts = model_utils.now_ts() + if not model_utils.valid_tax_cert_date(current_ts, tax_ts): + error_msg += validator_utils.LOCATION_TAX_DATE_INVALID + if tax_ts.year != current_ts.year: + error_msg += validator_utils.LOCATION_TAX_DATE_INVALID_QS + else: + error_msg += validator_utils.LOCATION_TAX_CERT_REQUIRED + return error_msg + + def validate_permit_location(json_data: dict, current_location: dict, staff: bool): """Perform all transport permit location validation checks not covered by schema validation.""" error_msg: str = '' diff --git a/mhr_api/src/mhr_api/utils/validator_utils.py b/mhr_api/src/mhr_api/utils/validator_utils.py index 6378d8c77..f44c57b5c 100644 --- a/mhr_api/src/mhr_api/utils/validator_utils.py +++ b/mhr_api/src/mhr_api/utils/validator_utils.py @@ -95,7 +95,6 @@ GROUP_COMMON_INVALID = 'More than 1 group is required with the Tenants in Common owner group type. ' ADD_SOLE_OWNER_INVALID = 'Only one sole owner and only one sole owner group can be added. ' CANCEL_PERMIT_INVALID = 'Cancel Transport Permit not allowed: no active, non-expired transport permit exists. ' - PPR_REG_TYPE_ALL = ' SA_TAX TA_TAX TM_TAX ' PPR_REG_TYPE_GOV = ' SA_GOV TA_GOV TM_GOV ' PPR_REG_TYPE_EXEMPTION = PPR_REG_TYPE_ALL + PPR_REG_TYPE_GOV + ' FR LT ML MN SG ' @@ -176,7 +175,7 @@ def validate_registration_state(reg: MhrRegistration, # pylint: disable=too-man if reg_type and reg_type in (MhrRegistrationTypes.EXEMPTION_NON_RES, MhrRegistrationTypes.EXEMPTION_RES): return validate_registration_state_exemption(reg, reg_type, staff) if reg_type and reg_type == MhrRegistrationTypes.PERMIT: # Prevent if active permit exists. - if not doc_type or doc_type != MhrDocumentTypes.AMEND_PERMIT: + if not doc_type or doc_type not in (MhrDocumentTypes.AMEND_PERMIT, MhrDocumentTypes.REG_103E): error_msg += validate_no_active_permit(reg, reg_json) if reg.status_type != MhrRegistrationStatusTypes.ACTIVE: if doc_type and doc_type == MhrDocumentTypes.EXRE: @@ -188,7 +187,7 @@ def validate_registration_state(reg: MhrRegistration, # pylint: disable=too-man doc_type == MhrDocumentTypes.CANCEL_PERMIT and reg.change_registrations: return check_state_cancel_permit(reg, error_msg) elif reg.status_type == MhrRegistrationStatusTypes.EXEMPT and doc_type and \ - doc_type == MhrDocumentTypes.AMEND_PERMIT and reg.change_registrations: + doc_type in (MhrDocumentTypes.AMEND_PERMIT, MhrDocumentTypes.REG_103E) and reg.change_registrations: return check_exempt_permit(reg, staff, error_msg) elif reg.status_type == MhrRegistrationStatusTypes.CANCELLED or \ doc_type is None or \ @@ -864,7 +863,8 @@ def has_active_permit(registration: MhrRegistration) -> bool: return False for reg in registration.change_registrations: if reg.notes and reg.notes[0] and reg.notes[0].status_type == MhrNoteStatusTypes.ACTIVE and \ - reg.notes[0].document_type in (MhrDocumentTypes.REG_103, MhrDocumentTypes.AMEND_PERMIT) and \ + reg.notes[0].document_type in (MhrDocumentTypes.REG_103, MhrDocumentTypes.REG_103E, + MhrDocumentTypes.AMEND_PERMIT) and \ not reg.notes[0].is_expired(): return True return False diff --git a/mhr_api/src/mhr_api/version.py b/mhr_api/src/mhr_api/version.py index f0136d15d..d46ee4360 100644 --- a/mhr_api/src/mhr_api/version.py +++ b/mhr_api/src/mhr_api/version.py @@ -22,4 +22,4 @@ Development release segment: .devN """ -__version__ = '1.8.24' # pylint: disable=invalid-name +__version__ = '1.8.25' # pylint: disable=invalid-name diff --git a/mhr_api/tests/unit/api/test_permits.py b/mhr_api/tests/unit/api/test_permits.py index e790dfa26..26283e01e 100644 --- a/mhr_api/tests/unit/api/test_permits.py +++ b/mhr_api/tests/unit/api/test_permits.py @@ -138,6 +138,11 @@ ('Valid staff', '000931', STAFF_ROLES, HTTPStatus.CREATED, 'PS12345', True), ('Valid non-staff ', '000931', QUALIFIED_USER_ROLES, HTTPStatus.CREATED, 'PS12345', False) ] +# testdata pattern is ({description}, {mhr_num}, {roles}, {status}, {account}, {ownland}) +TEST_EXTEND_DATA = [ + ('Valid staff', '000931', STAFF_ROLES, HTTPStatus.CREATED, 'PS12345', True), + ('Valid non-staff ', '000931', QUALIFIED_USER_ROLES, HTTPStatus.CREATED, 'PS12345', False) +] @pytest.mark.parametrize('desc,mhr_num,roles,status,account,ownland', TEST_CREATE_DATA) @@ -251,6 +256,59 @@ def test_amend(session, client, jwt, desc, mhr_num, roles, status, account, ownl assert 'ownLand' in reg_json +@pytest.mark.parametrize('desc,mhr_num,roles,status,account,ownland', TEST_EXTEND_DATA) +def test_extend(session, client, jwt, desc, mhr_num, roles, status, account, ownland): + """Assert that a post MH transport permit extension registration works as expected.""" + # setup + current_app.config.update(PAYMENT_SVC_URL=MOCK_PAY_URL) + current_app.config.update(AUTH_SVC_URL=MOCK_AUTH_URL) + headers = None + json_data = copy.deepcopy(PERMIT) + json_data['ownLand'] = ownland + if STAFF_ROLE in roles: + json_data['documentId'] = DOC_ID_VALID + else: + del json_data['documentId'] + json_data['mhrNumber'] = mhr_num + json_data['newLocation'] = LOCATION_OTHER + json_data['extension'] = True + if account: + headers = create_header_account(jwt, roles, 'UT-TEST', account) + else: + headers = create_header(jwt, roles) + if status == HTTPStatus.CREATED: + json_data['newLocation']['taxExpiryDate'] = get_valid_tax_cert_dt() + + # test + response = client.post('/api/v1/permits/' + mhr_num, + json=json_data, + headers=headers, + content_type='application/json') + + # check + # current_app.logger.info(response.json) + assert response.status_code == status + if response.status_code == HTTPStatus.CREATED: + resp_json = response.json + doc_id = resp_json.get('documentId') + assert doc_id + doc: MhrDocument = MhrDocument.find_by_document_id(doc_id) + assert doc + assert resp_json.get('extension') + assert resp_json.get('permitRegistrationNumber') + assert resp_json.get('permitDateTime') + assert resp_json.get('permitStatus') + assert resp_json.get('permitExpiryDateTime') + reg_report: MhrRegistrationReport = MhrRegistrationReport.find_by_registration_id(doc.registration_id) + assert reg_report + assert reg_report.batch_registration_data + registration: MhrRegistration = MhrRegistration.find_all_by_mhr_number(response.json['mhrNumber'], account) + assert registration + registration.current_view = True + reg_json = registration.new_registration_json + assert 'ownLand' in reg_json + + def get_valid_tax_cert_dt() -> str: """Create a valid tax certificate expiry date in the ISO format.""" now = model_utils.now_ts() diff --git a/mhr_api/tests/unit/models/test_mhr_registration.py b/mhr_api/tests/unit/models/test_mhr_registration.py index a0f1a48bd..8c384cf0a 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, batch_utils +from mhr_api.models import registration_change_utils as change_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 @@ -1192,7 +1193,9 @@ def test_save_exemption(session, mhr_num, user_group, account_id): 'userid', user_group) registration.save() - base_reg.save_exemption(registration.id) + # base_reg.save_exemption(registration.id) + change_utils.save_exemption(base_reg, registration.id) + reg_new = MhrRegistration.find_by_mhr_number(registration.mhr_number, account_id, False, @@ -1302,7 +1305,7 @@ def test_save_permit(session, mhr_num, user_group, account_id): 'userid', user_group) registration.save() - base_reg.save_permit(json_data, registration.id) + change_utils.save_permit(base_reg, json_data, registration.id) reg_new = MhrRegistration.find_by_mhr_number(registration.mhr_number, account_id, False, diff --git a/mhr_api/tests/unit/utils/test_permit_validator.py b/mhr_api/tests/unit/utils/test_permit_validator.py index b5cd8bb67..b69ea63c0 100644 --- a/mhr_api/tests/unit/utils/test_permit_validator.py +++ b/mhr_api/tests/unit/utils/test_permit_validator.py @@ -426,6 +426,17 @@ ('Invalid non-staff past', False, False, -1, validator_utils.LOCATION_TAX_DATE_INVALID, '000900', 'PS12345', REQUEST_TRANSPORT_PERMIT) ] +# test data pattern is ({description}, {valid}, {staff}, {message_content}, {mhr_num}, {account}, {group}) +TEST_EXTEND_PERMIT_DATA = [ + ('Valid staff tax cert', True, True, None, '000931', 'PS12345', STAFF_ROLE), + ('Valid non-staff tax cert', True, False, None, '000931', 'PS12345', QUALIFIED_USER_GROUP), + ('Valid staff', True, True, None, '000931', 'PS12345', STAFF_ROLE), + ('Valid non-staff', True, False, None, '000931', 'PS12345', QUALIFIED_USER_GROUP), + ('Invalid no permit', False, True, validator.EXTEND_PERMIT_INVALID, '000900', 'PS12345', STAFF_ROLE), + ('Invalid permit expired', False, True, validator.EXTEND_PERMIT_INVALID, '000930', 'PS12345', STAFF_ROLE), + ('Invalid non-staff EXEMPT', False, False, validator_utils.EXEMPT_PERMIT_INVALID, '000931', 'PS12345', + QUALIFIED_USER_GROUP) +] @pytest.mark.parametrize('desc,valid,staff,doc_id,message_content,mhr_num,account,group', TEST_PERMIT_DATA) @@ -552,6 +563,41 @@ def test_validate_amend_location(session, desc, valid, staff, mhr_num, street, c assert error_msg.find(message_content) != -1 +@pytest.mark.parametrize('desc,valid,staff,message_content,mhr_num,account,group', TEST_EXTEND_PERMIT_DATA) +def test_validate_extend_permit(session, desc, valid, staff, message_content, mhr_num, account, group): + """Assert that extend MH transport permit validation works as expected.""" + # setup + json_data = get_valid_registration() + json_data['documentId'] = DOC_ID_VALID + json_data['extension'] = True + if desc in ('Valid staff tax cert', 'Valid non-staff tax cert'): + json_data['newLocation']['taxExpiryDate'] = get_valid_tax_cert_dt() + else: + if 'taxExpiryDate' in json_data['newLocation']: + del json_data['newLocation']['taxExpiryDate'] + if 'taxCertificate' in json_data['newLocation']: + del json_data['newLocation']['taxCertificate'] + + # 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) + if desc in ('Valid staff EXEMPT', 'Invalid non-staff EXEMPT'): + registration.status_type = MhrRegistrationStatusTypes.EXEMPT + + error_msg = validator.validate_permit(registration, json_data, account, 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."""