diff --git a/pom.xml b/pom.xml
index 62593f28..11ad9f37 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.iemr.common-API
common-api
- 3.4.0
+ 3.6.0
war
Common-API
@@ -111,6 +111,12 @@
+
+
+ com.google.firebase
+ firebase-admin
+ 9.4.3
+
org.springframework.boot
spring-boot-starter-data-jpa
@@ -257,7 +263,7 @@
logback-core
test
-
+
org.springdoc
springdoc-openapi-starter-webmvc-ui
diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties
index a5e66660..0184b32f 100644
--- a/src/main/environment/common_ci.properties
+++ b/src/main/environment/common_ci.properties
@@ -32,6 +32,7 @@ identity-1097-api-url = @env.IDENTITY_1097_API_URL@
send-sms=@env.SEND_SMS@
sendSMSUrl = @env.SEND_SMS_URL@
source-address=@env.SMS_SOURCE_ADDRESS@
+sms-consent-source-address = @env.SMS_CONSENT_SOURCE_ADDRESS@
sms-username=@env.SMS_USERNAME@
sms-password=@env.SMS_PASSWORD@
send-message-url=@env.SMS_MESSAGE_URL@
@@ -40,6 +41,11 @@ send-message-url=@env.SMS_MESSAGE_URL@
start-sms-scheduler=true
cron-scheduler-sms=0 0/1 * * * ? *
+# Firebase Configuration
+firebase.enabled=@env.FIREBASE_ENABLE@
+# if using file
+firebase.credential-file=@env.FIREBASE_CREDENTIAL@
+
#### Email Configuration
send-email=@env.SEND_EMAIL@
spring.mail.host=@env.MAIL_HOST@
@@ -167,8 +173,8 @@ grievancePassword = @env.GRIEVANCE_PASSWORD@
grievanceUserAuthenticate = @env.GRIEVANCE_USER_AUTHENTICATE@
grievanceDataSyncDuration = @env.GRIEVANCE_DATA_SYNC_DURATION@
-springdoc.api-docs.enabled=false
-springdoc.swagger-ui.enabled=false
+springdoc.api-docs.enabled=@env.SWAGGER_DOC_ENABLED@
+springdoc.swagger-ui.enabled=@env.SWAGGER_DOC_ENABLED@
isProduction=@env.IS_PRODUCTION@
@@ -185,4 +191,16 @@ cors.allowed-origins=@env.CORS_ALLOWED_ORIGINS@
video-call-url=@env.VIDEO_CALL_URL@
jibri.output.path=@env.JIBRI_OUTPUT_PATH@
-video.recording.path=@env.VIDEO_RECORDING_PATH@
\ No newline at end of file
+video.recording.path=@env.VIDEO_RECORDING_PATH@
+
+platform.feedback.ratelimit.enabled=@env.PLATFORM_FEEDBACK_RATELIMIT_ENABLED@
+platform.feedback.ratelimit.pepper=@env.PLATFORM_FEEDBACK_RATELIMIT_PEPPER@
+platform.feedback.ratelimit.trust-forwarded-for=@env.PLATFORM_FEEDBACK_RATELIMIT_TRUST_FORWARDED_FOR@
+platform.feedback.ratelimit.forwarded-for-header=@env.PLATFORM_FEEDBACK_RATELIMIT_FORWARDED_FOR_HEADER@
+platform.feedback.ratelimit.minute-limit=@env.PLATFORM_FEEDBACK_RATELIMIT_MINUTE_LIMIT@
+platform.feedback.ratelimit.day-limit=@env.PLATFORM_FEEDBACK_RATELIMIT_DAY_LIMIT@
+platform.feedback.ratelimit.user-day-limit=@env.PLATFORM_FEEDBACK_RATELIMIT_USER_DAY_LIMIT@
+platform.feedback.ratelimit.fail-window-minutes=@env.PLATFORM_FEEDBACK_RATELIMIT_FAIL_WINDOW_MINUTES@
+platform.feedback.ratelimit.backoff-minutes=@env.PLATFORM_FEEDBACK_RATELIMIT_BACKOFF_MINUTES@
+generateBeneficiaryIDs-api-url=@env.GEN_BENEFICIARY_IDS_API_URL@
+
diff --git a/src/main/environment/common_docker.properties b/src/main/environment/common_docker.properties
index 41881886..a81ea62e 100644
--- a/src/main/environment/common_docker.properties
+++ b/src/main/environment/common_docker.properties
@@ -32,6 +32,7 @@ identity-1097-api-url = ${IDENTITY_1097_API_URL}
send-sms=${SEND_SMS}
sendSMSUrl = ${SEND_SMS_URL}
source-address=${SMS_SOURCE_ADDRESS}
+sms-consent-source-address=${SMS_CONSENT_SOURCE_ADDRESS}
sms-username=${SMS_USERNAME}
sms-password=${SMS_PASSWORD}
send-message-url=${SMS_MESSAGE_URL}
@@ -169,8 +170,8 @@ grievancePassword = ${GRIEVANCE_PASSWORD}
grievanceUserAuthenticate = ${GRIEVANCE_USER_AUTHENTICATE}
grievanceDataSyncDuration = ${GRIEVANCE_DATA_SYNC_DURATION}
-springdoc.api-docs.enabled=false
-springdoc.swagger-ui.enabled=false
+springdoc.api-docs.enabled=${SWAGGER_DOC_ENABLED}
+springdoc.swagger-ui.enabled=${SWAGGER_DOC_ENABLED}
isProduction=${IS_PRODUCTION}
@@ -185,6 +186,24 @@ captcha.enable-captcha=${ENABLE_CAPTCHA}
cors.allowed-origins=${CORS_ALLOWED_ORIGINS}
+# # Firebase Configuration
+firebase.enabled=${FIREBASE_ENABLE}
+# # if using file
+firebase.credential-file=${FIREBASE_CREDENTIAL}
+
+
video-call-url=${VIDEO_CALL_URL}
jibri.output.path={JIBRI_OUTPUT_PATH}
-video.recording.path={VIDEO_RECORDING_PATH}
\ No newline at end of file
+video.recording.path={VIDEO_RECORDING_PATH}
+
+# Platform Feedback module
+platform.feedback.ratelimit.enabled=${PLATFORM_FEEDBACK_RATELIMIT_ENABLED}
+platform.feedback.ratelimit.pepper=${PLATFORM_FEEDBACK_RATELIMIT_PEPPER}
+platform.feedback.ratelimit.trust-forwarded-for=${PLATFORM_FEEDBACK_RATELIMIT_TRUST_FORWARDED_FOR}
+platform.feedback.ratelimit.forwarded-for-header=${PLATFORM_FEEDBACK_RATELIMIT_FORWARDED_FOR_HEADER}
+platform.feedback.ratelimit.minute-limit=${PLATFORM_FEEDBACK_RATELIMIT_MINUTE_LIMIT}
+platform.feedback.ratelimit.day-limit=${PLATFORM_FEEDBACK_RATELIMIT_DAY_LIMIT}
+platform.feedback.ratelimit.user-day-limit=${PLATFORM_FEEDBACK_RATELIMIT_USER_DAY_LIMIT}
+platform.feedback.ratelimit.fail-window-minutes=${PLATFORM_FEEDBACK_RATELIMIT_FAIL_WINDOW_MINUTES}
+platform.feedback.ratelimit.backoff-minutes=${PLATFORM_FEEDBACK_RATELIMIT_BACKOFF_MINUTES}
+generateBeneficiaryIDs-api-url={GEN_BENEFICIARY_IDS_API_URL}
diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties
index 09a526dd..aca73ddb 100644
--- a/src/main/environment/common_example.properties
+++ b/src/main/environment/common_example.properties
@@ -208,3 +208,21 @@ captcha.enable-captcha=true
cors.allowed-origins=http://localhost:*
+# ---Platform Feedback module ---
+# Rate limiter OFF locally (no Redis required)
+platform.feedback.ratelimit.enabled=true
+platform.feedback.ratelimit.pepper=dev-pepper-123 # dummy
+
+# trust forwarded-for locally is harmless (localhost only)
+platform.feedback.ratelimit.trust-forwarded-for=false
+platform.feedback.ratelimit.forwarded-for-header=X-Forwarded-For
+
+# Optional overrides (not needed if disabled)
+platform.feedback.ratelimit.minute-limit=10
+platform.feedback.ratelimit.day-limit=100
+platform.feedback.ratelimit.user-day-limit=50
+platform.feedback.ratelimit.fail-window-minutes=5
+platform.feedback.ratelimit.backoff-minutes=15
+
+### generate Beneficiary IDs URL
+generateBeneficiaryIDs-api-url=/generateBeneficiaryController/generateBeneficiaryIDs
diff --git a/src/main/java/com/iemr/common/CommonApplication.java b/src/main/java/com/iemr/common/CommonApplication.java
index b9b797b2..e4a59994 100644
--- a/src/main/java/com/iemr/common/CommonApplication.java
+++ b/src/main/java/com/iemr/common/CommonApplication.java
@@ -29,7 +29,6 @@
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 org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.client.RestTemplate;
diff --git a/src/main/java/com/iemr/common/config/CorsConfig.java b/src/main/java/com/iemr/common/config/CorsConfig.java
index 2e226b79..fdd9b494 100644
--- a/src/main/java/com/iemr/common/config/CorsConfig.java
+++ b/src/main/java/com/iemr/common/config/CorsConfig.java
@@ -11,7 +11,6 @@ public class CorsConfig implements WebMvcConfigurer {
@Value("${cors.allowed-origins}")
private String allowedOrigins;
-
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
@@ -19,8 +18,9 @@ public void addCorsMappings(CorsRegistry registry) {
Arrays.stream(allowedOrigins.split(","))
.map(String::trim)
.toArray(String[]::new))
- .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
- .allowedHeaders("*")
+ .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
+ .allowedHeaders("Authorization", "Content-Type", "Accept", "Jwttoken",
+ "serverAuthorization", "ServerAuthorization", "serverauthorization", "Serverauthorization")
.exposedHeaders("Authorization", "Jwttoken")
.allowCredentials(true)
.maxAge(3600);
diff --git a/src/main/java/com/iemr/common/config/RedisConfig.java b/src/main/java/com/iemr/common/config/RedisConfig.java
index e812b3f9..796ad557 100644
--- a/src/main/java/com/iemr/common/config/RedisConfig.java
+++ b/src/main/java/com/iemr/common/config/RedisConfig.java
@@ -33,6 +33,7 @@
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.iemr.common.data.users.User;
+import org.springframework.data.redis.core.StringRedisTemplate;
@Configuration
public class RedisConfig {
@@ -57,4 +58,10 @@ public RedisTemplate redisTemplate(RedisConnectionFactory factor
return template;
}
+ // new bean for rate limiting & counters
+ @Bean
+ public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
+ return new StringRedisTemplate(factory);
+ }
+
}
diff --git a/src/main/java/com/iemr/common/config/firebase/FirebaseMessagingConfig.java b/src/main/java/com/iemr/common/config/firebase/FirebaseMessagingConfig.java
new file mode 100644
index 00000000..ebb697ec
--- /dev/null
+++ b/src/main/java/com/iemr/common/config/firebase/FirebaseMessagingConfig.java
@@ -0,0 +1,65 @@
+package com.iemr.common.config.firebase;
+
+import com.google.auth.oauth2.GoogleCredentials;
+import com.google.firebase.FirebaseApp;
+import com.google.firebase.FirebaseOptions;
+import com.google.firebase.messaging.FirebaseMessaging;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Base64;
+
+@Configuration
+public class FirebaseMessagingConfig {
+ private Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
+
+ @Value("${firebase.enabled:false}")
+ private boolean firebaseEnabled;
+
+ @Value("${firebase.credential-file:}")
+ private String firebaseCredentialFile;
+
+
+ @Bean
+ @ConditionalOnProperty(name = "firebase.enabled", havingValue = "true")
+ public FirebaseMessaging firebaseMessaging() throws IOException {
+ if (!firebaseEnabled) {
+ logger.error("⚠️ Firebase disabled by config");
+ return null;
+ }
+
+ try {
+ if (firebaseCredentialFile == null || firebaseCredentialFile.isBlank()) {
+ logger.error("⚠️ No Firebase credentials path provided");
+ return null; // don't throw, app will still start
+ }
+
+ GoogleCredentials credentials = GoogleCredentials.fromStream(
+ new ClassPathResource(firebaseCredentialFile).getInputStream()
+ );
+ FirebaseOptions options = FirebaseOptions.builder()
+ .setCredentials(credentials)
+ .build();
+
+ FirebaseApp firebaseApp = FirebaseApp.getApps().isEmpty()
+ ? FirebaseApp.initializeApp(options)
+ : FirebaseApp.getInstance();
+
+ return FirebaseMessaging.getInstance(firebaseApp);
+
+ } catch (Exception e) {
+ logger.error("⚠️ Firebase init failed: " + e.getMessage());
+ return null; // keep app running
+ }
+
+ }
+
+}
diff --git a/src/main/java/com/iemr/common/config/quartz/ScheduleForGrievanceDataSync.java b/src/main/java/com/iemr/common/config/quartz/ScheduleForGrievanceDataSync.java
index f016de3d..314b31ac 100644
--- a/src/main/java/com/iemr/common/config/quartz/ScheduleForGrievanceDataSync.java
+++ b/src/main/java/com/iemr/common/config/quartz/ScheduleForGrievanceDataSync.java
@@ -37,3 +37,4 @@ public void execute() {
}
}
+
diff --git a/src/main/java/com/iemr/common/controller/beneficiary/BeneficiaryRegistrationController.java b/src/main/java/com/iemr/common/controller/beneficiary/BeneficiaryRegistrationController.java
index d9b0f06f..8f573d6d 100644
--- a/src/main/java/com/iemr/common/controller/beneficiary/BeneficiaryRegistrationController.java
+++ b/src/main/java/com/iemr/common/controller/beneficiary/BeneficiaryRegistrationController.java
@@ -103,6 +103,7 @@ public class BeneficiaryRegistrationController {
private BeneficiaryOccupationService beneficiaryOccupationService;
private GovtIdentityTypeService govtIdentityTypeService;
+
@Autowired
public void setBenRelationshipTypeService(BenRelationshipTypeService benRelationshipTypeService) {
this.benRelationshipTypeService = benRelationshipTypeService;
diff --git a/src/main/java/com/iemr/common/controller/beneficiaryConsent/BeneficiaryConsentController.java b/src/main/java/com/iemr/common/controller/beneficiaryConsent/BeneficiaryConsentController.java
new file mode 100644
index 00000000..77492d89
--- /dev/null
+++ b/src/main/java/com/iemr/common/controller/beneficiaryConsent/BeneficiaryConsentController.java
@@ -0,0 +1,118 @@
+/*
+ * AMRIT – Accessible Medical Records via Integrated Technology
+ * 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.common.controller.beneficiaryConsent;
+
+import com.iemr.common.data.beneficiaryConsent.BeneficiaryConsentRequest;
+import com.iemr.common.service.beneficiaryOTPHandler.BeneficiaryOTPHandler;
+import com.iemr.common.utils.mapper.InputMapper;
+import com.iemr.common.utils.response.OutputResponse;
+import io.lettuce.core.dynamic.annotation.Param;
+import io.swagger.v3.oas.annotations.Operation;
+import jakarta.ws.rs.core.MediaType;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+@RequestMapping(value = { "/beneficiaryConsent" })
+@RestController
+public class BeneficiaryConsentController {
+ final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
+
+ @Autowired
+ private BeneficiaryOTPHandler beneficiaryOTPHandler;
+
+ @Operation(summary = "Send Consent")
+ @RequestMapping(value = "/sendConsent", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)
+ public String sendConsent(@Param(value = "{\"mobNo\":\"String\"}") @RequestBody String requestOBJ) {
+
+ OutputResponse response = new OutputResponse();
+
+ try {
+ BeneficiaryConsentRequest obj = InputMapper.gson().fromJson(requestOBJ, BeneficiaryConsentRequest.class);
+
+ String success = beneficiaryOTPHandler.sendOTP(obj); // method name unchanged if internal logic still uses 'OTP'
+ logger.info(success.toString());
+ response.setResponse(success);
+
+
+ } catch (Exception e) {
+ response.setError(500, "error : " + e);
+ }
+ return response.toString();
+ }
+
+ @Operation(summary = "Validate Consent")
+ @RequestMapping(value = "/validateConsent", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)
+ public String validateConsent(@Param(value = "{\"mobNo\":\"String\",\"otp\":\"Integer\"}") @RequestBody String requestOBJ) {
+
+ OutputResponse response = new OutputResponse();
+
+ try {
+ BeneficiaryConsentRequest obj = InputMapper.gson().fromJson(requestOBJ, BeneficiaryConsentRequest.class);
+
+ JSONObject responseOBJ = beneficiaryOTPHandler.validateOTP(obj);
+ if (responseOBJ != null)
+ response.setResponse(responseOBJ.toString());
+ else
+ response.setError(500, "failure");
+
+ } catch (Exception e) {
+ logger.error("error in validating Consent : " + e);
+ response.setError(500, "error : " + e);
+ }
+ return response.toString();
+ }
+
+ @Operation(summary = "Resend Consent")
+ @RequestMapping(value = "/resendConsent", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)
+ public String resendConsent(@Param(value = "{\"mobNo\":\"String\"}") @RequestBody String requestOBJ) {
+ logger.info(requestOBJ.toString());
+
+ OutputResponse response = new OutputResponse();
+
+ try {
+ BeneficiaryConsentRequest obj = InputMapper.gson().fromJson(requestOBJ, BeneficiaryConsentRequest.class);
+
+ String success = beneficiaryOTPHandler.resendOTP(obj);
+ logger.info(success.toString());
+
+ if (success.contains("otp"))
+ response.setResponse(success);
+ else
+ response.setError(500, "failure");
+
+ } catch (Exception e) {
+ logger.error("error in re-sending Consent : " + e);
+ response.setError(500, "error : " + e);
+ }
+ return response.toString();
+ }
+
+
+}
+
+
diff --git a/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java b/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java
new file mode 100644
index 00000000..30a1bc3f
--- /dev/null
+++ b/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java
@@ -0,0 +1,100 @@
+package com.iemr.common.controller.dynamicForm;
+
+import com.iemr.common.dto.dynamicForm.FieldDTO;
+import com.iemr.common.dto.dynamicForm.FormDTO;
+import com.iemr.common.dto.dynamicForm.ModuleDTO;
+import com.iemr.common.service.dynamicForm.FormMasterService;
+import com.iemr.common.utils.response.ApiResponse;
+import jakarta.validation.Valid;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RequestMapping(value = "dynamicForm")
+@RestController
+public class DynamicFormController {
+ @Autowired
+ private FormMasterService formMasterService;
+
+ @PostMapping(value = "createModule")
+ public ResponseEntity> createModule(@Valid @RequestBody ModuleDTO moduleDTO) {
+ try {
+ Object result = formMasterService.createModule(moduleDTO);
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success("Module created successfully", HttpStatus.OK.value(), result));
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.error("Invalid module data: " + e.getMessage(), HttpStatus.BAD_REQUEST.value(), null));
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.error("Failed to create module", HttpStatus.INTERNAL_SERVER_ERROR.value(), null));
+ }
+ }
+
+ @PostMapping(value = "createForm")
+ public ResponseEntity> createForm(@Valid @RequestBody FormDTO dto) {
+ try {
+ Object result = formMasterService.createForm(dto);
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success("Form created successfully", HttpStatus.OK.value(), result));
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.error("Failed to create form", HttpStatus.INTERNAL_SERVER_ERROR.value(), null));
+ }
+ }
+
+ @PostMapping(value = "createFields")
+ public ResponseEntity> createField(@Valid @RequestBody List dto) {
+ try {
+ Object result = formMasterService.createField(dto);
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success("Fields created successfully", HttpStatus.OK.value(), result));
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.error("Failed to create fields", HttpStatus.INTERNAL_SERVER_ERROR.value(), null));
+ }
+ }
+
+ @PostMapping(value = "field/update",headers = "Authorization")
+ public ResponseEntity> updateField(@Valid @RequestBody FieldDTO dto) {
+ try {
+ Object result = formMasterService.updateField(dto);
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success("Field updated successfully", HttpStatus.OK.value(), result));
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.error("Failed to update field", HttpStatus.INTERNAL_SERVER_ERROR.value(), null));
+ }
+ }
+
+ @DeleteMapping(value = "delete/{fieldId}/field",headers = "Authorization")
+ public ResponseEntity> deleteField(@PathVariable Long fieldId) {
+ try {
+ formMasterService.deleteField(fieldId);
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success("Field deleted successfully", HttpStatus.OK.value(), null));
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.error("Failed to delete field", HttpStatus.INTERNAL_SERVER_ERROR.value(), null));
+ }
+ }
+
+ @GetMapping(value = "form/{formId}/fields")
+ public ResponseEntity> getStructuredForm(@PathVariable String formId, @RequestParam(name = "lang", defaultValue = "en") String lang) {
+ try {
+ Object result = formMasterService.getStructuredFormByFormId(formId,lang);
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success("Form structure fetched successfully", HttpStatus.OK.value(), result));
+ } catch (Exception e) {
+
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.error("Failed to fetch form structure:"+e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value(), e));
+ }
+ }
+
+
+}
diff --git a/src/main/java/com/iemr/common/controller/firebaseNotification/FirebaseNotificationController.java b/src/main/java/com/iemr/common/controller/firebaseNotification/FirebaseNotificationController.java
new file mode 100644
index 00000000..3bb10cfc
--- /dev/null
+++ b/src/main/java/com/iemr/common/controller/firebaseNotification/FirebaseNotificationController.java
@@ -0,0 +1,61 @@
+/*
+* AMRIT – Accessible Medical Records via Integrated Technology
+* 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/.
+*
+/*
+* AMRIT – Accessible Medical Records via Integrated Technology
+*/
+package com.iemr.common.controller.firebaseNotification;
+
+import com.iemr.common.model.notification.NotificationMessage;
+import com.iemr.common.model.notification.UserToken;
+import com.iemr.common.service.firebaseNotification.FirebaseNotificationService;
+import com.iemr.common.utils.exception.IEMRException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping(value= "/firebaseNotification",headers = "Authorization")
+public class FirebaseNotificationController {
+ final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
+
+ @Autowired
+ FirebaseNotificationService firebaseNotificationService;
+
+ @RequestMapping(value = "sendNotification",method = RequestMethod.POST,headers = "Authorization")
+ public String sendNotificationByToken(@RequestBody NotificationMessage notificationMessage){
+ return firebaseNotificationService.sendNotification(notificationMessage);
+ }
+
+ @RequestMapping(value = "updateToken",method = RequestMethod.POST,headers = "Authorization")
+ public String updateToken(@RequestBody UserToken userToken){
+ return firebaseNotificationService.updateToken(userToken);
+ }
+
+ @RequestMapping(value = "getToken",method = RequestMethod.GET,headers = "Authorization")
+ public String getUserToken() throws IEMRException {
+
+ return firebaseNotificationService.getUserToken();
+ }
+
+
+}
diff --git a/src/main/java/com/iemr/common/controller/nhmdashboard/NHMDetailCallReportScheduler.java b/src/main/java/com/iemr/common/controller/nhmdashboard/NHMDetailCallReportScheduler.java
index 5fd3e281..d02eb3f2 100644
--- a/src/main/java/com/iemr/common/controller/nhmdashboard/NHMDetailCallReportScheduler.java
+++ b/src/main/java/com/iemr/common/controller/nhmdashboard/NHMDetailCallReportScheduler.java
@@ -181,3 +181,4 @@ private BeneficiaryCall getCallDetail(DetailedCallReport detailedCallReport) {
}
}
+
diff --git a/src/main/java/com/iemr/common/controller/platform_feedback/PlatformFeedbackController.java b/src/main/java/com/iemr/common/controller/platform_feedback/PlatformFeedbackController.java
new file mode 100644
index 00000000..556561cf
--- /dev/null
+++ b/src/main/java/com/iemr/common/controller/platform_feedback/PlatformFeedbackController.java
@@ -0,0 +1,76 @@
+/*
+ * AMRIT – Accessible Medical Records via Integrated Technology
+ * 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.common.controller.platform_feedback;
+
+import com.iemr.common.dto.platform_feedback.CategoryResponse;
+import com.iemr.common.dto.platform_feedback.FeedbackRequest;
+import com.iemr.common.dto.platform_feedback.FeedbackResponse;
+import com.iemr.common.service.platform_feedback.PlatformFeedbackService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.media.Content;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.annotation.Validated;
+import jakarta.validation.Valid;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@Tag(name = "Platform Feedback", description = "Feedback ingestion and category listing for platform-wide feedback")
+@RestController
+@RequestMapping("/platform-feedback")
+@Validated
+public class PlatformFeedbackController {
+
+ private final PlatformFeedbackService service;
+
+ public PlatformFeedbackController(PlatformFeedbackService service) {
+ this.service = service;
+ }
+
+ @Operation(summary = "Submit feedback (public endpoint)",
+ description = "Accepts feedback (anonymous or identified). Accepts categoryId or categorySlug; slug is preferred.")
+ @ApiResponse(responseCode = "201", description = "Feedback accepted")
+ @ApiResponse(responseCode = "400", description = "Validation or business error", content = @Content)
+ @PostMapping
+ public ResponseEntity submit(
+ @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "Feedback payload")
+ @Valid @RequestBody FeedbackRequest req) {
+ FeedbackResponse resp = service.submitFeedback(req);
+ return ResponseEntity.status(HttpStatus.CREATED).body(resp);
+ }
+
+ @Operation(summary = "List active categories",
+ description = "Returns active categories. Optionally filter by serviceLine (frontend convenience).")
+ @ApiResponse(responseCode = "200", description = "List of categories")
+ @GetMapping("/categories")
+ public ResponseEntity> list(
+ @Parameter(description = "Optional serviceLine to prefer scopes (1097|104|AAM|MMU|TM|ECD)")
+ @RequestParam(required = false) String serviceLine) {
+ if (serviceLine == null) serviceLine = "GLOBAL";
+ List list = service.listCategories(serviceLine);
+ return ResponseEntity.ok(list);
+ }
+}
diff --git a/src/main/java/com/iemr/common/controller/sms/SMSController.java b/src/main/java/com/iemr/common/controller/sms/SMSController.java
index ee985947..9bacf5b1 100644
--- a/src/main/java/com/iemr/common/controller/sms/SMSController.java
+++ b/src/main/java/com/iemr/common/controller/sms/SMSController.java
@@ -24,6 +24,7 @@
import java.util.Arrays;
import javax.ws.rs.core.MediaType;
+import jakarta.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -101,7 +102,7 @@ public String getFullSMSTemplate(
@Operation(summary = "Save SMS template")
@PostMapping(value = "/saveSMSTemplate", produces = MediaType.APPLICATION_JSON, headers = "Authorization")
public String saveSMSTemplate(
- @Param(value = "\"{\\\"createdBy\\\":\\\"String\\\",\\\"providerServiceMapID\\\":\\\"String\\\",\\\"smsParameterMaps\\\":\\\"String\\\",\\\"smsTemplate\\\":\\\"String\\\",\\\"smsTemplateName\\\":\\\"String\\\",\\\"smsTypeID\\\":\\\"Integer\\\"}\"") @RequestBody CreateSMSRequest request,
+ @Param(value = "\"{\\\"createdBy\\\":\\\"String\\\",\\\"providerServiceMapID\\\":\\\"String\\\",\\\"smsParameterMaps\\\":\\\"String\\\",\\\"smsTemplate\\\":\\\"String\\\",\\\"smsTemplateName\\\":\\\"String\\\",\\\"smsTypeID\\\":\\\"Integer\\\"}\"") @Valid @RequestBody CreateSMSRequest request,
HttpServletRequest serverRequest) {
OutputResponse response = new OutputResponse();
logger.info("saveSMSTemplate received request");
diff --git a/src/main/java/com/iemr/common/controller/users/EmployeeSignatureController.java b/src/main/java/com/iemr/common/controller/users/EmployeeSignatureController.java
index a2156af1..e29d3220 100644
--- a/src/main/java/com/iemr/common/controller/users/EmployeeSignatureController.java
+++ b/src/main/java/com/iemr/common/controller/users/EmployeeSignatureController.java
@@ -21,22 +21,28 @@
*/
package com.iemr.common.controller.users;
+import java.nio.charset.StandardCharsets;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
+import org.springframework.http.CacheControl;
+import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.InvalidMediaTypeException;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.server.ResponseStatusException;
import com.google.gson.Gson;
import com.iemr.common.data.users.EmployeeSignature;
import com.iemr.common.service.users.EmployeeSignatureServiceImpl;
-import com.iemr.common.utils.mapper.InputMapper;
import com.iemr.common.utils.response.OutputResponse;
import io.swagger.v3.oas.annotations.Operation;
@@ -51,29 +57,50 @@ public class EmployeeSignatureController {
@Autowired
EmployeeSignatureServiceImpl employeeSignatureServiceImpl;
- private InputMapper inputMapper = new InputMapper();
-
private Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
@Operation(summary = "Fetch file")
@RequestMapping(value = "/{userID}", headers = "Authorization", method = { RequestMethod.GET })
public ResponseEntity fetchFile(@PathVariable("userID") Long userID) throws Exception {
- OutputResponse response = new OutputResponse();
logger.debug("File download for userID" + userID);
try {
-
- EmployeeSignature userSignID = employeeSignatureServiceImpl.fetchSignature(userID);
- return ResponseEntity.ok().contentType(MediaType.parseMediaType(userSignID.getFileType()))
- .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + userSignID.getFileName() + "\"")
- .body(userSignID.getSignature());
+ EmployeeSignature userSignID = employeeSignatureServiceImpl.fetchActiveSignature(userID);
+
+ if (userSignID == null) {
+ throw new ResponseStatusException(HttpStatus.NOT_FOUND,
+ "Active signature not found for userID: " + userID);
+ }
+ String originalName = userSignID.getFileName();
+ if (originalName == null || originalName.isBlank()) {
+ originalName = "signature";
+ }
+ HttpHeaders responseHeaders = new HttpHeaders();
+ responseHeaders.setContentDisposition(
+ ContentDisposition.attachment().filename(originalName, StandardCharsets.UTF_8).build());
+ responseHeaders.setCacheControl(CacheControl.noStore());
+ responseHeaders.add(HttpHeaders.PRAGMA, "no-cache");
+ responseHeaders.setExpires(0);
+ MediaType mediaType;
+ try {
+ mediaType = MediaType.parseMediaType(userSignID.getFileType());
+ } catch (InvalidMediaTypeException | NullPointerException e) {
+ mediaType = MediaType.APPLICATION_OCTET_STREAM;
+ }
+
+ byte[] fileBytes = userSignID.getSignature(); // MUST be byte[]
+ if (fileBytes == null || fileBytes.length == 0) {
+ throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Signature not found for userID: " + userID);
+ }
+
+ return ResponseEntity.ok().headers(responseHeaders).contentType(mediaType).contentLength(fileBytes.length)
+ .body(fileBytes);
} catch (Exception e) {
logger.error("File download for userID failed with exception " + e.getMessage(), e);
+ throw new Exception("Error while downloading file. Please contact administrator..");
}
- return ResponseEntity.badRequest().body(new byte[] {});
-
}
@Operation(summary = "Fetch file from central")
diff --git a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java
index 28c7e4b9..8bc0e74d 100644
--- a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java
+++ b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java
@@ -1,8 +1,8 @@
/*
-* AMRIT – Accessible Medical Records via Integrated Technology
-* Integrated EHR (Electronic Health Records) Solution
+* AMRIT – Accessible Medical Records via Integrated Technology
+* Integrated EHR (Electronic Health Records) Solution
*
-* Copyright (C) "Piramal Swasthya Management and Research Institute"
+* Copyright (C) "Piramal Swasthya Management and Research Institute"
*
* This file is part of AMRIT.
*
@@ -80,8 +80,8 @@ public class IEMRAdminController {
private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
private InputMapper inputMapper = new InputMapper();
- @Value("${captcha.enable-captcha}")
- private boolean enableCaptcha;
+// @Value("${captcha.enable-captcha}")
+ private boolean enableCaptcha =false;
@Autowired
private CaptchaValidationService captchaValidatorService;
@@ -170,8 +170,8 @@ public String userAuthenticate(
JSONObject serviceRoleMap = new JSONObject();
JSONArray serviceRoleList = new JSONArray();
JSONObject previlegeObj = new JSONObject();
- if (m_User.getUserName() != null
- && (m_User.getDoLogout() == null || !m_User.getDoLogout())
+ if (m_User.getUserName() != null
+ && (m_User.getDoLogout() == null || !m_User.getDoLogout())
&& (m_User.getWithCredentials() != null && m_User.getWithCredentials())) {
String tokenFromRedis = getConcurrentCheckSessionObjectAgainstUser(
m_User.getUserName().trim().toLowerCase());
@@ -187,7 +187,7 @@ public String userAuthenticate(
String refreshToken = null;
if (mUser.size() == 1) {
jwtToken = jwtUtil.generateToken(m_User.getUserName(), mUser.get(0).getUserID().toString());
-
+
User user = new User(); // Assuming the Users class exists
user.setUserID(mUser.get(0).getUserID());
user.setUserName(mUser.get(0).getUserName());
@@ -278,15 +278,16 @@ public ResponseEntity> refreshToken(@RequestBody Map request)
// Get user details
String userId = claims.get("userId", String.class);
User user = iemrAdminUserServiceImpl.getUserById(Long.parseLong(userId));
-
+
// Validate that the user still exists and is active
if (user == null) {
logger.warn("Token validation failed: user not found for userId in token.");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized.");
}
-
- if (user.getM_status() == null || !"Active".equalsIgnoreCase(user.getM_status().getStatus())) {
- logger.warn("Token validation failed: user account is inactive or not in 'Active' status.");
+
+ if (user.getM_status() == null || !("Active".equalsIgnoreCase(user.getM_status().getStatus())
+ || "New".equalsIgnoreCase(user.getM_status().getStatus()))) {
+ logger.warn("Token validation failed: user account is neither 'Active' nor 'New'.");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized.");
}
// Generate new tokens
@@ -294,7 +295,7 @@ public ResponseEntity> refreshToken(@RequestBody Map request)
Map tokens = new HashMap<>();
tokens.put("jwtToken", newJwt);
-
+
// Generate and store a new refresh token (token rotation)
String newRefreshToken = jwtUtil.generateRefreshToken(user.getUserName(), userId);
String newJti = jwtUtil.getJtiFromToken(newRefreshToken);
@@ -343,9 +344,10 @@ public String logOutUserFromConcurrentSession(
deleteSessionObjectByGettingSessionDetails(previousTokenFromRedis);
sessionObject.deleteSessionObject(previousTokenFromRedis);
response.setResponse("User successfully logged out");
- } else
+ } else{
logger.error("Unable to fetch session from redis");
throw new IEMRException("Session error. Please try again later");
+ }
}
} else {
throw new IEMRException("Invalid request object");
@@ -360,7 +362,7 @@ public String logOutUserFromConcurrentSession(
}
/**
- *
+ *
* function to return session object against userName
*/
private String getConcurrentCheckSessionObjectAgainstUser(String userName) {
@@ -390,6 +392,7 @@ private void createUserMapping(User mUser, JSONObject resMap, JSONObject service
resMap.put("agentPassword", mUser.getAgentPassword());
resMap.put("m_UserLangMappings", new JSONArray(mUser.getM_UserLangMappings().toString()));
resMap.put("designationID", mUser.getDesignationID());
+ resMap.put("dhistoken",mUser.getDhistoken());
if (mUser.getDesignation() != null) {
resMap.put("designation", new JSONObject(mUser.getDesignation().toString()));
}
@@ -466,7 +469,7 @@ public String superUserAuthenticate(
resMap.put("isAuthenticated", /* Boolean.valueOf(true) */true);
resMap.put("userName", mUser.getUserName());
jwtToken = jwtUtil.generateToken(m_User.getUserName(), mUser.getUserID().toString());
-
+
User user = new User(); // Assuming the Users class exists
user.setUserID(mUser.getUserID());
user.setUserName(mUser.getUserName());
@@ -561,7 +564,7 @@ public String getLoginResponse(HttpServletRequest request) {
if (authHeader.isEmpty()) {
// Try JWT token from header first
String jwtToken = request.getHeader("Jwttoken");
-
+
// If not in header, try cookie
if (jwtToken == null) {
Cookie[] cookies = request.getCookies();
@@ -574,15 +577,15 @@ public String getLoginResponse(HttpServletRequest request) {
}
}
}
-
+
if (jwtToken == null) {
logger.warn("Authentication failed: no token found in header or cookies.");
throw new IEMRException("Authentication failed. Please log in again.");
}
-
+
// Extract user ID from the JWT token
String userId = jwtUtil.getUserIdFromToken(jwtToken);
-
+
// Get user details and prepare response
User user = iemrAdminUserServiceImpl.getUserById(Long.parseLong(userId));
if (user == null) {
@@ -759,7 +762,7 @@ public String saveUserSecurityQuesAns(
}
/**
- *
+ *
* @return security qtns
*/
@Operation(summary = "Get security quetions")
@@ -908,7 +911,7 @@ public String userLogout(HttpServletRequest request) {
}
/**
- *
+ *
* @param key
* @return
*/
@@ -952,7 +955,7 @@ public String forceLogout(@RequestBody ForceLogoutRequestModel request, HttpServ
if (token == null) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
outputResponse.setError(new RuntimeException("No JWT token found in request"));
- return outputResponse.toString();
+ return outputResponse.toString();
}
// Validate the token: Check if it is expired or in the deny list
@@ -989,7 +992,7 @@ private String getJwtTokenFromCookies(HttpServletRequest request) {
return null;
}
-
+
@Operation(summary = "User force log out")
@RequestMapping(value = "/userForceLogout", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON, headers = "Authorization")
public String userForceLogout(
@@ -1212,4 +1215,19 @@ private JSONObject prepareAuthenticationResponse(User mUser, String remoteAddres
return iemrAdminUserServiceImpl.generateKeyAndValidateIP(responseObj, remoteAddress, remoteHost);
}
+ @Operation(summary = "Get UserId based on userName")
+ @GetMapping(value = "/userName/{userName}", produces = MediaType.APPLICATION_JSON, headers = "Authorization")
+ public ResponseEntity> getUserDetails(@PathVariable("userName") String userName) {
+ try {
+ List users = iemrAdminUserServiceImpl.getUserIdbyUserName(userName);
+ if (users.isEmpty()) {
+ return new ResponseEntity<>(Map.of("error", "UserName Not Found"), HttpStatus.NOT_FOUND);
+ }
+ User user = users.get(0);
+ return new ResponseEntity<>(Map.of("userName", user.getUserName(), "userId", user.getUserID()), HttpStatus.OK);
+ } catch (Exception e) {
+ return new ResponseEntity<>(Map.of("error", "Internal server error"), HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+
+ }
}
diff --git a/src/main/java/com/iemr/common/data/beneficiaryConsent/BeneficiaryConsentRequest.java b/src/main/java/com/iemr/common/data/beneficiaryConsent/BeneficiaryConsentRequest.java
new file mode 100644
index 00000000..ac629a3c
--- /dev/null
+++ b/src/main/java/com/iemr/common/data/beneficiaryConsent/BeneficiaryConsentRequest.java
@@ -0,0 +1,12 @@
+package com.iemr.common.data.beneficiaryConsent;
+
+import lombok.Data;
+
+@Data
+public class BeneficiaryConsentRequest {
+ private String mobNo;
+ private int otp;
+ private String userName;
+ private String designation;
+
+}
diff --git a/src/main/java/com/iemr/common/data/dynamic_from/FormDefinition.java b/src/main/java/com/iemr/common/data/dynamic_from/FormDefinition.java
new file mode 100644
index 00000000..9e62b6d9
--- /dev/null
+++ b/src/main/java/com/iemr/common/data/dynamic_from/FormDefinition.java
@@ -0,0 +1,30 @@
+package com.iemr.common.data.dynamic_from;
+import jakarta.persistence.*;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+@Entity
+@Data
+@Table(name = "form_master")
+public class FormDefinition {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "form_id")
+ private String formId;
+
+ @Column(name = "form_name")
+ private String formName;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "module_id")
+ private FormModule module;
+
+ @Column(name = "created_at")
+ private LocalDateTime createdAt = LocalDateTime.now();
+ @Column(name = "version")
+ private Integer version;
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/iemr/common/data/dynamic_from/FormField.java b/src/main/java/com/iemr/common/data/dynamic_from/FormField.java
new file mode 100644
index 00000000..39785ae9
--- /dev/null
+++ b/src/main/java/com/iemr/common/data/dynamic_from/FormField.java
@@ -0,0 +1,59 @@
+package com.iemr.common.data.dynamic_from;
+import jakarta.persistence.*;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Entity
+@Data
+@Table(name = "form_fields")
+public class FormField {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "form_id", referencedColumnName = "form_id")
+ private FormDefinition form;
+
+ @Column(name = "section_title")
+ private String sectionTitle;
+
+ @Column(name = "field_id")
+ private String fieldId;
+
+ @Column(name = "label")
+ private String label;
+
+ @Column(name = "type")
+ private String type;
+
+ @Column(name = "is_required")
+ private Boolean isRequired;
+
+ @Column(name = "is_visible")
+ private Boolean isVisible;
+
+ @Column(name = "default_value")
+ private String defaultValue;
+
+ @Column(name = "placeholder")
+ private String placeholder;
+
+ @Column(name = "options", columnDefinition = "json")
+ private String options;
+
+ @Column(name = "validation", columnDefinition = "json")
+ private String validation; // includes error messages now
+
+ @Column(name = "conditional", columnDefinition = "json")
+ private String conditional;
+
+ @Column(name = "sequence")
+ private Integer sequence;
+
+ @Column(name = "created_at")
+ private LocalDateTime createdAt = LocalDateTime.now();
+
+}
diff --git a/src/main/java/com/iemr/common/data/dynamic_from/FormModule.java b/src/main/java/com/iemr/common/data/dynamic_from/FormModule.java
new file mode 100644
index 00000000..ba5d0170
--- /dev/null
+++ b/src/main/java/com/iemr/common/data/dynamic_from/FormModule.java
@@ -0,0 +1,23 @@
+package com.iemr.common.data.dynamic_from;
+
+import jakarta.persistence.*;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Entity
+@Data
+@Table(name = "form_module")
+public class FormModule {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "module_name")
+ private String moduleName;
+
+ @Column(name = "created_at")
+ private LocalDateTime createdAt = LocalDateTime.now();
+
+}
diff --git a/src/main/java/com/iemr/common/data/mmuDrugHistory/PrescribedMMUDrugDetail.java b/src/main/java/com/iemr/common/data/mmuDrugHistory/PrescribedMMUDrugDetail.java
new file mode 100644
index 00000000..e478420d
--- /dev/null
+++ b/src/main/java/com/iemr/common/data/mmuDrugHistory/PrescribedMMUDrugDetail.java
@@ -0,0 +1,119 @@
+package com.iemr.common.data.mmuDrugHistory;
+
+import java.sql.Date;
+import java.sql.Timestamp;
+
+import com.google.gson.annotations.Expose;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
+import jakarta.persistence.Transient;
+import lombok.Data;
+
+@Entity
+@Data
+@Table(name = "t_prescribeddrug")
+public class PrescribedMMUDrugDetail {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Expose
+ @Column(name = "PrescribedDrugID")
+ private Long prescribedDrugID;
+
+ @Expose
+ @Column(name = "BeneficiaryRegID")
+ private Long beneficiaryRegID;
+
+ @Expose
+ @Column(name = "BenVisitID")
+ private Long benVisitID;
+
+ @Expose
+ @Column(name = "ProviderServiceMapID")
+ private Integer providerServiceMapID;
+
+ @Expose
+ @Column(name = "VisitCode")
+ private Long visitCode;
+
+ @Expose
+ @Column(name = "PrescriptionID")
+ private Long prescriptionID;
+
+ @OneToOne(fetch = FetchType.EAGER)
+ @JoinColumn(name = "PrescriptionID", referencedColumnName = "PrescriptionID", insertable = false, updatable = false)
+ private PrescriptionMMU prescription;
+
+ @Expose
+ @Column(name = "DrugForm")
+ private String formName;
+
+ @Expose
+ @Column(name = "DrugTradeOrBrandName")
+ private String drugTradeOrBrandName;
+
+ @Expose
+ @Column(name = "DrugID")
+ private Integer drugID;
+
+ @Expose
+ @Column(name = "GenericDrugName")
+ private String drugName;
+
+ @Expose
+ @Column(name = "DrugStrength")
+ private String drugStrength;
+
+ @Expose
+ @Column(name = "Dose")
+ private String dose;
+
+ @Expose
+ @Column(name = "Route")
+ private String route;
+
+ @Expose
+ @Column(name = "Frequency")
+ private String frequency;
+
+ @Expose
+ @Column(name = "Duration")
+ private String duration;
+
+ @Expose
+ @Column(name = "DuartionUnit")
+ private String unit;
+
+ @Expose
+ @Column(name = "RelationToFood")
+ private String relationToFood;
+
+ @Expose
+ @Column(name = "SpecialInstruction")
+ private String instructions;
+
+ @Expose
+ @Column(name = "QtyPrescribed")
+ private Integer qtyPrescribed;
+
+ @Expose
+ @Column(name = "Deleted", insertable = false, updatable = true)
+ private Boolean deleted;
+
+ @Expose
+ @Column(name = "Processed", insertable = false, updatable = true)
+ private String processed;
+
+ @Expose
+ @Column(name = "CreatedBy")
+ private String createdBy;
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/iemr/common/data/mmuDrugHistory/PrescriptionMMU.java b/src/main/java/com/iemr/common/data/mmuDrugHistory/PrescriptionMMU.java
new file mode 100644
index 00000000..cd3f655e
--- /dev/null
+++ b/src/main/java/com/iemr/common/data/mmuDrugHistory/PrescriptionMMU.java
@@ -0,0 +1,43 @@
+package com.iemr.common.data.mmuDrugHistory;
+
+import com.google.gson.annotations.Expose;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import lombok.Data;
+
+@Entity
+@Data
+@Table(name = "t_prescription")
+public class PrescriptionMMU {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Expose
+ @Column(name = "PrescriptionID", insertable = false, updatable = false)
+ private Long prescriptionID;
+
+ @Expose
+ @Column(name = "BenVisitID")
+ private Long benVisitID;
+
+ @Expose
+ @Column(name = "ProviderServiceMapID")
+ private Integer providerServiceMapID;
+
+ @Expose
+ @Column(name = "DiagnosisProvided")
+ private String diagnosisProvided;
+
+ @Expose
+ @Column(name = "Remarks")
+ private String remarks;
+
+ @Expose
+ @Column(name = "Deleted", insertable = false, updatable = true)
+ private Boolean deleted;
+
+}
diff --git a/src/main/java/com/iemr/common/data/platform_feedback/Feedback.java b/src/main/java/com/iemr/common/data/platform_feedback/Feedback.java
new file mode 100644
index 00000000..776d3c08
--- /dev/null
+++ b/src/main/java/com/iemr/common/data/platform_feedback/Feedback.java
@@ -0,0 +1,171 @@
+/*
+ * AMRIT – Accessible Medical Records via Integrated Technology
+ * 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.common.data.platform_feedback;
+
+import jakarta.persistence.*;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.Size;
+import java.time.LocalDateTime;
+import java.util.UUID;
+
+@Entity
+@Table(name = "m_platform_feedback")
+public class Feedback {
+
+ @Id
+ @Column(name = "FeedbackID", length = 36, updatable = false, nullable = false)
+ private String feedbackId;
+
+ @Column(name = "CreatedAt", nullable = false, insertable = false, updatable = false)
+ private LocalDateTime createdAt;
+
+ @Column(name = "UpdatedAt", nullable = false, insertable = false, updatable = false)
+ private LocalDateTime updatedAt;
+
+ @Min(1)
+ @Max(5)
+ @Column(name = "Rating", nullable = false)
+ private int rating;
+
+ @Size(max = 2000)
+ @Column(name = "Comment", columnDefinition = "TEXT", nullable = true)
+ private String comment;
+
+ @Column(name = "ServiceLine", nullable = false, length = 10)
+ private String serviceLine;
+
+ @Column(name = "IsAnonymous", nullable = false)
+ private boolean isAnonymous = true;
+
+ @ManyToOne(fetch = FetchType.LAZY, optional = false)
+ @JoinColumn(name = "CategoryID", referencedColumnName = "CategoryID", nullable = false)
+ private FeedbackCategory category;
+
+ @Column(name = "UserID", nullable = true)
+ private Integer userId;
+
+ public Feedback() {
+ this.feedbackId = UUID.randomUUID().toString();
+ }
+
+ public Feedback(int rating, String comment, String serviceLine, boolean isAnonymous, FeedbackCategory category, Integer userId) {
+ this(); // ensures feedbackId
+ this.setRating(rating);
+ this.setComment(comment);
+ this.setServiceLine(serviceLine);
+ this.isAnonymous = isAnonymous;
+ this.category = category;
+ this.userId = userId;
+ }
+
+ public String getFeedbackId() {
+ return feedbackId;
+ }
+
+ // Don't usually set feedbackId externally, but keep setter for testing/migration if needed
+ public void setFeedbackId(String feedbackId) {
+ this.feedbackId = feedbackId;
+ }
+
+ public LocalDateTime getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(LocalDateTime createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public LocalDateTime getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(LocalDateTime updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public int getRating() {
+ return rating;
+ }
+
+ public void setRating(int rating) {
+ if (rating < 1 || rating > 5) {
+ throw new IllegalArgumentException("Rating must be between 1 and 5.");
+ }
+ this.rating = rating;
+ }
+
+ public String getComment() {
+ return comment;
+ }
+
+ public void setComment(String comment) {
+ if (comment != null && comment.length() > 2000) {
+ throw new IllegalArgumentException("Comment cannot exceed 2000 characters");
+ }
+ this.comment = (comment == null || comment.trim().isEmpty()) ? null : comment.trim();
+ }
+
+ public String getServiceLine() {
+ return serviceLine;
+ }
+
+ public void setServiceLine(String serviceLine) {
+ if (serviceLine == null || serviceLine.trim().isEmpty()) {
+ throw new IllegalArgumentException("ServiceLine must not be null or empty.");
+ }
+ this.serviceLine = serviceLine;
+ }
+
+ public boolean isAnonymous() {
+ return isAnonymous;
+ }
+
+ public void setAnonymous(boolean anonymous) {
+ isAnonymous = anonymous;
+ if (anonymous) {
+ this.userId = null;
+ }
+ }
+
+ public FeedbackCategory getCategory() {
+ return category;
+ }
+
+ public void setCategory(FeedbackCategory category) {
+ if (category == null) {
+ throw new IllegalArgumentException("Category must not be null.");
+ }
+ this.category = category;
+ }
+
+ public Integer getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Integer userId) {
+ this.userId = userId;
+ if (userId != null) {
+ this.isAnonymous = false;
+ }
+ }
+}
diff --git a/src/main/java/com/iemr/common/data/platform_feedback/FeedbackCategory.java b/src/main/java/com/iemr/common/data/platform_feedback/FeedbackCategory.java
new file mode 100644
index 00000000..a3e4c692
--- /dev/null
+++ b/src/main/java/com/iemr/common/data/platform_feedback/FeedbackCategory.java
@@ -0,0 +1,153 @@
+/*
+ * AMRIT – Accessible Medical Records via Integrated Technology
+ * 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.common.data.platform_feedback;
+
+import jakarta.persistence.*;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+import java.time.LocalDateTime;
+import java.util.UUID;
+
+/**
+ * FeedbackCategory maps to the m_feedback_category table.
+ */
+@Entity
+@Table(name = "m_feedback_category", uniqueConstraints = {
+ @UniqueConstraint(name = "uq_category_slug", columnNames = "Slug")
+})
+public class FeedbackCategory {
+
+ @Id
+ @Column(name = "CategoryID", length = 36, updatable = false, nullable = false)
+ private String categoryId;
+
+ @NotBlank
+ @Pattern(regexp = "^[a-z0-9]+(?:-[a-z0-9]+)*$", message = "Slug must be lowercase alphanumeric with optional single dashes")
+ @Size(max = 64)
+ @Column(name = "Slug", nullable = false, length = 64)
+ private String slug;
+
+ @NotBlank
+ @Size(max = 128)
+ @Column(name = "Label", nullable = false, length = 128)
+ private String label;
+
+ @NotBlank
+ @Size(max = 20)
+ @Column(name = "Scope", nullable = false, length = 20)
+ private String scope;
+
+ @Column(name = "Active", nullable = false)
+ private boolean active = true;
+
+
+ @Column(name = "CreatedAt", nullable = false, insertable = false, updatable = false)
+ private LocalDateTime createdAt;
+
+ @Column(name = "UpdatedAt", nullable = false, insertable = false, updatable = false)
+ private LocalDateTime updatedAt;
+
+ // ===== Constructors =====
+ public FeedbackCategory() {
+ // nothing — categoryId will be generated at persist if not provided
+ }
+
+ public FeedbackCategory(String slug, String label, String scope, boolean active) {
+ this.slug = slug;
+ this.label = label;
+ this.scope = scope;
+ this.active = active;
+ }
+
+ // ===== JPA lifecycle hooks =====
+ /**
+ * Ensure CategoryID exists for new rows created via JPA. If DB seeding provides IDs,
+ * those will be used instead (we only set if null).
+ */
+ @PrePersist
+ protected void ensureId() {
+ if (this.categoryId == null || this.categoryId.trim().isEmpty()) {
+ this.categoryId = UUID.randomUUID().toString();
+ }
+ }
+
+ // ===== Getters & Setters =====
+ public String getCategoryId() {
+ return categoryId;
+ }
+
+ // categoryId is generated at persist; setter kept for migration/tests
+ public void setCategoryId(String categoryId) {
+ this.categoryId = categoryId;
+ }
+
+ public String getSlug() {
+ return slug;
+ }
+
+ public void setSlug(String slug) {
+ this.slug = slug;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public String getScope() {
+ return scope;
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public void setActive(boolean active) {
+ this.active = active;
+ }
+
+ public LocalDateTime getCreatedAt() {
+ return createdAt;
+ }
+
+ // CreatedAt normally set by DB; setter available for tests/migrations
+ public void setCreatedAt(LocalDateTime createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public LocalDateTime getUpdatedAt() {
+ return updatedAt;
+ }
+
+ // UpdatedAt normally managed by DB
+ public void setUpdatedAt(LocalDateTime updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+}
diff --git a/src/main/java/com/iemr/common/data/translation/Translation.java b/src/main/java/com/iemr/common/data/translation/Translation.java
new file mode 100644
index 00000000..81a906fa
--- /dev/null
+++ b/src/main/java/com/iemr/common/data/translation/Translation.java
@@ -0,0 +1,23 @@
+package com.iemr.common.data.translation;
+
+import jakarta.persistence.*;
+import lombok.Data;
+
+@Entity
+@Table(name = "m_translation")
+@Data
+public class Translation {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private Long id;
+ @Column(name = "label_key")
+ private String labelKey;
+ @Column(name = "english")
+ private String english;
+ @Column(name = "hindi_translation")
+ private String hindiTranslation;
+ @Column(name = "is_active")
+ private Boolean isActive;
+}
diff --git a/src/main/java/com/iemr/common/data/userToken/UserTokenData.java b/src/main/java/com/iemr/common/data/userToken/UserTokenData.java
new file mode 100644
index 00000000..0646972e
--- /dev/null
+++ b/src/main/java/com/iemr/common/data/userToken/UserTokenData.java
@@ -0,0 +1,46 @@
+/*
+* AMRIT – Accessible Medical Records via Integrated Technology
+* 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/.
+*
+/*
+* AMRIT – Accessible Medical Records via Integrated Technology
+*/
+package com.iemr.common.data.userToken;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import lombok.Data;
+
+import java.sql.Timestamp;
+
+@Entity
+@Table(name = "user_tokens", schema = "db_iemr")
+@Data
+public class UserTokenData {
+ @Id
+ @Column(name = "user_id")
+ Integer userId;
+ @Column(name = "token")
+ String token;
+ @Column(name = "updated_at")
+ Timestamp updatedAt;
+}
diff --git a/src/main/java/com/iemr/common/data/users/User.java b/src/main/java/com/iemr/common/data/users/User.java
index e6184e60..275b0ec6 100644
--- a/src/main/java/com/iemr/common/data/users/User.java
+++ b/src/main/java/com/iemr/common/data/users/User.java
@@ -55,6 +55,7 @@
@Entity
@Table(name = "m_user")
@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -208,6 +209,10 @@ public class User implements Serializable {
@Column(name = "failed_attempt")
private Integer failedAttempt;
+ @Expose
+ @Column(name = "dhistoken")
+ private String dhistoken;
+
/*
* protected User() { }
*/
@@ -217,7 +222,7 @@ public static User initializeUsers(Long userID, Integer titleID, String firstNam
Timestamp dOJ, Integer qualificationID, String userName, String password, String emailID, Status m_Status,
List m_UserServiceRoleMapping, String emergencyContactPerson,
String emergencyContactNo, Boolean isSupervisor, Boolean deleted, String createdBy, Timestamp createdDate,
- String modifiedBy, Timestamp lastModDate, String newPassword) {
+ String modifiedBy, Timestamp lastModDate, String newPassword, String dhistoken) {
User user = new User();
user.userID = userID;
user.titleID = titleID;
@@ -244,6 +249,7 @@ public static User initializeUsers(Long userID, Integer titleID, String firstNam
user.modifiedBy = modifiedBy;
user.lastModDate = lastModDate;
user.newPassword = newPassword;
+ user.dhistoken = dhistoken;
return user;
}
@@ -530,6 +536,9 @@ public Integer getDesignationID() {
public Designation getDesignation() {
return designation;
}
+ public String getDhistoken() {
+ return dhistoken;
+ }
/*
* public User(String userName, String password) { this.userName = userName;
diff --git a/src/main/java/com/iemr/common/dto/dynamicForm/FieldDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/FieldDTO.java
new file mode 100644
index 00000000..894f03c2
--- /dev/null
+++ b/src/main/java/com/iemr/common/dto/dynamicForm/FieldDTO.java
@@ -0,0 +1,25 @@
+package com.iemr.common.dto.dynamicForm;
+
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+public class FieldDTO {
+ private Long id;
+ private String formId;
+ private String sectionTitle;
+ private String fieldId;
+ private String label;
+ private String type;
+ private Boolean isVisible;
+ private Boolean isRequired;
+ private String defaultValue;
+ private String placeholder;
+ private Integer sequence;
+ private String options; // ⬅️ changed from String to List
+ private String validation; // ⬅️ changed from String to Map
+ private String conditional; // ⬅️ changed from String to Map
+}
+
diff --git a/src/main/java/com/iemr/common/dto/dynamicForm/FieldResponseDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/FieldResponseDTO.java
new file mode 100644
index 00000000..3415d91a
--- /dev/null
+++ b/src/main/java/com/iemr/common/dto/dynamicForm/FieldResponseDTO.java
@@ -0,0 +1,24 @@
+package com.iemr.common.dto.dynamicForm;
+
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+public class FieldResponseDTO {
+ private Long id;
+ private String formId;
+ private String sectionTitle;
+ private String fieldId;
+ private String label;
+ private Boolean visible;
+ private String type;
+ private Boolean isRequired;
+ private String defaultValue;
+ private String placeholder;
+ private Integer sequence;
+ private List options;
+ private Map validation;
+ private Map conditional;
+}
\ No newline at end of file
diff --git a/src/main/java/com/iemr/common/dto/dynamicForm/FormDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/FormDTO.java
new file mode 100644
index 00000000..24788cac
--- /dev/null
+++ b/src/main/java/com/iemr/common/dto/dynamicForm/FormDTO.java
@@ -0,0 +1,10 @@
+package com.iemr.common.dto.dynamicForm;
+
+import lombok.Data;
+
+@Data
+public class FormDTO {
+ private String formId;
+ private String formName;
+ private Long moduleId;
+}
\ No newline at end of file
diff --git a/src/main/java/com/iemr/common/dto/dynamicForm/FormResponseDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/FormResponseDTO.java
new file mode 100644
index 00000000..26563927
--- /dev/null
+++ b/src/main/java/com/iemr/common/dto/dynamicForm/FormResponseDTO.java
@@ -0,0 +1,13 @@
+package com.iemr.common.dto.dynamicForm;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class FormResponseDTO {
+ private Integer version;
+ private String formId;
+ private String formName;
+ private List sections;
+}
diff --git a/src/main/java/com/iemr/common/dto/dynamicForm/GroupedFieldResponseDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/GroupedFieldResponseDTO.java
new file mode 100644
index 00000000..840c5097
--- /dev/null
+++ b/src/main/java/com/iemr/common/dto/dynamicForm/GroupedFieldResponseDTO.java
@@ -0,0 +1,11 @@
+package com.iemr.common.dto.dynamicForm;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class GroupedFieldResponseDTO {
+ private String sectionTitle;
+ private List fields;
+}
diff --git a/src/main/java/com/iemr/common/dto/dynamicForm/ModuleDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/ModuleDTO.java
new file mode 100644
index 00000000..3f4240c4
--- /dev/null
+++ b/src/main/java/com/iemr/common/dto/dynamicForm/ModuleDTO.java
@@ -0,0 +1,8 @@
+package com.iemr.common.dto.dynamicForm;
+
+import lombok.Data;
+
+@Data
+public class ModuleDTO {
+ private String moduleName;
+}
\ No newline at end of file
diff --git a/src/main/java/com/iemr/common/dto/identity/CommonIdentityDTO.java b/src/main/java/com/iemr/common/dto/identity/CommonIdentityDTO.java
index 431a267a..8e364eb3 100644
--- a/src/main/java/com/iemr/common/dto/identity/CommonIdentityDTO.java
+++ b/src/main/java/com/iemr/common/dto/identity/CommonIdentityDTO.java
@@ -54,6 +54,8 @@ public class CommonIdentityDTO {
private Integer beneficiaryRegId;
private Integer communityId;
private String community;
+ private Boolean isConsent=false;
+
private Timestamp dob;
private Integer ageAtMarriage;
private Integer educationId;
diff --git a/src/main/java/com/iemr/common/dto/platform_feedback/CategoryResponse.java b/src/main/java/com/iemr/common/dto/platform_feedback/CategoryResponse.java
new file mode 100644
index 00000000..c01ff197
--- /dev/null
+++ b/src/main/java/com/iemr/common/dto/platform_feedback/CategoryResponse.java
@@ -0,0 +1,24 @@
+/*
+ * AMRIT – Accessible Medical Records via Integrated Technology
+ * 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.common.dto.platform_feedback;
+
+public record CategoryResponse(String categoryId, String slug, String label, String scope, boolean active) {}
\ No newline at end of file
diff --git a/src/main/java/com/iemr/common/dto/platform_feedback/FeedbackRequest.java b/src/main/java/com/iemr/common/dto/platform_feedback/FeedbackRequest.java
new file mode 100644
index 00000000..02c52c3a
--- /dev/null
+++ b/src/main/java/com/iemr/common/dto/platform_feedback/FeedbackRequest.java
@@ -0,0 +1,37 @@
+/*
+ * AMRIT – Accessible Medical Records via Integrated Technology
+ * 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.common.dto.platform_feedback;
+
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+
+public record FeedbackRequest(
+ @Min(1) @Max(5) int rating,
+ String categoryId,
+ String categorySlug,
+ @Size(max = 2000) String comment,
+ boolean isAnonymous,
+ @Pattern(regexp = "^(1097|104|AAM|MMU|TM|ECD)$") String serviceLine,
+ Integer userId
+) {}
\ No newline at end of file
diff --git a/src/main/java/com/iemr/common/dto/platform_feedback/FeedbackResponse.java b/src/main/java/com/iemr/common/dto/platform_feedback/FeedbackResponse.java
new file mode 100644
index 00000000..51003353
--- /dev/null
+++ b/src/main/java/com/iemr/common/dto/platform_feedback/FeedbackResponse.java
@@ -0,0 +1,26 @@
+/*
+ * AMRIT – Accessible Medical Records via Integrated Technology
+ * 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.common.dto.platform_feedback;
+import java.time.LocalDateTime;
+
+
+public record FeedbackResponse(String id, LocalDateTime createdAt) {}
\ No newline at end of file
diff --git a/src/main/java/com/iemr/common/dto/sms/SMSTemplateDTO.java b/src/main/java/com/iemr/common/dto/sms/SMSTemplateDTO.java
new file mode 100644
index 00000000..ab71d8cc
--- /dev/null
+++ b/src/main/java/com/iemr/common/dto/sms/SMSTemplateDTO.java
@@ -0,0 +1,114 @@
+package com.iemr.common.dto.sms;
+
+public class SMSTemplateDTO {
+ private Integer smsTemplateID;
+ private String smsTemplateName;
+ private String smsTemplate;
+ private String dltTemplateId;
+ private String smsSenderID;
+ private Integer smsTypeID;
+ private Integer providerServiceMapID;
+ private Boolean deleted;
+ private String createdBy;
+ private String modifiedBy;
+ private String createdDate;
+ private String lastModDate;
+
+ // Getters and Setters for all fields
+
+ public Integer getSmsTemplateID() {
+ return smsTemplateID;
+ }
+
+ public void setSmsTemplateID(Integer smsTemplateID) {
+ this.smsTemplateID = smsTemplateID;
+ }
+
+ public String getSmsTemplateName() {
+ return smsTemplateName;
+ }
+
+ public void setSmsTemplateName(String smsTemplateName) {
+ this.smsTemplateName = smsTemplateName;
+ }
+
+ public String getSmsTemplate() {
+ return smsTemplate;
+ }
+
+ public void setSmsTemplate(String smsTemplate) {
+ this.smsTemplate = smsTemplate;
+ }
+
+ public String getDltTemplateId() {
+ return dltTemplateId;
+ }
+
+ public void setDltTemplateId(String dltTemplateId) {
+ this.dltTemplateId = dltTemplateId;
+ }
+
+ public String getSmsSenderID() {
+ return smsSenderID;
+ }
+
+ public void setSmsSenderID(String smsSenderID) {
+ this.smsSenderID = smsSenderID;
+ }
+
+ public Integer getSmsTypeID() {
+ return smsTypeID;
+ }
+
+ public void setSmsTypeID(Integer smsTypeID) {
+ this.smsTypeID = smsTypeID;
+ }
+
+ public Integer getProviderServiceMapID() {
+ return providerServiceMapID;
+ }
+
+ public void setProviderServiceMapID(Integer providerServiceMapID) {
+ this.providerServiceMapID = providerServiceMapID;
+ }
+
+ public Boolean getDeleted() {
+ return deleted;
+ }
+
+ public void setDeleted(Boolean deleted) {
+ this.deleted = deleted;
+ }
+
+ public String getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(String createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public String getModifiedBy() {
+ return modifiedBy;
+ }
+
+ public void setModifiedBy(String modifiedBy) {
+ this.modifiedBy = modifiedBy;
+ }
+
+ public String getCreatedDate() {
+ return createdDate;
+ }
+
+ public void setCreatedDate(String createdDate) {
+ this.createdDate = createdDate;
+ }
+
+ public String getLastModDate() {
+ return lastModDate;
+ }
+
+ public void setLastModDate(String lastModDate) {
+ this.lastModDate = lastModDate;
+ }
+}
diff --git a/src/main/java/com/iemr/common/exception/BadRequestException.java b/src/main/java/com/iemr/common/exception/BadRequestException.java
new file mode 100644
index 00000000..65d146a6
--- /dev/null
+++ b/src/main/java/com/iemr/common/exception/BadRequestException.java
@@ -0,0 +1,31 @@
+/*
+ * AMRIT – Accessible Medical Records via Integrated Technology
+ * 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.common.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+@ResponseStatus(HttpStatus.BAD_REQUEST)
+public class BadRequestException extends RuntimeException {
+ public BadRequestException(String message) { super(message); }
+ public BadRequestException(String message, Throwable cause) { super(message, cause); }
+}
diff --git a/src/main/java/com/iemr/common/exception/ValidationExceptionHandler.java b/src/main/java/com/iemr/common/exception/ValidationExceptionHandler.java
new file mode 100644
index 00000000..750d221c
--- /dev/null
+++ b/src/main/java/com/iemr/common/exception/ValidationExceptionHandler.java
@@ -0,0 +1,54 @@
+package com.iemr.common.exception;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RestControllerAdvice
+public class ValidationExceptionHandler {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity