Skip to content
Draft
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
1 change: 1 addition & 0 deletions bc_obps/reporting/schema/report_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,4 @@ class ReportOperationDataSchema(Schema):
show_activities: bool
reporting_year: int
is_sync_allowed: bool
selected_activities: List[int]
8 changes: 8 additions & 0 deletions bc_obps/reporting/service/report_operation_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from service.reporting_year_service import ReportingYearService
from reporting.service.sync_validation_service import SyncValidationService
from reporting.models import ReportActivity


class ReportOperationService:
Expand All @@ -23,6 +24,12 @@ def get_report_operation_data_by_version_id(cls, version_id: int) -> dict:
purpose = report_operation["registration_purpose"]
facility_id = FacilityReportService.get_facility_report_by_version_id(version_id)
is_sync_allowed = SyncValidationService.is_sync_allowed(version_id)
# Fetch distinct activity IDs that have report data for this report version.
activities_with_data = list(
ReportActivity.objects.filter(facility_report__report_version_id=version_id)
.values_list("activity_id", flat=True)
.distinct()
)
return {
"report_operation": report_operation,
"facility_id": facility_id,
Expand All @@ -48,6 +55,7 @@ def get_report_operation_data_by_version_id(cls, version_id: int) -> dict:
],
"reporting_year": reporting_year.reporting_year,
"is_sync_allowed": is_sync_allowed,
"selected_activities": activities_with_data,
}

@classmethod
Expand Down
2 changes: 2 additions & 0 deletions bc_obps/reporting/tests/api/test_report_operation_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def test_returns_report_operation_data(self, mock_get_report_operation_data):
"show_activities": True,
"reporting_year": self.reporting_year.reporting_year,
"is_sync_allowed": True,
"selected_activities": [1],
}
expected_purpose = self.report_operation["registration_purpose"]

Expand Down Expand Up @@ -130,6 +131,7 @@ def test_patch_report_operation_updates_successfully(
"show_activities": True,
"reporting_year": self.reporting_year.reporting_year,
"is_sync_allowed": True,
"selected_activities": [1],
}

TestUtils.authorize_current_user_as_operator_user(self, operator=report_version.report.operator)
Expand Down
34 changes: 34 additions & 0 deletions bc_obps/reporting/tests/service/test_report_operation_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,40 @@ def test_get_report_operation_data_by_version_id(self):
assert "is_sync_allowed" in result
assert isinstance(result["is_sync_allowed"], bool)
assert result["reporting_year"] == self.report_version.report.reporting_year.reporting_year
assert "selected_activities" in result
assert isinstance(result["selected_activities"], list)

def test_get_report_operation_data_by_version_id_selected_activities_empty_with_no_report_activities(self):
result = ReportOperationService.get_report_operation_data_by_version_id(self.report_version.id)
assert result["selected_activities"] == []

def test_get_report_operation_data_by_version_id_selected_activities_with_report_activities(self):
baker.make_recipe(
"reporting.tests.utils.report_activity",
facility_report=self.facility_report,
activity=self.activity,
)

result = ReportOperationService.get_report_operation_data_by_version_id(self.report_version.id)

assert self.activity.id in result["selected_activities"]
assert len(result["selected_activities"]) == 1

def test_get_report_operation_data_by_version_id_selected_activities_are_distinct(self):
baker.make_recipe(
"reporting.tests.utils.report_activity",
facility_report=self.facility_report,
activity=self.activity,
)
baker.make_recipe(
"reporting.tests.utils.report_activity",
facility_report=self.facility_report,
activity=self.activity,
)

result = ReportOperationService.get_report_operation_data_by_version_id(self.report_version.id)

assert result["selected_activities"].count(self.activity.id) == 1

def test_update_report_service(self):
self.operation.name = "New Operation Name"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ interface Props {
allRepresentatives: any[];
facilityId: string;
isSyncAllowed: boolean;
activitiesWithData: number[];
}

export default function OperationReviewForm({
Expand All @@ -47,9 +48,19 @@ export default function OperationReviewForm({
allRepresentatives,
facilityId,
isSyncAllowed,
activitiesWithData,
}: Props) {
const [pendingChangeReportType, setPendingChangeReportType] =
useState<string>();
type ModalConfig = {
title: string;
confirmText: string;
content: React.ReactNode;
onConfirm: () => void;
onCancel: () => void;
};

const [activeModal, setActiveModal] = useState<ModalConfig | undefined>();

const closeModal = () => setActiveModal(undefined);
const [formDataState, setFormDataState] = useState<any>(formData);
const [pageSchema, setPageSchema] = useState(schema);
const [hasReps, setHasReps] = useState(allRepresentatives.length > 0);
Expand Down Expand Up @@ -85,12 +96,80 @@ export default function OperationReviewForm({

const onChangeHandler = (data: { formData: any }) => {
const updatedFormData = data.formData;

if (
updatedFormData?.operation_report_type !== undefined &&
updatedFormData?.operation_report_type !==
formDataState?.operation_report_type
) {
setPendingChangeReportType(updatedFormData.operation_report_type);
setActiveModal({
title: "Confirmation",
confirmText: "Change report type",
content: (
<>
Are you sure you want to change your report type to{" "}
<strong>{updatedFormData.operation_report_type}</strong>? If you
proceed, all of the form data you have entered will be lost.
</>
),
onConfirm: async () => {
const response = await actionHandler(
`reporting/report-version/${version_id}/change-report-type`,
"POST",
"",
{
body: JSON.stringify({
report_type: updatedFormData.operation_report_type,
}),
},
);
if (response && !response.error) {
router.push(`/reports/${response}/review-operation-information`);
} else {
setApiError("Failed to change the report type. Please try again.");
}
closeModal();
},
onCancel: () => {
setFormDataState(formData);
setApiError(null);
closeModal();
},
});
return;
}

// Detect deselected activities
const previousActivities: number[] = formDataState?.activities ?? [];
const updatedActivities: number[] = updatedFormData?.activities ?? [];

const deselectedActivities = previousActivities.filter(
(id) => !updatedActivities.includes(id),
);

if (deselectedActivities.length > 0) {
const deselectedWithData = deselectedActivities.find((id) =>
(activitiesWithData ?? []).includes(id),
);

if (deselectedWithData !== undefined) {
const previousState = formDataState;
setActiveModal({
title: "Confirmation",
confirmText: "Remove Activity",
content:
"Are you sure you want to remove this activity? If you proceed, all of the form data you have entered will be lost.",
onConfirm: () => {
setFormDataState(updatedFormData);
closeModal();
},
onCancel: () => {
setFormDataState({ ...previousState });
closeModal();
},
});
return;
}
}

setFormDataState(updatedFormData);
Expand Down Expand Up @@ -141,26 +220,6 @@ export default function OperationReviewForm({
formData.operation_name,
);

const confirmReportTypeChange = async () => {
const method = "POST";
const endpoint = `reporting/report-version/${version_id}/change-report-type`;
const response = await actionHandler(endpoint, method, "", {
body: JSON.stringify({ report_type: pendingChangeReportType }),
});

if (response && !response.error) {
router.push(`/reports/${response}/review-operation-information`);
} else {
setApiError("Failed to change the report type. Please try again.");
}
};

const cancelReportTypeChange = () => {
setFormDataState(formData);
setApiError(null);
setPendingChangeReportType(undefined);
};

// Regulated product IDs 16 and 43 are the Pulp and paper: chemical pulp
// and Pulp and paper: lime recovered by kiln, respectively
const selectedProductIds: number[] = formDataState.regulated_products;
Expand All @@ -171,20 +230,16 @@ export default function OperationReviewForm({
return (
<>
<SimpleModal
title="Confirmation"
open={pendingChangeReportType !== undefined}
onCancel={cancelReportTypeChange}
onConfirm={confirmReportTypeChange}
confirmText="Change report type"
title={activeModal?.title ?? ""}
open={activeModal !== undefined}
onCancel={activeModal?.onCancel ?? closeModal}
onConfirm={activeModal?.onConfirm ?? closeModal}
confirmText={activeModal?.confirmText}
>
{apiError ? (
<div style={{ color: "red" }}>{apiError}</div>
) : (
<>
Are you sure you want to change your report type to{" "}
<strong>{pendingChangeReportType}</strong>? If you proceed, all of
the form data you have entered will be lost.
</>
activeModal?.content
)}
</SimpleModal>
<MultiStepFormWithTaskList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export default async function OperationReviewPage({
allRepresentatives={data.all_representatives}
facilityId={data.facility_id}
isSyncAllowed={isSyncAllowed}
activitiesWithData={data.selected_activities}
/>
);
}
Loading
Loading