diff --git a/pom.xml b/pom.xml index f23f68a5..8b238e13 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.iemr.inventory inventory-api - 3.4.0 + 3.6.0 war Inventory-API Inventory Page @@ -111,11 +111,11 @@ jersey-media-multipart 2.0-m11 - + org.springframework.boot spring-boot-starter-test @@ -215,14 +215,26 @@ org.springframework.boot spring-boot-starter - + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + slf4j-simple + ${slf4j.version} + + + org.springframework.plugin spring-plugin-core diff --git a/src/main/java/com/iemr/inventory/controller/report/CRMReportController.java b/src/main/java/com/iemr/inventory/controller/report/CRMReportController.java index 39c891da..3627768d 100644 --- a/src/main/java/com/iemr/inventory/controller/report/CRMReportController.java +++ b/src/main/java/com/iemr/inventory/controller/report/CRMReportController.java @@ -211,7 +211,7 @@ public String getShortExpiryReport(@RequestBody String request) { ItemStockEntryReport report = InputMapper.gson().fromJson(request, ItemStockEntryReport.class); String res = crmReportService.getShortExpiryReport(report); response.setResponse(res); - logger.info("getShortExpiryReport response " + response.toString()); + logger.info("Short Expiry Report response:" + response.toString()); } catch (Exception e) { logger.error(e.getMessage()); response.setError(e); diff --git a/src/main/java/com/iemr/inventory/mapper/report/InventoryReportMapper.java b/src/main/java/com/iemr/inventory/mapper/report/InventoryReportMapper.java index 712dd834..5347151a 100644 --- a/src/main/java/com/iemr/inventory/mapper/report/InventoryReportMapper.java +++ b/src/main/java/com/iemr/inventory/mapper/report/InventoryReportMapper.java @@ -53,6 +53,7 @@ public interface InventoryReportMapper { @Mappings({ @Mapping(target = "facilityName", expression = "java(entryReport.getFacilityName())"), @Mapping(target = "itemName", expression = "java(entryReport.getItemName())"), @Mapping(target = "itemCategory", expression = "java(entryReport.getItemCategoryName())"), + @Mapping(target = "strength", expression = "java(entryReport.getStrength())"), @Mapping(target = "batchNo", expression = "java(entryReport.getBatchNo())"), @Mapping(target = "unitCostPrice", expression = "java(entryReport.getUnitCostPrice())"), @Mapping(target = "expiryDate", expression = "java(entryReport.getExpiryDate())"), diff --git a/src/main/java/com/iemr/inventory/model/report/ExpiryReport.java b/src/main/java/com/iemr/inventory/model/report/ExpiryReport.java index addf157d..b1abd401 100644 --- a/src/main/java/com/iemr/inventory/model/report/ExpiryReport.java +++ b/src/main/java/com/iemr/inventory/model/report/ExpiryReport.java @@ -40,6 +40,8 @@ public class ExpiryReport { private String itemCategory; + private String strength; + private String batchNo; private Double unitCostPrice; @@ -52,12 +54,13 @@ public ExpiryReport() { } - public ExpiryReport(String facilityName, String itemName, String itemCategory, String batchNo, Double unitCostPrice, + public ExpiryReport(String facilityName, String itemName, String itemCategory, String Strength, String batchNo, Double unitCostPrice, Date expiryDate, Integer quantityInHand) { this.facilityName = facilityName; this.itemName = itemName; this.itemCategory = itemCategory; + this.strength = Strength; this.batchNo = batchNo; this.unitCostPrice = unitCostPrice; this.expiryDate = expiryDate; diff --git a/src/main/java/com/iemr/inventory/repo/report/ItemStockReportRepo.java b/src/main/java/com/iemr/inventory/repo/report/ItemStockReportRepo.java index af2885b3..99a9ca67 100644 --- a/src/main/java/com/iemr/inventory/repo/report/ItemStockReportRepo.java +++ b/src/main/java/com/iemr/inventory/repo/report/ItemStockReportRepo.java @@ -48,11 +48,11 @@ List getItemStockEntryReport(@Param("startDate") Timestamp List getItemStockEntryReportByFacilityID(@Param("startDate") Timestamp startDate, @Param("endDate") Timestamp endDate, @Param("facilityID") Integer facilityID); - @Query(value = "Select distinct FacilityName, ItemName, ItemCategoryName, BatchNo, UnitCostPrice, ExpiryDate, QuantityInHand from db_reporting.fact_itemstockentry " + @Query(value = "Select distinct FacilityName, ItemName, ItemCategoryName, Strength, BatchNo, UnitCostPrice, ExpiryDate, QuantityInHand from db_reporting.fact_itemstockentry " + "where ExpiryDate >= :startDate and ExpiryDate <= :endDate order by ExpiryDate asc",nativeQuery = true) List getExpiryReport(@Param("startDate") Date startDate, @Param("endDate") Date endDate); - @Query(value = "Select distinct FacilityName, ItemName, ItemCategoryName, BatchNo, UnitCostPrice, ExpiryDate, QuantityInHand from db_reporting.fact_itemstockentry " + @Query(value = "Select distinct FacilityName, ItemName, ItemCategoryName, Strength, BatchNo, UnitCostPrice, ExpiryDate, QuantityInHand from db_reporting.fact_itemstockentry " + "where ExpiryDate >= :startDate and ExpiryDate <= :endDate and FacilityID = :facilityID order by ExpiryDate asc",nativeQuery = true) List getExpiryReportByFacilityID(@Param("startDate") Date startDate, @Param("endDate") Date endDate, @Param("facilityID") Integer facilityID); @@ -99,11 +99,11 @@ List getDailyStockDetailReportByFacilityID(@Param("startDate") Date st List getDailyStockSummaryReportByFacilityID(@Param("startDate") Date startDate, @Param("endDate") Date endDate, @Param("facilityID") Integer facilityID); - @Query(value="Select distinct FacilityName, ItemName, ItemCategoryName, BatchNo, UnitCostPrice, ExpiryDate, QuantityInHand from db_reporting.fact_itemstockentry " + @Query(value="Select distinct FacilityName, ItemName, ItemCategoryName, Strength, BatchNo, UnitCostPrice, ExpiryDate, QuantityInHand from db_reporting.fact_itemstockentry " + "where ExpiryDate >= :startDate and ExpiryDate <= adddate(:startDate,AlertBeforeDays) and Deleted=false order by ExpiryDate asc",nativeQuery=true) List getShortExpiryReport(@Param("startDate") Date startDate); - @Query(value="Select distinct FacilityName, ItemName, ItemCategoryName, BatchNo, UnitCostPrice, ExpiryDate, QuantityInHand from db_reporting.fact_itemstockentry " + @Query(value="Select distinct FacilityName, ItemName, ItemCategoryName, Strength, BatchNo, UnitCostPrice, ExpiryDate, QuantityInHand from db_reporting.fact_itemstockentry " + "where ExpiryDate >= :startDate and ExpiryDate <= adddate(:startDate,AlertBeforeDays) and FacilityID = :facilityID and Deleted=false order by ExpiryDate asc",nativeQuery=true) List getShortExpiryReportByFacilityID(@Param("startDate") Date startDate, @Param("facilityID") Integer facilityID); diff --git a/src/main/java/com/iemr/inventory/service/report/CRMReportServiceImpl.java b/src/main/java/com/iemr/inventory/service/report/CRMReportServiceImpl.java index 714043b7..209ce571 100644 --- a/src/main/java/com/iemr/inventory/service/report/CRMReportServiceImpl.java +++ b/src/main/java/com/iemr/inventory/service/report/CRMReportServiceImpl.java @@ -27,6 +27,8 @@ import java.util.Calendar; import java.util.List; import java.util.Objects; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -57,6 +59,8 @@ public class CRMReportServiceImpl implements CRMReportService { @Autowired(required=false) InventoryReportMapper mapper; + private Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName()); + @Override public String getInwardStockReport(ItemStockEntryReport entryReport) { @@ -98,9 +102,10 @@ public String getExpiryReport(ItemStockEntryReport entryReport) { object[1] != null ? object[1].toString() : null, object[2] != null ? object[2].toString() : null, object[3] != null ? object[3].toString() : null, - object[4] != null ? Double.valueOf(object[4].toString()) : null, - (Date) (object[5] != null ? object[5] : null), - (Integer) (object[6] != null ? object[6] : null)); + object[4] != null ? object[4].toString() : null, + object[5] != null ? Double.valueOf(object[5].toString()) : null, + (Date) (object[6] != null ? object[6] : null), + (Integer) (object[7] != null ? object[7] : null)); report.setSlNo(slNo++); reportList.add(report); @@ -618,6 +623,10 @@ public String getShortExpiryReport(ItemStockEntryReport entryReport) { list = itemStockReportRepo.getShortExpiryReport(startExpiry); } + logger.info("Short Expiry Report Start Date: " + startExpiry + " End Date: " + endExpiry); + + logger.info("Short Expiry Report List Size: " + list.size()); + Long slNo = 1L; for (Object[] object : list) { @@ -627,9 +636,10 @@ public String getShortExpiryReport(ItemStockEntryReport entryReport) { object[1] != null ? object[1].toString() : null, object[2] != null ? object[2].toString() : null, object[3] != null ? object[3].toString() : null, - object[4] != null ? ((BigDecimal) object[4]).doubleValue() : null, - (Date) (object[5] != null ? object[5] : null), - (Integer) (object[6] != null ? object[6] : null)); + object[4] != null ? object[4].toString() : null, + object[5] != null ? ((BigDecimal) object[5]).doubleValue() : null, + (Date) (object[6] != null ? object[6] : null), + (Integer) (object[7] != null ? object[7] : null)); report.setSlNo(slNo++); reportList.add(report); diff --git a/src/main/java/com/iemr/inventory/service/stockEntry/StockEntryServiceImpl.java b/src/main/java/com/iemr/inventory/service/stockEntry/StockEntryServiceImpl.java index 5e13dc91..ae5247ad 100644 --- a/src/main/java/com/iemr/inventory/service/stockEntry/StockEntryServiceImpl.java +++ b/src/main/java/com/iemr/inventory/service/stockEntry/StockEntryServiceImpl.java @@ -148,22 +148,13 @@ public List getItemStockFromItemID(Integer facilityID, List allocateItemMapList = new ArrayList(); - + logger.info("ItemStockExitList Size:" + itemStockExitList.size()); for (ItemStockExit itemStockExit : itemStockExitList) { AllocateItemMap allocateItemMap = new AllocateItemMap(); List itemStockList = new ArrayList(); ItemMaster item = itemService.getItemMasterCatByID(itemStockExit.getItemID()); - -System.out.println("Test Item: " + item.toString()); -System.out.println("Test item category: "+ item.getItemCategory()); -System.out.println("Test item issuetype: "+ item.getItemCategory().getIssueType()); -System.out.println("Test facilityID: "+ item.getFacilityID()); -System.out.println("Test itemStockExit: "+ itemStockExit.toString()); -System.out.println("Test itemStockExit.getDuration(): "+ itemStockExit.getDuration()); - - allocateItemMap.setFacilityID(item.getFacilityID()); allocateItemMap.setItemID(item.getItemID()); allocateItemMap.setItemName(item.getItemName()); diff --git a/src/main/java/com/iemr/inventory/utils/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/inventory/utils/JwtUserIdValidationFilter.java index 9e0dfca5..6f37aa8b 100644 --- a/src/main/java/com/iemr/inventory/utils/JwtUserIdValidationFilter.java +++ b/src/main/java/com/iemr/inventory/utils/JwtUserIdValidationFilter.java @@ -38,27 +38,56 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo String origin = request.getHeader("Origin"); + String method = request.getMethod(); + String uri = request.getRequestURI(); + logger.debug("Incoming Origin: {}", origin); + logger.debug("Request Method: {}", method); + logger.debug("Request URI: {}", uri); logger.debug("Allowed Origins Configured: {}", allowedOrigins); - if (origin != null && isOriginAllowed(origin)) { - response.setHeader("Access-Control-Allow-Origin", origin); - response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); - response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, Jwttoken"); - response.setHeader("Vary", "Origin"); - response.setHeader("Access-Control-Allow-Credentials", "true"); + if ("OPTIONS".equalsIgnoreCase(method)) { + if (origin == null) { + logger.warn("BLOCKED - OPTIONS request without Origin header | Method: {} | URI: {}", method, uri); + response.sendError(HttpServletResponse.SC_FORBIDDEN, "OPTIONS request requires Origin header"); + return; + } + if (!isOriginAllowed(origin)) { + logger.warn("BLOCKED - Unauthorized Origin | Origin: {} | Method: {} | URI: {}", origin, method, uri); + response.sendError(HttpServletResponse.SC_FORBIDDEN, "Origin not allowed"); + return; + } } else { - logger.warn("Origin [{}] is NOT allowed. CORS headers NOT added.", origin); - } - - if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { - logger.info("OPTIONS request - skipping JWT validation"); - response.setStatus(HttpServletResponse.SC_OK); - return; + // For non-OPTIONS requests, validate origin if present + if (origin != null && !isOriginAllowed(origin)) { + logger.warn("BLOCKED - Unauthorized Origin | Origin: {} | Method: {} | URI: {}", origin, method, uri); + response.sendError(HttpServletResponse.SC_FORBIDDEN, "Origin not allowed"); + return; + } } String path = request.getRequestURI(); String contextPath = request.getContextPath(); + + // Set CORS headers and handle OPTIONS request only if origin is valid and + // allowed + if (origin != null && isOriginAllowed(origin)) { + addCorsHeaders(response, origin); + logger.info("Origin Validated | Origin: {} | Method: {} | URI: {}", origin, method, uri); + + if ("OPTIONS".equalsIgnoreCase(method)) { + // OPTIONS (preflight) - respond with full allowed methods + response.setStatus(HttpServletResponse.SC_OK); + return; + } + } else { + logger.warn("Origin [{}] is NOT allowed. CORS headers NOT added.", origin); + + if ("OPTIONS".equalsIgnoreCase(method)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "Origin not allowed for OPTIONS request"); + return; + } + } logger.info("JwtUserIdValidationFilter invoked for path: " + path); // Log cookies for debugging @@ -145,8 +174,7 @@ private boolean isOriginAllowed(String origin) { .anyMatch(pattern -> { String regex = pattern .replace(".", "\\.") - .replace("*", ".*") - .replace("http://localhost:.*", "http://localhost:\\d+"); // special case for wildcard port + .replace("*", ".*"); boolean matched = origin.matches(regex); return matched; @@ -180,4 +208,13 @@ private void clearUserIdCookie(HttpServletResponse response) { cookie.setMaxAge(0); // Invalidate the cookie response.addCookie(cookie); } + + private void addCorsHeaders(HttpServletResponse response, String origin) { + response.setHeader("Access-Control-Allow-Origin", origin); // Never use wildcard + response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS"); + response.setHeader("Access-Control-Allow-Headers", + "Authorization, Content-Type, Accept, Jwttoken, serverAuthorization, ServerAuthorization, serverauthorization, Serverauthorization"); + response.setHeader("Access-Control-Allow-Credentials", "true"); + response.setHeader("Access-Control-Max-Age", "3600"); + } } diff --git a/src/main/java/com/iemr/inventory/utils/http/HTTPRequestInterceptor.java b/src/main/java/com/iemr/inventory/utils/http/HTTPRequestInterceptor.java index 52e93eee..042539e4 100644 --- a/src/main/java/com/iemr/inventory/utils/http/HTTPRequestInterceptor.java +++ b/src/main/java/com/iemr/inventory/utils/http/HTTPRequestInterceptor.java @@ -24,6 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; @@ -36,11 +37,16 @@ import jakarta.ws.rs.core.MediaType; import java.io.OutputStream; import java.io.PrintStream; +import java.util.Arrays; @Component public class HTTPRequestInterceptor implements HandlerInterceptor { Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Value("${cors.allowed-origins}") + private String allowedOrigins; + @Autowired private RedisStorage redisStorage; @@ -105,7 +111,13 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons response.setContentType(MediaType.APPLICATION_JSON); - response.setHeader("Access-Control-Allow-Origin", "*"); + String origin = request.getHeader("Origin"); + if (origin != null && isOriginAllowed(origin)) { + response.setHeader("Access-Control-Allow-Origin", origin); + response.setHeader("Access-Control-Allow-Credentials", "true"); + } else if (origin != null) { + logger.warn("CORS headers NOT added for error response | Unauthorized origin: {}", origin); + } status = false; } } @@ -144,4 +156,19 @@ public void afterCompletion(HttpServletRequest request, HttpServletResponse resp } + private boolean isOriginAllowed(String origin) { + if (origin == null || allowedOrigins == null || allowedOrigins.trim().isEmpty()) { + return false; + } + + return Arrays.stream(allowedOrigins.split(",")) + .map(String::trim) + .anyMatch(pattern -> { + String regex = pattern + .replace(".", "\\.") + .replace("*", ".*"); + return origin.matches(regex); + }); + } + }