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 %}
-
{% 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."""