Skip to content

Commit b75dc55

Browse files
authored
[MDS-6259] Add ability to delete and update permit report requirements (#3391)
* add ability to delete and update permit report requirements * changes based on pr comments * moving getConditionsWithRequirements function
1 parent dd5c931 commit b75dc55

23 files changed

+755
-604
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- Update the cim_or_cpo_type ENUM type
2+
ALTER TYPE cim_or_cpo_type RENAME VALUE 'BOTH' to 'Both';

services/common/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,4 @@
8686
"jest-junit": {
8787
"output": "./coverage/tests-report.xml"
8888
}
89-
}
89+
}

services/common/src/components/common/LinkButton.js

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const propTypes = {
77
children: PropTypes.any,
88
disabled: PropTypes.bool,
99
title: PropTypes.string,
10+
className: PropTypes.string,
1011
};
1112

1213
const defaultProps = {
@@ -22,6 +23,7 @@ const LinkButton = (props) => (
2223
onKeyPress={props.onClick}
2324
tabIndex={props.tabIndex}
2425
disabled={props.disabled}
26+
className={props.className}
2527
{...props}
2628
>
2729
{props.children}

services/common/src/redux/reducers/rootReducerShared.ts

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import searchConditionCategoriesReducer, {
4040
searchConditionCategoriesType,
4141
} from "../slices/permitConditionCategorySlice";
4242
import helpReducer, { helpReducerType } from "../slices/helpSlice";
43+
import mineReportPermitRequirementReducer, { mineReportPermitRequirementReducerType } from "../slices/mineReportPermitRequirementSlice";
4344

4445
const networkReducers = Object.fromEntries(Object.entries(NetworkReducerTypes).map(([key, value]) =>
4546
[NetworkReducerTypes[key], createReducer(networkReducer, value)]
@@ -84,5 +85,6 @@ export const sharedReducer = {
8485
[helpReducerType]: helpReducer,
8586
[searchConditionCategoriesType]: searchConditionCategoriesReducer,
8687
[userReducerType]: userReducer,
88+
[mineReportPermitRequirementReducerType]: mineReportPermitRequirementReducer,
8789
...networkReducers
8890
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import {
2+
deleteMineReportPermitRequirement,
3+
updateMineReportPermitRequirement,
4+
mineReportPermitRequirementReducer
5+
} from "./mineReportPermitRequirementSlice";
6+
import CustomAxios from "@mds/common/redux/customAxios";
7+
import { configureStore } from "@reduxjs/toolkit";
8+
9+
const showLoadingMock = jest
10+
.fn()
11+
.mockReturnValue({ type: "SHOW_LOADING", payload: { show: true } });
12+
const hideLoadingMock = jest
13+
.fn()
14+
.mockReturnValue({ type: "HIDE_LOADING", payload: { show: false } });
15+
const notificationSuccessMock = jest.fn();
16+
17+
jest.mock("@mds/common/redux/customAxios");
18+
jest.mock("react-redux-loading-bar", () => ({
19+
showLoading: () => showLoadingMock,
20+
hideLoading: () => hideLoadingMock,
21+
}));
22+
23+
describe("mineReportPermitRequirementSlice", () => {
24+
let store;
25+
26+
beforeEach(() => {
27+
store = configureStore({
28+
reducer: {
29+
mineReportPermitRequirement: mineReportPermitRequirementReducer,
30+
},
31+
});
32+
});
33+
34+
afterEach(() => {
35+
jest.clearAllMocks();
36+
});
37+
38+
describe("deleteMineReportPermitRequirement", () => {
39+
const mockResponse = {
40+
data: "",
41+
status: 204,
42+
};
43+
44+
it("should successfully delete a report requirement", async () => {
45+
(CustomAxios as jest.Mock).mockImplementation(() => ({
46+
delete: jest.fn().mockResolvedValue(mockResponse),
47+
}));
48+
49+
const payload = {
50+
mineGuid: "f13d66db-8096-4e4b-85b8-6e0d231549fb",
51+
mine_report_permit_requirement_id: 5,
52+
};
53+
54+
await store.dispatch(deleteMineReportPermitRequirement(payload));
55+
56+
// Verify loading state management
57+
expect(showLoadingMock).toHaveBeenCalledTimes(1);
58+
expect(hideLoadingMock).toHaveBeenCalledTimes(1);
59+
60+
expect(CustomAxios).toHaveBeenCalledWith({
61+
errorToastMessage: "default",
62+
successToastMessage: "Successfully deleted report requirement",
63+
});
64+
});
65+
66+
it("should handle API error when deleting a report requirement", async () => {
67+
const error = new Error("API Error");
68+
(CustomAxios as jest.Mock).mockImplementation(() => ({
69+
delete: jest.fn().mockRejectedValue(error),
70+
}));
71+
72+
const payload = {
73+
mineGuid: "f13d66db-8096-4e4b-85b8-6e0d231549fb",
74+
mine_report_permit_requirement_id: 5,
75+
};
76+
77+
await store.dispatch(deleteMineReportPermitRequirement(payload));
78+
79+
expect(notificationSuccessMock).not.toHaveBeenCalled();
80+
});
81+
});
82+
83+
describe("updateMineReportPermitRequirement", () => {
84+
const mockResponse = {
85+
data: {
86+
report_name: null,
87+
mine_report_permit_requirement_id: 5,
88+
due_date_period_months: 6,
89+
initial_due_date: null,
90+
cim_or_cpo: "BOTH",
91+
ministry_recipient: ["RO"],
92+
permit_condition_id: 37815,
93+
},
94+
};
95+
96+
it("should successfully update a report requirement", async () => {
97+
(CustomAxios as jest.Mock).mockImplementation(() => ({
98+
put: jest.fn().mockResolvedValue(mockResponse),
99+
}));
100+
101+
const payload = {
102+
mineGuid: "5b415b64-58af-434b-8636-960d98e0654f",
103+
values: {
104+
report_name: null,
105+
mine_report_permit_requirement_id: 5,
106+
due_date_period_months: 6,
107+
initial_due_date: null,
108+
cim_or_cpo: "BOTH",
109+
ministry_recipient: ["RO"],
110+
permit_condition_id: 37815,
111+
stepPath: "test",
112+
permit_amendment_id: 7551
113+
}
114+
};
115+
116+
await store.dispatch(updateMineReportPermitRequirement(payload));
117+
118+
// Verify loading state management
119+
expect(showLoadingMock).toHaveBeenCalledTimes(1);
120+
expect(hideLoadingMock).toHaveBeenCalledTimes(1);
121+
122+
expect(CustomAxios).toHaveBeenCalledWith({
123+
errorToastMessage: "default",
124+
successToastMessage: "Successfully updated report requirement",
125+
});
126+
});
127+
128+
it("should handle API error when updating a report requirement", async () => {
129+
const error = new Error("API Error");
130+
(CustomAxios as jest.Mock).mockImplementation(() => ({
131+
put: jest.fn().mockRejectedValue(error),
132+
}));
133+
134+
const payload = {
135+
mineGuid: "5b415b64-58af-434b-8636-960d98e0654f",
136+
values: {
137+
report_name: null,
138+
mine_report_permit_requirement_id: 5,
139+
due_date_period_months: 6,
140+
initial_due_date: null,
141+
cim_or_cpo: "BOTH",
142+
ministry_recipient: ["RO"],
143+
permit_condition_id: 37815,
144+
stepPath: "test",
145+
permit_amendment_id: 7551
146+
}
147+
};
148+
149+
await store.dispatch(updateMineReportPermitRequirement(payload));
150+
151+
expect(notificationSuccessMock).not.toHaveBeenCalled();
152+
});
153+
});
154+
});

services/common/src/redux/slices/mineReportPermitRequirementSlice.ts

+47-1
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,55 @@ const mineReportPermitRequirementSlice = createAppSlice({
3939
return response.data;
4040
}
4141
),
42+
deleteMineReportPermitRequirement: create.asyncThunk(
43+
async (
44+
payload: {
45+
mineGuid: string;
46+
mine_report_permit_requirement_id: number;
47+
},
48+
thunkApi
49+
) => {
50+
const headers = createRequestHeader();
51+
thunkApi.dispatch(showLoading());
52+
const messages = {
53+
errorToastMessage: "default",
54+
successToastMessage: "Successfully deleted report requirement",
55+
};
56+
const { mineGuid, mine_report_permit_requirement_id } = payload;
57+
const response = await CustomAxios(messages).delete(
58+
`${ENVIRONMENT.apiUrl}${MINE_REPORT_PERMIT_REQUIREMENT(mineGuid)}?mine_report_permit_requirement_id=${mine_report_permit_requirement_id}`,
59+
headers
60+
);
61+
62+
thunkApi.dispatch(hideLoading());
63+
return response.data;
64+
},
65+
),
66+
updateMineReportPermitRequirement: create.asyncThunk(
67+
async (payload: {
68+
mineGuid: string;
69+
values: IMineReportPermitRequirement
70+
}, thunkApi) => {
71+
const headers = createRequestHeader();
72+
thunkApi.dispatch(showLoading());
73+
const messages = {
74+
errorToastMessage: "default",
75+
successToastMessage: "Successfully updated report requirement",
76+
};
77+
78+
const { mineGuid, values } = payload;
79+
const response = await CustomAxios(messages).put(
80+
`${ENVIRONMENT.apiUrl}${MINE_REPORT_PERMIT_REQUIREMENT(mineGuid)}`,
81+
values,
82+
headers,
83+
);
84+
thunkApi.dispatch(hideLoading());
85+
return response.data;
86+
},
87+
)
4288
}),
4389
});
4490

45-
export const { createMineReportPermitRequirement } = mineReportPermitRequirementSlice.actions;
91+
export const { createMineReportPermitRequirement, deleteMineReportPermitRequirement, updateMineReportPermitRequirement } = mineReportPermitRequirementSlice.actions;
4692
export const mineReportPermitRequirementReducer = mineReportPermitRequirementSlice.reducer;
4793
export default mineReportPermitRequirementReducer;

services/common/src/utils/helpers.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { isArray } from "lodash";
22
import { removeNullValuesRecursive } from "@mds/common/constants/utils";
33
import { AMS_AUTHORIZATION_TYPES } from "@mds/common/constants/enums";
4+
import { IPermitCondition } from "@mds/common/interfaces/permits/permitCondition.interface";
45

56
const transformAuthorizations = (
67
valuesFromForm: any,
@@ -80,4 +81,18 @@ export const formatPermitConditionStep = (step: string) => {
8081
return `${step}.`
8182
}
8283
return "";
83-
}
84+
}
85+
86+
export const getConditionsWithRequirements = (conditions: IPermitCondition[]) => {
87+
let result = [];
88+
conditions.forEach((condition) => {
89+
if (condition.mineReportPermitRequirement) {
90+
result.push(condition);
91+
}
92+
93+
if (condition.sub_conditions && condition.sub_conditions.length > 0) {
94+
result = result.concat(getConditionsWithRequirements(condition.sub_conditions));
95+
}
96+
});
97+
return result;
98+
};

services/core-api/app/api/mines/permits/permit/resources/permit.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,9 @@ def get(self, mine_guid):
114114
results = [permit] if permit else []
115115
else:
116116
results = Mine.find_by_mine_guid(mine_guid).mine_permit
117-
118117
for permit in results:
119118
for permit_amendment in permit.permit_amendments:
120-
permit_amendment.mine_report_permit_requirements = MineReportPermitRequirement.query.filter_by(permit_amendment_id=permit_amendment.permit_amendment_id).all()
119+
permit_amendment.mine_report_permit_requirements = MineReportPermitRequirement.query.filter_by(permit_amendment_id=permit_amendment.permit_amendment_id, deleted_ind=False).all()
121120
return results
122121

123122
@api.doc(params={'permit_guid': 'Permit guid.'})

services/core-api/app/api/mines/permits/permit_extraction/create_permit_condition_report_requirement.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def _parse_due_date_period(recurring, frequency):
118118
def _parse_cim_cpo(mention_chief_inspector, mention_chief_permitting_officer):
119119
cim_or_cpo = None
120120
if mention_chief_inspector and mention_chief_permitting_officer:
121-
cim_or_cpo = "BOTH"
121+
cim_or_cpo = "Both"
122122
elif mention_chief_inspector:
123123
cim_or_cpo = "CIM"
124124
elif mention_chief_permitting_officer:

services/core-api/app/api/mines/reports/models/mine_report_permit_requirement.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
class CimOrCpo(str, Enum):
1212
CIM = "CIM"
1313
CPO = "CPO"
14-
BOTH = "BOTH"
14+
Both = "Both"
1515

1616
def __str__(self):
1717
return self.value
@@ -43,12 +43,12 @@ class MineReportPermitRequirement(SoftDeleteMixin, Base, AuditMixin):
4343
permit_amendment_id: int = db.Column(db.Integer, db.ForeignKey('permit_amendment.permit_amendment_id'))
4444

4545
def __repr__(self):
46-
return '<MineReportPermitRequirement %r>' % self.permit_report_requirement_id
46+
return '<MineReportPermitRequirement %r>' % self.mine_report_permit_requirement_id
4747

4848
@classmethod
49-
def find_by_permit_report_requirement_id(cls, _id) -> "MineReportPermitRequirement":
49+
def find_by_mine_report_permit_requirement_id(cls, _id) -> "MineReportPermitRequirement":
5050
try:
51-
return cls.query.filter_by(permit_report_requirement_id=_id).first()
51+
return cls.query.filter_by(mine_report_permit_requirement_id=_id, deleted_ind=False).first()
5252
except ValueError:
5353
return None
5454

0 commit comments

Comments
 (0)