Skip to content

Commit

Permalink
[MDS-5947] Added ability to link a CRR to a HSRC code in core (#3106)
Browse files Browse the repository at this point in the history
* MDS-5947 Added support for linking CRRs to code sections

* Updated snasphost

* MDS-5947 Fixed error when not including linked reports
  • Loading branch information
simensma-fresh authored May 22, 2024
1 parent d5ef5fd commit cb0f9fc
Show file tree
Hide file tree
Showing 16 changed files with 567 additions and 182 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { formatComplianceCodeReportName } from "@mds/common/redux/utils/helpers";
import React, { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { Field } from "redux-form";

import { getMineReportDefinitionOptions } from "@mds/common/redux/selectors/staticContentSelectors";

import RenderSelect from "../forms/RenderSelect";
import { uniqBy } from "lodash";
import moment from "moment";

export interface ReportDefinitionFieldSelectProps {
id: string;
name: string;
label?: string;
disabled?: boolean;
required?: boolean;
placeholder?: string;
validate?: any[];
}

export const ReportDefinitionFieldSelect = (props: ReportDefinitionFieldSelectProps) => {
const mineReportDefinitionOptions = useSelector(getMineReportDefinitionOptions);

const [formattedMineReportDefinitionOptions, setFormatMineReportDefinitionOptions] = useState([]);

useEffect(() => {
// Format the mine report definition options for the search bar
const newFormattedMineReportDefinitionOptions = mineReportDefinitionOptions
.filter((m) => {
// Only include reports that are linked to a compliance code that have expired
// Reason: A report definition can only be linked to a single compliance code as it currently stands
return !m.compliance_articles.find((c) => moment().isBefore(moment(c.expiry_date)));
})
.map((report) => {
return {
label: formatComplianceCodeReportName(report),
value: report.mine_report_definition_guid,
};
})
.sort((a, b) => a.label.localeCompare(b.label));
setFormatMineReportDefinitionOptions(uniqBy(newFormattedMineReportDefinitionOptions, "value"));
}, [mineReportDefinitionOptions]);

return (
<Field
component={RenderSelect}
id={props.id}
name={props.name}
label={props.label || "Report Name"}
disabled={props.disabled || false}
props={{
data: formattedMineReportDefinitionOptions,
}}
required={props.required || false}
placeholder={props.placeholder || "Select a report type"}
validate={props.validate || undefined}
/>
);
};
3 changes: 3 additions & 0 deletions services/common/src/interfaces/complianceArticle.interface.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { IMineReportDefinition } from "./reports";

export interface IComplianceArticle {
compliance_article_id: number;
articleNumber?: string;
Expand All @@ -13,4 +15,5 @@ export interface IComplianceArticle {
expiry_date: Date;
help_reference_link: string;
cim_or_cpo: string;
reports: IMineReportDefinition[];
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
from flask_restx import Resource, inputs, reqparse
from datetime import datetime
from app.api.compliance.models.compliance_article import ComplianceArticle
from app.api.mines.reports.models.mine_report_definition import MineReportDefinition
from app.api.compliance.response_models import COMPLIANCE_ARTICLE_MODEL
from app.api.utils.resources_mixins import UserMixin
from app.extensions import api
from app.api.utils.access_decorators import EDIT_CODE, requires_any_of
from werkzeug.exceptions import BadRequest

from app.api.exports.static_content.cache_service import reset_static_content_cache

class ComplianceArticleCreateResource(Resource, UserMixin):
parser = reqparse.RequestParser()
reports_parser = reqparse.RequestParser()

parser.add_argument(
'article_act_code',
Expand Down Expand Up @@ -89,6 +91,14 @@ class ComplianceArticleCreateResource(Resource, UserMixin):
location='json',
)

parser.add_argument(
'reports',
type=list,
location='json',
store_missing=False,
required=False
)

@api.doc(description='Create a new Compliance Article.')
@api.expect(parser)
@api.marshal_with(COMPLIANCE_ARTICLE_MODEL, code=201)
Expand All @@ -108,6 +118,10 @@ def post(self):
effective_date = data.get('effective_date')
expiry_date = data.get('expiry_date')


reports = data.get('reports')


compliance_article = ComplianceArticle.find_existing_compliance_article(article_act_code, section, sub_section,
paragraph,
sub_paragraph,
Expand All @@ -126,5 +140,17 @@ def post(self):
expiry_date,
help_reference_link,
cim_or_cpo)


if reports is not None and len(reports):
report_guids = [r.get('mine_report_definition_guid') for r in reports]
reports = MineReportDefinition.find_by_mine_report_definition_many(report_guids)

new_compliance_article.reports = reports
new_compliance_article.save()

# Mine report definitions are cached for 60min by the API as they're rarely updated
# Manually clear the cache to apply the changes immediately
reset_static_content_cache()

return new_compliance_article, 201
17 changes: 16 additions & 1 deletion services/core-api/app/api/compliance/response_models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
from app.extensions import api
from flask_restx import fields

MINE_REPORT_DEFINITION_BASE_MODEL = api.model(
'MineReportDefinitionBase', {
'mine_report_definition_guid': fields.String,
'report_name': fields.String,
'description': fields.String,
'due_date_period_months': fields.Integer,
'mine_report_due_date_type': fields.String,
'default_due_date': fields.Date,
'active_ind': fields.Boolean,
'is_common': fields.Boolean,
'is_prr_only': fields.Boolean,
})


COMPLIANCE_ARTICLE_MODEL = api.model(
'ComplianceArticle', {
'compliance_article_id': fields.Integer,
Expand All @@ -14,7 +28,8 @@
'effective_date': fields.Date,
'expiry_date': fields.Date,
'help_reference_link': fields.String,
'cim_or_cpo': fields.String
'cim_or_cpo': fields.String,
'reports': fields.List(fields.Nested(MINE_REPORT_DEFINITION_BASE_MODEL))
})

COMPLIANCE_ARTICLE_UPDATE_MODEL = api.model(
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

from app.extensions import cache
from app.api.constants import STATIC_CONTENT_KEY

def reset_static_content_cache():
cache.delete(STATIC_CONTENT_KEY)
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ class MineReportDefinition(Base, AuditMixin):
compliance_articles = db.relationship(
'ComplianceArticle',
lazy='selectin',
secondary='mine_report_definition_compliance_article_xref')
secondary='mine_report_definition_compliance_article_xref',
backref='reports'
)

def __repr__(self):
return '<MineReportDefinition %r>' % self.mine_report_definition_guid
Expand All @@ -52,6 +54,13 @@ def find_by_mine_report_definition_id(cls, _id):
except ValueError:
return None

@classmethod
def find_by_mine_report_definition_many(cls, _guids):
try:
return cls.query.filter(cls.mine_report_definition_guid.in_(_guids)).all()
except ValueError:
return None

@classmethod
def find_by_mine_report_definition_guid(cls, _id):
try:
Expand Down
9 changes: 6 additions & 3 deletions services/core-api/app/api/mines/response_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -762,8 +762,8 @@ def format(self, value):
'active_ind': fields.Boolean
})

MINE_REPORT_DEFINITION_MODEL = api.model(
'MineReportDefinition', {
MINE_REPORT_DEFINITION_BASE_MODEL = api.model(
'MineReportDefinitionBase', {
'mine_report_definition_guid': fields.String,
'report_name': fields.String,
'description': fields.String,
Expand All @@ -772,11 +772,14 @@ def format(self, value):
'default_due_date': fields.Date,
'active_ind': fields.Boolean,
'categories': fields.List(fields.Nested(MINE_REPORT_DEFINITION_CATEGORIES)),
'compliance_articles': fields.List(fields.Nested(COMPLIANCE_ARTICLE_MODEL)),
'is_common': fields.Boolean,
'is_prr_only': fields.Boolean,
})

MINE_REPORT_DEFINITION_MODEL = api.inherit('MineReportDefinition', MINE_REPORT_DEFINITION_BASE_MODEL, {
'compliance_articles': fields.List(fields.Nested(COMPLIANCE_ARTICLE_MODEL)),
})

PAGINATED_LIST = api.model(
'List', {
'current_page': fields.Integer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useDispatch, useSelector } from "react-redux";
import { change, Field, initialize, reset } from "redux-form";
import SearchOutlined from "@ant-design/icons/SearchOutlined";
import PlusOutlined from "@ant-design/icons/PlusOutlined";
import { Button, Input, Row, Table, Typography } from "antd";
import { Button, Input, Row, Table, Tag, Typography } from "antd";

import CoreTable from "@mds/common/components/common/CoreTable";
import {
Expand All @@ -28,6 +28,9 @@ import {
} from "@mds/common/redux/slices/complianceCodesSlice";
import AuthorizationGuard from "@/HOC/AuthorizationGuard";
import * as Permission from "@/constants/permissions";
import { faLink } from "@fortawesome/pro-light-svg-icons";
import { EMPTY_FIELD } from "@mds/common";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";

const ComplianceCodeManagement: FC = () => {
const dispatch = useDispatch();
Expand Down Expand Up @@ -214,6 +217,23 @@ const ComplianceCodeManagement: FC = () => {
);
},
},
{
title: "Description",
dataIndex: "description",
key: "description",
render: (text, record) => {
return (
<Row justify="space-between">
{text ?? EMPTY_FIELD}{" "}
{!!record.reports?.length && (
<Tag title="Report" className="tag-secondary">
<FontAwesomeIcon icon={faLink} /> Report
</Tag>
)}
</Row>
);
},
},
renderTextColumn("description", "Description"),
{ ...renderDateColumn("effective_date", "Date Active"), width: 150 },
{
Expand Down
Loading

0 comments on commit cb0f9fc

Please sign in to comment.