diff --git a/inventory_management_system_api/routers/v1/setting.py b/inventory_management_system_api/routers/v1/setting.py index d7f3a5b2..f1fcfd6c 100644 --- a/inventory_management_system_api/routers/v1/setting.py +++ b/inventory_management_system_api/routers/v1/setting.py @@ -43,3 +43,16 @@ def update_spares_definition( logger.exception(message) raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=message) from exc # pylint: enable=duplicate-code + + +@router.get( + path="/spares_definition", summary="Get the definition of a spare", response_description="Spares definition" +) +def get_spares_definition(setting_service: SettingServiceDep) -> SparesDefinitionSchema: + # pylint: disable=missing-function-docstring + logger.info("Getting spares definition") + + spares_definition = setting_service.get_spares_definition() + if not spares_definition: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Spares definition not found.") + return SparesDefinitionSchema(**spares_definition.model_dump()) diff --git a/inventory_management_system_api/services/setting.py b/inventory_management_system_api/services/setting.py index af248608..c1825261 100644 --- a/inventory_management_system_api/services/setting.py +++ b/inventory_management_system_api/services/setting.py @@ -88,3 +88,12 @@ def update_spares_definition(self, spares_definition: SparesDefinitionPutSchema) ) return new_spares_definition + + def get_spares_definition(self) -> SparesDefinitionOut: + """ + Retrieves the spares definition. + + :return: Retrieved spares definition or `None` if not found. + """ + + return self._setting_repository.get(SparesDefinitionOut) diff --git a/test/e2e/test_setting.py b/test/e2e/test_setting.py index 0ba75ec6..db6d5d4d 100644 --- a/test/e2e/test_setting.py +++ b/test/e2e/test_setting.py @@ -170,6 +170,57 @@ def test_update_spares_definition_with_invalid_usage_status_id(self): self.check_put_spares_definition_failed_with_detail(422, "A specified usage status does not exist") +class GetSparesDefinitionDSL(UpdateSparesDefinitionDSL): + """Base class for get spares definition tests.""" + + _get_response_spares_definition: Response + + def get_spares_definition(self): + """Gets the spares definition.""" + + self._get_response_spares_definition = self.test_client.get("/v1/settings/spares_definition") + + def check_get_spares_definition_success(self, expected_spares_definition_get_data: dict): + """ + Checks that a prior call to `get_spares_definition` gave a successful response with the expected data returned. + + :param expected_spares_definition_get_data: Dictionary containing the expected system data returned as would be + required for a `SparesDefinitionSchema`. + """ + + assert self._get_response_spares_definition.status_code == 200 + assert self._get_response_spares_definition.json() == expected_spares_definition_get_data + + def check_get_spares_definition_failed_with_detail(self, status_code: int, detail: str): + """ + Checks that a prior call to `get_spares_definition` gave a failed response with the expected code and error + message. + + :param status_code: Expected status code of the response. + :param detail: Expected detail given in the response. + """ + + assert self._get_response_spares_definition.status_code == status_code + assert self._get_response_spares_definition.json()["detail"] == detail + + +class TestGetSparesDefinition(GetSparesDefinitionDSL): + """Tests for getting the spares definition.""" + + def test_get_spares_definition(self): + """Test getting the spares definition.""" + + self.put_spares_definition_and_post_prerequisites(SETTING_SPARES_DEFINITION_DATA_NEW_USED) + self.get_spares_definition() + self.check_get_spares_definition_success(SETTING_SPARES_DEFINITION_GET_DATA_NEW_USED) + + def test_get_spares_definition_when_non_existent(self): + """Test getting the spares definition when it is non-existent.""" + + self.get_spares_definition() + self.check_get_spares_definition_failed_with_detail(404, "Spares definition not found.") + + class SparesDefinitionDSL(UpdateSparesDefinitionDSL, ItemDeleteDSL, CatalogueItemGetDSL): """Base class for spares definition tests.""" diff --git a/test/unit/services/test_setting.py b/test/unit/services/test_setting.py index 8297b0e4..09b6e9da 100644 --- a/test/unit/services/test_setting.py +++ b/test/unit/services/test_setting.py @@ -211,3 +211,39 @@ def test_update_spare_definition_with_non_existent_usage_status_id(self): # pylint: disable=unsubscriptable-object f"No usage status found with ID: {self._spares_definition_put.usage_statuses[1].id}" ) + + +class GetSparesDefinitionDSL(SettingServiceDSL): + """Base class for `get_spares_definition` tests.""" + + _expected_spares_definition: MagicMock + _obtained_spares_definition: MagicMock + + def mock_get_spares_definition(self) -> None: + """Mocks repo methods appropriately to test the `get_spares_definition` service method.""" + + # Simply a return currently, so no need to use actual data + self._expected_spares_definition = MagicMock() + ServiceTestHelpers.mock_get(self.mock_setting_repository, self._expected_spares_definition) + + def call_get_spares_definition(self) -> None: + """Calls the `SettingService` `get_spares_definition` method.""" + + self._obtained_spares_definition = self.setting_service.get_spares_definition() + + def check_get_spares_definition_success(self) -> None: + """Checks that a prior call to `call_get_spares_definition` worked as expected.""" + + self.mock_setting_repository.get.assert_called_once_with(SparesDefinitionOut) + assert self._obtained_spares_definition == self._expected_spares_definition + + +class TestGetSparesDefinition(GetSparesDefinitionDSL): + """Tests for getting the spares definition.""" + + def test_get(self): + """Test getting the spares definition.""" + + self.mock_get_spares_definition() + self.call_get_spares_definition() + self.check_get_spares_definition_success()