From 55fa68b2811fbd35fca37297f69a0d68ffcb7fac Mon Sep 17 00:00:00 2001 From: matbusby Date: Tue, 17 Oct 2023 14:32:54 -0600 Subject: [PATCH 1/8] Add history view and comparison feature for Explosives Permits Added a feature to show the history of amendments in an Explosives Permit. This feature provides a clear way to track changes and the reasons for the modifications in the permit overtime. Updates were made in respective models, interfaces and file structures. Code enhancement also includes providing table views and detailed comparisons of permits history for each amendment. This assists users to see differences between various versions of permit and understand the changes that were made. User interface was also improved to allow better navigation. --- bin/setenv.sh | 2 +- .../permits/explosivesPermit.interface.ts | 3 +- .../explosivesPermitAmendment.interface.ts | 6 + .../common/src/interfaces/permits/index.ts | 1 + .../models/explosives_permit.py | 211 +++++---------- .../explosives_permit/response_models.py | 44 +++- .../models/explosives_permit_amendment.py | 2 +- .../resources/explosives_permit_amendment.py | 2 +- .../explosives_permit_amendment_list.py | 2 +- .../response_models.py | 44 +--- .../ExplosivesPermitDiffModal.tsx | 242 ++++++++++++++++++ .../ExplosivesPermit/ExplosivesPermit.tsx | 5 + .../MineExplosivesPermitTable.tsx | 12 +- .../ExplosivesPermitViewModal.tsx | 206 ++++++++++++--- .../styles/components/ExplosivesPermits.scss | 29 ++- .../core-web/src/styles/generic/layout.scss | 4 + 16 files changed, 575 insertions(+), 240 deletions(-) create mode 100644 services/common/src/interfaces/permits/explosivesPermitAmendment.interface.ts create mode 100644 services/core-web/common/components/explosivesPermits/ExplosivesPermitDiffModal.tsx diff --git a/bin/setenv.sh b/bin/setenv.sh index 10fb69b700..47d4339bcb 100755 --- a/bin/setenv.sh +++ b/bin/setenv.sh @@ -37,7 +37,7 @@ function loadExternalSecrets() { echo -e "Make sure you download the OpenShift cli binary (oc) from https://github.com/openshift/okd/releases ?" if [ "$CODESPACES" = "true" ]; then - echo -e "${bold}Do you want to download and install oc? (only accepts 'yes')${normal}" + echo -e "${bold}Do you want to download and install oc? (answering anything except 'yes' will bypass this step)${normal}" read INSTALL_OC if [ "$INSTALL_OC" = "yes" ]; then diff --git a/services/common/src/interfaces/permits/explosivesPermit.interface.ts b/services/common/src/interfaces/permits/explosivesPermit.interface.ts index 21aa62ef9b..b154b4b821 100644 --- a/services/common/src/interfaces/permits/explosivesPermit.interface.ts +++ b/services/common/src/interfaces/permits/explosivesPermit.interface.ts @@ -1,4 +1,4 @@ -import { IMagazine } from "@/index"; +import { IExplosivesPermitAmendment, IMagazine } from "./"; export interface IExplosivesPermit { explosives_permit_id: number; @@ -35,4 +35,5 @@ export interface IExplosivesPermit { documents: any[]; mines_permit_number: string; now_number: string; + explosives_permit_amendments: IExplosivesPermitAmendment[]; } diff --git a/services/common/src/interfaces/permits/explosivesPermitAmendment.interface.ts b/services/common/src/interfaces/permits/explosivesPermitAmendment.interface.ts new file mode 100644 index 0000000000..b6aa1e4d2f --- /dev/null +++ b/services/common/src/interfaces/permits/explosivesPermitAmendment.interface.ts @@ -0,0 +1,6 @@ +import { IExplosivesPermit } from "./"; + +export interface IExplosivesPermitAmendment extends IExplosivesPermit { + explosives_permit_amendment_id: number; + explosives_permit_amendment_guid: string; +} diff --git a/services/common/src/interfaces/permits/index.ts b/services/common/src/interfaces/permits/index.ts index 8b83769faa..1d0c0957e9 100644 --- a/services/common/src/interfaces/permits/index.ts +++ b/services/common/src/interfaces/permits/index.ts @@ -17,3 +17,4 @@ export * from "./updatePermitAmendmentPayload.interface"; export * from "./PermitAmendmentMineDocument.interface"; export * from "./patchPermitNumber.interface"; export * from "./draftPermitAmendment.interface"; +export * from "./explosivesPermitAmendment.interface"; diff --git a/services/core-api/app/api/mines/explosives_permit/models/explosives_permit.py b/services/core-api/app/api/mines/explosives_permit/models/explosives_permit.py index b7ce70994c..0309316641 100644 --- a/services/core-api/app/api/mines/explosives_permit/models/explosives_permit.py +++ b/services/core-api/app/api/mines/explosives_permit/models/explosives_permit.py @@ -1,49 +1,41 @@ -from flask import current_app from datetime import datetime -from pytz import timezone - -from sqlalchemy.dialects.postgresql import UUID -from sqlalchemy.ext.hybrid import hybrid_property -from sqlalchemy.schema import FetchedValue, Sequence -from sqlalchemy import and_, func -from app.api.utils.models_mixins import SoftDeleteMixin, AuditMixin, PermitMixin, Base -from app.extensions import db +# from app.api.mines.explosives_permit_amendment.models.explosives_permit_amendment import ExplosivesPermitAmendment +from app.api.mines.documents.models.mine_document import MineDocument from app.api.mines.explosives_permit.models.explosives_permit_document_type import ExplosivesPermitDocumentType -from app.api.mines.explosives_permit.models.explosives_permit_magazine import ExplosivesPermitMagazine from app.api.mines.explosives_permit.models.explosives_permit_document_xref import ExplosivesPermitDocumentXref -from app.api.mines.documents.models.mine_document import MineDocument +from app.api.mines.explosives_permit.models.explosives_permit_magazine import ExplosivesPermitMagazine from app.api.parties.party.models.party import Party +from app.api.utils.models_mixins import SoftDeleteMixin, AuditMixin, PermitMixin, Base +from app.extensions import db +from flask import current_app +from pytz import timezone +from sqlalchemy import func +from sqlalchemy.dialects.postgresql import UUID +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.schema import FetchedValue, Sequence class ExplosivesPermit(SoftDeleteMixin, AuditMixin, PermitMixin, Base): __tablename__ = 'explosives_permit' - explosives_permit_guid = db.Column( - UUID(as_uuid=True), primary_key=True, server_default=FetchedValue()) - explosives_permit_id = db.Column( - db.Integer, server_default=FetchedValue(), nullable=False, unique=True) + explosives_permit_guid = db.Column(UUID(as_uuid=True), primary_key=True, server_default=FetchedValue()) + explosives_permit_id = db.Column(db.Integer, server_default=FetchedValue(), nullable=False, unique=True) permit_number = db.Column(db.String, unique=True) - explosive_magazines = db.relationship( - 'ExplosivesPermitMagazine', - lazy='select', - primaryjoin='and_(ExplosivesPermitMagazine.explosives_permit_id == ExplosivesPermit.explosives_permit_id, ExplosivesPermitMagazine.explosives_permit_magazine_type_code == "EXP", ExplosivesPermitMagazine.deleted_ind == False)' - ) - detonator_magazines = db.relationship( - 'ExplosivesPermitMagazine', - lazy='select', - primaryjoin='and_(ExplosivesPermitMagazine.explosives_permit_id == ExplosivesPermit.explosives_permit_id, ExplosivesPermitMagazine.explosives_permit_magazine_type_code == "DET", ExplosivesPermitMagazine.deleted_ind == False)' - ) + explosives_permit_amendments = db.relationship('ExplosivesPermitAmendment', lazy='select', + primaryjoin='ExplosivesPermit.explosives_permit_id == ExplosivesPermitAmendment.explosives_permit_id', + back_populates='explosives_permit') + + explosive_magazines = db.relationship('ExplosivesPermitMagazine', lazy='select', + primaryjoin='and_(ExplosivesPermitMagazine.explosives_permit_id == ExplosivesPermit.explosives_permit_id, ExplosivesPermitMagazine.explosives_permit_magazine_type_code == "EXP", ExplosivesPermitMagazine.deleted_ind == False)') + detonator_magazines = db.relationship('ExplosivesPermitMagazine', lazy='select', + primaryjoin='and_(ExplosivesPermitMagazine.explosives_permit_id == ExplosivesPermit.explosives_permit_id, ExplosivesPermitMagazine.explosives_permit_magazine_type_code == "DET", ExplosivesPermitMagazine.deleted_ind == False)') documents = db.relationship('ExplosivesPermitDocumentXref', lazy='select') - mine_documents = db.relationship( - 'MineDocument', - lazy='select', - secondary='explosives_permit_document_xref', - secondaryjoin='and_(foreign(ExplosivesPermitDocumentXref.mine_document_guid) == remote(MineDocument.mine_document_guid), MineDocument.deleted_ind == False)' - ) + mine_documents = db.relationship('MineDocument', lazy='select', secondary='explosives_permit_document_xref', + secondaryjoin='and_(foreign(ExplosivesPermitDocumentXref.mine_document_guid) == remote(MineDocument.mine_document_guid), MineDocument.deleted_ind == False)') mines_act_permit = db.relationship('Permit', lazy='select') now_application_identity = db.relationship('NOWApplicationIdentity', lazy='select') @@ -58,29 +50,10 @@ def issuing_inspector_name(self): return party.name return None - def update(self, - permit_guid, - now_application_guid, - issuing_inspector_party_guid, - mine_manager_mine_party_appt_id, - permittee_mine_party_appt_id, - application_status, - issue_date, - expiry_date, - decision_reason, - is_closed, - closed_reason, - closed_timestamp, - latitude, - longitude, - application_date, - description, - letter_date, - letter_body, - explosive_magazines=[], - detonator_magazines=[], - documents=[], - add_to_session=True): + def update(self, permit_guid, now_application_guid, issuing_inspector_party_guid, mine_manager_mine_party_appt_id, + permittee_mine_party_appt_id, application_status, issue_date, expiry_date, decision_reason, is_closed, + closed_reason, closed_timestamp, latitude, longitude, application_date, description, letter_date, + letter_body, explosive_magazines=[], detonator_magazines=[], documents=[], add_to_session=True): # Update simple properties. self.permit_guid = permit_guid @@ -107,9 +80,7 @@ def update(self, def process_magazines(magazines, updated_magazines, type): # Get the IDs of the updated magazines. - updated_magazines_ids = [ - magazine.get('explosives_permit_magazine_id') for magazine in updated_magazines - ] + updated_magazines_ids = [magazine.get('explosives_permit_magazine_id') for magazine in updated_magazines] # Delete deleted magazines. for magazine in magazines: @@ -145,16 +116,12 @@ def process_magazines(magazines, updated_magazines, type): explosives_permit_document_type_code = doc.get('explosives_permit_document_type_code') mine_document_guid = doc.get('mine_document_guid') if mine_document_guid: - explosives_permit_doc = ExplosivesPermitDocumentXref.find_by_mine_document_guid( - mine_document_guid) + explosives_permit_doc = ExplosivesPermitDocumentXref.find_by_mine_document_guid(mine_document_guid) explosives_permit_doc.explosives_permit_document_type_code = explosives_permit_document_type_code else: - mine_doc = MineDocument( - mine_guid=self.mine_guid, - document_name=doc.get('document_name'), + mine_doc = MineDocument(mine_guid=self.mine_guid, document_name=doc.get('document_name'), document_manager_guid=doc.get('document_manager_guid')) - explosives_permit_doc = ExplosivesPermitDocumentXref( - mine_document_guid=mine_doc.mine_document_guid, + explosives_permit_doc = ExplosivesPermitDocumentXref(mine_document_guid=mine_doc.mine_document_guid, explosives_permit_id=self.explosives_permit_id, explosives_permit_document_type_code=explosives_permit_document_type_code) explosives_permit_doc.mine_document = mine_doc @@ -166,55 +133,48 @@ def process_magazines(magazines, updated_magazines, type): self.decision_timestamp = datetime.utcnow() self.decision_reason = decision_reason - if (self.application_status == 'REC' - or self.application_status == 'APP') and application_status == 'APP': - from app.api.document_generation.resources.explosives_permit_document_resource import ExplosivesPermitDocumentResource - from app.api.mines.explosives_permit.resources.explosives_permit_document_type import ExplosivesPermitDocumentGenerateResource + if (self.application_status == 'REC' or self.application_status == 'APP') and application_status == 'APP': + from app.api.document_generation.resources.explosives_permit_document_resource import \ + ExplosivesPermitDocumentResource + from app.api.mines.explosives_permit.resources.explosives_permit_document_type import \ + ExplosivesPermitDocumentGenerateResource def create_permit_enclosed_letter(): mine = self.mine # TODO: Implement a method in the document type to automatically get all read-only context values. - template_data = { - 'letter_date': letter_date, - 'letter_body': letter_body, + template_data = {'letter_date': letter_date, 'letter_body': letter_body, 'rc_office_email': mine.region.regional_contact_office.email, 'rc_office_phone_number': mine.region.regional_contact_office.phone_number, 'rc_office_fax_number': mine.region.regional_contact_office.fax_number, - 'rc_office_mailing_address_line_1': - mine.region.regional_contact_office.mailing_address_line_1, - 'rc_office_mailing_address_line_2': - mine.region.regional_contact_office.mailing_address_line_2, - 'is_draft': False - } - explosives_permit_document_type = ExplosivesPermitDocumentType.get_with_context( - 'LET', self.explosives_permit_guid) - template_data = explosives_permit_document_type.transform_template_data( - template_data, self) + 'rc_office_mailing_address_line_1': mine.region.regional_contact_office.mailing_address_line_1, + 'rc_office_mailing_address_line_2': mine.region.regional_contact_office.mailing_address_line_2, + 'is_draft': False} + explosives_permit_document_type = ExplosivesPermitDocumentType.get_with_context('LET', + self.explosives_permit_guid) + template_data = explosives_permit_document_type.transform_template_data(template_data, self) token = ExplosivesPermitDocumentGenerateResource.get_explosives_document_generate_token( explosives_permit_document_type.explosives_permit_document_type_code, self.explosives_permit_guid, template_data) # TODO: Remove Logs for generate document current_app.logger.debug( - f'explosives_permit_document_type: {explosives_permit_document_type}, token (create_permit_enclosed_letter): {token}' - ) - return ExplosivesPermitDocumentResource.generate_explosives_permit_document( - token, True, False, False) + f'explosives_permit_document_type: {explosives_permit_document_type}, token (create_permit_enclosed_letter): {token}') + return ExplosivesPermitDocumentResource.generate_explosives_permit_document(token, True, False, + False) def create_issued_permit(): template_data = {'is_draft': False} - explosives_permit_document_type = ExplosivesPermitDocumentType.get_with_context( - 'PER', self.explosives_permit_guid) - template_data = explosives_permit_document_type.transform_template_data( - template_data, self) + explosives_permit_document_type = ExplosivesPermitDocumentType.get_with_context('PER', + self.explosives_permit_guid) + template_data = explosives_permit_document_type.transform_template_data(template_data, self) token = ExplosivesPermitDocumentGenerateResource.get_explosives_document_generate_token( explosives_permit_document_type.explosives_permit_document_type_code, self.explosives_permit_guid, template_data) # TODO: Remove Logs for generate document current_app.logger.debug( - f'explosives_permit_document_type: {explosives_permit_document_type}, token (create_issued_permit): {token}' - ) - return ExplosivesPermitDocumentResource.generate_explosives_permit_document( - token, True, False, False) + f'explosives_permit_document_type: {explosives_permit_document_type}, token (create_issued_permit): {token}') + return ExplosivesPermitDocumentResource.generate_explosives_permit_document(token, True, False, + False) + if self.application_status == 'REC' and application_status == 'APP': self.permit_number = ExplosivesPermit.get_next_permit_number() create_permit_enclosed_letter() @@ -254,28 +214,10 @@ def get_next_permit_number(cls): return func.concat(prefix, next_value) @classmethod - def create(cls, - mine, - permit_guid, - application_date, - originating_system, - latitude, - longitude, - description, - issue_date, - expiry_date, - permit_number, - issuing_inspector_party_guid, - mine_manager_mine_party_appt_id, - permittee_mine_party_appt_id, - is_closed, - closed_reason, - closed_timestamp, - explosive_magazines=[], - detonator_magazines=[], - documents=[], - now_application_guid=None, - add_to_session=True): + def create(cls, mine, permit_guid, application_date, originating_system, latitude, longitude, description, + issue_date, expiry_date, permit_number, issuing_inspector_party_guid, mine_manager_mine_party_appt_id, + permittee_mine_party_appt_id, is_closed, closed_reason, closed_timestamp, explosive_magazines=[], + detonator_magazines=[], documents=[], now_application_guid=None, add_to_session=True): application_number = None received_timestamp = None @@ -297,26 +239,14 @@ def create(cls, closed_reason = None closed_timestamp = None - explosives_permit = cls( - permit_guid=permit_guid, - application_status=application_status, - application_number=application_number, - received_timestamp=received_timestamp, - application_date=application_date, - originating_system=originating_system, - latitude=latitude, - longitude=longitude, - description=description, - issue_date=issue_date, - expiry_date=expiry_date, - permit_number=permit_number, - issuing_inspector_party_guid=issuing_inspector_party_guid, + explosives_permit = cls(permit_guid=permit_guid, application_status=application_status, + application_number=application_number, received_timestamp=received_timestamp, + application_date=application_date, originating_system=originating_system, latitude=latitude, + longitude=longitude, description=description, issue_date=issue_date, expiry_date=expiry_date, + permit_number=permit_number, issuing_inspector_party_guid=issuing_inspector_party_guid, mine_manager_mine_party_appt_id=mine_manager_mine_party_appt_id, - permittee_mine_party_appt_id=permittee_mine_party_appt_id, - is_closed=is_closed, - closed_reason=closed_reason, - closed_timestamp=closed_timestamp, - now_application_guid=now_application_guid) + permittee_mine_party_appt_id=permittee_mine_party_appt_id, is_closed=is_closed, closed_reason=closed_reason, + closed_timestamp=closed_timestamp, now_application_guid=now_application_guid) mine.explosives_permits.append(explosives_permit) @@ -330,12 +260,9 @@ def create(cls, for doc in documents: explosives_permit_document_type_code = doc.get('explosives_permit_document_type_code') - mine_doc = MineDocument( - mine_guid=mine.mine_guid, - document_name=doc.get('document_name'), + mine_doc = MineDocument(mine_guid=mine.mine_guid, document_name=doc.get('document_name'), document_manager_guid=doc.get('document_manager_guid')) - explosives_permit_doc = ExplosivesPermitDocumentXref( - mine_document_guid=mine_doc.mine_document_guid, + explosives_permit_doc = ExplosivesPermitDocumentXref(mine_document_guid=mine_doc.mine_document_guid, explosives_permit_id=explosives_permit.explosives_permit_id, explosives_permit_document_type_code=explosives_permit_document_type_code) explosives_permit_doc.mine_document = mine_doc @@ -351,11 +278,9 @@ def find_by_mine_guid(cls, mine_guid): @classmethod def find_by_explosives_permit_guid(cls, explosives_permit_guid): - return cls.query.filter_by( - explosives_permit_guid=explosives_permit_guid, deleted_ind=False).one_or_none() + return cls.query.filter_by(explosives_permit_guid=explosives_permit_guid, deleted_ind=False).one_or_none() @classmethod def find_permit_number_by_explosives_permit_id(cls, explosives_permit_id): - obj = cls.query.filter_by( - explosives_permit_id=explosives_permit_id, deleted_ind=False).one_or_none() + obj = cls.query.filter_by(explosives_permit_id=explosives_permit_id, deleted_ind=False).one_or_none() return obj.permit_number if obj else None diff --git a/services/core-api/app/api/mines/explosives_permit/response_models.py b/services/core-api/app/api/mines/explosives_permit/response_models.py index 57c94115e8..48cc4ad43b 100644 --- a/services/core-api/app/api/mines/explosives_permit/response_models.py +++ b/services/core-api/app/api/mines/explosives_permit/response_models.py @@ -1,3 +1,5 @@ +from app.api.mines.explosives_permit_amendment.response_models import EXPLOSIVES_PERMIT_AMENDMENT_MAGAZINE_MODEL, \ + EXPLOSIVES_PERMIT_AMENDMENT_DOCUMENT_MODEL from app.extensions import api from flask_restplus import fields from app.api.mines.response_models import MINE_DOCUMENT_MODEL @@ -27,6 +29,45 @@ 'explosives_permit_document_type_code': fields.String }) +EXPLOSIVES_PERMIT_AMENDMENT_MODEL = api.model( + 'ExplosivesPermitAmendment', { + 'explosives_permit_amendment_id': fields.Integer, + 'explosives_permit_amendment_guid': fields.String, + 'mine_guid': fields.String, + 'permit_guid': fields.String, + 'now_application_guid': fields.String, + 'explosives_permit_id': fields.Integer, + 'issuing_inspector_party_guid': fields.String, + 'issuing_inspector_name': fields.String, + 'mine_manager_mine_party_appt_id': fields.Integer, + 'permittee_mine_party_appt_id': fields.Integer, + 'mine_manager_name': fields.String, + 'permittee_name': fields.String, + 'application_status': fields.String, + 'permit_number': fields.String, + 'issue_date': fields.Date, + 'expiry_date': fields.Date, + 'application_number': fields.String, + 'application_date': fields.Date, + 'originating_system': fields.String, + 'received_timestamp': fields.DateTime, + 'decision_timestamp': fields.DateTime, + 'decision_reason': fields.String, + 'latitude': fields.Fixed(decimals=7), + 'longitude': fields.Fixed(decimals=7), + 'is_closed': fields.Boolean, + 'closed_timestamp': fields.DateTime, + 'closed_reason': fields.String, + 'total_detonator_quantity': fields.Integer, + 'total_explosive_quantity': fields.Integer, + 'description': fields.String, + 'explosive_magazines': fields.List(fields.Nested(EXPLOSIVES_PERMIT_AMENDMENT_MAGAZINE_MODEL)), + 'detonator_magazines': fields.List(fields.Nested(EXPLOSIVES_PERMIT_AMENDMENT_MAGAZINE_MODEL)), + 'documents': fields.List(fields.Nested(EXPLOSIVES_PERMIT_AMENDMENT_DOCUMENT_MODEL)), + 'mines_permit_number': fields.String(attribute='mines_act_permit.permit_no'), + 'now_number': fields.String(attribute='now_application_identity.now_number') + }) + EXPLOSIVES_PERMIT_MODEL = api.model( 'ExplosivesPermit', { 'explosives_permit_id': fields.Integer, @@ -62,7 +103,8 @@ 'detonator_magazines': fields.List(fields.Nested(EXPLOSIVES_PERMIT_MAGAZINE_MODEL)), 'documents': fields.List(fields.Nested(EXPLOSIVES_PERMIT_DOCUMENT_MODEL)), 'mines_permit_number': fields.String(attribute='mines_act_permit.permit_no'), - 'now_number': fields.String(attribute='now_application_identity.now_number') + 'now_number': fields.String(attribute='now_application_identity.now_number'), + 'explosives_permit_amendments': fields.List(fields.Nested(EXPLOSIVES_PERMIT_AMENDMENT_MODEL)) }) EXPLOSIVES_PERMIT_STATUS_MODEL = api.model( diff --git a/services/core-api/app/api/mines/explosives_permit_amendment/models/explosives_permit_amendment.py b/services/core-api/app/api/mines/explosives_permit_amendment/models/explosives_permit_amendment.py index eb46873409..fce06e1e93 100644 --- a/services/core-api/app/api/mines/explosives_permit_amendment/models/explosives_permit_amendment.py +++ b/services/core-api/app/api/mines/explosives_permit_amendment/models/explosives_permit_amendment.py @@ -35,7 +35,7 @@ class ExplosivesPermitAmendment(SoftDeleteMixin, AuditMixin, PermitMixin, Base): explosives_permit = db.relationship( 'ExplosivesPermit', primaryjoin='ExplosivesPermit.explosives_permit_id == ExplosivesPermitAmendment.explosives_permit_id', - backref='explosives_permit_amendments' + back_populates='explosives_permit_amendments' ) documents = db.relationship('ExplosivesPermitAmendmentDocumentXref', lazy='select') diff --git a/services/core-api/app/api/mines/explosives_permit_amendment/resources/explosives_permit_amendment.py b/services/core-api/app/api/mines/explosives_permit_amendment/resources/explosives_permit_amendment.py index 3a33098394..483d2ba665 100644 --- a/services/core-api/app/api/mines/explosives_permit_amendment/resources/explosives_permit_amendment.py +++ b/services/core-api/app/api/mines/explosives_permit_amendment/resources/explosives_permit_amendment.py @@ -4,12 +4,12 @@ from werkzeug.exceptions import NotFound from flask_restplus import Resource, inputs +from app.api.mines.explosives_permit.response_models import EXPLOSIVES_PERMIT_AMENDMENT_MODEL from app.api.mines.mine.models.mine import Mine from app.extensions import api from app.api.utils.access_decorators import requires_any_of, VIEW_ALL, MINESPACE_PROPONENT, MINE_ADMIN, requires_role_edit_explosives_permit from app.api.utils.resources_mixins import UserMixin from app.api.utils.custom_reqparser import CustomReqparser -from app.api.mines.explosives_permit_amendment.response_models import EXPLOSIVES_PERMIT_AMENDMENT_MODEL from app.api.mines.explosives_permit_amendment.models.explosives_permit_amendment import ExplosivesPermitAmendment class ExplosivesPermitAmendmentResource(Resource, UserMixin): parser = CustomReqparser() diff --git a/services/core-api/app/api/mines/explosives_permit_amendment/resources/explosives_permit_amendment_list.py b/services/core-api/app/api/mines/explosives_permit_amendment/resources/explosives_permit_amendment_list.py index 1e22680e89..b0868e7b94 100644 --- a/services/core-api/app/api/mines/explosives_permit_amendment/resources/explosives_permit_amendment_list.py +++ b/services/core-api/app/api/mines/explosives_permit_amendment/resources/explosives_permit_amendment_list.py @@ -2,8 +2,8 @@ from werkzeug.exceptions import NotFound from decimal import Decimal +from app.api.mines.explosives_permit.response_models import EXPLOSIVES_PERMIT_AMENDMENT_MODEL from app.api.mines.explosives_permit_amendment.models.explosives_permit_amendment import ExplosivesPermitAmendment -from app.api.mines.explosives_permit_amendment.response_models import EXPLOSIVES_PERMIT_AMENDMENT_MODEL from app.extensions import api from app.api.utils.resources_mixins import UserMixin from app.api.utils.custom_reqparser import CustomReqparser diff --git a/services/core-api/app/api/mines/explosives_permit_amendment/response_models.py b/services/core-api/app/api/mines/explosives_permit_amendment/response_models.py index 63e9546003..84a7e36708 100644 --- a/services/core-api/app/api/mines/explosives_permit_amendment/response_models.py +++ b/services/core-api/app/api/mines/explosives_permit_amendment/response_models.py @@ -1,4 +1,3 @@ -from app.api.mines.explosives_permit.response_models import EXPLOSIVES_PERMIT_MODEL from app.api.mines.response_models import MINE_DOCUMENT_MODEL from app.extensions import api from flask_restplus import fields @@ -25,45 +24,4 @@ EXPLOSIVES_PERMIT_AMENDMENT_DOCUMENT_MODEL = api.inherit('ExplosivesPermitAmendmentDocument', MINE_DOCUMENT_MODEL, { 'explosives_permit_amendment_id': fields.Integer, 'explosives_permit_amendment_document_type_code': fields.String -}) - -EXPLOSIVES_PERMIT_AMENDMENT_MODEL = api.model( - 'ExplosivesPermitAmendment', { - 'explosives_permit_amendment_id': fields.Integer, - 'explosives_permit_amendment_guid': fields.String, - 'mine_guid': fields.String, - 'permit_guid': fields.String, - 'now_application_guid': fields.String, - 'explosives_permit_id': fields.Integer, - 'now_application_guid': fields.String, - 'issuing_inspector_party_guid': fields.String, - 'issuing_inspector_name': fields.String, - 'mine_manager_mine_party_appt_id': fields.Integer, - 'permittee_mine_party_appt_id': fields.Integer, - 'mine_manager_name': fields.String, - 'permittee_name': fields.String, - 'application_status': fields.String, - 'permit_number': fields.String, - 'issue_date': fields.Date, - 'expiry_date': fields.Date, - 'application_number': fields.String, - 'application_date': fields.Date, - 'originating_system': fields.String, - 'received_timestamp': fields.DateTime, - 'decision_timestamp': fields.DateTime, - 'decision_reason': fields.String, - 'latitude': fields.Fixed(decimals=7), - 'longitude': fields.Fixed(decimals=7), - 'is_closed': fields.Boolean, - 'closed_timestamp': fields.DateTime, - 'closed_reason': fields.String, - 'total_detonator_quantity': fields.Integer, - 'total_explosive_quantity': fields.Integer, - 'description': fields.String, - 'explosives_permit': fields.Nested(EXPLOSIVES_PERMIT_MODEL), - 'explosive_magazines': fields.List(fields.Nested(EXPLOSIVES_PERMIT_AMENDMENT_MAGAZINE_MODEL)), - 'detonator_magazines': fields.List(fields.Nested(EXPLOSIVES_PERMIT_AMENDMENT_MAGAZINE_MODEL)), - 'documents': fields.List(fields.Nested(EXPLOSIVES_PERMIT_AMENDMENT_DOCUMENT_MODEL)), - 'mines_permit_number': fields.String(attribute='mines_act_permit.permit_no'), - 'now_number': fields.String(attribute='now_application_identity.now_number') - }) \ No newline at end of file +}) \ No newline at end of file diff --git a/services/core-web/common/components/explosivesPermits/ExplosivesPermitDiffModal.tsx b/services/core-web/common/components/explosivesPermits/ExplosivesPermitDiffModal.tsx new file mode 100644 index 0000000000..a5ac57401e --- /dev/null +++ b/services/core-web/common/components/explosivesPermits/ExplosivesPermitDiffModal.tsx @@ -0,0 +1,242 @@ +import { Button, Modal, Table, Typography } from "antd"; +import React, { FC, useEffect, useState } from "react"; +import { IExplosivesPermit } from "@mds/common"; +import { formatDateTime } from "@common/utils/helpers"; +import { isDate, isEqual } from "lodash"; + +interface ExplosivesPermitDiffModalProps { + explosivesPermit: IExplosivesPermit; + open: boolean; + onCancel: () => void; +} + +interface IPermitDifference { + fieldName: string; + previousValue: any; + currentValue: any; +} + +interface IPermitDifferencesByAmendment { + [amendmentId: string]: IPermitDifference[]; +} + +const ExplosivesPermitDiffModal: FC = ({ + explosivesPermit, + open = false, + onCancel, +}) => { + const [differences, setDifferences] = useState({}); + + const getPermitDifferences = (permit: IExplosivesPermit): IPermitDifferencesByAmendment => { + const permitVersions = [permit, ...permit.explosives_permit_amendments].sort( + (a, b) => a.explosives_permit_amendment_id - b.explosives_permit_amendment_id + ); + + const ignoredFields = ["explosives_permit_amendment_id", "explosives_permit_amendment_guid"]; + + const differences: IPermitDifferencesByAmendment = permitVersions.reduce( + (acc, currAmendment, i) => { + if (i === 0) { + acc["0"] = []; + return acc; + } + + const previousAmendment = permitVersions[i - 1]; + + Object.entries(currAmendment).forEach(([key, newValue]) => { + const oldValue = previousAmendment[key]; + + if ( + (key === "detonator_magazines" || key === "explosive_magazines") && + Array.isArray(newValue) + ) { + for (const [idx, newVal] of newValue.entries()) { + const oldVal = oldValue[idx]; + + if (!isEqual(newVal, oldVal)) { + if (!acc[currAmendment.explosives_permit_amendment_id]) { + acc[currAmendment.explosives_permit_amendment_id] = []; + } + + for (const [magazineKey, magazineValue] of Object.entries(newVal)) { + const oldMagazineValue = oldVal?.[magazineKey]; + const ignoredMagazineFields = [ + "explosives_permit_amendment_magazine_id", + "explosives_permit_amendment_magazine_type_code", + "explosives_permit_magazine_id", + "explosives_permit_magazine_type_code", + ]; + + if ( + magazineValue !== oldMagazineValue && + !ignoredMagazineFields.includes(magazineKey) + ) { + const fieldPrefix = + key === "detonator_magazines" ? "Detonator Magazine" : "Explosive Magazine"; + const diff: IPermitDifference = { + fieldName: `${fieldPrefix} ${idx} - ${magazineKey}`, + previousValue: oldMagazineValue, + currentValue: magazineValue, + }; + acc[currAmendment.explosives_permit_amendment_id].push(diff); + } + } + } + } + + return; + } + + if (typeof newValue === "object" && newValue !== null) { + return; + } + + if (!acc[currAmendment.explosives_permit_amendment_id]) { + acc[currAmendment.explosives_permit_amendment_id] = []; + } + + if (newValue !== oldValue && !ignoredFields.includes(key)) { + const diff: IPermitDifference = { + fieldName: key, + previousValue: oldValue, + currentValue: newValue, + }; + + acc[currAmendment.explosives_permit_amendment_id].push(diff); + } + }); + + const amendmentDocuments = currAmendment.documents.map((doc) => doc.document_name); + if (amendmentDocuments && amendmentDocuments.length > 0) { + acc[currAmendment.explosives_permit_amendment_id].push({ + fieldName: "Documents", + previousValue: [], + currentValue: amendmentDocuments, + }); + } + return acc; + }, + {} + ); + + return differences; + }; + + useEffect(() => { + if (explosivesPermit) { + const differencesList = getPermitDifferences(explosivesPermit); + setDifferences(differencesList); + } + }, [explosivesPermit]); + + const valueOrNoData = (value: any) => { + if (typeof value === "boolean") { + return value ? "True" : "False"; + } + + return value ? value : "No Data"; + }; + + const columns = [ + { + title: "Now Number", + dataIndex: "now_number", + key: "now_number", + }, + { + title: "Status", + key: "is_closed", + render: (record: any) => { + return record.is_closed ? "Closed" : "Open"; + }, + }, + { + title: "Amendment", + key: "order_no", + dataIndex: "order_no", + }, + { + title: "Changes", + dataIndex: "differences", + key: "differences", + render: (differences: IPermitDifference[]) => + differences.map((diff) => ( +
+ {diff.fieldName === "Documents" ? ( +
+ + Files Added: + + {diff.currentValue.map((file: any, index) => ( + + {file} + + ))} +
+ ) : ( +
+ + {diff.fieldName} + + {diff.fieldName !== "None" && ( + + + {valueOrNoData(diff.previousValue)} + + {` => `} + + {valueOrNoData(diff.currentValue)} + + + )} +
+ )} +
+ )), + }, + ]; + + const data = Object.keys(differences) + .map((key: any, index: number) => { + const amendment = explosivesPermit.explosives_permit_amendments.find( + (amendment) => amendment.explosives_permit_amendment_id == key + ); + + const permit = key === "0" ? explosivesPermit : amendment; + + return { + ...permit, + differences: differences[key].length > 0 ? differences[key] : [{ fieldName: "None" }], + order_no: index, + }; + }) + .reverse(); + + return ( + + Close + , + ]} + width={1000} + > + View History + + You are viewing the past history of explosive storage and use permits for this permit ( + Permit # {explosivesPermit.permit_number}) + + + + ); +}; + +export default ExplosivesPermitDiffModal; diff --git a/services/core-web/src/components/mine/ExplosivesPermit/ExplosivesPermit.tsx b/services/core-web/src/components/mine/ExplosivesPermit/ExplosivesPermit.tsx index 783ec4f4c2..c8214aa899 100644 --- a/services/core-web/src/components/mine/ExplosivesPermit/ExplosivesPermit.tsx +++ b/services/core-web/src/components/mine/ExplosivesPermit/ExplosivesPermit.tsx @@ -152,15 +152,20 @@ export const ExplosivesPermit: FC = ({ const handleOpenViewExplosivesPermitModal = (event, record) => { event.preventDefault(); const mine = mines[mineGuid]; + const parentPermit = explosivesPermits.find( + ({ explosives_permit_id }) => explosives_permit_id === record.explosives_permit_id + ); props.openModal({ props: { title: "View Explosives Storage & Use Permit", explosivesPermit: record, + parentPermit, mine, closeModal: props.closeModal, }, content: modalConfig.EXPLOSIVES_PERMIT_VIEW_MODAL, isViewOnly: true, + width: "75vw", }); }; diff --git a/services/core-web/src/components/mine/ExplosivesPermit/MineExplosivesPermitTable.tsx b/services/core-web/src/components/mine/ExplosivesPermit/MineExplosivesPermitTable.tsx index 8043d42bb3..05b9f72e49 100644 --- a/services/core-web/src/components/mine/ExplosivesPermit/MineExplosivesPermitTable.tsx +++ b/services/core-web/src/components/mine/ExplosivesPermit/MineExplosivesPermitTable.tsx @@ -43,11 +43,15 @@ interface MineExplosivesPermitTableProps { const transformRowData = (permits: IExplosivesPermit[]) => { return permits.map((permit) => { + const mostRecentVersion = + permit.explosives_permit_amendments.length > 0 + ? permit.explosives_permit_amendments[permit.explosives_permit_amendments.length - 1] + : permit; return { - ...permit, - key: permit.explosives_permit_guid, - documents: permit.documents, - isExpired: permit.expiry_date && moment(permit.expiry_date).isBefore(), + ...mostRecentVersion, + key: mostRecentVersion.explosives_permit_guid, + documents: mostRecentVersion.documents, + isExpired: mostRecentVersion.expiry_date && moment(mostRecentVersion.expiry_date).isBefore(), }; }); }; diff --git a/services/core-web/src/components/modalContent/ExplosivesPermitViewModal.tsx b/services/core-web/src/components/modalContent/ExplosivesPermitViewModal.tsx index 9b9fc8212c..25e7a5aa55 100644 --- a/services/core-web/src/components/modalContent/ExplosivesPermitViewModal.tsx +++ b/services/core-web/src/components/modalContent/ExplosivesPermitViewModal.tsx @@ -1,6 +1,6 @@ import "@ant-design/compatible/assets/index.css"; -import { Button, Col, Row, Table, Typography } from "antd"; +import { Alert, Button, Col, Row, Table, Typography } from "antd"; import { IExplosivesPermit, IMine } from "@mds/common"; import React, { FC, useEffect, useState } from "react"; import { connect } from "react-redux"; @@ -10,6 +10,7 @@ import Magazine from "@/components/mine/ExplosivesPermit/Magazine"; import { bindActionCreators } from "redux"; import { openDocument } from "@/components/syncfusion/DocumentViewer"; import { downloadFileFromDocumentManager } from "@common/utils/actionlessNetworkCalls"; +import ExplosivesPermitDiffModal from "@common/components/explosivesPermits/ExplosivesPermitDiffModal"; export const getGeneratedDocCategory = (doc: IExplosivesPermit) => { switch (doc.explosives_permit_document_type_code) { @@ -66,6 +67,7 @@ export const supportingDocColumns = [ interface ExplosivesPermitViewModalProps { explosivesPermit: IExplosivesPermit; + parentPermit: IExplosivesPermit; mine: IMine; title: string; closeModal: () => void; @@ -73,29 +75,132 @@ interface ExplosivesPermitViewModalProps { } export const ExplosivesPermitViewModal: FC = (props) => { - const { explosivesPermit, mine, title } = props; + const { explosivesPermit, parentPermit, mine, title } = props; + const amendmentsCount = parentPermit?.explosives_permit_amendments?.length || 0; const [generatedDocs, setGeneratedDocs] = useState([]); const [supportingDocs, setSupportingDocs] = useState([]); + const [currentPermit, setCurrentPermit] = useState(explosivesPermit); + const [openDiffModal, setOpenDiffModal] = useState(false); + + const permitHistoryColumns = [ + { + title: "Issued", + dataIndex: "issue_date", + key: "issue_date", + render: (text) =>
{formatDate(text)}
, + }, + { + title: "Expiry", + dataIndex: "expiry_date", + key: "expiry_date", + render: (text) =>
{formatDate(text)}
, + }, + { + title: "Status", + dataIndex: "is_closed", + key: "is_closed", + render: (text) =>
{text}
, + }, + { + title: "Amendment", + key: "amendment_order", + dataIndex: "amendment_order", + render: (text) =>
{text}
, + }, + { + title: "", + key: "action", + render: (text, record) => { + const recordGuid = record.explosives_permit_guid || record.explosives_permit_amendment_guid; + if ( + recordGuid === currentPermit?.explosives_permit_guid || + recordGuid === currentPermit?.explosives_permit_amendment_guid + ) + return null; + return ( + + ); + }, + }, + ]; + + const transformPermitHistoryData = () => { + const permitHistory = parentPermit.explosives_permit_amendments?.map((permit) => { + return { + ...permit, + issue_date: permit.issue_date, + expiry_date: permit.expiry_date, + is_closed: permit.is_closed ? "Closed" : "Open", + }; + }); + permitHistory.unshift({ + ...parentPermit, + issue_date: parentPermit.issue_date, + expiry_date: parentPermit.expiry_date, + is_closed: parentPermit.is_closed ? "Closed" : "Open", + }); + return permitHistory + .map((amendment, index) => { + return { ...amendment, amendment_order: index }; + }) + .reverse(); + }; useEffect(() => { - if (explosivesPermit) { + if (currentPermit) { const generatedTypes = ["LET", "PER"]; + const allDocs = [ + ...parentPermit?.documents, + ...parentPermit?.explosives_permit_amendments + .map((amendment) => amendment.documents) + .flat(), + ]; setGeneratedDocs( - explosivesPermit.documents.filter((doc) => - generatedTypes.includes(doc.explosives_permit_document_type_code) - ) + allDocs.filter((doc) => generatedTypes.includes(doc.explosives_permit_document_type_code)) ); setSupportingDocs( - explosivesPermit.documents.filter( - (doc) => !generatedTypes.includes(doc.explosives_permit_document_type_code) - ) + allDocs.filter((doc) => !generatedTypes.includes(doc.explosives_permit_document_type_code)) ); } - }, [explosivesPermit]); + }, [currentPermit]); return (
+ {amendmentsCount > 0 && ( + 1 ? "s" : "" + }`} + description={ +
+ Click View History to See all past versions + + +
+ } + type="info" + showIcon + /> + )} Explosive Storage and Use Permit @@ -111,19 +216,17 @@ export const ExplosivesPermitViewModal: FC = (pr
Issue Date - {explosivesPermit.issue_date} + {currentPermit.issue_date}Expiry Date - {explosivesPermit.expiry_date} + {currentPermit.expiry_date} Issuing Inspector - - {explosivesPermit.issuing_inspector_name} - + {currentPermit.issuing_inspector_name} @@ -131,7 +234,7 @@ export const ExplosivesPermitViewModal: FC = (pr Explosives Permit Number - {explosivesPermit.permit_number} + {currentPermit.permit_number}@@ -140,39 +243,39 @@ export const ExplosivesPermitViewModal: FC = (pr Notice of Work Number - {explosivesPermit.now_number} + {currentPermit.now_number} Mine Manager - {explosivesPermit.mine_manager_mine_party_appt_id} + {currentPermit.mine_manager_mine_party_appt_id} Permittee - {explosivesPermit.permittee_mine_party_appt_id} + {currentPermit.permittee_mine_party_appt_id} Application Date - {explosivesPermit.application_date} + {currentPermit.application_date}Other Information - {explosivesPermit.description} + {currentPermit.description} Storage Details Latitude - {explosivesPermit?.latitude} + {currentPermit?.latitude}Longitude - {explosivesPermit?.longitude} + {currentPermit?.longitude} - +
{supportingDocs.length > 0 && ( @@ -203,12 +306,12 @@ export const ExplosivesPermitViewModal: FC = (pr Permit Status -
+ Permit Status - {explosivesPermit.is_closed && ( + {currentPermit.is_closed && ( Date Closed @@ -217,15 +320,15 @@ export const ExplosivesPermitViewModal: FC = (pr )} - + - {explosivesPermit.is_closed ? "Closed" : "Open"} + {currentPermit.is_closed ? "Closed" : "Open"} - - {explosivesPermit.is_closed ? ( + + {currentPermit.is_closed ? ( - {formatDate(explosivesPermit.closed_timestamp)} + {formatDate(currentPermit.closed_timestamp)} ) : ( Reason for Closure- {explosivesPermit.closed_reason} + {currentPermit.closed_reason} )} Explosives Magazines - {explosivesPermit?.explosive_magazines?.length > 0 && - explosivesPermit.explosive_magazines.map((magazine, index) => ( + {currentPermit?.explosive_magazines?.length > 0 && + currentPermit.explosive_magazines.map((magazine, index) => ( = (pr Detonator Magazines - {explosivesPermit?.detonator_magazines?.length > 0 && - explosivesPermit.detonator_magazines.map((magazine, index) => ( + {currentPermit?.detonator_magazines?.length > 0 && + currentPermit.detonator_magazines.map((magazine, index) => ( ))} - - Permit History - + + + + Permit History + + + + + + +
@@ -277,6 +398,11 @@ export const ExplosivesPermitViewModal: FC = (pr Close + setOpenDiffModal(false)} + explosivesPermit={parentPermit} + /> ); }; diff --git a/services/core-web/src/styles/components/ExplosivesPermits.scss b/services/core-web/src/styles/components/ExplosivesPermits.scss index 1cb7053a29..f300417564 100644 --- a/services/core-web/src/styles/components/ExplosivesPermits.scss +++ b/services/core-web/src/styles/components/ExplosivesPermits.scss @@ -25,11 +25,32 @@ } .esup-alert { - background-color: #F4F0F0; - border: 1px solid #6B6363; + background-color: #f4f0f0; + border: 1px solid #6b6363; + margin-bottom: 56px; +} + +.esup-alert .ant-alert-content .ant-alert-description div { + position: relative; +} + +.esup-history-button { + background-color: transparent; + color: black !important; + border: 2px solid $violet; +} + +.esup-alert .ant-alert-content .ant-alert-description div button { + position: absolute; + right: 0; + top: -75%; +} + +.esup-history-button:hover { + background-color: white; } .esup-alert > span > svg { - fill: #6B6363; - background-color: #F4F0F0; + fill: #6b6363; + background-color: #f4f0f0; } diff --git a/services/core-web/src/styles/generic/layout.scss b/services/core-web/src/styles/generic/layout.scss index 93bbfd5b05..ab50fe152d 100644 --- a/services/core-web/src/styles/generic/layout.scss +++ b/services/core-web/src/styles/generic/layout.scss @@ -65,6 +65,10 @@ html { color: $alert-red; } +.green { + color: $ok-green; +} + .right { text-align: right; } From 44e36a94421fd0c7419d20195236974eaafe4276 Mon Sep 17 00:00:00 2001 From: matbusby Date: Tue, 17 Oct 2023 14:57:22 -0600 Subject: [PATCH 2/8] added diff modal to common folder in minespace --- .../ExplosivesPermitDiffModal.tsx | 242 ++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 services/minespace-web/common/components/explosivesPermits/ExplosivesPermitDiffModal.tsx diff --git a/services/minespace-web/common/components/explosivesPermits/ExplosivesPermitDiffModal.tsx b/services/minespace-web/common/components/explosivesPermits/ExplosivesPermitDiffModal.tsx new file mode 100644 index 0000000000..a5ac57401e --- /dev/null +++ b/services/minespace-web/common/components/explosivesPermits/ExplosivesPermitDiffModal.tsx @@ -0,0 +1,242 @@ +import { Button, Modal, Table, Typography } from "antd"; +import React, { FC, useEffect, useState } from "react"; +import { IExplosivesPermit } from "@mds/common"; +import { formatDateTime } from "@common/utils/helpers"; +import { isDate, isEqual } from "lodash"; + +interface ExplosivesPermitDiffModalProps { + explosivesPermit: IExplosivesPermit; + open: boolean; + onCancel: () => void; +} + +interface IPermitDifference { + fieldName: string; + previousValue: any; + currentValue: any; +} + +interface IPermitDifferencesByAmendment { + [amendmentId: string]: IPermitDifference[]; +} + +const ExplosivesPermitDiffModal: FC = ({ + explosivesPermit, + open = false, + onCancel, +}) => { + const [differences, setDifferences] = useState({}); + + const getPermitDifferences = (permit: IExplosivesPermit): IPermitDifferencesByAmendment => { + const permitVersions = [permit, ...permit.explosives_permit_amendments].sort( + (a, b) => a.explosives_permit_amendment_id - b.explosives_permit_amendment_id + ); + + const ignoredFields = ["explosives_permit_amendment_id", "explosives_permit_amendment_guid"]; + + const differences: IPermitDifferencesByAmendment = permitVersions.reduce( + (acc, currAmendment, i) => { + if (i === 0) { + acc["0"] = []; + return acc; + } + + const previousAmendment = permitVersions[i - 1]; + + Object.entries(currAmendment).forEach(([key, newValue]) => { + const oldValue = previousAmendment[key]; + + if ( + (key === "detonator_magazines" || key === "explosive_magazines") && + Array.isArray(newValue) + ) { + for (const [idx, newVal] of newValue.entries()) { + const oldVal = oldValue[idx]; + + if (!isEqual(newVal, oldVal)) { + if (!acc[currAmendment.explosives_permit_amendment_id]) { + acc[currAmendment.explosives_permit_amendment_id] = []; + } + + for (const [magazineKey, magazineValue] of Object.entries(newVal)) { + const oldMagazineValue = oldVal?.[magazineKey]; + const ignoredMagazineFields = [ + "explosives_permit_amendment_magazine_id", + "explosives_permit_amendment_magazine_type_code", + "explosives_permit_magazine_id", + "explosives_permit_magazine_type_code", + ]; + + if ( + magazineValue !== oldMagazineValue && + !ignoredMagazineFields.includes(magazineKey) + ) { + const fieldPrefix = + key === "detonator_magazines" ? "Detonator Magazine" : "Explosive Magazine"; + const diff: IPermitDifference = { + fieldName: `${fieldPrefix} ${idx} - ${magazineKey}`, + previousValue: oldMagazineValue, + currentValue: magazineValue, + }; + acc[currAmendment.explosives_permit_amendment_id].push(diff); + } + } + } + } + + return; + } + + if (typeof newValue === "object" && newValue !== null) { + return; + } + + if (!acc[currAmendment.explosives_permit_amendment_id]) { + acc[currAmendment.explosives_permit_amendment_id] = []; + } + + if (newValue !== oldValue && !ignoredFields.includes(key)) { + const diff: IPermitDifference = { + fieldName: key, + previousValue: oldValue, + currentValue: newValue, + }; + + acc[currAmendment.explosives_permit_amendment_id].push(diff); + } + }); + + const amendmentDocuments = currAmendment.documents.map((doc) => doc.document_name); + if (amendmentDocuments && amendmentDocuments.length > 0) { + acc[currAmendment.explosives_permit_amendment_id].push({ + fieldName: "Documents", + previousValue: [], + currentValue: amendmentDocuments, + }); + } + return acc; + }, + {} + ); + + return differences; + }; + + useEffect(() => { + if (explosivesPermit) { + const differencesList = getPermitDifferences(explosivesPermit); + setDifferences(differencesList); + } + }, [explosivesPermit]); + + const valueOrNoData = (value: any) => { + if (typeof value === "boolean") { + return value ? "True" : "False"; + } + + return value ? value : "No Data"; + }; + + const columns = [ + { + title: "Now Number", + dataIndex: "now_number", + key: "now_number", + }, + { + title: "Status", + key: "is_closed", + render: (record: any) => { + return record.is_closed ? "Closed" : "Open"; + }, + }, + { + title: "Amendment", + key: "order_no", + dataIndex: "order_no", + }, + { + title: "Changes", + dataIndex: "differences", + key: "differences", + render: (differences: IPermitDifference[]) => + differences.map((diff) => ( +
+ {diff.fieldName === "Documents" ? ( +
+ + Files Added: + + {diff.currentValue.map((file: any, index) => ( + + {file} + + ))} +
+ ) : ( +
+ + {diff.fieldName} + + {diff.fieldName !== "None" && ( + + + {valueOrNoData(diff.previousValue)} + + {` => `} + + {valueOrNoData(diff.currentValue)} + + + )} +
+ )} +
+ )), + }, + ]; + + const data = Object.keys(differences) + .map((key: any, index: number) => { + const amendment = explosivesPermit.explosives_permit_amendments.find( + (amendment) => amendment.explosives_permit_amendment_id == key + ); + + const permit = key === "0" ? explosivesPermit : amendment; + + return { + ...permit, + differences: differences[key].length > 0 ? differences[key] : [{ fieldName: "None" }], + order_no: index, + }; + }) + .reverse(); + + return ( + + Close + , + ]} + width={1000} + > + View History + + You are viewing the past history of explosive storage and use permits for this permit ( + Permit # {explosivesPermit.permit_number}) + +
+ + ); +}; + +export default ExplosivesPermitDiffModal; From 1036252c09732e84030063986c3ddd5edb4937ab Mon Sep 17 00:00:00 2001 From: matbusby Date: Tue, 17 Oct 2023 15:04:29 -0600 Subject: [PATCH 3/8] updated amendment model import --- .../resources/test_explosives_permit_amendment_resource.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core-api/tests/mines/explosives_permit_amendment/resources/test_explosives_permit_amendment_resource.py b/services/core-api/tests/mines/explosives_permit_amendment/resources/test_explosives_permit_amendment_resource.py index 673e4f646e..336f0e7871 100644 --- a/services/core-api/tests/mines/explosives_permit_amendment/resources/test_explosives_permit_amendment_resource.py +++ b/services/core-api/tests/mines/explosives_permit_amendment/resources/test_explosives_permit_amendment_resource.py @@ -2,7 +2,7 @@ from tests.factories import ExplosivesPermitAmendmentFactory from flask_restplus import marshal -from app.api.mines.explosives_permit_amendment.response_models import EXPLOSIVES_PERMIT_AMENDMENT_MODEL +from app.api.mines.explosives_permit.response_models import EXPLOSIVES_PERMIT_AMENDMENT_MODEL def test_get_explosives_permit_amendment_by_explosives_permit_amendment_guid(test_client, db_session, auth_headers): From e76278424cfc6f2f73c64e67ae4bf5a471b1592d Mon Sep 17 00:00:00 2001 From: matbusby Date: Tue, 17 Oct 2023 15:31:30 -0600 Subject: [PATCH 4/8] fixed length check --- .../mine/ExplosivesPermit/MineExplosivesPermitTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core-web/src/components/mine/ExplosivesPermit/MineExplosivesPermitTable.tsx b/services/core-web/src/components/mine/ExplosivesPermit/MineExplosivesPermitTable.tsx index 05b9f72e49..a455c45f37 100644 --- a/services/core-web/src/components/mine/ExplosivesPermit/MineExplosivesPermitTable.tsx +++ b/services/core-web/src/components/mine/ExplosivesPermit/MineExplosivesPermitTable.tsx @@ -44,7 +44,7 @@ interface MineExplosivesPermitTableProps { const transformRowData = (permits: IExplosivesPermit[]) => { return permits.map((permit) => { const mostRecentVersion = - permit.explosives_permit_amendments.length > 0 + permit.explosives_permit_amendments?.length > 0 ? permit.explosives_permit_amendments[permit.explosives_permit_amendments.length - 1] : permit; return { From c54cb374193f4dafce20d57ecb2cf4a11e45cfc5 Mon Sep 17 00:00:00 2001 From: matbusby Date: Wed, 18 Oct 2023 15:49:54 -0600 Subject: [PATCH 5/8] used colour variables --- .../core-web/src/styles/components/ExplosivesPermits.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core-web/src/styles/components/ExplosivesPermits.scss b/services/core-web/src/styles/components/ExplosivesPermits.scss index f300417564..dcda946022 100644 --- a/services/core-web/src/styles/components/ExplosivesPermits.scss +++ b/services/core-web/src/styles/components/ExplosivesPermits.scss @@ -25,8 +25,8 @@ } .esup-alert { - background-color: #f4f0f0; - border: 1px solid #6b6363; + background-color: $lightest-grey; + border: 1px solid $mediumGrey; margin-bottom: 56px; } From c3978f1215ac30352b4f2599d48f727db4158621 Mon Sep 17 00:00:00 2001 From: matbusby Date: Wed, 18 Oct 2023 15:52:38 -0600 Subject: [PATCH 6/8] used colour variables --- services/core-web/src/styles/settings/theme.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/services/core-web/src/styles/settings/theme.scss b/services/core-web/src/styles/settings/theme.scss index e6ea3a7ff3..694477822c 100755 --- a/services/core-web/src/styles/settings/theme.scss +++ b/services/core-web/src/styles/settings/theme.scss @@ -7,6 +7,7 @@ $yellow: #f3cd65; $red: #d40d0d; $light-grey: #ded9d9; $lightest-grey: #f4f0f0; +$medium-grey: #6b6363; // Below matches ant design divider colour $layout-grey: #e8e8e8; From cfdba7f3bc4c07f5af309b18978a1ce69b37364d Mon Sep 17 00:00:00 2001 From: matbusby Date: Wed, 18 Oct 2023 15:53:10 -0600 Subject: [PATCH 7/8] used colour variables --- services/core-web/src/styles/components/ExplosivesPermits.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core-web/src/styles/components/ExplosivesPermits.scss b/services/core-web/src/styles/components/ExplosivesPermits.scss index dcda946022..f8a7933f5a 100644 --- a/services/core-web/src/styles/components/ExplosivesPermits.scss +++ b/services/core-web/src/styles/components/ExplosivesPermits.scss @@ -26,7 +26,7 @@ .esup-alert { background-color: $lightest-grey; - border: 1px solid $mediumGrey; + border: 1px solid $medium-grey; margin-bottom: 56px; } From 497db463ab357f94aad93c759af5e4eaa51c07c3 Mon Sep 17 00:00:00 2001 From: matbusby Date: Wed, 18 Oct 2023 15:55:22 -0600 Subject: [PATCH 8/8] used colour variables --- services/minespace-web/src/styles/settings/variables.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/services/minespace-web/src/styles/settings/variables.scss b/services/minespace-web/src/styles/settings/variables.scss index 718e7a5ada..1f120b361b 100755 --- a/services/minespace-web/src/styles/settings/variables.scss +++ b/services/minespace-web/src/styles/settings/variables.scss @@ -5,6 +5,7 @@ // Primary Colours $black: #161616; $darkest-grey: #3c3636; +$lightest-grey: #f4f0f0; $medium-grey: #6b6363; $violet: #5e46a1; $light-violet: #7c66ad;