Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MDS-5947] Added ability to link a CRR to a HSRC code in core #3106

Merged
merged 3 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition!

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
Loading