diff --git a/pom.xml b/pom.xml
index 1dcc6441..9411119c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -125,10 +125,6 @@
com.vaadin.external.google
android-json
-
- com.jayway.jsonpath
- json-path
-
@@ -285,6 +281,17 @@
h2
runtime
+
+ com.jayway.jsonpath
+ json-path
+ 2.9.0
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ test
+
${artifactId}-${version}
diff --git a/src/test/java/com/iemr/inventory/RoleMasterApplicationTest.java b/src/test/java/com/iemr/inventory/RoleMasterApplicationTest.java
new file mode 100644
index 00000000..2c99b90d
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/RoleMasterApplicationTest.java
@@ -0,0 +1,100 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory;
+
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertSame;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import com.iemr.inventory.utils.IEMRApplBeans;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("RoleMasterApplication Test Suite")
+class RoleMasterApplicationTest {
+
+ @Mock
+ private RedisConnectionFactory connectionFactory;
+
+ private final RoleMasterApplication application = new RoleMasterApplication();
+
+ @Test
+ @DisplayName("configProperties should supply a fresh properties holder on each call")
+ void configProperties_shouldSupplyFreshHolder() {
+ assertNotNull(application.configProperties());
+ assertNotSame(application.configProperties(), application.configProperties());
+ }
+
+ @Test
+ @DisplayName("instantiateBeans should supply the shared bean configuration")
+ void instantiateBeans_shouldSupplyBeanConfiguration() {
+ assertInstanceOf(IEMRApplBeans.class, application.instantiateBeans());
+ }
+
+ @Test
+ @DisplayName("configure should point the servlet container at this application class")
+ void configure_shouldPointAtApplicationClass() {
+ SpringApplicationBuilder builder = new SpringApplicationBuilder();
+
+ assertSame(builder, application.configure(builder));
+ }
+
+ @Test
+ @DisplayName("redisTemplate should bind the connection factory and serialise keys as plain strings")
+ void redisTemplate_shouldBindFactoryAndConfigureSerializers() {
+ RedisTemplate template = application.redisTemplate(connectionFactory);
+
+ assertSame(connectionFactory, template.getConnectionFactory());
+ assertInstanceOf(StringRedisSerializer.class, template.getKeySerializer());
+ assertInstanceOf(Jackson2JsonRedisSerializer.class, template.getValueSerializer());
+ }
+
+ @Test
+ @DisplayName("ServletInitializer should point the WAR deployment at the same application class")
+ void servletInitializer_shouldPointAtApplicationClass() {
+ SpringApplicationBuilder builder = new SpringApplicationBuilder();
+
+ assertSame(builder, new ServletInitializer().configure(builder));
+ }
+
+ @Test
+ @DisplayName("ServletInitializer onStartup should complete without touching the servlet context")
+ void servletInitializer_onStartupShouldCompleteQuietly() throws Exception {
+ jakarta.servlet.ServletContext servletContext =
+ org.mockito.Mockito.mock(jakarta.servlet.ServletContext.class);
+
+ new ServletInitializer().onStartup(servletContext);
+
+ org.mockito.Mockito.verifyNoInteractions(servletContext);
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/config/HttpInterceptorConfigTest.java b/src/test/java/com/iemr/inventory/config/HttpInterceptorConfigTest.java
new file mode 100644
index 00000000..496bff6f
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/config/HttpInterceptorConfigTest.java
@@ -0,0 +1,77 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.config;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+
+import com.iemr.inventory.utils.http.HTTPRequestInterceptor;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("Web MVC configuration Test Suite")
+class HttpInterceptorConfigTest {
+
+ @Mock
+ private HTTPRequestInterceptor httpInterceptor;
+ @Mock
+ private InterceptorRegistry registry;
+ @Mock
+ private InterceptorRegistration registration;
+ @Mock
+ private HttpServletRequest request;
+ @Mock
+ private HttpServletResponse response;
+
+ @Test
+ @DisplayName("addInterceptors should register the session-checking interceptor")
+ void addInterceptors_shouldRegisterSessionInterceptor() {
+ HttpInterceptorConfig config = new HttpInterceptorConfig();
+ ReflectionTestUtils.setField(config, "httpInterceptor", httpInterceptor);
+ when(registry.addInterceptor(httpInterceptor)).thenReturn(registration);
+
+ config.addInterceptors(registry);
+
+ verify(registry).addInterceptor(httpInterceptor);
+ }
+
+ @Test
+ @DisplayName("BlockingMethodInterceptor should complete its post-handle and after-completion hooks quietly")
+ void blockingMethodInterceptor_shouldCompleteHooksQuietly() {
+ BlockingMethodInterceptor interceptor = new BlockingMethodInterceptor();
+
+ assertDoesNotThrow(() -> interceptor.postHandle(request, response, new Object(), null));
+ assertDoesNotThrow(() -> interceptor.afterCompletion(request, response, new Object(), null));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/config/RedisConfigTest.java b/src/test/java/com/iemr/inventory/config/RedisConfigTest.java
new file mode 100644
index 00000000..ce9865f6
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/config/RedisConfigTest.java
@@ -0,0 +1,88 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.config;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import com.iemr.inventory.data.user.M_User;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("RedisConfig Test Suite")
+class RedisConfigTest {
+
+ @Mock
+ private RedisConnectionFactory connectionFactory;
+
+ private RedisConfig redisConfig;
+
+ @BeforeEach
+ @DisplayName("Create the configuration with Redis coordinates before each test")
+ void setUp() {
+ redisConfig = new RedisConfig();
+ ReflectionTestUtils.setField(redisConfig, "redisHost", "redis.example.org");
+ ReflectionTestUtils.setField(redisConfig, "redisPort", 6379);
+ }
+
+ @Test
+ @DisplayName("lettuceConnectionFactory should point Lettuce at the configured host and port")
+ void lettuceConnectionFactory_shouldUseConfiguredHostAndPort() {
+ LettuceConnectionFactory factory = redisConfig.lettuceConnectionFactory();
+
+ assertNotNull(factory);
+ assertEquals("redis.example.org", factory.getHostName());
+ assertEquals(6379, factory.getPort());
+ }
+
+ @Test
+ @DisplayName("redisTemplate should bind the supplied connection factory")
+ void redisTemplate_shouldBindSuppliedConnectionFactory() {
+ RedisTemplate template = redisConfig.redisTemplate(connectionFactory);
+
+ assertNotNull(template);
+ assertSame(connectionFactory, template.getConnectionFactory());
+ }
+
+ @Test
+ @DisplayName("redisTemplate should serialise keys as plain strings and values as M_User JSON")
+ void redisTemplate_shouldConfigureSerializers() {
+ RedisTemplate template = redisConfig.redisTemplate(connectionFactory);
+
+ assertInstanceOf(StringRedisSerializer.class, template.getKeySerializer());
+ assertInstanceOf(Jackson2JsonRedisSerializer.class, template.getValueSerializer());
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/config/SwaggerConfigTest.java b/src/test/java/com/iemr/inventory/config/SwaggerConfigTest.java
new file mode 100644
index 00000000..05c0e341
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/config/SwaggerConfigTest.java
@@ -0,0 +1,101 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.config;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.mock.env.MockEnvironment;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DisplayName("SwaggerConfig Test Suite")
+class SwaggerConfigTest {
+
+ private static final String SECURITY_SCHEME_NAME = "bearerAuth";
+ private static final String DEFAULT_URL = "http://localhost:9090";
+
+ private SwaggerConfig swaggerConfig;
+ private MockEnvironment environment;
+
+ @BeforeEach
+ @DisplayName("Create the configuration and an empty environment before each test")
+ void setUp() {
+ swaggerConfig = new SwaggerConfig();
+ environment = new MockEnvironment();
+ }
+
+ @Test
+ @DisplayName("customOpenAPI should describe the inventory API")
+ void customOpenAPI_shouldDescribeTheApi() {
+ OpenAPI openAPI = swaggerConfig.customOpenAPI(environment);
+
+ assertNotNull(openAPI.getInfo());
+ assertEquals("Inventory API", openAPI.getInfo().getTitle());
+ assertEquals("version", openAPI.getInfo().getVersion());
+ assertTrue(openAPI.getInfo().getDescription().contains("inventory management"));
+ }
+
+ @Test
+ @DisplayName("customOpenAPI should declare a bearer security scheme and require it")
+ void customOpenAPI_shouldDeclareBearerSecurityScheme() {
+ OpenAPI openAPI = swaggerConfig.customOpenAPI(environment);
+
+ SecurityScheme scheme = openAPI.getComponents().getSecuritySchemes().get(SECURITY_SCHEME_NAME);
+ assertNotNull(scheme);
+ assertEquals(SecurityScheme.Type.HTTP, scheme.getType());
+ assertEquals("bearer", scheme.getScheme());
+ assertEquals(1, openAPI.getSecurity().size());
+ assertTrue(openAPI.getSecurity().get(0).containsKey(SECURITY_SCHEME_NAME));
+ }
+
+ @Test
+ @DisplayName("customOpenAPI should fall back to localhost for every unset server url")
+ void customOpenAPI_shouldFallBackToLocalhostForUnsetUrls() {
+ OpenAPI openAPI = swaggerConfig.customOpenAPI(environment);
+
+ assertEquals(3, openAPI.getServers().size());
+ openAPI.getServers().forEach(server -> assertEquals(DEFAULT_URL, server.getUrl()));
+ assertEquals("Dev", openAPI.getServers().get(0).getDescription());
+ assertEquals("UAT", openAPI.getServers().get(1).getDescription());
+ assertEquals("Demo", openAPI.getServers().get(2).getDescription());
+ }
+
+ @Test
+ @DisplayName("customOpenAPI should use the configured dev, UAT and demo urls when present")
+ void customOpenAPI_shouldUseConfiguredUrls() {
+ environment.setProperty("api.dev.url", "https://dev.amrit.example.org");
+ environment.setProperty("api.uat.url", "https://uat.amrit.example.org");
+ environment.setProperty("api.demo.url", "https://demo.amrit.example.org");
+
+ OpenAPI openAPI = swaggerConfig.customOpenAPI(environment);
+
+ assertEquals("https://dev.amrit.example.org", openAPI.getServers().get(0).getUrl());
+ assertEquals("https://uat.amrit.example.org", openAPI.getServers().get(1).getUrl());
+ assertEquals("https://demo.amrit.example.org", openAPI.getServers().get(2).getUrl());
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/Supplier/SupplierMasterControllerTest.java b/src/test/java/com/iemr/inventory/controller/Supplier/SupplierMasterControllerTest.java
new file mode 100644
index 00000000..b43076fa
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/Supplier/SupplierMasterControllerTest.java
@@ -0,0 +1,220 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.Supplier;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.supplier.M_Supplier;
+import com.iemr.inventory.data.supplier.M_Supplieraddress;
+import com.iemr.inventory.service.supplier.SupplierInter;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("SupplierMasterController Test Suite")
+class SupplierMasterControllerTest {
+
+ private static final String AUTH = "test-session-key";
+
+ @Mock
+ private SupplierInter supplierInter;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked supplier service")
+ void setUp() {
+ SupplierMasterController controller = new SupplierMasterController();
+ ReflectionTestUtils.setField(controller, "supplierInter", supplierInter);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ private static M_Supplier supplier(Integer id, String name) {
+ M_Supplier supplier = new M_Supplier();
+ supplier.setSupplierID(id);
+ supplier.setSupplierName(name);
+ supplier.setProviderServiceMapID(3);
+ return supplier;
+ }
+
+ @Test
+ @DisplayName("createSupplier should persist the supplier and derive its address row from the same payload")
+ void createSupplier_shouldPersistSupplierAndAddress() throws Exception {
+ when(supplierInter.createSupplier(anyList())).thenReturn(new ArrayList<>(List.of(supplier(11, "Acme"))));
+ when(supplierInter.createAddress(anyList())).thenReturn(new ArrayList<>());
+
+ mockMvc.perform(post("/createSupplier").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("[{\"supplierName\":\"Acme\",\"providerServiceMapID\":3,\"addressLine1\":\"12 Mill Road\","
+ + "\"addressLine2\":\"Suite 4\",\"district\":\"Pune\",\"state\":\"MH\",\"country\":\"IN\","
+ + "\"pinCode\":\"411001\",\"createdBy\":\"tester\"}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].supplierName").value("Acme"));
+
+ ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class);
+ verify(supplierInter).createAddress(captor.capture());
+ M_Supplieraddress address = captor.getValue().get(0);
+ assertEquals(11, address.getSupplierID());
+ assertEquals("12 Mill Road", address.getAddressLine1());
+ assertEquals("Pune", address.getDistrict());
+ assertEquals("411001", address.getPinCode());
+ assertEquals("tester", address.getCreatedBy());
+ }
+
+ @Test
+ @DisplayName("createSupplier should report the failure when the service blows up")
+ void createSupplier_shouldReportServiceFailure() throws Exception {
+ when(supplierInter.createSupplier(anyList())).thenThrow(new RuntimeException("db unavailable"));
+
+ mockMvc.perform(post("/createSupplier").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("[{}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("db unavailable"));
+ }
+
+ @Test
+ @DisplayName("createSupplier should report the failure when the supplier save returns nothing to map")
+ void createSupplier_shouldReportFailureWhenNothingSaved() throws Exception {
+ when(supplierInter.createSupplier(anyList())).thenReturn(null);
+
+ mockMvc.perform(post("/createSupplier").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("[{\"supplierName\":\"Acme\"}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("getSupplier should look the rows up by the posted provider service map id")
+ void getSupplier_shouldLookUpByProviderServiceMapId() throws Exception {
+ when(supplierInter.getSupplier(3))
+ .thenReturn(new ArrayList<>(List.of(supplier(11, "Acme"), supplier(12, "Beta"))));
+
+ mockMvc.perform(post("/getSupplier").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.length()").value(2));
+
+ verify(supplierInter).getSupplier(3);
+ }
+
+ @Test
+ @DisplayName("getSupplier should report the failure when the lookup throws")
+ void getSupplier_shouldReportServiceFailure() throws Exception {
+ when(supplierInter.getSupplier(anyInt())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getSupplier").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("editSupplier should copy every editable field onto the stored row before saving")
+ void editSupplier_shouldCopyEditableFieldsBeforeSaving() throws Exception {
+ M_Supplier stored = supplier(11, "old name");
+ when(supplierInter.editSupplier(11)).thenReturn(stored);
+ when(supplierInter.saveEditedData(any(M_Supplier.class))).thenAnswer(inv -> inv.getArgument(0));
+
+ mockMvc.perform(post("/editSupplier").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"supplierID\":11,\"supplierName\":\"new name\",\"supplierDesc\":\"new desc\","
+ + "\"supplierCode\":\"NEW\",\"status\":\"Inactive\",\"contactPerson\":\"Alex\","
+ + "\"drugLicenseNo\":\"DL-1\",\"cST_GST_No\":\"GST-9\",\"tIN_No\":\"TIN-4\","
+ + "\"email\":\"acme@example.org\",\"phoneNo1\":\"111\",\"phoneNo2\":\"222\","
+ + "\"modifiedBy\":\"tester\"}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.supplierName").value("new name"));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_Supplier.class);
+ verify(supplierInter).saveEditedData(captor.capture());
+ M_Supplier saved = captor.getValue();
+ assertEquals("DL-1", saved.getDrugLicenseNo());
+ assertEquals("GST-9", saved.getcST_GST_No());
+ assertEquals("TIN-4", saved.gettIN_No());
+ assertEquals("acme@example.org", saved.getEmail());
+ assertEquals("111", saved.getPhoneNo1());
+ assertEquals("222", saved.getPhoneNo2());
+ assertEquals("tester", saved.getModifiedBy());
+ }
+
+ @Test
+ @DisplayName("editSupplier should report the failure when the row cannot be found")
+ void editSupplier_shouldReportFailureWhenRowMissing() throws Exception {
+ when(supplierInter.editSupplier(11)).thenReturn(null);
+
+ mockMvc.perform(post("/editSupplier").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"supplierID\":11}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("deleteSupplier should flip the deleted flag on the stored row and save it")
+ void deleteSupplier_shouldFlipDeletedFlag() throws Exception {
+ M_Supplier stored = supplier(11, "Acme");
+ when(supplierInter.editSupplier(11)).thenReturn(stored);
+ when(supplierInter.saveEditedData(any(M_Supplier.class))).thenAnswer(inv -> inv.getArgument(0));
+
+ mockMvc.perform(post("/deleteSupplier").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"supplierID\":11,\"deleted\":true}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_Supplier.class);
+ verify(supplierInter).saveEditedData(captor.capture());
+ assertEquals(Boolean.TRUE, captor.getValue().getDeleted());
+ }
+
+ @Test
+ @DisplayName("deleteSupplier should report the failure when the row cannot be found")
+ void deleteSupplier_shouldReportFailureWhenRowMissing() throws Exception {
+ when(supplierInter.editSupplier(11)).thenReturn(null);
+
+ mockMvc.perform(post("/deleteSupplier").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"supplierID\":11}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/dispenseagainst_rx/DispenseAgainstRXTest.java b/src/test/java/com/iemr/inventory/controller/dispenseagainst_rx/DispenseAgainstRXTest.java
new file mode 100644
index 00000000..48c7d1da
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/dispenseagainst_rx/DispenseAgainstRXTest.java
@@ -0,0 +1,103 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.dispenseagainst_rx;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.service.dispenseagainst_rx.DispenseAgainstRXimpl;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("DispenseAgainstRX controller Test Suite")
+class DispenseAgainstRXTest {
+
+ private static final String AUTH = "test-session-key";
+ private static final String REQUEST = "{\"beneficiaryRegID\":101,\"visitCode\":5001,\"facilityID\":7}";
+
+ @Mock
+ private DispenseAgainstRXimpl dispenseAgainstRXimpl;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked dispensing service")
+ void setUp() {
+ DispenseAgainstRX controller = new DispenseAgainstRX();
+ ReflectionTestUtils.setField(controller, "dispenseAgainstRXimpl", dispenseAgainstRXimpl);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ @Test
+ @DisplayName("getPrescribedMedicines should hand the service payload back to the caller")
+ void getPrescribedMedicines_shouldReturnServicePayload() throws Exception {
+ when(dispenseAgainstRXimpl.getPrescribedMedicines(anyString()))
+ .thenReturn("{\"prescriptionID\":9001}");
+
+ mockMvc.perform(post("/RX/getPrescribedMedicines").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(REQUEST))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.prescriptionID").value(9001));
+
+ verify(dispenseAgainstRXimpl).getPrescribedMedicines(REQUEST);
+ }
+
+ @Test
+ @DisplayName("getPrescribedMedicines should leave the generic failure standing when the service returns nothing")
+ void getPrescribedMedicines_shouldLeaveGenericFailureWhenServiceReturnsNothing() throws Exception {
+ when(dispenseAgainstRXimpl.getPrescribedMedicines(anyString())).thenReturn(null);
+
+ mockMvc.perform(post("/RX/getPrescribedMedicines").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(REQUEST))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.status").value("FAILURE"));
+ }
+
+ @Test
+ @DisplayName("getPrescribedMedicines should report the failure when the service throws")
+ void getPrescribedMedicines_shouldReportServiceFailure() throws Exception {
+ when(dispenseAgainstRXimpl.getPrescribedMedicines(anyString()))
+ .thenThrow(new RuntimeException("prescription lookup failed"));
+
+ mockMvc.perform(post("/RX/getPrescribedMedicines").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(REQUEST))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("prescription lookup failed"));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/drugtype/DrugtypeControllerTest.java b/src/test/java/com/iemr/inventory/controller/drugtype/DrugtypeControllerTest.java
new file mode 100644
index 00000000..360b8cf6
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/drugtype/DrugtypeControllerTest.java
@@ -0,0 +1,202 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.drugtype;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.drugtype.M_Drugtype;
+import com.iemr.inventory.service.drugtype.DrugtypeInter;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("DrugtypeController Test Suite")
+class DrugtypeControllerTest {
+
+ private static final String AUTH = "test-session-key";
+
+ @Mock
+ private DrugtypeInter drugtypeInter;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked drug type service")
+ void setUp() {
+ DrugtypeController controller = new DrugtypeController();
+ ReflectionTestUtils.setField(controller, "drugtypeInter", drugtypeInter);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ private static M_Drugtype row(Integer id, String name) {
+ M_Drugtype row = new M_Drugtype();
+ row.setDrugTypeID(id);
+ row.setDrugTypeName(name);
+ row.setProviderServiceMapID(3);
+ return row;
+ }
+
+ private static ArrayList rows(M_Drugtype... items) {
+ return new ArrayList<>(List.of(items));
+ }
+
+ @Test
+ @DisplayName("createManufacturer should persist the posted array and answer with the saved rows")
+ void createManufacturer_shouldPersistPostedArray() throws Exception {
+ when(drugtypeInter.createDrugtypeData(anyList())).thenReturn(rows(row(1, "first")));
+
+ mockMvc.perform(post("/createDrugtype").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("[{\"drugTypeName\":\"first\",\"providerServiceMapID\":3}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].drugTypeName").value("first"));
+
+ ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class);
+ verify(drugtypeInter).createDrugtypeData(captor.capture());
+ assertEquals(1, captor.getValue().size());
+ }
+
+ @Test
+ @DisplayName("createManufacturer should report the failure when the service blows up")
+ void createManufacturer_shouldReportServiceFailure() throws Exception {
+ when(drugtypeInter.createDrugtypeData(anyList())).thenThrow(new RuntimeException("db unavailable"));
+
+ mockMvc.perform(post("/createDrugtype").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("[{}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("db unavailable"));
+ }
+
+ @Test
+ @DisplayName("createManufacturer should report a parse failure for a malformed body")
+ void createManufacturer_shouldReportParseFailure() throws Exception {
+ mockMvc.perform(post("/createDrugtype").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("not-json"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getManufacturer should look the rows up by the posted provider service map id")
+ void getManufacturer_shouldLookUpByProviderServiceMapId() throws Exception {
+ when(drugtypeInter.getDrugtypeData(3)).thenReturn(rows(row(1, "first"), row(2, "second")));
+
+ mockMvc.perform(post("/getDrugtype").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.length()").value(2));
+
+ verify(drugtypeInter).getDrugtypeData(3);
+ }
+
+ @Test
+ @DisplayName("getManufacturer should report the failure when the lookup throws")
+ void getManufacturer_shouldReportServiceFailure() throws Exception {
+ when(drugtypeInter.getDrugtypeData(anyInt())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getDrugtype").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("editManufacturer should copy the editable fields onto the stored row before saving")
+ void editManufacturer_shouldCopyEditableFieldsBeforeSaving() throws Exception {
+ M_Drugtype stored = row(1, "old name");
+ when(drugtypeInter.editDrugtypeData(1)).thenReturn(stored);
+ when(drugtypeInter.saveeditDrugtype(any(M_Drugtype.class))).thenAnswer(invocation -> invocation.getArgument(0));
+
+ mockMvc.perform(post("/editDrugtype").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"drugTypeID\":1,\"drugTypeName\":\"new name\",\"drugTypeDesc\":\"new desc\","
+ + "\"drugTypeCode\":\"NEW\",\"status\":\"Inactive\",\"modifiedBy\":\"tester\"}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.drugTypeName").value("new name"));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_Drugtype.class);
+ verify(drugtypeInter).saveeditDrugtype(captor.capture());
+ assertEquals("tester", captor.getValue().getModifiedBy());
+ }
+
+ @Test
+ @DisplayName("editManufacturer should report the failure when the row cannot be found")
+ void editManufacturer_shouldReportFailureWhenRowMissing() throws Exception {
+ when(drugtypeInter.editDrugtypeData(1)).thenReturn(null);
+
+ mockMvc.perform(post("/editDrugtype").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"drugTypeID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("deleteManufacturer should flip the deleted flag on the stored row and save it")
+ void deleteManufacturer_shouldFlipDeletedFlag() throws Exception {
+ M_Drugtype stored = row(1, "first");
+ when(drugtypeInter.editDrugtypeData(1)).thenReturn(stored);
+ when(drugtypeInter.saveeditDrugtype(any(M_Drugtype.class))).thenAnswer(invocation -> invocation.getArgument(0));
+
+ mockMvc.perform(post("/deleteDrugtype").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"drugTypeID\":1,\"deleted\":true}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_Drugtype.class);
+ verify(drugtypeInter).saveeditDrugtype(captor.capture());
+ assertEquals(Boolean.TRUE, captor.getValue().getDeleted());
+ }
+
+ @Test
+ @DisplayName("deleteManufacturer should report the failure when the row cannot be found")
+ void deleteManufacturer_shouldReportFailureWhenRowMissing() throws Exception {
+ when(drugtypeInter.editDrugtypeData(1)).thenReturn(null);
+
+ mockMvc.perform(post("/deleteDrugtype").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"drugTypeID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/facilitytype/FacilitytypeControllerTest.java b/src/test/java/com/iemr/inventory/controller/facilitytype/FacilitytypeControllerTest.java
new file mode 100644
index 00000000..681fddfd
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/facilitytype/FacilitytypeControllerTest.java
@@ -0,0 +1,202 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.facilitytype;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.facilitytype.M_facilitytype;
+import com.iemr.inventory.service.facilitytype.M_facilitytypeInter;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("FacilitytypeController Test Suite")
+class FacilitytypeControllerTest {
+
+ private static final String AUTH = "test-session-key";
+
+ @Mock
+ private M_facilitytypeInter m_facilitytypeInter;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked facility type service")
+ void setUp() {
+ FacilitytypeController controller = new FacilitytypeController();
+ ReflectionTestUtils.setField(controller, "m_facilitytypeInter", m_facilitytypeInter);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ private static M_facilitytype row(Integer id, String name) {
+ M_facilitytype row = new M_facilitytype();
+ row.setFacilityTypeID(id);
+ row.setFacilityTypeName(name);
+ row.setProviderServiceMapID(3);
+ return row;
+ }
+
+ private static ArrayList rows(M_facilitytype... items) {
+ return new ArrayList<>(List.of(items));
+ }
+
+ @Test
+ @DisplayName("addFacility should persist the posted array and answer with the saved rows")
+ void addFacility_shouldPersistPostedArray() throws Exception {
+ when(m_facilitytypeInter.addAllFicilityData(anyList())).thenReturn(rows(row(1, "first")));
+
+ mockMvc.perform(post("/addFacility").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("[{\"facilityTypeName\":\"first\",\"providerServiceMapID\":3}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].facilityTypeName").value("first"));
+
+ ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class);
+ verify(m_facilitytypeInter).addAllFicilityData(captor.capture());
+ assertEquals(1, captor.getValue().size());
+ }
+
+ @Test
+ @DisplayName("addFacility should report the failure when the service blows up")
+ void addFacility_shouldReportServiceFailure() throws Exception {
+ when(m_facilitytypeInter.addAllFicilityData(anyList())).thenThrow(new RuntimeException("db unavailable"));
+
+ mockMvc.perform(post("/addFacility").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("[{}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("db unavailable"));
+ }
+
+ @Test
+ @DisplayName("addFacility should report a parse failure for a malformed body")
+ void addFacility_shouldReportParseFailure() throws Exception {
+ mockMvc.perform(post("/addFacility").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("not-json"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getFacility should look the rows up by the posted provider service map id")
+ void getFacility_shouldLookUpByProviderServiceMapId() throws Exception {
+ when(m_facilitytypeInter.getAllFicilityData(3)).thenReturn(rows(row(1, "first"), row(2, "second")));
+
+ mockMvc.perform(post("/getFacility").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.length()").value(2));
+
+ verify(m_facilitytypeInter).getAllFicilityData(3);
+ }
+
+ @Test
+ @DisplayName("getFacility should report the failure when the lookup throws")
+ void getFacility_shouldReportServiceFailure() throws Exception {
+ when(m_facilitytypeInter.getAllFicilityData(anyInt())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getFacility").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("editFacility should copy the editable fields onto the stored row before saving")
+ void editFacility_shouldCopyEditableFieldsBeforeSaving() throws Exception {
+ M_facilitytype stored = row(1, "old name");
+ when(m_facilitytypeInter.editAllFicilityData(1)).thenReturn(stored);
+ when(m_facilitytypeInter.updateFacilityData(any(M_facilitytype.class))).thenAnswer(invocation -> invocation.getArgument(0));
+
+ mockMvc.perform(post("/editFacility").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityTypeID\":1,\"facilityTypeName\":\"new name\",\"facilityTypeDesc\":\"new desc\","
+ + "\"facilityTypeCode\":\"NEW\",\"modifiedBy\":\"tester\"}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.facilityTypeName").value("new name"));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_facilitytype.class);
+ verify(m_facilitytypeInter).updateFacilityData(captor.capture());
+ assertEquals("tester", captor.getValue().getModifiedBy());
+ }
+
+ @Test
+ @DisplayName("editFacility should report the failure when the row cannot be found")
+ void editFacility_shouldReportFailureWhenRowMissing() throws Exception {
+ when(m_facilitytypeInter.editAllFicilityData(1)).thenReturn(null);
+
+ mockMvc.perform(post("/editFacility").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityTypeID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("deleteFacility should flip the deleted flag on the stored row and save it")
+ void deleteFacility_shouldFlipDeletedFlag() throws Exception {
+ M_facilitytype stored = row(1, "first");
+ when(m_facilitytypeInter.editAllFicilityData(1)).thenReturn(stored);
+ when(m_facilitytypeInter.updateFacilityData(any(M_facilitytype.class))).thenAnswer(invocation -> invocation.getArgument(0));
+
+ mockMvc.perform(post("/deleteFacility").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityTypeID\":1,\"deleted\":true}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_facilitytype.class);
+ verify(m_facilitytypeInter).updateFacilityData(captor.capture());
+ assertEquals(Boolean.TRUE, captor.getValue().getDeleted());
+ }
+
+ @Test
+ @DisplayName("deleteFacility should report the failure when the row cannot be found")
+ void deleteFacility_shouldReportFailureWhenRowMissing() throws Exception {
+ when(m_facilitytypeInter.editAllFicilityData(1)).thenReturn(null);
+
+ mockMvc.perform(post("/deleteFacility").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityTypeID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/health/HealthControllerTest.java b/src/test/java/com/iemr/inventory/controller/health/HealthControllerTest.java
new file mode 100644
index 00000000..5cb9a4ac
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/health/HealthControllerTest.java
@@ -0,0 +1,106 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.health;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.service.health.HealthService;
+
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("HealthController Test Suite")
+class HealthControllerTest {
+
+ @Mock
+ private HealthService healthService;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Set up standalone MockMvc before each test")
+ void setUp() {
+ mockMvc = MockMvcBuilders.standaloneSetup(new HealthController(healthService)).build();
+ }
+
+ private Map healthResponse(String overallStatus) {
+ Map response = new LinkedHashMap<>();
+ response.put("status", overallStatus);
+ response.put("checkedAt", "2025-06-25T10:00:00Z");
+ return response;
+ }
+
+ @Test
+ @DisplayName("checkHealth should return 200 with the payload when all services are UP")
+ void checkHealth_shouldReturnOkWhenStatusIsUp() throws Exception {
+ when(healthService.checkHealth()).thenReturn(healthResponse("UP"));
+
+ mockMvc.perform(get("/health"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.status").value("UP"))
+ .andExpect(jsonPath("$.checkedAt").value("2025-06-25T10:00:00Z"));
+ }
+
+ @Test
+ @DisplayName("checkHealth should return 200 when DEGRADED, since the instance is still operational")
+ void checkHealth_shouldReturnOkWhenStatusIsDegraded() throws Exception {
+ when(healthService.checkHealth()).thenReturn(healthResponse("DEGRADED"));
+
+ mockMvc.perform(get("/health"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.status").value("DEGRADED"));
+ }
+
+ @Test
+ @DisplayName("checkHealth should return 503 when a critical service is DOWN")
+ void checkHealth_shouldReturnServiceUnavailableWhenStatusIsDown() throws Exception {
+ when(healthService.checkHealth()).thenReturn(healthResponse("DOWN"));
+
+ mockMvc.perform(get("/health"))
+ .andExpect(status().isServiceUnavailable())
+ .andExpect(jsonPath("$.status").value("DOWN"));
+ }
+
+ @Test
+ @DisplayName("checkHealth should return 503 with a DOWN payload when the service throws unexpectedly")
+ void checkHealth_shouldReturnServiceUnavailableWhenServiceThrows() throws Exception {
+ when(healthService.checkHealth()).thenThrow(new IllegalStateException("unexpected failure"));
+
+ mockMvc.perform(get("/health"))
+ .andExpect(status().isServiceUnavailable())
+ .andExpect(jsonPath("$.status").value("DOWN"))
+ .andExpect(jsonPath("$.timestamp").exists());
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/indent/IndentControllerTest.java b/src/test/java/com/iemr/inventory/controller/indent/IndentControllerTest.java
new file mode 100644
index 00000000..bd21d1cb
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/indent/IndentControllerTest.java
@@ -0,0 +1,323 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.indent;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.indent.Indent;
+import com.iemr.inventory.data.indent.IndentIssue;
+import com.iemr.inventory.data.indent.IndentOrder;
+import com.iemr.inventory.data.indent.ItemfacilitymappingIndent;
+import com.iemr.inventory.service.indent.IndentService;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("IndentController Test Suite")
+class IndentControllerTest {
+
+ private static final String AUTH = "test-session-key";
+
+ @Mock
+ private IndentService indentService;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked indent service")
+ void setUp() {
+ IndentController controller = new IndentController();
+ ReflectionTestUtils.setField(controller, "IndentService", indentService);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ @Test
+ @DisplayName("partialsearchindentitems should trim the posted item name before searching")
+ void partialsearchindentitems_shouldTrimItemName() throws Exception {
+ when(indentService.findItemIndent(1, "Para")).thenReturn(List.of(new ItemfacilitymappingIndent()));
+
+ mockMvc.perform(post("/indentController/partialsearchindentitems").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"itemName\":\" Para \",\"facilityID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(indentService).findItemIndent(1, "Para");
+ }
+
+ @Test
+ @DisplayName("partialsearchindentitems should report the failure when the search throws")
+ void partialsearchindentitems_shouldReportServiceFailure() throws Exception {
+ when(indentService.findItemIndent(anyInt(), anyString())).thenThrow(new RuntimeException("search failed"));
+
+ mockMvc.perform(post("/indentController/partialsearchindentitems").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"itemName\":\"Para\",\"facilityID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("createIndentRequest should hand the posted indent to the service")
+ void createIndentRequest_shouldHandIndentToService() throws Exception {
+ when(indentService.createIndentRequest(any(Indent.class))).thenReturn("{\"indentID\":88}");
+
+ mockMvc.perform(post("/indentController/createIndentRequest").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"fromFacilityID\":1,\"toFacilityID\":2,\"indentOrder\":[]}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.indentID").value(88));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(Indent.class);
+ verify(indentService).createIndentRequest(captor.capture());
+ assertEquals(1, captor.getValue().getFromFacilityID());
+ }
+
+ @Test
+ @DisplayName("createIndentRequest should report the failure when the service throws")
+ void createIndentRequest_shouldReportServiceFailure() throws Exception {
+ when(indentService.createIndentRequest(any(Indent.class))).thenThrow(new RuntimeException("db unavailable"));
+
+ mockMvc.perform(post("/indentController/createIndentRequest").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"fromFacilityID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getIndentHistory should hand the posted indent probe to the service")
+ void getIndentHistory_shouldHandProbeToService() throws Exception {
+ when(indentService.getIndentHistory(any(Indent.class))).thenReturn("[]");
+
+ mockMvc.perform(post("/indentController/getIndentHistory").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"fromFacilityID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(Indent.class);
+ verify(indentService).getIndentHistory(captor.capture());
+ assertEquals(1, captor.getValue().getFromFacilityID());
+ }
+
+ @Test
+ @DisplayName("getIndentHistory should report the failure when the lookup throws")
+ void getIndentHistory_shouldReportServiceFailure() throws Exception {
+ when(indentService.getIndentHistory(any(Indent.class))).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/indentController/getIndentHistory").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"fromFacilityID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getOrdersByIndentID should hand the posted order probe to the service")
+ void getOrdersByIndentID_shouldHandProbeToService() throws Exception {
+ when(indentService.getOrdersByIndentID(any(IndentOrder.class))).thenReturn("[]");
+
+ mockMvc.perform(post("/indentController/getOrdersByIndentID").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"indentID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(IndentOrder.class);
+ verify(indentService).getOrdersByIndentID(captor.capture());
+ assertEquals(88L, captor.getValue().getIndentID());
+ }
+
+ @Test
+ @DisplayName("getOrdersByIndentID should report the failure when the lookup throws")
+ void getOrdersByIndentID_shouldReportServiceFailure() throws Exception {
+ when(indentService.getOrdersByIndentID(any(IndentOrder.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/indentController/getOrdersByIndentID").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"indentID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getIndentWorklist should hand the posted worklist filter to the service")
+ void getIndentWorklist_shouldHandFilterToService() throws Exception {
+ when(indentService.getIndentWorklist(any(IndentOrder.class))).thenReturn("[]");
+
+ mockMvc.perform(post("/indentController/getIndentWorklist").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"facilityID\":2}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(IndentOrder.class);
+ verify(indentService).getIndentWorklist(captor.capture());
+ assertEquals(2, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getIndentWorklist should report the failure when the lookup throws")
+ void getIndentWorklist_shouldReportServiceFailure() throws Exception {
+ when(indentService.getIndentWorklist(any(IndentOrder.class))).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/indentController/getIndentWorklist").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"facilityID\":2}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getIndentOrderWorklist should hand the posted order probe to the service")
+ void getIndentOrderWorklist_shouldHandProbeToService() throws Exception {
+ when(indentService.getIndentOrderWorklist(any(IndentOrder.class))).thenReturn("[]");
+
+ mockMvc.perform(post("/indentController/getIndentOrderWorklist").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"indentID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(indentService).getIndentOrderWorklist(any(IndentOrder.class));
+ }
+
+ @Test
+ @DisplayName("getIndentOrderWorklist should report the failure when the lookup throws")
+ void getIndentOrderWorklist_shouldReportServiceFailure() throws Exception {
+ when(indentService.getIndentOrderWorklist(any(IndentOrder.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/indentController/getIndentOrderWorklist").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"indentID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("issueIndent should hand the posted array of issue lines to the service")
+ void issueIndent_shouldHandIssueLinesToService() throws Exception {
+ when(indentService.issueIndent(any(IndentIssue[].class))).thenReturn("Dispensed successfully");
+
+ mockMvc.perform(post("/indentController/issueIndent").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("[{\"indentID\":88,\"action\":\"Issued\",\"issuedQty\":6}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.response").value("Dispensed successfully"));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(IndentIssue[].class);
+ verify(indentService).issueIndent(captor.capture());
+ assertEquals("Issued", captor.getValue()[0].getAction());
+ }
+
+ @Test
+ @DisplayName("issueIndent should report the failure when the issue throws")
+ void issueIndent_shouldReportServiceFailure() throws Exception {
+ when(indentService.issueIndent(any(IndentIssue[].class))).thenThrow(new RuntimeException("issue failed"));
+
+ mockMvc.perform(post("/indentController/issueIndent").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("[{}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("cancelIndentOrder should hand the posted indent to the service")
+ void cancelIndentOrder_shouldHandIndentToService() throws Exception {
+ when(indentService.cancelIndentOrder(any(Indent.class))).thenReturn("Cancelled successfully");
+
+ mockMvc.perform(post("/indentController/cancelIndentOrder").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"indentID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.data.response").value("Cancelled successfully"));
+ }
+
+ @Test
+ @DisplayName("cancelIndentOrder should report the failure when the cancellation throws")
+ void cancelIndentOrder_shouldReportServiceFailure() throws Exception {
+ when(indentService.cancelIndentOrder(any(Indent.class))).thenThrow(new RuntimeException("cancel failed"));
+
+ mockMvc.perform(post("/indentController/cancelIndentOrder").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"indentID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("receiveIndent should hand the posted indent to the service")
+ void receiveIndent_shouldHandIndentToService() throws Exception {
+ when(indentService.receiveIndent(any(Indent.class))).thenReturn("Received successfully");
+
+ mockMvc.perform(post("/indentController/receiveIndent").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"indentID\":88,\"fromFacilityID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.data.response").value("Received successfully"));
+ }
+
+ @Test
+ @DisplayName("receiveIndent should report the failure when the receipt throws")
+ void receiveIndent_shouldReportServiceFailure() throws Exception {
+ when(indentService.receiveIndent(any(Indent.class))).thenThrow(new RuntimeException("receive failed"));
+
+ mockMvc.perform(post("/indentController/receiveIndent").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"indentID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("updateIndentOrder should hand the posted indent to the service")
+ void updateIndentOrder_shouldHandIndentToService() throws Exception {
+ when(indentService.updateIndentOrder(any(Indent.class))).thenReturn("Updated successfully");
+
+ mockMvc.perform(post("/indentController/updateIndentOrder").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"indentID\":88,\"fromFacilityID\":1,\"indentOrder\":[]}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.data.response").value("Updated successfully"));
+ }
+
+ @Test
+ @DisplayName("updateIndentOrder should report the failure when the update throws")
+ void updateIndentOrder_shouldReportServiceFailure() throws Exception {
+ when(indentService.updateIndentOrder(any(Indent.class))).thenThrow(new RuntimeException("update failed"));
+
+ mockMvc.perform(post("/indentController/updateIndentOrder").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"indentID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/item/ItemControllerTest.java b/src/test/java/com/iemr/inventory/controller/item/ItemControllerTest.java
new file mode 100644
index 00000000..8d7699fa
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/item/ItemControllerTest.java
@@ -0,0 +1,355 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.item;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.items.ItemMaster;
+import com.iemr.inventory.data.items.M_ItemCategory;
+import com.iemr.inventory.data.items.M_ItemForm;
+import com.iemr.inventory.data.items.M_Route;
+import com.iemr.inventory.service.item.ItemService;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("ItemController Test Suite")
+class ItemControllerTest {
+
+ private static final String AUTH = "test-session-key";
+
+ @Mock
+ private ItemService itemService;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked item service")
+ void setUp() {
+ ItemController controller = new ItemController();
+ ReflectionTestUtils.setField(controller, "itemService", itemService);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ private static ItemMaster item(Integer id, String name) {
+ ItemMaster item = new ItemMaster();
+ item.setItemID(id);
+ item.setItemName(name);
+ item.setProviderServiceMapID(3);
+ return item;
+ }
+
+ @Test
+ @DisplayName("getItemForm should return the forms configured for the provider service map")
+ void getItemForm_shouldReturnFormsForProviderServiceMap() throws Exception {
+ when(itemService.getItemFormProviderServiceMapID(3)).thenReturn(List.of(new M_ItemForm()));
+
+ mockMvc.perform(get("/getItemForm/3").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.length()").value(1));
+ }
+
+ @Test
+ @DisplayName("getItemForm should report the failure when the lookup throws")
+ void getItemForm_shouldReportServiceFailure() throws Exception {
+ when(itemService.getItemFormProviderServiceMapID(anyInt())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(get("/getItemForm/3").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getItemRoute should return the routes configured for the provider service map")
+ void getItemRoute_shouldReturnRoutesForProviderServiceMap() throws Exception {
+ when(itemService.getItemRouteProviderServiceMapID(3)).thenReturn(List.of(new M_Route()));
+
+ mockMvc.perform(get("/getItemRoute/3").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+ }
+
+ @Test
+ @DisplayName("getItemRoute should report the failure when the lookup throws")
+ void getItemRoute_shouldReportServiceFailure() throws Exception {
+ when(itemService.getItemRouteProviderServiceMapID(anyInt())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(get("/getItemRoute/3").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getItemCategory should ask for every category when the flag path segment is zero")
+ void getItemCategory_shouldAskForEveryCategoryWhenFlagIsZero() throws Exception {
+ when(itemService.getItemCategory(true, 3)).thenReturn(List.of(new M_ItemCategory()));
+
+ mockMvc.perform(get("/getItemCategory/3/0").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(itemService).getItemCategory(true, 3);
+ }
+
+ @Test
+ @DisplayName("getItemCategory should ask for the live categories only when the flag path segment is not zero")
+ void getItemCategory_shouldAskForLiveCategoriesWhenFlagIsNotZero() throws Exception {
+ when(itemService.getItemCategory(false, 3)).thenReturn(List.of(new M_ItemCategory()));
+
+ mockMvc.perform(get("/getItemCategory/3/1").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(itemService).getItemCategory(false, 3);
+ }
+
+ @Test
+ @DisplayName("getItemCategory should report the failure when the lookup throws")
+ void getItemCategory_shouldReportServiceFailure() throws Exception {
+ when(itemService.getItemCategory(true, 3)).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(get("/getItemCategory/3/0").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("createItemMaster should save the posted batch and answer with the stored rows")
+ void createItemMaster_shouldSavePostedBatch() throws Exception {
+ when(itemService.addAllItemMaster(anyList())).thenReturn(List.of(item(1, "Paracetamol")));
+
+ mockMvc.perform(post("/createItemMaster").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("[{\"itemName\":\"Paracetamol\",\"providerServiceMapID\":3}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].itemName").value("Paracetamol"));
+
+ ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class);
+ verify(itemService).addAllItemMaster(captor.capture());
+ assertEquals(1, captor.getValue().size());
+ }
+
+ @Test
+ @DisplayName("createItemMaster should report the failure when the save throws")
+ void createItemMaster_shouldReportServiceFailure() throws Exception {
+ when(itemService.addAllItemMaster(anyList())).thenThrow(new RuntimeException("db unavailable"));
+
+ mockMvc.perform(post("/createItemMaster").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("[{}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getItemMaster should return the items of the provider service map")
+ void getItemMaster_shouldReturnItemsOfProviderServiceMap() throws Exception {
+ when(itemService.getItemMaster(3)).thenReturn(List.of(item(1, "Paracetamol")));
+
+ mockMvc.perform(get("/getItemMaster/3").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.data[0].itemName").value("Paracetamol"));
+ }
+
+ @Test
+ @DisplayName("getItemMaster should report the failure when the lookup throws")
+ void getItemMaster_shouldReportServiceFailure() throws Exception {
+ when(itemService.getItemMaster(anyInt())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(get("/getItemMaster/3").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getActiveItemMaster should pass the posted probe item to the service")
+ void getActiveItemMaster_shouldPassProbeItemThrough() throws Exception {
+ when(itemService.getActiveItemMaster(any(ItemMaster.class))).thenReturn(List.of(item(1, "Paracetamol")));
+
+ mockMvc.perform(post("/getActiveItemMaster").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"deleted\":false,\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemMaster.class);
+ verify(itemService).getActiveItemMaster(captor.capture());
+ assertEquals(Boolean.FALSE, captor.getValue().getDeleted());
+ assertEquals(3, captor.getValue().getProviderServiceMapID());
+ }
+
+ @Test
+ @DisplayName("getActiveItemMaster should report the failure when the lookup throws")
+ void getActiveItemMaster_shouldReportServiceFailure() throws Exception {
+ when(itemService.getActiveItemMaster(any(ItemMaster.class))).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getActiveItemMaster").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("blockItemMaster should pass the item id and the delete flag straight through")
+ void blockItemMaster_shouldPassIdAndFlagThrough() throws Exception {
+ when(itemService.blockItemMaster(9, true)).thenReturn(1);
+
+ mockMvc.perform(get("/blockItemMaster/9/true").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.response").value("1"));
+
+ verify(itemService).blockItemMaster(9, true);
+ }
+
+ @Test
+ @DisplayName("blockItemMaster should report the failure when the update throws")
+ void blockItemMaster_shouldReportServiceFailure() throws Exception {
+ when(itemService.blockItemMaster(9, true)).thenThrow(new RuntimeException("update failed"));
+
+ mockMvc.perform(get("/blockItemMaster/9/true").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("discontinueItemMaster should pass the item id and the discontinue flag straight through")
+ void discontinueItemMaster_shouldPassIdAndFlagThrough() throws Exception {
+ when(itemService.discontinueItemMaster(9, false)).thenReturn(1);
+
+ mockMvc.perform(get("/discontinueItemMaster/9/false").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(itemService).discontinueItemMaster(9, false);
+ }
+
+ @Test
+ @DisplayName("discontinueItemMaster should report the failure when the update throws")
+ void discontinueItemMaster_shouldReportServiceFailure() throws Exception {
+ when(itemService.discontinueItemMaster(9, false)).thenThrow(new RuntimeException("update failed"));
+
+ mockMvc.perform(get("/discontinueItemMaster/9/false").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("editItemMaster should copy the description and modifier onto the stored item before saving")
+ void editItemMaster_shouldCopyEditableFields() throws Exception {
+ ItemMaster stored = item(9, "Paracetamol");
+ when(itemService.getItemMasterByID(9)).thenReturn(stored);
+ when(itemService.createItemMaster(any(ItemMaster.class))).thenAnswer(inv -> inv.getArgument(0));
+
+ mockMvc.perform(post("/editItemMaster").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"itemID\":9,\"itemDesc\":\"new desc\",\"modifiedBy\":\"tester\"}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemMaster.class);
+ verify(itemService).createItemMaster(captor.capture());
+ assertEquals("new desc", captor.getValue().getItemDesc());
+ assertEquals("tester", captor.getValue().getModifiedBy());
+ }
+
+ @Test
+ @DisplayName("editItemMaster should report the failure when the item cannot be found")
+ void editItemMaster_shouldReportFailureWhenItemMissing() throws Exception {
+ when(itemService.getItemMasterByID(9)).thenReturn(null);
+
+ mockMvc.perform(post("/editItemMaster").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"itemID\":9}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("configItemIssue should push the posted categories into the issue configuration")
+ void configItemIssue_shouldUpdateIssueConfiguration() throws Exception {
+ when(itemService.updateItemIssueConfig(anyList())).thenReturn(2);
+
+ mockMvc.perform(post("/configItemIssue").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("[{\"itemCategoryID\":1,\"issueType\":\"Bulk\"},{\"itemCategoryID\":2,\"issueType\":\"Single\"}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.response").value("2"));
+ }
+
+ @Test
+ @DisplayName("configItemIssue should report the failure when the update throws")
+ void configItemIssue_shouldReportServiceFailure() throws Exception {
+ when(itemService.updateItemIssueConfig(anyList())).thenThrow(new RuntimeException("update failed"));
+
+ mockMvc.perform(post("/configItemIssue").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("[{}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getItem should narrow the items to the posted provider service map and category")
+ void getItem_shouldNarrowByProviderServiceMapAndCategory() throws Exception {
+ when(itemService.getItemMasters(3, 5)).thenReturn(List.of(item(1, "Paracetamol")));
+
+ mockMvc.perform(post("/getItem").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3,\"itemCategoryID\":5}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(itemService).getItemMasters(3, 5);
+ }
+
+ @Test
+ @DisplayName("getItem should report the failure when the lookup throws")
+ void getItem_shouldReportServiceFailure() throws Exception {
+ when(itemService.getItemMasters(anyInt(), anyInt())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getItem").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3,\"itemCategoryID\":5}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/itemfacilitymapping/ItemfacilitymappingControllerTest.java b/src/test/java/com/iemr/inventory/controller/itemfacilitymapping/ItemfacilitymappingControllerTest.java
new file mode 100644
index 00000000..ef244522
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/itemfacilitymapping/ItemfacilitymappingControllerTest.java
@@ -0,0 +1,314 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.itemfacilitymapping;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.items.ItemInStore;
+import com.iemr.inventory.data.items.ItemMaster;
+import com.iemr.inventory.data.itemfacilitymapping.M_itemfacilitymapping;
+import com.iemr.inventory.data.itemfacilitymapping.V_fetchItemFacilityMap;
+import com.iemr.inventory.data.stockentry.ItemStockEntry;
+import com.iemr.inventory.service.itemfacilitymapping.M_itemfacilitymappingInter;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("ItemfacilitymappingController Test Suite")
+class ItemfacilitymappingControllerTest {
+
+ private static final String AUTH = "test-session-key";
+
+ @Mock
+ private M_itemfacilitymappingInter m_itemfacilitymappingInter;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked item-facility mapping service")
+ void setUp() {
+ ItemfacilitymappingController controller = new ItemfacilitymappingController();
+ ReflectionTestUtils.setField(controller, "M_itemfacilitymappingInter", m_itemfacilitymappingInter);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ private static M_itemfacilitymapping mapping(Integer id) {
+ M_itemfacilitymapping mapping = new M_itemfacilitymapping();
+ mapping.setItemStoreMapID(id);
+ mapping.setFacilityID(7);
+ mapping.setItemID(11);
+ return mapping;
+ }
+
+ @Test
+ @DisplayName("mapItemtoStrore should fan the posted item id array out into one mapping row per item")
+ void mapItemtoStrore_shouldFanItemArrayIntoRows() throws Exception {
+ when(m_itemfacilitymappingInter.mapItemtoStore(anyList()))
+ .thenReturn(new ArrayList<>(List.of(mapping(1), mapping(2))));
+
+ mockMvc.perform(post("/mapItemtoStrore").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("[{\"facilityID\":7,\"mappingType\":\"Main\",\"providerServiceMapID\":3,"
+ + "\"status\":\"Active\",\"createdBy\":\"tester\",\"itemID1\":[11,12,13]}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class);
+ verify(m_itemfacilitymappingInter).mapItemtoStore(captor.capture());
+ List sent = captor.getValue();
+ assertEquals(3, sent.size());
+ assertEquals(11, sent.get(0).getItemID());
+ assertEquals(13, sent.get(2).getItemID());
+ assertEquals(7, sent.get(0).getFacilityID());
+ assertEquals("Main", sent.get(0).getMappingType());
+ assertEquals("tester", sent.get(0).getCreatedBy());
+ }
+
+ @Test
+ @DisplayName("mapItemtoStrore should report the failure when the posted payload carries no item id array")
+ void mapItemtoStrore_shouldReportFailureWhenItemArrayMissing() throws Exception {
+ mockMvc.perform(post("/mapItemtoStrore").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("[{\"facilityID\":7}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("editItemtoStrore should copy the editable fields onto the stored mapping before saving")
+ void editItemtoStrore_shouldCopyEditableFields() throws Exception {
+ M_itemfacilitymapping stored = mapping(5);
+ when(m_itemfacilitymappingInter.editdata(5)).thenReturn(stored);
+ when(m_itemfacilitymappingInter.saveEditedItem(any(M_itemfacilitymapping.class)))
+ .thenAnswer(inv -> inv.getArgument(0));
+
+ mockMvc.perform(post("/editItemtoStrore").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"itemFacilityMapID\":5,\"facilityID\":9,\"itemID\":22,\"mappingType\":\"Sub\","
+ + "\"providerServiceMapID\":3,\"status\":\"Inactive\"}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_itemfacilitymapping.class);
+ verify(m_itemfacilitymappingInter).saveEditedItem(captor.capture());
+ assertEquals(9, captor.getValue().getFacilityID());
+ assertEquals(22, captor.getValue().getItemID());
+ assertEquals("Sub", captor.getValue().getMappingType());
+ assertEquals("Inactive", captor.getValue().getStatus());
+ }
+
+ @Test
+ @DisplayName("editItemtoStrore should report the failure when the mapping cannot be found")
+ void editItemtoStrore_shouldReportFailureWhenMappingMissing() throws Exception {
+ when(m_itemfacilitymappingInter.editdata(5)).thenReturn(null);
+
+ mockMvc.perform(post("/editItemtoStrore").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"itemFacilityMapID\":5}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("deleteItemtoStrore should flip the deleted flag on the stored mapping and save it")
+ void deleteItemtoStrore_shouldFlipDeletedFlag() throws Exception {
+ M_itemfacilitymapping stored = mapping(5);
+ when(m_itemfacilitymappingInter.editdata(5)).thenReturn(stored);
+ when(m_itemfacilitymappingInter.saveEditedItem(any(M_itemfacilitymapping.class)))
+ .thenAnswer(inv -> inv.getArgument(0));
+
+ mockMvc.perform(post("/deleteItemtoStrore").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"itemFacilityMapID\":5,\"deleted\":true}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_itemfacilitymapping.class);
+ verify(m_itemfacilitymappingInter).saveEditedItem(captor.capture());
+ assertEquals(Boolean.TRUE, captor.getValue().getDeleted());
+ }
+
+ @Test
+ @DisplayName("deleteItemtoStrore should report the failure when the mapping cannot be found")
+ void deleteItemtoStrore_shouldReportFailureWhenMappingMissing() throws Exception {
+ when(m_itemfacilitymappingInter.editdata(5)).thenReturn(null);
+
+ mockMvc.perform(post("/deleteItemtoStrore").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"itemFacilityMapID\":5}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("getSubStroreitem should look the sub-store items up by provider service map and facility")
+ void getSubStroreitem_shouldLookUpByProviderServiceMapAndFacility() throws Exception {
+ when(m_itemfacilitymappingInter.getsubitemforsubStote(3, 7))
+ .thenReturn(new ArrayList<>(List.of(mapping(1))));
+
+ mockMvc.perform(post("/getSubStoreitem").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3,\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(m_itemfacilitymappingInter).getsubitemforsubStote(3, 7);
+ }
+
+ @Test
+ @DisplayName("getSubStroreitem should report the failure when the lookup throws")
+ void getSubStroreitem_shouldReportServiceFailure() throws Exception {
+ when(m_itemfacilitymappingInter.getsubitemforsubStote(anyInt(), anyInt()))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getSubStoreitem").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3,\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getAllFacilityMappedData should look the mapped rows up by provider service map")
+ void getAllFacilityMappedData_shouldLookUpByProviderServiceMap() throws Exception {
+ when(m_itemfacilitymappingInter.getAllFacilityMappedData(3))
+ .thenReturn(new ArrayList<>(List.of(new V_fetchItemFacilityMap())));
+
+ mockMvc.perform(post("/getAllFacilityMappedData").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(m_itemfacilitymappingInter).getAllFacilityMappedData(3);
+ }
+
+ @Test
+ @DisplayName("getAllFacilityMappedData should report the failure when the lookup throws")
+ void getAllFacilityMappedData_shouldReportServiceFailure() throws Exception {
+ when(m_itemfacilitymappingInter.getAllFacilityMappedData(anyInt()))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getAllFacilityMappedData").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getItemFromStoreID should return the items the store holds")
+ void getItemFromStoreID_shouldReturnItemsOfStore() throws Exception {
+ when(m_itemfacilitymappingInter.getItemMastersFromStoreID(7))
+ .thenReturn(List.of(new ItemInStore(7, 11, "Paracetamol", 40L)));
+
+ mockMvc.perform(post("/getItemFromStoreID/7").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(m_itemfacilitymappingInter).getItemMastersFromStoreID(7);
+ }
+
+ @Test
+ @DisplayName("getItemFromStoreID should report the failure when the lookup throws")
+ void getItemFromStoreID_shouldReportServiceFailure() throws Exception {
+ when(m_itemfacilitymappingInter.getItemMastersFromStoreID(anyInt()))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getItemFromStoreID/7").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("itemPartialSearch should pass the item name and facility from the posted probe item")
+ void itemPartialSearch_shouldPassNameAndFacility() throws Exception {
+ when(m_itemfacilitymappingInter.getItemMastersPartialSearch("Para", 7))
+ .thenReturn(List.of(new ItemMaster()));
+
+ mockMvc.perform(post("/itemPartialSearch").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"itemName\":\"Para\",\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(m_itemfacilitymappingInter).getItemMastersPartialSearch("Para", 7);
+ }
+
+ @Test
+ @DisplayName("itemPartialSearch should report the failure when the search throws")
+ void itemPartialSearch_shouldReportServiceFailure() throws Exception {
+ when(m_itemfacilitymappingInter.getItemMastersPartialSearch(anyString(), anyInt()))
+ .thenThrow(new RuntimeException("search failed"));
+
+ mockMvc.perform(post("/itemPartialSearch").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"itemName\":\"Para\",\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getItemBatchForStoreTransfer should pass the two facilities and the item name straight through")
+ void getItemBatchForStoreTransfer_shouldPassTransferDetails() throws Exception {
+ when(m_itemfacilitymappingInter.getItemBatchForStoreTransfer(1, 2, "Para"))
+ .thenReturn(List.of(new ItemStockEntry()));
+
+ mockMvc.perform(post("/getItemBatchForStoreTransfer").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"transferFromFacilityID\":1,\"transferToFacilityID\":2,\"itemName\":\"Para\"}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(m_itemfacilitymappingInter).getItemBatchForStoreTransfer(1, 2, "Para");
+ }
+
+ @Test
+ @DisplayName("getItemBatchForStoreTransfer should report the failure when the lookup throws")
+ void getItemBatchForStoreTransfer_shouldReportServiceFailure() throws Exception {
+ when(m_itemfacilitymappingInter.getItemBatchForStoreTransfer(anyInt(), anyInt(), anyString()))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getItemBatchForStoreTransfer").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"transferFromFacilityID\":1,\"transferToFacilityID\":2,\"itemName\":\"Para\"}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/manufacturer/ManufacturerControllerTest.java b/src/test/java/com/iemr/inventory/controller/manufacturer/ManufacturerControllerTest.java
new file mode 100644
index 00000000..23d86143
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/manufacturer/ManufacturerControllerTest.java
@@ -0,0 +1,203 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.manufacturer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.manufacturer.M_Manufacturer;
+import com.iemr.inventory.service.manufacturer.ManufacturerInter;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("ManufacturerController Test Suite")
+class ManufacturerControllerTest {
+
+ private static final String AUTH = "test-session-key";
+
+ @Mock
+ private ManufacturerInter manufacturerInter;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked manufacturer service")
+ void setUp() {
+ ManufacturerController controller = new ManufacturerController();
+ ReflectionTestUtils.setField(controller, "manufacturerInter", manufacturerInter);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ private static M_Manufacturer row(Integer id, String name) {
+ M_Manufacturer row = new M_Manufacturer();
+ row.setManufacturerID(id);
+ row.setManufacturerName(name);
+ row.setProviderServiceMapID(3);
+ return row;
+ }
+
+ private static ArrayList rows(M_Manufacturer... items) {
+ return new ArrayList<>(List.of(items));
+ }
+
+ @Test
+ @DisplayName("createManufacturer should persist the posted array and answer with the saved rows")
+ void createManufacturer_shouldPersistPostedArray() throws Exception {
+ when(manufacturerInter.createManufacturer(anyList())).thenReturn(rows(row(1, "first")));
+
+ mockMvc.perform(post("/createManufacturer").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("[{\"manufacturerName\":\"first\",\"providerServiceMapID\":3}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].manufacturerName").value("first"));
+
+ ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class);
+ verify(manufacturerInter).createManufacturer(captor.capture());
+ assertEquals(1, captor.getValue().size());
+ }
+
+ @Test
+ @DisplayName("createManufacturer should report the failure when the service blows up")
+ void createManufacturer_shouldReportServiceFailure() throws Exception {
+ when(manufacturerInter.createManufacturer(anyList())).thenThrow(new RuntimeException("db unavailable"));
+
+ mockMvc.perform(post("/createManufacturer").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("[{}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("db unavailable"));
+ }
+
+ @Test
+ @DisplayName("createManufacturer should report a parse failure for a malformed body")
+ void createManufacturer_shouldReportParseFailure() throws Exception {
+ mockMvc.perform(post("/createManufacturer").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("not-json"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getManufacturer should look the rows up by the posted provider service map id")
+ void getManufacturer_shouldLookUpByProviderServiceMapId() throws Exception {
+ when(manufacturerInter.createManufacturer(3)).thenReturn(rows(row(1, "first"), row(2, "second")));
+
+ mockMvc.perform(post("/getManufacturer").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.length()").value(2));
+
+ verify(manufacturerInter).createManufacturer(3);
+ }
+
+ @Test
+ @DisplayName("getManufacturer should report the failure when the lookup throws")
+ void getManufacturer_shouldReportServiceFailure() throws Exception {
+ when(manufacturerInter.createManufacturer(anyInt())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getManufacturer").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("editManufacturer should copy the editable fields onto the stored row before saving")
+ void editManufacturer_shouldCopyEditableFieldsBeforeSaving() throws Exception {
+ M_Manufacturer stored = row(1, "old name");
+ when(manufacturerInter.editManufacturer(1)).thenReturn(stored);
+ when(manufacturerInter.saveEditedData(any(M_Manufacturer.class))).thenAnswer(invocation -> invocation.getArgument(0));
+
+ mockMvc.perform(post("/editManufacturer").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"manufacturerID\":1,\"manufacturerName\":\"new name\",\"manufacturerDesc\":\"new desc\","
+ + "\"manufacturerCode\":\"NEW\",\"status\":\"Inactive\",\"contactPerson\":\"Alex\","
+ + "\"cST_GST_No\":\"GST-9\",\"modifiedBy\":\"tester\"}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.manufacturerName").value("new name"));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_Manufacturer.class);
+ verify(manufacturerInter).saveEditedData(captor.capture());
+ assertEquals("tester", captor.getValue().getModifiedBy());
+ }
+
+ @Test
+ @DisplayName("editManufacturer should report the failure when the row cannot be found")
+ void editManufacturer_shouldReportFailureWhenRowMissing() throws Exception {
+ when(manufacturerInter.editManufacturer(1)).thenReturn(null);
+
+ mockMvc.perform(post("/editManufacturer").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"manufacturerID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("deleteManufacturer should flip the deleted flag on the stored row and save it")
+ void deleteManufacturer_shouldFlipDeletedFlag() throws Exception {
+ M_Manufacturer stored = row(1, "first");
+ when(manufacturerInter.editManufacturer(1)).thenReturn(stored);
+ when(manufacturerInter.saveEditedData(any(M_Manufacturer.class))).thenAnswer(invocation -> invocation.getArgument(0));
+
+ mockMvc.perform(post("/deleteManufacturer").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"manufacturerID\":1,\"deleted\":true}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_Manufacturer.class);
+ verify(manufacturerInter).saveEditedData(captor.capture());
+ assertEquals(Boolean.TRUE, captor.getValue().getDeleted());
+ }
+
+ @Test
+ @DisplayName("deleteManufacturer should report the failure when the row cannot be found")
+ void deleteManufacturer_shouldReportFailureWhenRowMissing() throws Exception {
+ when(manufacturerInter.editManufacturer(1)).thenReturn(null);
+
+ mockMvc.perform(post("/deleteManufacturer").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"manufacturerID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/patientreturn/PatientReturnControllerTest.java b/src/test/java/com/iemr/inventory/controller/patientreturn/PatientReturnControllerTest.java
new file mode 100644
index 00000000..952cf105
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/patientreturn/PatientReturnControllerTest.java
@@ -0,0 +1,195 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.patientreturn;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.sql.Timestamp;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.patientreturn.ItemDetailModel;
+import com.iemr.inventory.data.patientreturn.PatientReturnModel;
+import com.iemr.inventory.data.patientreturn.ReturnHistoryModel;
+import com.iemr.inventory.data.stockExit.ItemReturnEntry;
+import com.iemr.inventory.data.stockExit.T_PatientIssue;
+import com.iemr.inventory.service.patientreturn.PatientReturnService;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("PatientReturnController Test Suite")
+class PatientReturnControllerTest {
+
+ private static final String AUTH = "test-session-key";
+
+ @Mock
+ private PatientReturnService patientReturnService;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked patient return service")
+ void setUp() {
+ PatientReturnController controller = new PatientReturnController();
+ ReflectionTestUtils.setField(controller, "patientReturnService", patientReturnService);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ @Test
+ @DisplayName("getItemNameByRegID should forward the beneficiary and facility from the posted payload")
+ void getItemNameByRegID_shouldForwardBeneficiaryAndFacility() throws Exception {
+ when(patientReturnService.getItemNameByRegID(any(T_PatientIssue.class)))
+ .thenReturn(List.of(new PatientReturnModel(101L, 7, 11, "Paracetamol")));
+
+ mockMvc.perform(post("/patientReturnController/getItemNameByRegID").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"benRegID\":101,\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].itemName").value("Paracetamol"));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(T_PatientIssue.class);
+ verify(patientReturnService).getItemNameByRegID(captor.capture());
+ assertEquals(101L, captor.getValue().getBenRegID());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getItemNameByRegID should report the failure when the lookup throws")
+ void getItemNameByRegID_shouldReportServiceFailure() throws Exception {
+ when(patientReturnService.getItemNameByRegID(any(T_PatientIssue.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/patientReturnController/getItemNameByRegID").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"benRegID\":101,\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getItemDetailByBen should forward the beneficiary, item and facility from the posted payload")
+ void getItemDetailByBen_shouldForwardProbe() throws Exception {
+ when(patientReturnService.getItemDetailByBen(any(ItemDetailModel.class)))
+ .thenReturn(List.of(new ItemDetailModel(11, "Paracetamol", "B-1", 20,
+ Timestamp.valueOf("2025-01-31 10:15:30"), false, false, 501L, 601L, 701L, 801L, 101L, 3, 7)));
+
+ mockMvc.perform(post("/patientReturnController/getItemDetailByBen").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"benRegID\":101,\"itemID\":11,\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].batchNo").value("B-1"));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemDetailModel.class);
+ verify(patientReturnService).getItemDetailByBen(captor.capture());
+ assertEquals(11, captor.getValue().getItemID());
+ }
+
+ @Test
+ @DisplayName("getItemDetailByBen should report the failure when the lookup throws")
+ void getItemDetailByBen_shouldReportServiceFailure() throws Exception {
+ when(patientReturnService.getItemDetailByBen(any(ItemDetailModel.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/patientReturnController/getItemDetailByBen").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"benRegID\":101}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("updateQuantityReturned should pass the posted array of returned lines to the service")
+ void updateQuantityReturned_shouldPassReturnedLines() throws Exception {
+ when(patientReturnService.updateQuantityReturned(any(ItemDetailModel[].class)))
+ .thenReturn("Quantity updated successfully");
+
+ mockMvc.perform(post("/patientReturnController/updateQuantityReturned").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("[{\"itemStockEntryID\":601,\"itemStockExitID\":501,\"returnQuantity\":4}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.response").value("Quantity updated successfully"));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemDetailModel[].class);
+ verify(patientReturnService).updateQuantityReturned(captor.capture());
+ assertEquals(1, captor.getValue().length);
+ assertEquals(4, captor.getValue()[0].getReturnQuantity());
+ }
+
+ @Test
+ @DisplayName("updateQuantityReturned should report the failure when the update throws")
+ void updateQuantityReturned_shouldReportServiceFailure() throws Exception {
+ when(patientReturnService.updateQuantityReturned(any(ItemDetailModel[].class)))
+ .thenThrow(new RuntimeException("update failed"));
+
+ mockMvc.perform(post("/patientReturnController/updateQuantityReturned").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("[{}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getBenReturnHistory should forward the facility and the date window from the posted payload")
+ void getBenReturnHistory_shouldForwardWindow() throws Exception {
+ when(patientReturnService.getBenReturnHistory(any(ItemReturnEntry.class)))
+ .thenReturn(List.of(new ReturnHistoryModel("Paracetamol", "B-1", 20,
+ Timestamp.valueOf("2025-01-31 10:15:30"), 701L, 801L, "Jane Doe", 34, "Female",
+ Timestamp.valueOf("2025-02-01 09:00:00"))));
+
+ mockMvc.perform(post("/patientReturnController/getBenReturnHistory").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].patientName").value("Jane Doe"));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemReturnEntry.class);
+ verify(patientReturnService).getBenReturnHistory(captor.capture());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getBenReturnHistory should report the failure when the lookup throws")
+ void getBenReturnHistory_shouldReportServiceFailure() throws Exception {
+ when(patientReturnService.getBenReturnHistory(any(ItemReturnEntry.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/patientReturnController/getBenReturnHistory").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/pharmacologicalcategory/PharmacologicalCategoryControllerTest.java b/src/test/java/com/iemr/inventory/controller/pharmacologicalcategory/PharmacologicalCategoryControllerTest.java
new file mode 100644
index 00000000..63297885
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/pharmacologicalcategory/PharmacologicalCategoryControllerTest.java
@@ -0,0 +1,202 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.pharmacologicalcategory;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.pharmacologicalcategory.M_Pharmacologicalcategory;
+import com.iemr.inventory.service.pharmacologicalcategory.PharmacologicalcategoryInter;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("PharmacologicalCategoryController Test Suite")
+class PharmacologicalCategoryControllerTest {
+
+ private static final String AUTH = "test-session-key";
+
+ @Mock
+ private PharmacologicalcategoryInter pharmacologicalcategoryInter;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked pharmacological category service")
+ void setUp() {
+ PharmacologicalCategoryController controller = new PharmacologicalCategoryController();
+ ReflectionTestUtils.setField(controller, "pharmacologicalcategoryInter", pharmacologicalcategoryInter);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ private static M_Pharmacologicalcategory row(Integer id, String name) {
+ M_Pharmacologicalcategory row = new M_Pharmacologicalcategory();
+ row.setPharmCategoryID(id);
+ row.setPharmCategoryName(name);
+ row.setProviderServiceMapID(3);
+ return row;
+ }
+
+ private static ArrayList rows(M_Pharmacologicalcategory... items) {
+ return new ArrayList<>(List.of(items));
+ }
+
+ @Test
+ @DisplayName("createPharmacologicalcategory should persist the posted array and answer with the saved rows")
+ void createPharmacologicalcategory_shouldPersistPostedArray() throws Exception {
+ when(pharmacologicalcategoryInter.createPharmacologicalcategory(anyList())).thenReturn(rows(row(1, "Analgesic")));
+
+ mockMvc.perform(post("/createPharmacologicalcategory").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("[{\"pharmCategoryName\":\"Analgesic\",\"providerServiceMapID\":3}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].pharmCategoryName").value("Analgesic"));
+
+ ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class);
+ verify(pharmacologicalcategoryInter).createPharmacologicalcategory(captor.capture());
+ assertEquals(1, captor.getValue().size());
+ }
+
+ @Test
+ @DisplayName("createPharmacologicalcategory should report the failure when the service blows up")
+ void createPharmacologicalcategory_shouldReportServiceFailure() throws Exception {
+ when(pharmacologicalcategoryInter.createPharmacologicalcategory(anyList()))
+ .thenThrow(new RuntimeException("db unavailable"));
+
+ mockMvc.perform(post("/createPharmacologicalcategory").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("[{}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("db unavailable"));
+ }
+
+ @Test
+ @DisplayName("getPharmacologicalcategory should look the rows up by the posted provider service map id")
+ void getPharmacologicalcategory_shouldLookUpByProviderServiceMapId() throws Exception {
+ when(pharmacologicalcategoryInter.getPharmacologicalcategory(3))
+ .thenReturn(rows(row(1, "Analgesic"), row(2, "Antibiotic")));
+
+ mockMvc.perform(post("/getPharmacologicalcategory").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.length()").value(2));
+
+ verify(pharmacologicalcategoryInter).getPharmacologicalcategory(3);
+ }
+
+ @Test
+ @DisplayName("getPharmacologicalcategory should report the failure when the lookup throws")
+ void getPharmacologicalcategory_shouldReportServiceFailure() throws Exception {
+ when(pharmacologicalcategoryInter.getPharmacologicalcategory(anyInt()))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getPharmacologicalcategory").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("editPharmacologicalcategory should copy the description and modifier onto the stored row")
+ void editPharmacologicalcategory_shouldCopyEditableFields() throws Exception {
+ M_Pharmacologicalcategory stored = row(1, "Analgesic");
+ when(pharmacologicalcategoryInter.editPharmacologicalcategory(1)).thenReturn(stored);
+ when(pharmacologicalcategoryInter.saveEditedPharData(any(M_Pharmacologicalcategory.class)))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+
+ mockMvc.perform(post("/editPharmacologicalcategory").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"pharmacologyCategoryID\":1,\"pharmCategoryDesc\":\"new desc\",\"modifiedBy\":\"tester\"}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.pharmCategoryDesc").value("new desc"));
+
+ ArgumentCaptor captor =
+ ArgumentCaptor.forClass(M_Pharmacologicalcategory.class);
+ verify(pharmacologicalcategoryInter).saveEditedPharData(captor.capture());
+ assertEquals("tester", captor.getValue().getModifiedBy());
+ }
+
+ @Test
+ @DisplayName("editPharmacologicalcategory should report the failure when the row cannot be found")
+ void editPharmacologicalcategory_shouldReportFailureWhenRowMissing() throws Exception {
+ when(pharmacologicalcategoryInter.editPharmacologicalcategory(1)).thenReturn(null);
+
+ mockMvc.perform(post("/editPharmacologicalcategory").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"pharmacologyCategoryID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("deletePharmacologicalcategory should flip the deleted flag on the stored row and save it")
+ void deletePharmacologicalcategory_shouldFlipDeletedFlag() throws Exception {
+ M_Pharmacologicalcategory stored = row(1, "Analgesic");
+ when(pharmacologicalcategoryInter.editPharmacologicalcategory(1)).thenReturn(stored);
+ when(pharmacologicalcategoryInter.saveEditedPharData(any(M_Pharmacologicalcategory.class)))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+
+ mockMvc.perform(post("/deletePharmacologicalcategory").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"pharmacologyCategoryID\":1,\"deleted\":true}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor =
+ ArgumentCaptor.forClass(M_Pharmacologicalcategory.class);
+ verify(pharmacologicalcategoryInter).saveEditedPharData(captor.capture());
+ assertEquals(Boolean.TRUE, captor.getValue().getDeleted());
+ }
+
+ @Test
+ @DisplayName("deletePharmacologicalcategory should report the failure when the row cannot be found")
+ void deletePharmacologicalcategory_shouldReportFailureWhenRowMissing() throws Exception {
+ when(pharmacologicalcategoryInter.editPharmacologicalcategory(1)).thenReturn(null);
+
+ mockMvc.perform(post("/deletePharmacologicalcategory").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"pharmacologyCategoryID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/report/CRMReportControllerTest.java b/src/test/java/com/iemr/inventory/controller/report/CRMReportControllerTest.java
new file mode 100644
index 00000000..1421dc70
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/report/CRMReportControllerTest.java
@@ -0,0 +1,349 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.report;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.report.ItemStockEntryReport;
+import com.iemr.inventory.data.report.ItemStockExitReport;
+import com.iemr.inventory.data.report.PatientIssueExitReport;
+import com.iemr.inventory.service.report.CRMReportService;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("CRMReportController Test Suite")
+class CRMReportControllerTest {
+
+ private static final String AUTH = "test-session-key";
+ private static final String WINDOW =
+ "{\"facilityID\":7,\"startDate\":\"2025-01-01T00:00:00.000\",\"endDate\":\"2025-01-31T23:59:00.000\"}";
+
+ @Mock
+ private CRMReportService crmReportService;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked report service")
+ void setUp() {
+ CRMReportController controller = new CRMReportController();
+ ReflectionTestUtils.setField(controller, "crmReportService", crmReportService);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ @Test
+ @DisplayName("getInwardStockReport should hand the posted window to the service and answer with the report")
+ void getInwardStockReport_shouldReturnReport() throws Exception {
+ when(crmReportService.getInwardStockReport(any(ItemStockEntryReport.class))).thenReturn("[{\"slNo\":1}]");
+
+ mockMvc.perform(post("/crmReportController/getInwardStockReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].slNo").value(1));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemStockEntryReport.class);
+ verify(crmReportService).getInwardStockReport(captor.capture());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getInwardStockReport should report the failure when the report generation throws")
+ void getInwardStockReport_shouldReportServiceFailure() throws Exception {
+ when(crmReportService.getInwardStockReport(any(ItemStockEntryReport.class))).thenThrow(new RuntimeException("report failed"));
+
+ mockMvc.perform(post("/crmReportController/getInwardStockReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("report failed"));
+ }
+
+ @Test
+ @DisplayName("getExpiryReport should hand the posted window to the service and answer with the report")
+ void getExpiryReport_shouldReturnReport() throws Exception {
+ when(crmReportService.getExpiryReport(any(ItemStockEntryReport.class))).thenReturn("[{\"slNo\":1}]");
+
+ mockMvc.perform(post("/crmReportController/getExpiryReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].slNo").value(1));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemStockEntryReport.class);
+ verify(crmReportService).getExpiryReport(captor.capture());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getExpiryReport should report the failure when the report generation throws")
+ void getExpiryReport_shouldReportServiceFailure() throws Exception {
+ when(crmReportService.getExpiryReport(any(ItemStockEntryReport.class))).thenThrow(new RuntimeException("report failed"));
+
+ mockMvc.perform(post("/crmReportController/getExpiryReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("report failed"));
+ }
+
+ @Test
+ @DisplayName("getConsumptionReport should hand the posted window to the service and answer with the report")
+ void getConsumptionReport_shouldReturnReport() throws Exception {
+ when(crmReportService.getConsumptionReport(any(ItemStockExitReport.class))).thenReturn("[{\"slNo\":1}]");
+
+ mockMvc.perform(post("/crmReportController/getConsumptionReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].slNo").value(1));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemStockExitReport.class);
+ verify(crmReportService).getConsumptionReport(captor.capture());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getConsumptionReport should report the failure when the report generation throws")
+ void getConsumptionReport_shouldReportServiceFailure() throws Exception {
+ when(crmReportService.getConsumptionReport(any(ItemStockExitReport.class))).thenThrow(new RuntimeException("report failed"));
+
+ mockMvc.perform(post("/crmReportController/getConsumptionReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("report failed"));
+ }
+
+ @Test
+ @DisplayName("getBenDrugIssueReport should hand the posted window to the service and answer with the report")
+ void getBenDrugIssueReport_shouldReturnReport() throws Exception {
+ when(crmReportService.getBenDrugIssueReport(any(PatientIssueExitReport.class))).thenReturn("[{\"slNo\":1}]");
+
+ mockMvc.perform(post("/crmReportController/getBenDrugIssueReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].slNo").value(1));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(PatientIssueExitReport.class);
+ verify(crmReportService).getBenDrugIssueReport(captor.capture());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getBenDrugIssueReport should report the failure when the report generation throws")
+ void getBenDrugIssueReport_shouldReportServiceFailure() throws Exception {
+ when(crmReportService.getBenDrugIssueReport(any(PatientIssueExitReport.class))).thenThrow(new RuntimeException("report failed"));
+
+ mockMvc.perform(post("/crmReportController/getBenDrugIssueReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("report failed"));
+ }
+
+ @Test
+ @DisplayName("getDailyStockDetailReport should hand the posted window to the service and answer with the report")
+ void getDailyStockDetailReport_shouldReturnReport() throws Exception {
+ when(crmReportService.getDailyStockDetailsReport(any(ItemStockEntryReport.class))).thenReturn("[{\"slNo\":1}]");
+
+ mockMvc.perform(post("/crmReportController/getDailyStockDetailReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].slNo").value(1));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemStockEntryReport.class);
+ verify(crmReportService).getDailyStockDetailsReport(captor.capture());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getDailyStockDetailReport should report the failure when the report generation throws")
+ void getDailyStockDetailReport_shouldReportServiceFailure() throws Exception {
+ when(crmReportService.getDailyStockDetailsReport(any(ItemStockEntryReport.class))).thenThrow(new RuntimeException("report failed"));
+
+ mockMvc.perform(post("/crmReportController/getDailyStockDetailReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("report failed"));
+ }
+
+ @Test
+ @DisplayName("getDailyStockSummaryReport should hand the posted window to the service and answer with the report")
+ void getDailyStockSummaryReport_shouldReturnReport() throws Exception {
+ when(crmReportService.getDailyStockSummaryReport(any(ItemStockEntryReport.class))).thenReturn("[{\"slNo\":1}]");
+
+ mockMvc.perform(post("/crmReportController/getDailyStockSummaryReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].slNo").value(1));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemStockEntryReport.class);
+ verify(crmReportService).getDailyStockSummaryReport(captor.capture());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getDailyStockSummaryReport should report the failure when the report generation throws")
+ void getDailyStockSummaryReport_shouldReportServiceFailure() throws Exception {
+ when(crmReportService.getDailyStockSummaryReport(any(ItemStockEntryReport.class))).thenThrow(new RuntimeException("report failed"));
+
+ mockMvc.perform(post("/crmReportController/getDailyStockSummaryReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("report failed"));
+ }
+
+ @Test
+ @DisplayName("getMonthlyReport should hand the posted window to the service and answer with the report")
+ void getMonthlyReport_shouldReturnReport() throws Exception {
+ when(crmReportService.getMonthlyReport(any(ItemStockEntryReport.class))).thenReturn("[{\"slNo\":1}]");
+
+ mockMvc.perform(post("/crmReportController/getMonthlyReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].slNo").value(1));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemStockEntryReport.class);
+ verify(crmReportService).getMonthlyReport(captor.capture());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getMonthlyReport should report the failure when the report generation throws")
+ void getMonthlyReport_shouldReportServiceFailure() throws Exception {
+ when(crmReportService.getMonthlyReport(any(ItemStockEntryReport.class))).thenThrow(new RuntimeException("report failed"));
+
+ mockMvc.perform(post("/crmReportController/getMonthlyReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("report failed"));
+ }
+
+ @Test
+ @DisplayName("getYearlyReport should hand the posted window to the service and answer with the report")
+ void getYearlyReport_shouldReturnReport() throws Exception {
+ when(crmReportService.getYearlyReport(any(ItemStockEntryReport.class))).thenReturn("[{\"slNo\":1}]");
+
+ mockMvc.perform(post("/crmReportController/getYearlyReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].slNo").value(1));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemStockEntryReport.class);
+ verify(crmReportService).getYearlyReport(captor.capture());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getYearlyReport should report the failure when the report generation throws")
+ void getYearlyReport_shouldReportServiceFailure() throws Exception {
+ when(crmReportService.getYearlyReport(any(ItemStockEntryReport.class))).thenThrow(new RuntimeException("report failed"));
+
+ mockMvc.perform(post("/crmReportController/getYearlyReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("report failed"));
+ }
+
+ @Test
+ @DisplayName("getShortExpiryReport should hand the posted window to the service and answer with the report")
+ void getShortExpiryReport_shouldReturnReport() throws Exception {
+ when(crmReportService.getShortExpiryReport(any(ItemStockEntryReport.class))).thenReturn("[{\"slNo\":1}]");
+
+ mockMvc.perform(post("/crmReportController/getShortExpiryReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].slNo").value(1));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemStockEntryReport.class);
+ verify(crmReportService).getShortExpiryReport(captor.capture());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getShortExpiryReport should report the failure when the report generation throws")
+ void getShortExpiryReport_shouldReportServiceFailure() throws Exception {
+ when(crmReportService.getShortExpiryReport(any(ItemStockEntryReport.class))).thenThrow(new RuntimeException("report failed"));
+
+ mockMvc.perform(post("/crmReportController/getShortExpiryReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("report failed"));
+ }
+
+ @Test
+ @DisplayName("getTransitReport should hand the posted window to the service and answer with the report")
+ void getTransitReport_shouldReturnReport() throws Exception {
+ when(crmReportService.getTransitReport(any(ItemStockEntryReport.class))).thenReturn("[{\"slNo\":1}]");
+
+ mockMvc.perform(post("/crmReportController/getTransitReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].slNo").value(1));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemStockEntryReport.class);
+ verify(crmReportService).getTransitReport(captor.capture());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getTransitReport should report the failure when the report generation throws")
+ void getTransitReport_shouldReportServiceFailure() throws Exception {
+ when(crmReportService.getTransitReport(any(ItemStockEntryReport.class))).thenThrow(new RuntimeException("report failed"));
+
+ mockMvc.perform(post("/crmReportController/getTransitReport").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("report failed"));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/stockEntry/StockEntryControllerTest.java b/src/test/java/com/iemr/inventory/controller/stockEntry/StockEntryControllerTest.java
new file mode 100644
index 00000000..97351f4f
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/stockEntry/StockEntryControllerTest.java
@@ -0,0 +1,300 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.stockEntry;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.stockExit.ItemStockExit;
+import com.iemr.inventory.data.stockentry.AllocateItemMap;
+import com.iemr.inventory.data.stockentry.ItemMasterWithQuantityMap;
+import com.iemr.inventory.data.stockentry.ItemStockEntry;
+import com.iemr.inventory.data.stockentry.ItemStockEntryinput;
+import com.iemr.inventory.data.stockentry.PhysicalStockEntry;
+import com.iemr.inventory.service.stockEntry.StockEntryServiceImpl;
+import com.iemr.inventory.utils.exception.InventoryException;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("StockEntryController Test Suite")
+class StockEntryControllerTest {
+
+ private static final String AUTH = "test-session-key";
+
+ @Mock
+ private StockEntryServiceImpl stockEntryService;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked stock entry service")
+ void setUp() {
+ StockEntryController controller = new StockEntryController();
+ ReflectionTestUtils.setField(controller, "stockEntryService", stockEntryService);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ private static PhysicalStockEntry physical() {
+ PhysicalStockEntry physical = new PhysicalStockEntry();
+ physical.setPhyEntryID(77L);
+ physical.setFacilityID(7);
+ return physical;
+ }
+
+ private static ItemStockEntry batch() {
+ ItemStockEntry entry = new ItemStockEntry();
+ entry.setItemStockEntryID(601);
+ entry.setBatchNo("B-1");
+ return entry;
+ }
+
+ @Test
+ @DisplayName("physicalStockEntry should book the posted stock in and answer with the saved header")
+ void physicalStockEntry_shouldBookStockIn() throws Exception {
+ when(stockEntryService.savePhysicalStockEntry(any(PhysicalStockEntry.class))).thenReturn(physical());
+
+ mockMvc.perform(post("/physicalStockEntry").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityID\":7,\"itemStockEntry\":[]}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(PhysicalStockEntry.class);
+ verify(stockEntryService).savePhysicalStockEntry(captor.capture());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("physicalStockEntry should surface the duplicate-batch refusal from the service")
+ void physicalStockEntry_shouldSurfaceDuplicateRefusal() throws Exception {
+ when(stockEntryService.savePhysicalStockEntry(any(PhysicalStockEntry.class)))
+ .thenThrow(new InventoryException("Duplicate stock entry: Item ID 11 with batch 'B-1' already exists"));
+
+ mockMvc.perform(post("/physicalStockEntry").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5010));
+ }
+
+ @Test
+ @DisplayName("getItemBatchForStoreID should pass the posted probe batch to the service")
+ void getItemBatchForStoreID_shouldPassProbeThrough() throws Exception {
+ when(stockEntryService.getItemBatchForStoreID(any(ItemStockEntry.class))).thenReturn(List.of(batch()));
+
+ mockMvc.perform(post("/getItemBatchForStoreID").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"facilityID\":7,\"itemID\":11}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemStockEntry.class);
+ verify(stockEntryService).getItemBatchForStoreID(captor.capture());
+ assertEquals(11, captor.getValue().getItemID());
+ }
+
+ @Test
+ @DisplayName("getItemBatchForStoreID should report the failure when the lookup throws")
+ void getItemBatchForStoreID_shouldReportServiceFailure() throws Exception {
+ when(stockEntryService.getItemBatchForStoreID(any(ItemStockEntry.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getItemBatchForStoreID").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("allocateStockFromItemID should allocate for the facility named in the path")
+ void allocateStockFromItemID_shouldAllocateForPathFacility() throws Exception {
+ when(stockEntryService.getItemStockFromItemID(anyInt(), anyList()))
+ .thenReturn(List.of(new AllocateItemMap()));
+
+ mockMvc.perform(post("/allocateStockFromItemID/7").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("[{\"itemID\":11,\"quantity\":6}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class);
+ verify(stockEntryService).getItemStockFromItemID(anyInt(), captor.capture());
+ assertEquals(11, captor.getValue().get(0).getItemID());
+ }
+
+ @Test
+ @DisplayName("allocateStockFromItemID should report the failure when the allocation throws")
+ void allocateStockFromItemID_shouldReportServiceFailure() throws Exception {
+ when(stockEntryService.getItemStockFromItemID(anyInt(), anyList()))
+ .thenThrow(new InventoryException("no stock"));
+
+ mockMvc.perform(post("/allocateStockFromItemID/7").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("[{}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5010));
+ }
+
+ @Test
+ @DisplayName("getPhysicalStockEntry should return the entries in the posted window")
+ void getPhysicalStockEntry_shouldReturnEntriesInWindow() throws Exception {
+ when(stockEntryService.getPhysicalStockEntry(any(ItemStockEntryinput.class)))
+ .thenReturn(List.of(physical()));
+
+ mockMvc.perform(post("/getPhysicalStockEntry").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityID\":7,\"fromDate\":1735706400000,\"toDate\":1738298400000}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+ }
+
+ @Test
+ @DisplayName("getPhysicalStockEntry should report the failure when the lookup throws")
+ void getPhysicalStockEntry_shouldReportServiceFailure() throws Exception {
+ when(stockEntryService.getPhysicalStockEntry(any(ItemStockEntryinput.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getPhysicalStockEntry").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("itemPartialSearch should pass the item name and facility from the posted probe item")
+ void itemPartialSearch_shouldPassNameAndFacility() throws Exception {
+ when(stockEntryService.getItemMastersPartialSearch("Para", 7)).thenReturn(List.of(batch()));
+
+ mockMvc.perform(post("/itemBatchPartialSearch").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"itemName\":\"Para\",\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(stockEntryService).getItemMastersPartialSearch("Para", 7);
+ }
+
+ @Test
+ @DisplayName("itemPartialSearch should report the failure when the search throws")
+ void itemPartialSearch_shouldReportServiceFailure() throws Exception {
+ when(stockEntryService.getItemMastersPartialSearch(anyString(), anyInt()))
+ .thenThrow(new RuntimeException("search failed"));
+
+ mockMvc.perform(post("/itemBatchPartialSearch").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"itemName\":\"Para\",\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("itemBatchWithZeroPartialSearch should include the batches that hold no stock left")
+ void itemBatchWithZeroPartialSearch_shouldIncludeEmptyBatches() throws Exception {
+ when(stockEntryService.getItemMastersPartialSearchWithZero("Para", 7)).thenReturn(List.of(batch()));
+
+ mockMvc.perform(post("/itemBatchWithZeroPartialSearch").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"itemName\":\"Para\",\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(stockEntryService).getItemMastersPartialSearchWithZero("Para", 7);
+ }
+
+ @Test
+ @DisplayName("itemBatchWithZeroPartialSearch should report the failure when the search throws")
+ void itemBatchWithZeroPartialSearch_shouldReportServiceFailure() throws Exception {
+ when(stockEntryService.getItemMastersPartialSearchWithZero(anyString(), anyInt()))
+ .thenThrow(new RuntimeException("search failed"));
+
+ mockMvc.perform(post("/itemBatchWithZeroPartialSearch").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"itemName\":\"Para\",\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getPhysicalStockEntryItems should load the batches booked under the posted header id")
+ void getPhysicalStockEntryItems_shouldLoadBatchesOfHeader() throws Exception {
+ when(stockEntryService.getPhysicalStockEntryItems(77L)).thenReturn(List.of(batch()));
+
+ mockMvc.perform(post("/getPhysicalStockEntryItems").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"phyEntryID\":77}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(stockEntryService).getPhysicalStockEntryItems(77L);
+ }
+
+ @Test
+ @DisplayName("getPhysicalStockEntryItems should report the failure when the header is missing")
+ void getPhysicalStockEntryItems_shouldReportFailureWhenHeaderMissing() throws Exception {
+ when(stockEntryService.getPhysicalStockEntryItems(anyLong()))
+ .thenThrow(new java.util.NoSuchElementException("No value present"));
+
+ mockMvc.perform(post("/getPhysicalStockEntryItems").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"phyEntryID\":77}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getItemwithQuantityPartialSearch should pass the item name and facility from the posted probe")
+ void getItemwithQuantityPartialSearch_shouldPassNameAndFacility() throws Exception {
+ when(stockEntryService.getItemwithQuantityPartialSearch("Para", 7))
+ .thenReturn(List.of(new ItemMasterWithQuantityMap()));
+
+ mockMvc.perform(post("/getItemwithQuantityPartialSearch").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"itemName\":\"Para\",\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(stockEntryService).getItemwithQuantityPartialSearch("Para", 7);
+ }
+
+ @Test
+ @DisplayName("getItemwithQuantityPartialSearch should report the failure when the search throws")
+ void getItemwithQuantityPartialSearch_shouldReportServiceFailure() throws Exception {
+ when(stockEntryService.getItemwithQuantityPartialSearch(anyString(), anyInt()))
+ .thenThrow(new RuntimeException("search failed"));
+
+ mockMvc.perform(post("/getItemwithQuantityPartialSearch").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"itemName\":\"Para\",\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/stockExit/StockExitControllerTest.java b/src/test/java/com/iemr/inventory/controller/stockExit/StockExitControllerTest.java
new file mode 100644
index 00000000..839226fd
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/stockExit/StockExitControllerTest.java
@@ -0,0 +1,334 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.stockExit;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.stockExit.ItemStockExitMap;
+import com.iemr.inventory.data.stockExit.StoreSelfConsumption;
+import com.iemr.inventory.data.stockExit.T_PatientIssue;
+import com.iemr.inventory.data.stockExit.T_StockTransfer;
+import com.iemr.inventory.data.stockentry.ItemStockEntryinput;
+import com.iemr.inventory.service.stockExit.StockExitServiceImpl;
+import com.iemr.inventory.utils.exception.InventoryException;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("StockExitController Test Suite")
+class StockExitControllerTest {
+
+ private static final String AUTH = "test-session-key";
+ private static final String WINDOW =
+ "{\"facilityID\":7,\"fromDate\":1735706400000,\"toDate\":1738298400000}";
+
+ @Mock
+ private StockExitServiceImpl stockExitService;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked stock exit service")
+ void setUp() {
+ StockExitController controller = new StockExitController();
+ ReflectionTestUtils.setField(controller, "stockExitService", stockExitService);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ @Test
+ @DisplayName("patientIssue should confirm the dispense when the service books it")
+ void patientIssue_shouldConfirmDispense() throws Exception {
+ when(stockExitService.issuePatientDrugs(any(T_PatientIssue.class))).thenReturn(1);
+
+ mockMvc.perform(post("/patientIssue").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityID\":7,\"benRegID\":101,\"itemStockExit\":[]}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.response").value("Successfully Created"));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(T_PatientIssue.class);
+ verify(stockExitService).issuePatientDrugs(captor.capture());
+ assertEquals(101L, captor.getValue().getBenRegID());
+ }
+
+ @Test
+ @DisplayName("patientIssue should report a failure when the service books nothing")
+ void patientIssue_shouldReportFailureWhenNothingBooked() throws Exception {
+ when(stockExitService.issuePatientDrugs(any(T_PatientIssue.class))).thenReturn(0);
+
+ mockMvc.perform(post("/patientIssue").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("Error occured while saving the request"));
+ }
+
+ @Test
+ @DisplayName("patientIssue should surface the inventory failure raised by the service")
+ void patientIssue_shouldSurfaceInventoryFailure() throws Exception {
+ when(stockExitService.issuePatientDrugs(any(T_PatientIssue.class)))
+ .thenThrow(new InventoryException("No item found to dispense."));
+
+ mockMvc.perform(post("/patientIssue").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5010));
+ }
+
+ @Test
+ @DisplayName("storeSelfConsumption should confirm the consumption when the service books it")
+ void storeSelfConsumption_shouldConfirmConsumption() throws Exception {
+ when(stockExitService.storeSelfConsumption(any(StoreSelfConsumption.class))).thenReturn(1);
+
+ mockMvc.perform(post("/storeSelfConsumption").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityID\":7,\"itemStockExit\":[]}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.data.response").value("Successfully Created"));
+ }
+
+ @Test
+ @DisplayName("storeSelfConsumption should report a failure when the service books nothing")
+ void storeSelfConsumption_shouldReportFailureWhenNothingBooked() throws Exception {
+ when(stockExitService.storeSelfConsumption(any(StoreSelfConsumption.class))).thenReturn(0);
+
+ mockMvc.perform(post("/storeSelfConsumption").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("storeTransfer should confirm the transfer when the service books it")
+ void storeTransfer_shouldConfirmTransfer() throws Exception {
+ when(stockExitService.storeTransfer(any(T_StockTransfer.class))).thenReturn(1);
+
+ mockMvc.perform(post("/storeTransfer").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"transferFromFacilityID\":1,\"transferToFacilityID\":2,\"itemStockExit\":[]}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.data.response").value("Successfully Created"));
+ }
+
+ @Test
+ @DisplayName("storeTransfer should report a failure when the service books nothing")
+ void storeTransfer_shouldReportFailureWhenNothingBooked() throws Exception {
+ when(stockExitService.storeTransfer(any(T_StockTransfer.class))).thenReturn(0);
+
+ mockMvc.perform(post("/storeTransfer").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"transferFromFacilityID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getPatientissue should return the patient issues in the posted window")
+ void getPatientissue_shouldReturnIssuesInWindow() throws Exception {
+ when(stockExitService.getpatientIssue(any(ItemStockEntryinput.class)))
+ .thenReturn(List.of(new T_PatientIssue()));
+
+ mockMvc.perform(post("/getPatientissue").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+ }
+
+ @Test
+ @DisplayName("getPatientissue should report the failure when the lookup throws")
+ void getPatientissue_shouldReportServiceFailure() throws Exception {
+ when(stockExitService.getpatientIssue(any(ItemStockEntryinput.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getPatientissue").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getSelfConsumption should return the consumptions in the posted window")
+ void getSelfConsumption_shouldReturnConsumptionsInWindow() throws Exception {
+ when(stockExitService.getstoreSelfConsumption(any(ItemStockEntryinput.class)))
+ .thenReturn(List.of(new StoreSelfConsumption()));
+
+ mockMvc.perform(post("/getSelfConsumption").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+ }
+
+ @Test
+ @DisplayName("getSelfConsumption should report the failure when the lookup throws")
+ void getSelfConsumption_shouldReportServiceFailure() throws Exception {
+ when(stockExitService.getstoreSelfConsumption(any(ItemStockEntryinput.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getSelfConsumption").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getStoreTransfer should return the transfers in the posted window")
+ void getStoreTransfer_shouldReturnTransfersInWindow() throws Exception {
+ when(stockExitService.getStoreTransfer(any(ItemStockEntryinput.class)))
+ .thenReturn(List.of(new T_StockTransfer()));
+
+ mockMvc.perform(post("/getStoreTransfer").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+ }
+
+ @Test
+ @DisplayName("getStoreTransfer should report the failure when the lookup throws")
+ void getStoreTransfer_shouldReportServiceFailure() throws Exception {
+ when(stockExitService.getStoreTransfer(any(ItemStockEntryinput.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getStoreTransfer").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getPatientissueAllDetail should load the issue named by the posted id")
+ void getPatientissueAllDetail_shouldLoadIssueById() throws Exception {
+ when(stockExitService.getPatientissueAllDetail(88L)).thenReturn(new T_PatientIssue());
+
+ mockMvc.perform(post("/getPatientissueAllDetail").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"patientIssueID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(stockExitService).getPatientissueAllDetail(88L);
+ }
+
+ @Test
+ @DisplayName("getPatientissueAllDetail should report the failure when the issue is missing")
+ void getPatientissueAllDetail_shouldReportFailureWhenIssueMissing() throws Exception {
+ when(stockExitService.getPatientissueAllDetail(anyLong())).thenReturn(null);
+
+ mockMvc.perform(post("/getPatientissueAllDetail").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"patientIssueID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("getPatientissueItemEntry should project the lines booked under the posted issue")
+ void getPatientissueItemEntry_shouldProjectBookedLines() throws Exception {
+ when(stockExitService.getpatientIssueItemLIst(any(ItemStockEntryinput.class)))
+ .thenReturn(List.of(new ItemStockExitMap()));
+
+ mockMvc.perform(post("/getPatientissueItemEntry").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"patientIssueID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+ }
+
+ @Test
+ @DisplayName("getPatientissueItemEntry should report the failure when the lookup throws")
+ void getPatientissueItemEntry_shouldReportServiceFailure() throws Exception {
+ when(stockExitService.getpatientIssueItemLIst(any(ItemStockEntryinput.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getPatientissueItemEntry").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"patientIssueID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getSelfConsumptionItemEntry should project the lines booked under the posted consumption")
+ void getSelfConsumptionItemEntry_shouldProjectBookedLines() throws Exception {
+ when(stockExitService.getstoreSelfConsumptionItemList(any(ItemStockEntryinput.class)))
+ .thenReturn(List.of(new ItemStockExitMap()));
+
+ mockMvc.perform(post("/getSelfConsumptionItemEntry").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"consumptionID\":66}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemStockEntryinput.class);
+ verify(stockExitService).getstoreSelfConsumptionItemList(captor.capture());
+ assertEquals(66L, captor.getValue().getConsumptionID());
+ }
+
+ @Test
+ @DisplayName("getSelfConsumptionItemEntry should report the failure when the lookup throws")
+ void getSelfConsumptionItemEntry_shouldReportServiceFailure() throws Exception {
+ when(stockExitService.getstoreSelfConsumptionItemList(any(ItemStockEntryinput.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getSelfConsumptionItemEntry").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"consumptionID\":66}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getStoreTransferItemEntry should project the batches booked under the posted transfer")
+ void getStoreTransferItemEntry_shouldProjectBookedBatches() throws Exception {
+ when(stockExitService.getStoreTransferItemEntry(any(ItemStockEntryinput.class)))
+ .thenReturn(List.of(new ItemStockExitMap()));
+
+ mockMvc.perform(post("/getStoreTransferItemEntry").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"stockTransferID\":99}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+ }
+
+ @Test
+ @DisplayName("getStoreTransferItemEntry should report the failure when the lookup throws")
+ void getStoreTransferItemEntry_shouldReportServiceFailure() throws Exception {
+ when(stockExitService.getStoreTransferItemEntry(any(ItemStockEntryinput.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getStoreTransferItemEntry").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"stockTransferID\":99}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/store/StockAdjustmentControllerTest.java b/src/test/java/com/iemr/inventory/controller/store/StockAdjustmentControllerTest.java
new file mode 100644
index 00000000..f470359a
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/store/StockAdjustmentControllerTest.java
@@ -0,0 +1,239 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.store;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.stockadjustment.StockAdjustment;
+import com.iemr.inventory.data.stockadjustment.StockAdjustmentDraft;
+import com.iemr.inventory.data.stockentry.ItemStockEntryinput;
+import com.iemr.inventory.service.stockadjustment.StockAdjustmentServiceImpl;
+import com.iemr.inventory.utils.exception.InventoryException;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("StockAdjustmentController Test Suite")
+class StockAdjustmentControllerTest {
+
+ private static final String AUTH = "test-session-key";
+ private static final String WINDOW =
+ "{\"facilityID\":7,\"fromDate\":1735706400000,\"toDate\":1738298400000}";
+
+ @Mock
+ private StockAdjustmentServiceImpl stockAdjustmentServiceImpl;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked stock adjustment service")
+ void setUp() {
+ StockAdjustmentController controller = new StockAdjustmentController();
+ ReflectionTestUtils.setField(controller, "stockAdjustmentServiceImpl", stockAdjustmentServiceImpl);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ private static StockAdjustmentDraft draft(Long id) {
+ StockAdjustmentDraft draft = new StockAdjustmentDraft();
+ draft.setStockAdjustmentDraftID(id);
+ draft.setFacilityID(7);
+ return draft;
+ }
+
+ private static StockAdjustment adjustment(Long id) {
+ StockAdjustment adjustment = new StockAdjustment();
+ adjustment.setStockAdjustmentID(id);
+ adjustment.setFacilityID(7);
+ return adjustment;
+ }
+
+ @Test
+ @DisplayName("stockadjustmentdraft should save the posted draft and answer with the stored row")
+ void stockadjustmentdraft_shouldSavePostedDraft() throws Exception {
+ when(stockAdjustmentServiceImpl.saveDraft(any(StockAdjustmentDraft.class))).thenReturn(draft(55L));
+
+ mockMvc.perform(post("/stockadjustmentdraft").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityID\":7,\"draftName\":\"a name\",\"stockAdjustmentItemDraft\":[]}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(StockAdjustmentDraft.class);
+ verify(stockAdjustmentServiceImpl).saveDraft(captor.capture());
+ assertEquals("a name", captor.getValue().getDraftName());
+ }
+
+ @Test
+ @DisplayName("stockadjustmentdraft should report the failure when the save throws")
+ void stockadjustmentdraft_shouldReportServiceFailure() throws Exception {
+ when(stockAdjustmentServiceImpl.saveDraft(any(StockAdjustmentDraft.class)))
+ .thenThrow(new RuntimeException("db unavailable"));
+
+ mockMvc.perform(post("/stockadjustmentdraft").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getstockadjustmentdraftTransaction should return the drafts in the posted window")
+ void getstockadjustmentdraftTransaction_shouldReturnDraftsInWindow() throws Exception {
+ when(stockAdjustmentServiceImpl.getStockAjustmentDraftTransaction(any(ItemStockEntryinput.class)))
+ .thenReturn(List.of(draft(55L)));
+
+ mockMvc.perform(post("/getstockadjustmentdraftTransaction").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ItemStockEntryinput.class);
+ verify(stockAdjustmentServiceImpl).getStockAjustmentDraftTransaction(captor.capture());
+ assertEquals(7, captor.getValue().getFacilityID());
+ }
+
+ @Test
+ @DisplayName("getstockadjustmentdraftTransaction should report the failure when the lookup throws")
+ void getstockadjustmentdraftTransaction_shouldReportServiceFailure() throws Exception {
+ when(stockAdjustmentServiceImpl.getStockAjustmentDraftTransaction(any(ItemStockEntryinput.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getstockadjustmentdraftTransaction").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getforEditsSockAdjustmentdraftTransaction should load the draft named by the posted id")
+ void getforEditsSockAdjustmentdraftTransaction_shouldLoadDraftById() throws Exception {
+ when(stockAdjustmentServiceImpl.getforeditStockAjustmentDraftTransaction(55L)).thenReturn(draft(55L));
+
+ mockMvc.perform(post("/getforEditsStockAdjustmentdraftTransaction").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"stockAdjustmentDraftID\":55}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(stockAdjustmentServiceImpl).getforeditStockAjustmentDraftTransaction(55L);
+ }
+
+ @Test
+ @DisplayName("getforEditsSockAdjustmentdraftTransaction should report the failure when the draft is missing")
+ void getforEditsSockAdjustmentdraftTransaction_shouldReportFailureWhenDraftMissing() throws Exception {
+ when(stockAdjustmentServiceImpl.getforeditStockAjustmentDraftTransaction(anyLong())).thenReturn(null);
+
+ mockMvc.perform(post("/getforEditsStockAdjustmentdraftTransaction").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"stockAdjustmentDraftID\":55}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("stockadjustment should post the adjustment and answer with the stored row")
+ void stockadjustment_shouldPostAdjustment() throws Exception {
+ when(stockAdjustmentServiceImpl.savetransaction(any(StockAdjustment.class))).thenReturn(adjustment(88L));
+
+ mockMvc.perform(post("/stockadjustment").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityID\":7,\"stockAdjustmentItem\":[]}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+ }
+
+ @Test
+ @DisplayName("stockadjustment should surface the inventory failure raised by the service")
+ void stockadjustment_shouldSurfaceInventoryFailure() throws Exception {
+ when(stockAdjustmentServiceImpl.savetransaction(any(StockAdjustment.class)))
+ .thenThrow(new InventoryException("Adjustment Quantity for issue should be more than available quantity"));
+
+ mockMvc.perform(post("/stockadjustment").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5010));
+ }
+
+ @Test
+ @DisplayName("getforeditStockAdjustmentTransaction should return the adjustments in the posted window")
+ void getforeditStockAdjustmentTransaction_shouldReturnAdjustmentsInWindow() throws Exception {
+ when(stockAdjustmentServiceImpl.getStockAjustmentTransaction(any(ItemStockEntryinput.class)))
+ .thenReturn(List.of(adjustment(88L)));
+
+ mockMvc.perform(post("/getStockAdjustmentTransaction").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+ }
+
+ @Test
+ @DisplayName("getforeditStockAdjustmentTransaction should report the failure when the lookup throws")
+ void getforeditStockAdjustmentTransaction_shouldReportServiceFailure() throws Exception {
+ when(stockAdjustmentServiceImpl.getStockAjustmentTransaction(any(ItemStockEntryinput.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getStockAdjustmentTransaction").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content(WINDOW))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getforEditsStockAdjustmentTransaction should load the adjustment named by the posted id")
+ void getforEditsStockAdjustmentTransaction_shouldLoadAdjustmentById() throws Exception {
+ when(stockAdjustmentServiceImpl.getforeditStockAjustmentTransaction(88L)).thenReturn(adjustment(88L));
+
+ mockMvc.perform(post("/getforEditsStockAdjustmentTransaction").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"stockAdjustmentID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(stockAdjustmentServiceImpl).getforeditStockAjustmentTransaction(88L);
+ }
+
+ @Test
+ @DisplayName("getforEditsStockAdjustmentTransaction should report the failure when the adjustment is missing")
+ void getforEditsStockAdjustmentTransaction_shouldReportFailureWhenAdjustmentMissing() throws Exception {
+ when(stockAdjustmentServiceImpl.getforeditStockAjustmentTransaction(anyLong())).thenReturn(null);
+
+ mockMvc.perform(post("/getforEditsStockAdjustmentTransaction").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{\"stockAdjustmentID\":88}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/store/StoreControllerTest.java b/src/test/java/com/iemr/inventory/controller/store/StoreControllerTest.java
new file mode 100644
index 00000000..9ae662d9
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/store/StoreControllerTest.java
@@ -0,0 +1,323 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.store;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.store.M_Facility;
+import com.iemr.inventory.data.store.M_Van;
+import com.iemr.inventory.service.store.StoreService;
+import com.iemr.inventory.utils.exception.IEMRException;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("StoreController Test Suite")
+class StoreControllerTest {
+
+ private static final String AUTH = "test-session-key";
+
+ @Mock
+ private StoreService storeService;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked store service")
+ void setUp() {
+ StoreController controller = new StoreController();
+ ReflectionTestUtils.setField(controller, "storeService", storeService);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ private static M_Facility facility(Integer id, String name) {
+ M_Facility facility = new M_Facility();
+ facility.setFacilityID(id);
+ facility.setFacilityName(name);
+ facility.setProviderServiceMapID(3);
+ return facility;
+ }
+
+ @Test
+ @DisplayName("createStore should save the posted batch of stores")
+ void createStore_shouldSavePostedBatch() throws Exception {
+ when(storeService.addAllMainStore(anyList())).thenReturn(List.of(facility(7, "Main store")));
+
+ mockMvc.perform(post("/createStore").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("[{\"facilityName\":\"Main store\",\"providerServiceMapID\":3}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class);
+ verify(storeService).addAllMainStore(captor.capture());
+ assertEquals(1, captor.getValue().size());
+ }
+
+ @Test
+ @DisplayName("createStore should report the failure when the save throws")
+ void createStore_shouldReportServiceFailure() throws Exception {
+ when(storeService.addAllMainStore(anyList())).thenThrow(new RuntimeException("db unavailable"));
+
+ mockMvc.perform(post("/createStore").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("[{}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("editStore should copy the description and modifier onto the stored facility before saving")
+ void editStore_shouldCopyEditableFields() throws Exception {
+ M_Facility stored = facility(7, "Main store");
+ when(storeService.getMainStore(7)).thenReturn(stored);
+ when(storeService.createMainStore(any(M_Facility.class))).thenAnswer(inv -> inv.getArgument(0));
+
+ mockMvc.perform(post("/editStore").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityID\":7,\"facilityDesc\":\"new desc\",\"modifiedBy\":\"tester\"}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_Facility.class);
+ verify(storeService).createMainStore(captor.capture());
+ assertEquals("new desc", captor.getValue().getFacilityDesc());
+ assertEquals("tester", captor.getValue().getModifiedBy());
+ }
+
+ @Test
+ @DisplayName("editStore should report the failure when the store cannot be found")
+ void editStore_shouldReportFailureWhenStoreMissing() throws Exception {
+ when(storeService.getMainStore(7)).thenReturn(null);
+
+ mockMvc.perform(post("/editStore").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("getAllStore should return every store of the provider service map named in the path")
+ void getAllStore_shouldReturnStoresOfProviderServiceMap() throws Exception {
+ when(storeService.getAllMainStore(3)).thenReturn(List.of(facility(7, "Main store")));
+
+ mockMvc.perform(post("/getAllStore/3").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(storeService).getAllMainStore(3);
+ }
+
+ @Test
+ @DisplayName("getAllStore should report the failure when the lookup throws")
+ void getAllStore_shouldReportServiceFailure() throws Exception {
+ when(storeService.getAllMainStore(anyInt())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getAllStore/3").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getAllActiveStore should pass the posted probe facility straight to the service")
+ void getAllActiveStore_shouldPassProbeThrough() throws Exception {
+ when(storeService.getAllActiveStore(any(M_Facility.class)))
+ .thenReturn(List.of(facility(7, "Main store")));
+
+ mockMvc.perform(post("/getAllActiveStore").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3,\"deleted\":false}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_Facility.class);
+ verify(storeService).getAllActiveStore(captor.capture());
+ assertEquals(Boolean.FALSE, captor.getValue().getDeleted());
+ }
+
+ @Test
+ @DisplayName("getAllActiveStore should report the failure when the lookup throws")
+ void getAllActiveStore_shouldReportServiceFailure() throws Exception {
+ when(storeService.getAllActiveStore(any(M_Facility.class)))
+ .thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getAllActiveStore").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("{}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getMainFacility should pass the provider service map and the main-facility flag through")
+ void getMainFacility_shouldPassFlagThrough() throws Exception {
+ when(storeService.getMainFacility(3, true))
+ .thenReturn(new ArrayList<>(List.of(facility(7, "Main store"))));
+
+ mockMvc.perform(post("/getMainFacility").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3,\"isMainFacility\":true}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(storeService).getMainFacility(3, true);
+ }
+
+ @Test
+ @DisplayName("getMainFacility should report the failure when the lookup throws")
+ void getMainFacility_shouldReportServiceFailure() throws Exception {
+ when(storeService.getMainFacility(anyInt(), anyBoolean())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getMainFacility").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3,\"isMainFacility\":true}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getsubFacility should look the sub-stores up under the posted parent facility")
+ void getsubFacility_shouldLookUpUnderParent() throws Exception {
+ when(storeService.getChildFacility(3, 7))
+ .thenReturn(new ArrayList<>(List.of(facility(8, "Sub store"))));
+
+ mockMvc.perform(post("/getsubFacility").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3,\"mainFacilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(storeService).getChildFacility(3, 7);
+ }
+
+ @Test
+ @DisplayName("getsubFacility should report the failure when the lookup throws")
+ void getsubFacility_shouldReportServiceFailure() throws Exception {
+ when(storeService.getChildFacility(anyInt(), anyInt())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getsubFacility").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3,\"mainFacilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("deleteStore should answer with the facility the service deactivated")
+ void deleteStore_shouldReturnDeactivatedFacility() throws Exception {
+ when(storeService.deleteStore(any(M_Facility.class))).thenReturn(facility(7, "Main store"));
+
+ mockMvc.perform(post("/deleteStore").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityID\":7,\"deleted\":true}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+ }
+
+ @Test
+ @DisplayName("deleteStore should answer 200 with the refusal text when the service rejects the request")
+ void deleteStore_shouldReturnRefusalTextAsSuccessfulResponse() throws Exception {
+ when(storeService.deleteStore(any(M_Facility.class)))
+ .thenThrow(new IEMRException("Child Stores are still active"));
+
+ mockMvc.perform(post("/deleteStore").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityID\":7,\"deleted\":true}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.response").value("Child Stores are still active"));
+ }
+
+ @Test
+ @DisplayName("getStoreByID should return the store behind the posted facility id")
+ void getStoreByID_shouldReturnStore() throws Exception {
+ when(storeService.getStoreByID(7)).thenReturn(facility(7, "Main store"));
+
+ mockMvc.perform(post("/getStoreByID").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(storeService).getStoreByID(7);
+ }
+
+ @Test
+ @DisplayName("getStoreByID should answer 200 with the failure text when the lookup throws")
+ void getStoreByID_shouldReturnFailureTextAsSuccessfulResponse() throws Exception {
+ when(storeService.getStoreByID(anyInt())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getStoreByID").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"facilityID\":7}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+ }
+
+ @Test
+ @DisplayName("getVanByStoreID should return the van attached to the store")
+ void getVanByStoreID_shouldReturnVan() throws Exception {
+ M_Van van = new M_Van();
+ van.setVanID(4);
+ when(storeService.getVanByStoreID(7)).thenReturn(van);
+
+ mockMvc.perform(post("/getVanByStoreID/7").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(storeService).getVanByStoreID(7);
+ }
+
+ @Test
+ @DisplayName("getVanByStoreID should answer with an empty van when the store has none attached")
+ void getVanByStoreID_shouldReturnEmptyVanWhenNoneAttached() throws Exception {
+ when(storeService.getVanByStoreID(7)).thenReturn(null);
+
+ mockMvc.perform(post("/getVanByStoreID/7").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+ }
+
+ @Test
+ @DisplayName("getVanByStoreID should report the failure when the lookup throws")
+ void getVanByStoreID_shouldReportServiceFailure() throws Exception {
+ when(storeService.getVanByStoreID(anyInt())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getVanByStoreID/7").header("Authorization", AUTH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/uom/UnitOfMeasurementControllerTest.java b/src/test/java/com/iemr/inventory/controller/uom/UnitOfMeasurementControllerTest.java
new file mode 100644
index 00000000..6db8dc98
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/uom/UnitOfMeasurementControllerTest.java
@@ -0,0 +1,204 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.uom;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.uom.M_Uom;
+import com.iemr.inventory.service.uom.UomInter;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("UnitOfMeasurementController Test Suite")
+class UnitOfMeasurementControllerTest {
+
+ @Mock
+ private UomInter uomInter;
+
+ private static final String AUTH = "test-session-key";
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked UoM service")
+ void setUp() {
+ UnitOfMeasurementController controller = new UnitOfMeasurementController();
+ ReflectionTestUtils.setField(controller, "uomInter", uomInter);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ private static M_Uom uom(Integer id, String name) {
+ M_Uom uom = new M_Uom();
+ uom.setuOMID(id);
+ uom.setuOMName(name);
+ uom.setuOMDesc("a description");
+ uom.setuOMCode("CODE");
+ uom.setStatus("Active");
+ uom.setProviderServiceMapID(3);
+ return uom;
+ }
+
+ private static ArrayList uomList(M_Uom... items) {
+ return new ArrayList<>(List.of(items));
+ }
+
+ @Test
+ @DisplayName("createUom should persist the posted array and answer with the saved rows")
+ void createUom_shouldPersistPostedArray() throws Exception {
+ when(uomInter.createDrugtypeData(anyList())).thenReturn(uomList(uom(1, "Tablet")));
+
+ mockMvc.perform(post("/createUom").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("[{\"uOMName\":\"Tablet\",\"providerServiceMapID\":3}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data[0].uOMName").value("Tablet"));
+
+ ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class);
+ verify(uomInter).createDrugtypeData(captor.capture());
+ org.junit.jupiter.api.Assertions.assertEquals(1, captor.getValue().size());
+ }
+
+ @Test
+ @DisplayName("createUom should report the failure when the service blows up")
+ void createUom_shouldReportServiceFailure() throws Exception {
+ when(uomInter.createDrugtypeData(anyList())).thenThrow(new RuntimeException("db unavailable"));
+
+ mockMvc.perform(post("/createUom").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON).content("[{}]"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("db unavailable"));
+ }
+
+ @Test
+ @DisplayName("createUom should report a parse failure for a malformed body")
+ void createUom_shouldReportParseFailure() throws Exception {
+ mockMvc.perform(post("/createUom").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON).content("not-json"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("getUom should look the rows up by the posted provider service map id")
+ void getUom_shouldLookUpByProviderServiceMapId() throws Exception {
+ when(uomInter.createDrugtypeData(3)).thenReturn(uomList(uom(1, "Tablet"), uom(2, "Syrup")));
+
+ mockMvc.perform(post("/getUom").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.length()").value(2));
+
+ verify(uomInter).createDrugtypeData(3);
+ }
+
+ @Test
+ @DisplayName("getUom should report the failure when the lookup throws")
+ void getUom_shouldReportServiceFailure() throws Exception {
+ when(uomInter.createDrugtypeData(anyInt())).thenThrow(new RuntimeException("lookup failed"));
+
+ mockMvc.perform(post("/getUom").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000));
+ }
+
+ @Test
+ @DisplayName("editUom should copy the editable fields onto the stored row before saving")
+ void editUom_shouldCopyEditableFieldsBeforeSaving() throws Exception {
+ M_Uom stored = uom(1, "old name");
+ when(uomInter.editDrugtypeData(1)).thenReturn(stored);
+ when(uomInter.saveeditedData(any(M_Uom.class))).thenAnswer(invocation -> invocation.getArgument(0));
+
+ mockMvc.perform(post("/editUom").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"uomID\":1,\"uOMName\":\"new name\",\"uOMDesc\":\"new desc\","
+ + "\"uOMCode\":\"NEW\",\"status\":\"Inactive\",\"modifiedBy\":\"tester\"}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200))
+ .andExpect(jsonPath("$.data.uOMName").value("new name"));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_Uom.class);
+ verify(uomInter).saveeditedData(captor.capture());
+ M_Uom saved = captor.getValue();
+ org.junit.jupiter.api.Assertions.assertEquals("new desc", saved.getuOMDesc());
+ org.junit.jupiter.api.Assertions.assertEquals("NEW", saved.getuOMCode());
+ org.junit.jupiter.api.Assertions.assertEquals("Inactive", saved.getStatus());
+ org.junit.jupiter.api.Assertions.assertEquals("tester", saved.getModifiedBy());
+ }
+
+ @Test
+ @DisplayName("editUom should report the failure when the row cannot be found")
+ void editUom_shouldReportFailureWhenRowMissing() throws Exception {
+ when(uomInter.editDrugtypeData(1)).thenReturn(null);
+
+ mockMvc.perform(post("/editUom").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON).content("{\"uomID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+
+ @Test
+ @DisplayName("deleteUom should flip the deleted flag on the stored row and save it")
+ void deleteUom_shouldFlipDeletedFlag() throws Exception {
+ M_Uom stored = uom(1, "Tablet");
+ when(uomInter.editDrugtypeData(1)).thenReturn(stored);
+ when(uomInter.saveeditedData(any(M_Uom.class))).thenAnswer(invocation -> invocation.getArgument(0));
+
+ mockMvc.perform(post("/deleteUom").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON)
+ .content("{\"uomID\":1,\"deleted\":true}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(M_Uom.class);
+ verify(uomInter).saveeditedData(captor.capture());
+ org.junit.jupiter.api.Assertions.assertEquals(Boolean.TRUE, captor.getValue().getDeleted());
+ }
+
+ @Test
+ @DisplayName("deleteUom should report the failure when the row cannot be found")
+ void deleteUom_shouldReportFailureWhenRowMissing() throws Exception {
+ when(uomInter.editDrugtypeData(1)).thenReturn(null);
+
+ mockMvc.perform(post("/deleteUom").header("Authorization", AUTH).contentType(MediaType.APPLICATION_JSON).content("{\"uomID\":1}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5005));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/version/VersionControllerTest.java b/src/test/java/com/iemr/inventory/controller/version/VersionControllerTest.java
new file mode 100644
index 00000000..b3c26821
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/version/VersionControllerTest.java
@@ -0,0 +1,78 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.version;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("VersionController Test Suite")
+class VersionControllerTest {
+
+ private MockMvc mockMvc;
+ private ObjectMapper objectMapper;
+
+ @BeforeEach
+ void setUp() {
+ VersionController versionController = new VersionController();
+
+ mockMvc = MockMvcBuilders.standaloneSetup(versionController).build();
+
+ objectMapper = new ObjectMapper();
+ }
+
+ @Test
+ @DisplayName("Should return version details sourced from git.properties on the classpath")
+ void versionInformation_shouldReturnGitPropertiesContent() throws Exception {
+ Properties gitProperties = new Properties();
+ try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("git.properties")) {
+ if (inputStream == null) {
+ throw new IOException("git.properties file not found in test resources.");
+ }
+ gitProperties.load(inputStream);
+ }
+
+ mockMvc.perform(get("/version"))
+ .andDo(MockMvcResultHandlers.print())
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.buildTimestamp").value(gitProperties.getProperty("git.build.time", "unknown")))
+ .andExpect(jsonPath("$.version").value(gitProperties.getProperty("git.build.version", "unknown")))
+ .andExpect(jsonPath("$.branch").value(gitProperties.getProperty("git.branch", "unknown")))
+ .andExpect(jsonPath("$.commitHash").value(gitProperties.getProperty("git.commit.id.abbrev", "unknown")));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/controller/visit/VisitControllerTest.java b/src/test/java/com/iemr/inventory/controller/visit/VisitControllerTest.java
new file mode 100644
index 00000000..70396807
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/controller/visit/VisitControllerTest.java
@@ -0,0 +1,143 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.controller.visit;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.MediaType;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.iemr.inventory.data.visit.BeneficiaryModel;
+import com.iemr.inventory.service.visit.VisitService;
+import com.iemr.inventory.utils.exception.InventoryException;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("VisitController Test Suite")
+class VisitControllerTest {
+
+ private static final String AUTH = "test-session-key";
+
+ @Mock
+ private VisitService visitService;
+
+ private MockMvc mockMvc;
+
+ @BeforeEach
+ @DisplayName("Stand the controller up with a mocked visit service")
+ void setUp() {
+ VisitController controller = new VisitController();
+ ReflectionTestUtils.setField(controller, "visitService", visitService);
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+ }
+
+ private static BeneficiaryModel beneficiary(Long regID) {
+ BeneficiaryModel model = new BeneficiaryModel();
+ model.setBeneficiaryRegID(regID);
+ return model;
+ }
+
+ @Test
+ @DisplayName("getVisitFromBenRegID should forward the beneficiary id, provider service map and auth header")
+ void getVisitFromBenRegID_shouldForwardRequestDetails() throws Exception {
+ when(visitService.getVisitDetail(eq("12345"), eq(3), eq(AUTH))).thenReturn(beneficiary(77L));
+
+ mockMvc.perform(post("/getVisitFromBenID").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"beneficiaryID\":\"12345\",\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(visitService).getVisitDetail("12345", 3, AUTH);
+ }
+
+ @Test
+ @DisplayName("getVisitFromBenRegID should report the failure when the beneficiary id is blank")
+ void getVisitFromBenRegID_shouldReportFailureForBlankBeneficiaryId() throws Exception {
+ when(visitService.getVisitDetail(eq(" "), anyInt(), anyString())).thenReturn(beneficiary(77L));
+
+ mockMvc.perform(post("/getVisitFromBenID").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"beneficiaryID\":\" \",\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("Beneficiary ID cannot be null or empty"));
+ }
+
+ @Test
+ @DisplayName("getVisitFromBenRegID should report the inventory failure raised by the service")
+ void getVisitFromBenRegID_shouldReportInventoryFailure() throws Exception {
+ when(visitService.getVisitDetail(anyString(), anyInt(), anyString()))
+ .thenThrow(new InventoryException("Invalid Beneficiary ID"));
+
+ mockMvc.perform(post("/getVisitFromBenID").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"beneficiaryID\":\"12345\",\"providerServiceMapID\":3}"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5010))
+ .andExpect(jsonPath("$.errorMessage").value("Invalid Beneficiary ID"));
+ }
+
+ @Test
+ @DisplayName("getVisitFromAdvanceSearch should forward the raw search payload and the auth header")
+ void getVisitFromAdvanceSearch_shouldForwardSearchPayload() throws Exception {
+ when(visitService.getVisitFromAdvanceSearch(anyString(), eq(AUTH)))
+ .thenReturn(List.of(beneficiary(77L)));
+
+ mockMvc.perform(post("/getVisitFromAdvanceSearch").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("12345"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(200));
+
+ verify(visitService).getVisitFromAdvanceSearch("12345", AUTH);
+ }
+
+ @Test
+ @DisplayName("getVisitFromAdvanceSearch should report the failure when the search throws")
+ void getVisitFromAdvanceSearch_shouldReportServiceFailure() throws Exception {
+ when(visitService.getVisitFromAdvanceSearch(anyString(), any()))
+ .thenThrow(new RuntimeException("search unavailable"));
+
+ mockMvc.perform(post("/getVisitFromAdvanceSearch").header("Authorization", AUTH)
+ .contentType(MediaType.APPLICATION_JSON).content("12345"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.statusCode").value(5000))
+ .andExpect(jsonPath("$.errorMessage").value("search unavailable"));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/exceptionhandler/DataNotFoundTest.java b/src/test/java/com/iemr/inventory/exceptionhandler/DataNotFoundTest.java
new file mode 100644
index 00000000..bf2b9df3
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/exceptionhandler/DataNotFoundTest.java
@@ -0,0 +1,41 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.exceptionhandler;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("DataNotFound Test Suite")
+class DataNotFoundTest {
+
+ @Test
+ @DisplayName("DataNotFound should be an unchecked exception carrying the supplied message")
+ void dataNotFound_shouldCarryMessage() {
+ DataNotFound exception = new DataNotFound("no such item");
+
+ assertEquals("no such item", exception.getMessage());
+ assertInstanceOf(RuntimeException.class, exception);
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/mapper/report/InventoryReportMapperTest.java b/src/test/java/com/iemr/inventory/mapper/report/InventoryReportMapperTest.java
new file mode 100644
index 00000000..18d46cd2
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/mapper/report/InventoryReportMapperTest.java
@@ -0,0 +1,143 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.mapper.report;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import java.sql.Date;
+import java.sql.Timestamp;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import com.iemr.inventory.data.report.ItemStockEntryReport;
+import com.iemr.inventory.data.report.PatientIssueExitReport;
+import com.iemr.inventory.model.report.BenDrugIssueReport;
+import com.iemr.inventory.model.report.ExpiryReport;
+import com.iemr.inventory.model.report.InwardStockReport;
+
+@DisplayName("InventoryReportMapper Test Suite")
+class InventoryReportMapperTest {
+
+ private static final Date EXPIRY = Date.valueOf("2026-01-31");
+ private static final Timestamp CREATED = Timestamp.valueOf("2025-01-31 10:15:30");
+
+ private final InventoryReportMapper mapper = InventoryReportMapper.INSTANCE;
+
+ private static ItemStockEntryReport entryReport() {
+ ItemStockEntryReport report = new ItemStockEntryReport();
+ report.setFacilityName("Main store");
+ report.setItemName("Paracetamol");
+ report.setItemCategoryName("Analgesic");
+ report.setStrength("500mg");
+ report.setBatchNo("B-1");
+ report.setUnitCostPrice(2.5d);
+ report.setExpiryDate(EXPIRY);
+ report.setCreatedDate(CREATED);
+ report.setEntryType("Purchase");
+ report.setQuantity(100);
+ report.setQuantityInHand(40);
+ return report;
+ }
+
+ private static PatientIssueExitReport exitReport() {
+ PatientIssueExitReport report = new PatientIssueExitReport();
+ report.setCreatedDate(CREATED);
+ report.setPatientName("Jane Doe");
+ report.setGender("Female");
+ report.setAge(34);
+ report.setItemName("Paracetamol");
+ report.setItemCategoryName("Analgesic");
+ report.setBatchNo("B-1");
+ report.setExpiryDate(EXPIRY);
+ report.setStrength("500mg");
+ report.setQuantityGiven(6);
+ return report;
+ }
+
+ @Test
+ @DisplayName("mapInwardStockReport should carry the inward columns across, with the created date as inward date")
+ void mapInwardStockReport_shouldCarryInwardColumns() {
+ InwardStockReport report = mapper.mapInwardStockReport(entryReport());
+
+ assertEquals("Main store", report.getFacilityName());
+ assertEquals("Paracetamol", report.getItemName());
+ assertEquals("Analgesic", report.getItemCategory());
+ assertEquals("B-1", report.getBatchNo());
+ assertEquals(2.5d, report.getUnitCostPrice());
+ assertEquals(EXPIRY, report.getExpiryDate());
+ assertEquals(CREATED, report.getInwardDate());
+ assertEquals("Purchase", report.getEntryType());
+ assertEquals(100, report.getQuantity());
+ }
+
+ @Test
+ @DisplayName("mapInwardStockReport should return null for a null entry report")
+ void mapInwardStockReport_shouldReturnNullForNull() {
+ assertNull(mapper.mapInwardStockReport(null));
+ }
+
+ @Test
+ @DisplayName("mapExpiryReport should carry the expiry columns across, including the quantity still in hand")
+ void mapExpiryReport_shouldCarryExpiryColumns() {
+ ExpiryReport report = mapper.mapExpiryReport(entryReport());
+
+ assertEquals("Main store", report.getFacilityName());
+ assertEquals("Paracetamol", report.getItemName());
+ assertEquals("Analgesic", report.getItemCategory());
+ assertEquals("500mg", report.getStrength());
+ assertEquals("B-1", report.getBatchNo());
+ assertEquals(2.5d, report.getUnitCostPrice());
+ assertEquals(EXPIRY, report.getExpiryDate());
+ assertEquals(40, report.getQuantityInHand());
+ }
+
+ @Test
+ @DisplayName("mapExpiryReport should return null for a null entry report")
+ void mapExpiryReport_shouldReturnNullForNull() {
+ assertNull(mapper.mapExpiryReport(null));
+ }
+
+ @Test
+ @DisplayName("mapBenDrugIssueReport should carry the beneficiary and the dispensed quantity across")
+ void mapBenDrugIssueReport_shouldCarryBeneficiaryAndQuantity() {
+ BenDrugIssueReport report = mapper.mapBenDrugIssueReport(exitReport());
+
+ assertEquals(CREATED, report.getDate());
+ assertEquals("Jane Doe", report.getBeneficiaryName());
+ assertEquals("Female", report.getGender());
+ assertEquals(34, report.getAge());
+ assertEquals("Paracetamol", report.getItemName());
+ assertEquals("Analgesic", report.getItemCategory());
+ assertEquals("B-1", report.getBatchNo());
+ assertEquals(EXPIRY, report.getExpiryDate());
+ assertEquals("500mg", report.getStrength());
+ assertEquals(6, report.getDispensedQuantity());
+ }
+
+ @Test
+ @DisplayName("mapBenDrugIssueReport should return null for a null exit report")
+ void mapBenDrugIssueReport_shouldReturnNullForNull() {
+ assertNull(mapper.mapBenDrugIssueReport(null));
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/mapper/stockExit/StockExitMapperTest.java b/src/test/java/com/iemr/inventory/mapper/stockExit/StockExitMapperTest.java
new file mode 100644
index 00000000..055ac08c
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/mapper/stockExit/StockExitMapperTest.java
@@ -0,0 +1,246 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.mapper.stockExit;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.sql.Date;
+import java.util.List;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import com.iemr.inventory.data.items.ItemMaster;
+import com.iemr.inventory.data.stockExit.ItemStockExit;
+import com.iemr.inventory.data.stockExit.ItemStockExitMap;
+import com.iemr.inventory.data.stockentry.AllocateItemMap;
+import com.iemr.inventory.data.stockentry.ItemBatchList;
+import com.iemr.inventory.data.stockentry.ItemMasterWithQuantityMap;
+import com.iemr.inventory.data.stockentry.ItemStockEntry;
+
+@DisplayName("Stock exit mapper Test Suite")
+class StockExitMapperTest {
+
+ private static final Date EXPIRY = Date.valueOf("2026-01-31");
+
+ private static ItemStockEntry stockEntry() {
+ ItemMaster item = new ItemMaster();
+ item.setItemName("Paracetamol");
+ item.setItemID(11);
+
+ ItemStockEntry entry = new ItemStockEntry();
+ entry.setItemStockEntryID(601);
+ entry.setFacilityID(7);
+ entry.setItemID(11);
+ entry.setBatchNo("B-1");
+ entry.setExpiryDate(EXPIRY);
+ entry.setQuantity(100);
+ entry.setQuantityInHand(40);
+ entry.setCreatedBy("tester");
+ entry.setDeleted(false);
+ entry.setItem(item);
+ return entry;
+ }
+
+ private static ItemStockExit stockExit() {
+ ItemStockExit exit = new ItemStockExit();
+ exit.setItemStockExitID(501L);
+ exit.setItemStockEntryID(601L);
+ exit.setFacilityID(7);
+ exit.setItemID(11);
+ exit.setQuantity(6);
+ exit.setDeleted(false);
+ exit.setCreatedBy("tester");
+ exit.setItemStockEntry(stockEntry());
+ return exit;
+ }
+
+ @Nested
+ @DisplayName("ItemStockExitMapper")
+ class ItemStockExitMapperTests {
+
+ private final ItemStockExitMapper mapper = ItemStockExitMapper.INSTANCE;
+
+ @Test
+ @DisplayName("getItemStockExitMap should flatten the batch of the exit onto the projection")
+ void getItemStockExitMap_shouldFlattenBatch() {
+ ItemStockExitMap result = mapper.getItemStockExitMap(stockExit());
+
+ assertEquals("Paracetamol", result.getItemName());
+ assertEquals("B-1", result.getBatchNo());
+ assertEquals(EXPIRY, result.getExpiryDate());
+ assertEquals(6, result.getQuantity());
+ assertEquals("tester", result.getCreatedBy());
+ assertEquals(Boolean.FALSE, result.getDeleted());
+ }
+
+ @Test
+ @DisplayName("getItemStockExitMap should return null for a null exit")
+ void getItemStockExitMap_shouldReturnNullForNull() {
+ assertNull(mapper.getItemStockExitMap((ItemStockExit) null));
+ }
+
+ @Test
+ @DisplayName("getItemStockExitMapList should project every exit in the list")
+ void getItemStockExitMapList_shouldProjectEveryExit() {
+ List result = mapper.getItemStockExitMapList(List.of(stockExit(), stockExit()));
+
+ assertEquals(2, result.size());
+ assertEquals("B-1", result.get(1).getBatchNo());
+ }
+
+ @Test
+ @DisplayName("getItemStockEntryMapList should project an entry row the same way")
+ void getItemStockEntryMapList_shouldProjectEntry() {
+ ItemStockExitMap result = mapper.getItemStockEntryMapList(stockEntry());
+
+ assertEquals("Paracetamol", result.getItemName());
+ assertEquals("B-1", result.getBatchNo());
+ assertEquals(100, result.getQuantity());
+ }
+
+ @Test
+ @DisplayName("getItemStockEntryMapList should project every entry in the list")
+ void getItemStockEntryMapList_shouldProjectEveryEntry() {
+ assertEquals(2, mapper.getItemStockEntryMapList(List.of(stockEntry(), stockEntry())).size());
+ }
+
+ @Test
+ @DisplayName("getItemStockEntryMapList should return null for a null list")
+ void getItemStockEntryMapList_shouldReturnNullForNullList() {
+ assertNull(mapper.getItemStockEntryMapList((List) null));
+ }
+ }
+
+ @Nested
+ @DisplayName("ItemBatchListMap")
+ class ItemBatchListMapTests {
+
+ private final ItemBatchListMap mapper = ItemBatchListMap.INSTANCE;
+
+ @Test
+ @DisplayName("getItemStockExitMap should carry the batch identity and both quantities across")
+ void getItemStockExitMap_shouldCarryBatchIdentity() {
+ ItemBatchList result = mapper.getItemStockExitMap(stockEntry());
+
+ assertEquals(601L, result.getItemStockEntryID());
+ assertEquals(7, result.getFacilityID());
+ assertEquals(11, result.getItemID());
+ assertEquals(100, result.getQuantity());
+ assertEquals(40, result.getQuantityInHand());
+ assertEquals("B-1", result.getBatchNo());
+ assertEquals(EXPIRY, result.getExpiryDate());
+ }
+
+ @Test
+ @DisplayName("getItemStockExitMap should return null for a null entry")
+ void getItemStockExitMap_shouldReturnNullForNull() {
+ assertNull(mapper.getItemStockExitMap(null));
+ }
+
+ @Test
+ @DisplayName("getItemStockExitMapList should project every batch in the list")
+ void getItemStockExitMapList_shouldProjectEveryBatch() {
+ assertEquals(2, mapper.getItemStockExitMapList(List.of(stockEntry(), stockEntry())).size());
+ }
+
+ @Test
+ @DisplayName("getItemStockExitMapList should return null for a null list")
+ void getItemStockExitMapList_shouldReturnNullForNullList() {
+ assertNull(mapper.getItemStockExitMapList(null));
+ }
+ }
+
+ @Nested
+ @DisplayName("ItemMasterWithQuantityMapper")
+ class ItemMasterWithQuantityMapperTests {
+
+ private final ItemMasterWithQuantityMapper mapper = ItemMasterWithQuantityMapper.INSTANCE;
+
+ @Test
+ @DisplayName("getItemStockExitMap should carry the batch identity and the item across")
+ void getItemStockExitMap_shouldCarryItem() {
+ ItemMasterWithQuantityMap result = mapper.getItemStockExitMap(stockEntry());
+
+ assertEquals(601L, result.getItemStockEntryID());
+ assertEquals(7, result.getFacilityID());
+ assertEquals(11, result.getItemID());
+ assertEquals(40, result.getQuantityInHand());
+ assertEquals("Paracetamol", result.getItem().getItemName());
+ }
+
+ @Test
+ @DisplayName("getItemStockExitMap should return null for a null entry")
+ void getItemStockExitMap_shouldReturnNullForNull() {
+ assertNull(mapper.getItemStockExitMap(null));
+ }
+
+ @Test
+ @DisplayName("getItemStockExitMapList should project every entry in the list")
+ void getItemStockExitMapList_shouldProjectEveryEntry() {
+ assertEquals(2, mapper.getItemStockExitMapList(List.of(stockEntry(), stockEntry())).size());
+ }
+
+ @Test
+ @DisplayName("getItemStockExitMapList should return null for a null list")
+ void getItemStockExitMapList_shouldReturnNullForNullList() {
+ assertNull(mapper.getItemStockExitMapList(null));
+ }
+ }
+
+ @Nested
+ @DisplayName("AllocateItemMapper")
+ class AllocateItemMapperTests {
+
+ private final AllocateItemMapper mapper = AllocateItemMapper.INSTANCE;
+
+ @Test
+ @DisplayName("getItemStockExitMap should carry the facility and item across")
+ void getItemStockExitMap_shouldCarryFacilityAndItem() {
+ AllocateItemMap result = mapper.getItemStockExitMap(stockExit());
+
+ assertEquals(7, result.getFacilityID());
+ assertEquals(11, result.getItemID());
+ }
+
+ @Test
+ @DisplayName("getItemStockExitMap should return null for a null exit")
+ void getItemStockExitMap_shouldReturnNullForNull() {
+ assertNull(mapper.getItemStockExitMap(null));
+ }
+
+ @Test
+ @DisplayName("getItemStockExitMapList should project every exit in the list")
+ void getItemStockExitMapList_shouldProjectEveryExit() {
+ assertEquals(2, mapper.getItemStockExitMapList(List.of(stockExit(), stockExit())).size());
+ }
+
+ @Test
+ @DisplayName("getItemStockExitMapList should return null for a null list")
+ void getItemStockExitMapList_shouldReturnNullForNullList() {
+ assertNull(mapper.getItemStockExitMapList(null));
+ }
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/mapper/stockadjustment/StockAdjustmentItemDraftMapperTest.java b/src/test/java/com/iemr/inventory/mapper/stockadjustment/StockAdjustmentItemDraftMapperTest.java
new file mode 100644
index 00000000..bd32bdb6
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/mapper/stockadjustment/StockAdjustmentItemDraftMapperTest.java
@@ -0,0 +1,249 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.mapper.stockadjustment;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import com.iemr.inventory.data.items.ItemMaster;
+import com.iemr.inventory.data.stockadjustment.StockAdjustmentItem;
+import com.iemr.inventory.data.stockadjustment.StockAdjustmentItemDraft;
+import com.iemr.inventory.data.stockadjustment.StockAdjustmentItemDraftEdit;
+import com.iemr.inventory.data.stockentry.ItemStockEntry;
+
+@DisplayName("StockAdjustmentItemDraftMapper Test Suite")
+class StockAdjustmentItemDraftMapperTest {
+
+ private final StockAdjustmentItemDraftMapper mapper = StockAdjustmentItemDraftMapper.INSTANCE;
+
+ private static ItemStockEntry stockEntry(String batchNo, String itemName, Integer inHand) {
+ ItemStockEntry entry = new ItemStockEntry();
+ entry.setBatchNo(batchNo);
+ entry.setQuantityInHand(inHand);
+ if (itemName != null) {
+ ItemMaster item = new ItemMaster();
+ item.setItemName(itemName);
+ entry.setItem(item);
+ }
+ return entry;
+ }
+
+ private static StockAdjustmentItemDraft draftItem(Long mapID, boolean deleted, ItemStockEntry entry) {
+ StockAdjustmentItemDraft draftItem = new StockAdjustmentItemDraft();
+ draftItem.setSADraftItemMapID(mapID);
+ draftItem.setItemStockEntryID(601L);
+ draftItem.setAdjustedQuantity(4);
+ draftItem.setCreatedBy("tester");
+ draftItem.setProviderServiceMapID(3);
+ draftItem.setIsAdded(true);
+ draftItem.setDeleted(deleted);
+ draftItem.setReason("damaged");
+ draftItem.setItemStockEntry(entry);
+ return draftItem;
+ }
+
+ private static StockAdjustmentItem adjustmentItem(Long mapID, ItemStockEntry entry) {
+ StockAdjustmentItem item = new StockAdjustmentItem();
+ item.setSAItemMapID(mapID);
+ item.setItemStockEntryID(601L);
+ item.setAdjustedQuantity(4);
+ item.setCreatedBy("tester");
+ item.setProviderServiceMapID(3);
+ item.setIsAdded(false);
+ item.setDeleted(false);
+ item.setReason("expired");
+ item.setItemStockEntry(entry);
+ return item;
+ }
+
+ @Test
+ @DisplayName("getStockAdjustmentItemDraftEdit should flatten the batch and item name onto the edit projection")
+ void getStockAdjustmentItemDraftEdit_shouldFlattenBatchAndItemName() {
+ StockAdjustmentItemDraftEdit edit =
+ mapper.getStockAdjustmentItemDraftEdit(draftItem(9L, false, stockEntry("B-1", "Paracetamol", 40)));
+
+ assertEquals(9L, edit.getSADraftItemMapID());
+ assertEquals(601L, edit.getItemStockEntryID());
+ assertEquals("B-1", edit.getBatchID());
+ assertEquals("Paracetamol", edit.getItemName());
+ assertEquals(40, edit.getQuantityInHand());
+ assertEquals(4, edit.getAdjustedQuantity());
+ assertEquals("tester", edit.getCreatedBy());
+ assertEquals(3, edit.getProviderServiceMapID());
+ assertEquals(Boolean.TRUE, edit.getIsAdded());
+ assertEquals("damaged", edit.getReason());
+ }
+
+ @Test
+ @DisplayName("getStockAdjustmentItemDraftEdit should leave the item name blank when the batch has no item")
+ void getStockAdjustmentItemDraftEdit_shouldLeaveItemNameBlankWithoutItem() {
+ StockAdjustmentItemDraftEdit edit =
+ mapper.getStockAdjustmentItemDraftEdit(draftItem(9L, false, stockEntry("B-1", null, 40)));
+
+ assertEquals("B-1", edit.getBatchID());
+ assertNull(edit.getItemName());
+ }
+
+ @Test
+ @DisplayName("getStockAdjustmentItemDraftEdit should leave the batch fields blank when no batch is attached")
+ void getStockAdjustmentItemDraftEdit_shouldLeaveBatchFieldsBlankWithoutBatch() {
+ StockAdjustmentItemDraftEdit edit = mapper.getStockAdjustmentItemDraftEdit(draftItem(9L, false, null));
+
+ assertNull(edit.getBatchID());
+ assertNull(edit.getQuantityInHand());
+ }
+
+ @Test
+ @DisplayName("getStockAdjustmentItemDraftEdit should return an empty projection for a null draft item")
+ void getStockAdjustmentItemDraftEdit_shouldReturnEmptyProjectionForNull() {
+ StockAdjustmentItemDraftEdit edit = mapper.getStockAdjustmentItemDraftEdit(null);
+
+ assertNull(edit.getSADraftItemMapID());
+ }
+
+ @Test
+ @DisplayName("getStockAdjustmentItemDraftEditList should leave the soft-deleted draft rows out")
+ void getStockAdjustmentItemDraftEditList_shouldSkipDeletedRows() {
+ List rows = new ArrayList<>(Arrays.asList(
+ draftItem(9L, false, stockEntry("B-1", "Paracetamol", 40)),
+ draftItem(10L, true, stockEntry("B-2", "Ibuprofen", 10))));
+
+ List result = mapper.getStockAdjustmentItemDraftEditList(rows);
+
+ assertEquals(1, result.size());
+ assertEquals(9L, result.get(0).getSADraftItemMapID());
+ }
+
+ @Test
+ @DisplayName("getStockAdjustmentItemDraftEditList should return nothing for an empty draft")
+ void getStockAdjustmentItemDraftEditList_shouldReturnNothingForEmptyDraft() {
+ assertTrue(mapper.getStockAdjustmentItemDraftEditList(new ArrayList<>()).isEmpty());
+ }
+
+ @Test
+ @DisplayName("getStockAdjustmentItemEditList should project every posted adjustment line")
+ void getStockAdjustmentItemEditList_shouldProjectEveryLine() {
+ List rows = new ArrayList<>(Arrays.asList(
+ adjustmentItem(21L, stockEntry("B-1", "Paracetamol", 40)),
+ adjustmentItem(22L, null)));
+
+ List result = mapper.getStockAdjustmentItemEditList(rows);
+
+ assertEquals(2, result.size());
+ assertEquals(21L, result.get(0).getSAItemMapID());
+ assertEquals("Paracetamol", result.get(0).getItemName());
+ assertEquals("expired", result.get(0).getReason());
+ assertNull(result.get(1).getBatchID());
+ }
+
+ @Test
+ @DisplayName("mapSADraftItemMapID should read any numeric-looking value as a long, and null as null")
+ void mapSADraftItemMapID_shouldReadNumericValues() {
+ assertEquals(9L, mapper.mapSADraftItemMapID("9"));
+ assertEquals(9L, mapper.mapSADraftItemMapID(9));
+ assertNull(mapper.mapSADraftItemMapID(null));
+ }
+
+ @Test
+ @DisplayName("mapCreatedBy should stringify any value, and leave null as null")
+ void mapCreatedBy_shouldStringifyValues() {
+ assertEquals("tester", mapper.mapCreatedBy("tester"));
+ assertEquals("9", mapper.mapCreatedBy(9));
+ assertNull(mapper.mapCreatedBy(null));
+ }
+
+ @Test
+ @DisplayName("mapCreatedDate should produce a date for any value, and null for null")
+ void mapCreatedDate_shouldProduceDateForAnyValue() {
+ assertTrue(mapper.mapCreatedDate("anything") != null);
+ assertNull(mapper.mapCreatedDate(null));
+ }
+
+ /**
+ * The MapStruct-generated delegate that sits behind the hand-written decorator. The decorator
+ * overrides every method, so these are the only tests that exercise the generated mapping code.
+ */
+ @org.junit.jupiter.api.Nested
+ @DisplayName("Generated delegate")
+ class GeneratedDelegateTests {
+
+ private final StockAdjustmentItemDraftMapper delegate = new StockAdjustmentItemDraftMapperImpl_();
+
+ @Test
+ @DisplayName("the delegate should copy the draft item's own fields onto the edit projection")
+ void delegate_shouldCopyDraftFields() {
+ StockAdjustmentItemDraftEdit edit =
+ delegate.getStockAdjustmentItemDraftEdit(draftItem(9L, false, stockEntry("B-1", "Paracetamol", 40)));
+
+ assertEquals(9L, edit.getSADraftItemMapID());
+ assertEquals(601L, edit.getItemStockEntryID());
+ assertEquals(4, edit.getAdjustedQuantity());
+ assertEquals("tester", edit.getCreatedBy());
+ assertEquals(3, edit.getProviderServiceMapID());
+ assertEquals("damaged", edit.getReason());
+ }
+
+ @Test
+ @DisplayName("the delegate should return null for a null draft item")
+ void delegate_shouldReturnNullForNullDraftItem() {
+ assertNull(delegate.getStockAdjustmentItemDraftEdit(null));
+ }
+
+ @Test
+ @DisplayName("the delegate should project every draft row, deleted ones included")
+ void delegate_shouldProjectEveryDraftRow() {
+ List rows = new ArrayList<>(Arrays.asList(
+ draftItem(9L, false, null), draftItem(10L, true, null)));
+
+ assertEquals(2, delegate.getStockAdjustmentItemDraftEditList(rows).size());
+ }
+
+ @Test
+ @DisplayName("the delegate should return null for a null draft list")
+ void delegate_shouldReturnNullForNullDraftList() {
+ assertNull(delegate.getStockAdjustmentItemDraftEditList(null));
+ }
+
+ @Test
+ @DisplayName("the delegate should project every posted adjustment line")
+ void delegate_shouldProjectEveryAdjustmentLine() {
+ List rows = new ArrayList<>(Arrays.asList(
+ adjustmentItem(21L, null), adjustmentItem(22L, null)));
+
+ assertEquals(2, delegate.getStockAdjustmentItemEditList(rows).size());
+ }
+
+ @Test
+ @DisplayName("the delegate should return null for a null adjustment list")
+ void delegate_shouldReturnNullForNullAdjustmentList() {
+ assertNull(delegate.getStockAdjustmentItemEditList(null));
+ }
+ }
+}
diff --git a/src/test/java/com/iemr/inventory/service/dispenseagainst_rx/DispenseAgainstRXimplTest.java b/src/test/java/com/iemr/inventory/service/dispenseagainst_rx/DispenseAgainstRXimplTest.java
new file mode 100644
index 00000000..b47ecbbb
--- /dev/null
+++ b/src/test/java/com/iemr/inventory/service/dispenseagainst_rx/DispenseAgainstRXimplTest.java
@@ -0,0 +1,205 @@
+/*
+* AMRIT - Accessible Medical Records via Integrated Technologies
+* Integrated EHR (Electronic Health Records) Solution
+*
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
+*
+* This file is part of AMRIT.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+package com.iemr.inventory.service.dispenseagainst_rx;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.when;
+
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.iemr.inventory.repo.dispenseagainst_rx.PrescribedDrugDetailsRepo;
+
+@ExtendWith(MockitoExtension.class)
+@DisplayName("DispenseAgainstRXimpl Test Suite")
+class DispenseAgainstRXimplTest {
+
+ private static final String REQUEST =
+ "{\"beneficiaryRegID\":101,\"visitCode\":5001,\"facilityID\":7}";
+
+ @Mock
+ private PrescribedDrugDetailsRepo prescribedDrugDetailsRepo;
+
+ @InjectMocks
+ private DispenseAgainstRXimpl service;
+
+ /**
+ * Builds one result-set row in the column order the native query returns, with a batch that
+ * expires the given number of days from now and the given quantity in hand.
+ */
+ private static Object[] row(Integer drugID, String batchNo, Integer stockEntryID, int qtyInHand,
+ int expiresInDays) {
+ Timestamp expiry = new Timestamp(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(expiresInDays));
+ return new Object[] {
+ 101L, 5001L, 9001L, drugID,
+ "Paracetamol", "Tablet", "500mg", "1", "Oral", "BD",
+ "5", "Days", "After food", "with water",
+ Timestamp.valueOf("2025-01-31 10:15:30"), "dr.smith",
+ stockEntryID, batchNo, qtyInHand, expiry, 10, Boolean.TRUE
+ };
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Map parse(String json) {
+ return new Gson().fromJson(json, new TypeToken