From 610aece1f6ca5153e54e21bb7ec652331026afaf Mon Sep 17 00:00:00 2001 From: rajesh Date: Thu, 6 Feb 2025 15:11:42 +0530 Subject: [PATCH 1/3] Done ticket GEPAFINBE-162 --- pom.xml | 6 + .../constants/GepafinConstant.java | 1 + .../tendermanagement/dao/ApplicationDao.java | 202 +++++++++++++++--- .../tendermanagement/util/FieldValidator.java | 24 ++- .../gepafin/tendermanagement/util/Utils.java | 25 ++- src/main/resources/message_en.properties | 1 + src/main/resources/message_it.properties | 3 +- 7 files changed, 227 insertions(+), 35 deletions(-) diff --git a/pom.xml b/pom.xml index c463be91..a42534bf 100644 --- a/pom.xml +++ b/pom.xml @@ -245,6 +245,12 @@ reactor-netty + + net.objecthunter + exp4j + 0.4.8 + + diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 9010e157..f6d9ac42 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -407,5 +407,6 @@ public class GepafinConstant { public static final String ASSIGNED_APPLICATION_STATUS_UPDATED_SUCCESSFULLY = "assigned.application.status.updated.successfully"; public static final String REQUIRED_REQUESTED_AMOUNT_MSG = "validation.required.requested.amount"; + public static final String FORMULA_AMOUNT_NOT_MATCHED="formula.amount.not.matches.requested.amount"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index 794e7796..f43a030f 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -31,6 +31,7 @@ import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundExceptio import net.gepafin.tendermanagement.web.rest.api.errors.Status; import org.h2.util.IOUtils; +import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -49,11 +50,16 @@ import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.text.MessageFormat; +import java.text.NumberFormat; +import java.text.ParseException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -94,29 +100,29 @@ public class ApplicationDao { @Autowired private FlowDataRepository flowDataRepository; - + @Autowired private UserCompanyDelegationRepository userCompanyDelegationRepository; - + @Autowired private Validator validator; - + @Autowired private CompanyService companyService; @Autowired private S3PathConfig s3PathConfig; - + @Autowired private SystemEmailTemplatesService systemEmailTemplatesService; @Autowired private AssignedApplicationsRepository assignedApplicationsRepository; - + @Value("${default_System_Receiver_Email}") private String defaultSystemReceiverEmail; - + @Value("${rinaldo_email}") private String rinaldoEmail; - + @Value("${carlo_email}") private String carloEmail; @@ -125,37 +131,37 @@ public class ApplicationDao { @Autowired private AmazonS3Service amazonS3Service; - + @Autowired private ApplicationSignedDocumentRepository applicationSignedDocumentRepository; - + // @Value("${aws.s3.url.folder.signed.document}") // private String signedDocumentS3Folder; - + @Value("${default.hub.uuid}") private String defaultHubUuid; - + @Autowired private UserService userService; @Autowired private S3PathConfig s3ConfigBean; - + @Autowired private ProtocolDao protocolDao; - + @Autowired private HubService hubService; @Autowired private EmailNotificationDao emailNotificationDao; - + @Autowired private FormDao formDao; @Autowired private EmailLogDao emailLogDao; - + @Autowired private UserWithCompanyRepository userWithCompanyRepository; @@ -183,6 +189,7 @@ public class ApplicationDao { @Autowired private ApplicationEvaluationRepository applicationEvaluationRepository; + public ApplicationResponseBean createApplication(HttpServletRequest request, ApplicationRequestBean applicationRequestBean, Long formId, Long applicationId) { FormEntity formEntity = formService.validateForm(formId); // callService.validatePublishedCall(formEntity.getCall().getId()); @@ -258,7 +265,7 @@ public class ApplicationDao { // List contentResponseBeans = Utils.convertJsonStringToList( // applicationFormEntity.getForm().getContent(), ContentResponseBean.class); - + List contentResponseBeans = formDao.convertFormEntityToFormResponseBean(applicationFormEntity.getForm()).getContent(); for (ApplicationFormFieldEntity applicationFormFieldEntity : applicationFormFieldEntities) { @@ -309,7 +316,7 @@ public class ApplicationDao { ); } ApplicationEntity oldApplicationDataEntity = Utils.getClonedEntityForData(applicationEntity); - + validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); applicationEntity.setIsDeleted(true); applicationEntity = applicationRepository.save(applicationEntity); @@ -356,9 +363,9 @@ public class ApplicationDao { // // return applicationResponses; // } - + public List getAllApplications(UserEntity userEntity, Long callId, Long companyId,List statusList) { - + log.info("Fetching applications for RoleType: {}", userEntity.getRoleEntity().getRoleType()); Specification spec = search(userEntity, callId, companyId,statusList); @@ -482,15 +489,18 @@ public class ApplicationDao { public List createOrUpdateMultipleFormFields(List formFieldResponseBeans, ApplicationFormEntity applicationFormEntity, FormEntity formEntity) { + FieldValidator fieldValidator = FieldValidator.create(); List existingFields = applicationFormFieldRepository.findByApplicationFormId(applicationFormEntity.getId()); - return formFieldResponseBeans.stream().map(requestBean -> createOrUpdateApplicationFormField(requestBean, applicationFormEntity, existingFields, formEntity)) + List applicationFormFieldEntities=formFieldResponseBeans.stream().map(requestBean -> createOrUpdateApplicationFormField(requestBean, applicationFormEntity, existingFields, formEntity,fieldValidator)) .collect(Collectors.toList()); + fieldValidator.validate(); + return applicationFormFieldEntities; } public ApplicationFormFieldEntity createOrUpdateApplicationFormField(ApplicationFormFieldRequestBean applicationFormFieldRequestBean, - ApplicationFormEntity applicationFormEntity, List applicationFormFieldEntities, FormEntity formEntity) { + ApplicationFormEntity applicationFormEntity, List applicationFormFieldEntities, FormEntity formEntity,FieldValidator fieldValidator) { ApplicationFormFieldEntity applicationFormFieldEntity = new ApplicationFormFieldEntity(); @@ -506,7 +516,7 @@ public class ApplicationDao { .filter(setting -> "isRequestedAmount".equals(setting.getName()) && Boolean.TRUE.equals(setting.getValue())) .findFirst() .ifPresent(setting -> { - + Object fieldValue = applicationFormFieldRequestBean.getFieldValue(); if(fieldValue!=null) { try { @@ -538,6 +548,7 @@ public class ApplicationDao { } } } + calculationProcessForFormula(applicationFormEntity,contentResponseBeans,applicationFormFieldRequestBean,fieldValidator); Utils.setIfUpdated(applicationFormFieldEntity::getFieldId, applicationFormFieldEntity::setFieldId, applicationFormFieldRequestBean.getFieldId()); if (applicationFormFieldRequestBean.getFieldValue() != null) { @@ -560,7 +571,6 @@ public class ApplicationDao { VersionHistoryRequest.builder().request(request).actionType(actionType).oldData(oldApplicationFormFieldData).newData(applicationFormField).build()); log.info("Version history logged for action: {}, Field ID: {}", actionType, applicationFormFieldEntity.getFieldId()); - return applicationFormField; } @@ -818,7 +828,7 @@ public class ApplicationDao { if(formApplicationResponse.getContent() != null && formApplicationResponse.getFormFields() != null) { formApplicationResponses.add(formApplicationResponse); } - + } public FormApplicationResponse processForm(FormEntity formEntity, ApplicationEntity applicationEntity) { @@ -954,7 +964,7 @@ public class ApplicationDao { return (int) Math.round(progress); } public void validateFormFields(ApplicationRequestBean request, FormEntity formEntity) { - + // List contentResponseBeans=Utils.convertJsonStringToList(formEntity.getContent(),ContentResponseBean.class); List contentResponseBeans=formDao.convertFormEntityToFormResponseBean(formEntity).getContent(); @@ -1034,7 +1044,7 @@ public class ApplicationDao { SystemEmailTemplateResponse systemEmailTemplateResponse = systemEmailTemplatesService .retrieveTemplateByTypeAndCall(SystemEmailTemplatesEntityTypeEnum.APPLICATION_SUBMISSION_TO_USER_AND_COMPANY, hub, null); - + // Create the map for subject placeholders Map subjectPlaceholders = new HashMap<>(); subjectPlaceholders.put("{{call_name}}", call.getName()); @@ -1211,17 +1221,17 @@ public class ApplicationDao { } public ApplicationSignedDocumentResponse getSignedDocument(HttpServletRequest request, Long applicationId) { - + ApplicationEntity applicationEntity = validateApplication(applicationId); // validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); - + if (validator.checkIsPreInstructor()) { ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluationByApplicationId(applicationId); validator.validatePreInstructor(request, applicationEvaluationEntity.getUserId()); } else { validator.validateUserId(request, applicationEntity.getUserId()); } - + ApplicationSignedDocumentEntity applicationSignedDocument = applicationSignedDocumentRepository .findByApplicationIdAndStatus(applicationId, ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); if(applicationSignedDocument == null) { @@ -1230,11 +1240,11 @@ public class ApplicationDao { } return convertApplicationSignedDocumentToApplicationSignedDocumentResponse(applicationSignedDocument); } - + public void deleteSignedDocument(HttpServletRequest request, Long applicationId) { ApplicationEntity applicationEntity = validateApplication(applicationId); validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); - + ApplicationSignedDocumentEntity applicationSignedDocument = applicationSignedDocumentRepository .findByApplicationIdAndStatus(applicationId, ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); //cloned entity for old data @@ -1539,5 +1549,135 @@ public class ApplicationDao { } } + public void calculationProcessForFormula(ApplicationFormEntity applicationFormEntity, List contentResponseBeans, ApplicationFormFieldRequestBean applicationFormFieldRequestBean,FieldValidator fieldValidator) { + List formulaValue = new ArrayList<>(); + String formulaValueOpt=null; + String label=null; + for (ContentResponseBean contentResponseBean:contentResponseBeans){ + if(contentResponseBean.getId().equals(applicationFormFieldRequestBean.getFieldId())){ + for (SettingResponseBean settingResponseBean:contentResponseBean.getSettings()){ + if (settingResponseBean.getName().equals("label")){ + label= String.valueOf(settingResponseBean.getValue()); + } + if(settingResponseBean.getName().equals("formula")){ + String value= (String) settingResponseBean.getValue(); + formulaValueOpt=value; + formulaValue=Utils.extractValues(value); + } + } + } + } + Map mappedFormulaValue = new HashMap<>(); + Object fieldValue = applicationFormFieldRequestBean.getFieldValue(); + if (formulaValueOpt != null && fieldValue==null) { + fieldValue=0; + } + + for (ContentResponseBean contentResponseBean : contentResponseBeans) { + String contentId = contentResponseBean.getId(); + + // Extract variable values once per contentResponseBean to avoid repeated stream operations + Set variableValues = contentResponseBean.getSettings().stream() + .filter(setting -> "variable".equals(setting.getName())) + .flatMap(setting -> { + Object value = setting.getValue(); // Get the raw value + if (value instanceof String) { + return Stream.of((String) value); // Handle single String case + } else if (value instanceof List) { + return ((List) value).stream() + .filter(item -> item instanceof String) // Ensure it's a String + .map(item -> (String) item); // Convert to String + } else { + return Stream.empty(); // Ignore unexpected types + } + }) + .collect(Collectors.toSet()); // Collect into a Set for uniqueness + + for (String formula : formulaValue) { + if (variableValues.contains(formula)) { // O(1) lookup instead of O(n) + mappedFormulaValue.put(formula, contentId); + } + } + } + Map updatedMappedFormulaValue = new HashMap<>(); + + for (Map.Entry entry : mappedFormulaValue.entrySet()) { + String variable = entry.getKey(); + String contentId = entry.getValue(); + + // Repository call using contentId + Optional optionalEntity = applicationFormFieldRepository.findByApplicationFormIdAndFieldId(applicationFormEntity.getId(),contentId); + // If entity is found, extract fieldValue and fieldId + optionalEntity.ifPresent(entity -> { + String entityFieldValue = entity.getFieldValue(); // Assuming getter method exists + String fieldId = entity.getFieldId(); // Assuming getter method exists + String tableType = contentResponseBeans.stream() + .filter(content -> content.getId().equals(fieldId)) // Match Content ID with fieldId + .flatMap(content -> content.getSettings().stream()) // Extract settings + .filter(setting -> "criteria_table_columns".equals(setting.getName())) // Match name + .map(setting -> setting.getName()) // Return the name of the setting + .findFirst() // Get the first match + .orElse(null); // Default to null if no match + + if(tableType!=null){ + JSONObject jsonObject = new JSONObject(entityFieldValue); + + // Extract the value of total + entityFieldValue = jsonObject.getString("total"); + + } + + updatedMappedFormulaValue.put(fieldId, entityFieldValue); + }); + } + if(formulaValueOpt==null || formulaValueOpt.isEmpty()){ + return; + } + double finalValue = evaluateFormula(formulaValueOpt, mappedFormulaValue, updatedMappedFormulaValue); + + fieldValidator.formulaValidation(fieldValue, finalValue, label); + } + + + public static double evaluateFormula(String formula, Map mappedFormulaValue, Map updatedMappedFormulaValue) { + // Step 1: Extract all placeholders (variables) like {rest}, {another_var}, etc. + Pattern pattern = Pattern.compile("\\{(.*?)\\}"); + Matcher matcher = pattern.matcher(formula); + List variables = new ArrayList<>(); + + while (matcher.find()) { + variables.add(matcher.group(1)); // Extract variable names inside the curly braces + } + + // Step 2: Replace placeholders with corresponding fieldValue + Map variableValues = new HashMap<>(); + + for (String variable : variables) { + String fieldId = mappedFormulaValue.get(variable); + if (fieldId != null && updatedMappedFormulaValue.containsKey(fieldId)) { + String fieldValueStr = updatedMappedFormulaValue.get(fieldId); + try { + double fieldValue = Double.parseDouble(fieldValueStr); // Assuming fieldValue is numeric + variableValues.put(variable, fieldValue); + } catch (NumberFormatException e) { + // Handle invalid number format gracefully (e.g., log an error or default to 0) + variableValues.put(variable, 0.0); + } + } + } + + // Step 3: Replace variables in the formula with their corresponding values + String expression = formula; + for (String variable : variables) { + Double value = variableValues.get(variable); + if (value != null) { + // Replace {variable} with its corresponding value in the formula + expression = expression.replace("{" + variable + "}", String.valueOf(value)); + } + } + + // Step 4: Evaluate the mathematical expression + return Utils.evaluateExpression(expression); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/util/FieldValidator.java b/src/main/java/net/gepafin/tendermanagement/util/FieldValidator.java index 9fb108ae..1d335735 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/FieldValidator.java +++ b/src/main/java/net/gepafin/tendermanagement/util/FieldValidator.java @@ -2,6 +2,10 @@ package net.gepafin.tendermanagement.util; import java.text.MessageFormat; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -9,12 +13,18 @@ import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.dao.FormDao; import net.gepafin.tendermanagement.dao.VatCheckDao; +import net.gepafin.tendermanagement.entities.ApplicationFormEntity; +import net.gepafin.tendermanagement.entities.ApplicationFormFieldEntity; +import net.gepafin.tendermanagement.model.request.ApplicationFormFieldRequestBean; import net.gepafin.tendermanagement.model.request.ContentRequestBean; import net.gepafin.tendermanagement.model.response.ContentResponseBean; import net.gepafin.tendermanagement.model.response.SettingResponseBean; +import net.gepafin.tendermanagement.repositories.ApplicationFormFieldRepository; +import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; import net.gepafin.tendermanagement.web.rest.api.errors.Status; import net.gepafin.tendermanagement.web.rest.api.errors.ValidationException; import org.apache.commons.lang3.StringUtils; +import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -232,5 +242,17 @@ public class FieldValidator { // Now contentRequestBean is populated with the data from the JSON return contentRequestBean; } - + public FieldValidator formulaValidation(Object fieldValue, double finalValue, String label) { + if (fieldValue != null) { + try { + double fieldValueAsDouble = Double.parseDouble(fieldValue.toString()); // Convert fieldValue to double + if (Double.compare(finalValue, fieldValueAsDouble) != 0) { // Compare doubles safely + errors.add(MessageFormat.format(Translator.toLocale(GepafinConstant.FORMULA_AMOUNT_NOT_MATCHED), label)); + } + } catch (NumberFormatException e) { + throw new CustomValidationException(Status.BAD_REQUEST, "Invalid field value: " + fieldValue); + } + } + return this; + } } diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java index 2f063173..68e8c8b0 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java @@ -11,6 +11,7 @@ import java.text.SimpleDateFormat; import java.util.*; import java.util.function.Consumer; import java.util.function.Supplier; +import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -27,6 +28,8 @@ import jakarta.servlet.http.HttpServletRequest; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.model.request.GlobalFilters; +import net.objecthunter.exp4j.Expression; +import net.objecthunter.exp4j.ExpressionBuilder; import org.apache.commons.collections4.MapUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,6 +57,9 @@ import javax.crypto.Cipher; import javax.crypto.Mac; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; import static org.apache.commons.lang3.StringUtils.isEmpty; @@ -753,6 +759,23 @@ public class Utils { private static Map defaultErrorResponse() { return Collections.singletonMap("message", Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); } + public static List extractValues(String input) { + List extractedValues = new ArrayList<>(); + Pattern pattern = Pattern.compile("\\{(.*?)\\}"); // Regex to match {value} + Matcher matcher = pattern.matcher(input); - + while (matcher.find()) { + extractedValues.add(matcher.group(1)); // Extract value inside {} + } + return extractedValues; + } + public static double evaluateExpression(String expression) { + try { + Expression exp = new ExpressionBuilder(expression).build(); + return exp.evaluate(); + } catch (Exception e) { + e.printStackTrace(); + return Double.NaN; // Return NaN if the expression is invalid + } + } } \ No newline at end of file diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index 6e058a9f..ab9b1d8c 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -367,5 +367,6 @@ either.applicationId.or.assignedApplicationId.must.be.provided=Either applicatio assigned.application.status.updated.successfully=Assigned application status updated successfully. validation.required.requested.amount=The Requested Amount configuration should be mandatory. +formula.amount.not.matches.requested.amount= The {0} does not matches to calculated amount. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 624c7dfe..c7f83aed 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -358,6 +358,5 @@ either.applicationId.or.assignedApplicationId.must.be.provided = "� necessario assigned.application.status.updated.successfully=Stato dell'applicazione assegnata aggiornato con successo. validation.required.requested.amount=La configurazione dell'importo richiesto � obbligatoria. - - +formula.amount.not.matches.requested.amount=Il {0} non corrisponde all'importo calcolato. From 8d78f32234cf65498269061b274bccb6c26c336f Mon Sep 17 00:00:00 2001 From: Piyush Date: Thu, 6 Feb 2025 16:58:30 +0530 Subject: [PATCH 2/3] Added new form field data --- .../resources/db/changelog/db.changelog-1.0.0.xml | 8 ++++++++ .../db/dump/update_form_field_data_06-02-2025.sql | 14 ++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/main/resources/db/dump/update_form_field_data_06-02-2025.sql diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index ff297cba..eab66c3d 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2379,4 +2379,12 @@ + + + + + + + diff --git a/src/main/resources/db/dump/update_form_field_data_06-02-2025.sql b/src/main/resources/db/dump/update_form_field_data_06-02-2025.sql new file mode 100644 index 00000000..970f442b --- /dev/null +++ b/src/main/resources/db/dump/update_form_field_data_06-02-2025.sql @@ -0,0 +1,14 @@ + +INSERT INTO FORM_FIELD (ID, SORT_ORDER, NAME, LABEL, DESCRIPTION, SETTINGS, VALIDATORS, CREATED_DATE, UPDATED_DATE) +VALUES +( + 22, + 22, + 'switch', + 'Casella di spunta "Checklist"', + 'Per selezioni binarie, accettazioni, conferme', + '[{"name":"label","value":"Casella di Spunta"},{"name":"isChecklistItem","value":true}]', + '{"isRequired":false}', + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP +); \ No newline at end of file From da677ca039ee67f8fa94556c311073a2826a3ed7 Mon Sep 17 00:00:00 2001 From: rajesh Date: Thu, 6 Feb 2025 20:33:40 +0530 Subject: [PATCH 3/3] Created a new endpoint to update user --- .../gepafin/tendermanagement/dao/UserDao.java | 54 +++++++++++++++++++ .../request/UpdateUserReqForBeneficiary.java | 18 +++++++ .../tendermanagement/service/UserService.java | 2 + .../service/impl/UserServiceImpl.java | 6 +++ .../web/rest/api/UserApi.java | 20 ++++++- .../web/rest/api/impl/UserApiController.java | 18 ++++++- 6 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/model/request/UpdateUserReqForBeneficiary.java diff --git a/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java index 0ffa0b42..acb098ef 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java @@ -20,6 +20,7 @@ import net.gepafin.tendermanagement.util.LoggingUtil; import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.util.Validator; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; +import net.gepafin.tendermanagement.web.rest.api.errors.ForbiddenAccessException; import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundException; import net.gepafin.tendermanagement.web.rest.api.errors.Status; @@ -597,5 +598,58 @@ public class UserDao { return userResponseBeans; } + public UserResponseBean updateUserDetails(HttpServletRequest request , Long userId, UpdateUserReqForBeneficiary userReq){ + log.info("Updating user by beneficiary with ID: {}", userId); + UserEntity userEntity = validator.validateUserId(request, userId); + + UserEntity oldUserEntity = Utils.getClonedEntityForData(userEntity); + log.info("Current user details: {}", userEntity); + log.info("New user details: {}", userReq); + + HubEntity hubEntity = hubService.valdateHub(userEntity.getHub().getId()); + String beneficiaryRoleType = RoleStatusEnum.ROLE_BENEFICIARY.getValue(); + + if (validator.checkIsBeneficiary()) { + // Validate if the new email already exists for another beneficiary in the same hub + boolean emailExistsForBeneficiary = userRepository.existsByEmailIgnoreCaseForBeneficiaries( + userReq.getEmail(), hubEntity.getUniqueUuid(), beneficiaryRoleType); + + if (emailExistsForBeneficiary) { + throw new CustomValidationException(Status.VALIDATION_ERROR, + Translator.toLocale(GepafinConstant.EMAIL_ALREADY_EXISTS)); + } + + setIfUpdated(userEntity::getEmail,userEntity::setEmail,userReq.getEmail()); // Only update email if role is beneficiary + } + + BeneficiaryEntity oldBeneficiaryEntity = null; + + if(userEntity.getBeneficiary()!=null) { + oldBeneficiaryEntity = Utils.getClonedEntityForData(userEntity.getBeneficiary()); + setIfUpdated(userEntity.getBeneficiary()::getFirstName, userEntity.getBeneficiary()::setFirstName, userReq.getFirstName()); + setIfUpdated(userEntity.getBeneficiary()::getLastName, userEntity.getBeneficiary()::setLastName, userReq.getLastName()); + setIfUpdated(userEntity.getBeneficiary()::getOrganization, userEntity.getBeneficiary()::setOrganization, userReq.getOrganization()); + setIfUpdated(userEntity.getBeneficiary()::getAddress, userEntity.getBeneficiary()::setAddress, userReq.getAddress()); + setIfUpdated(userEntity.getBeneficiary()::getPhoneNumber, userEntity.getBeneficiary()::setPhoneNumber, userReq.getPhoneNumber()); + setIfUpdated(userEntity.getBeneficiary()::getDateOfBirth, userEntity.getBeneficiary()::setDateOfBirth, userReq.getDateOfBirth()); + setIfUpdated(userEntity.getBeneficiary()::getCity, userEntity.getBeneficiary()::setCity, userReq.getCity()); + setIfUpdated(userEntity.getBeneficiary()::getCountry, userEntity.getBeneficiary()::setCountry, userReq.getCountry()); + + /** This code is responsible for adding a version history log for the "Update beneficiary details " operation **/ + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(oldBeneficiaryEntity).newData(userEntity.getBeneficiary()).build()); + } + + userEntity = userRepository.save(userEntity); + + /** This code is responsible for adding a version history log for the "Update user details by beneficiary" operation **/ + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(oldUserEntity).newData(userEntity).build()); + + return convertUserEntityToUserResponse(userEntity); + } + + + + + } diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/UpdateUserReqForBeneficiary.java b/src/main/java/net/gepafin/tendermanagement/model/request/UpdateUserReqForBeneficiary.java new file mode 100644 index 00000000..3516db8f --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/request/UpdateUserReqForBeneficiary.java @@ -0,0 +1,18 @@ +package net.gepafin.tendermanagement.model.request; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class UpdateUserReqForBeneficiary { + private String firstName; + private String lastName; + private String email; + private String phoneNumber; + private String organization; + private String address; + private String city; + private String country; + private LocalDateTime dateOfBirth; +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/UserService.java b/src/main/java/net/gepafin/tendermanagement/service/UserService.java index 6a92a667..d13d8dff 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/UserService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/UserService.java @@ -47,4 +47,6 @@ public interface UserService { public UserEntity getUserEntityById(Long userId); List getAllUsers(HttpServletRequest request, List roleIds); + UserResponseBean updateUserDetails(HttpServletRequest request, Long userId, UpdateUserReqForBeneficiary userReq); + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java index b959ba61..320cb616 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java @@ -130,4 +130,10 @@ public class UserServiceImpl implements UserService { UserEntity user=validator.validateUser(request); return userDao.getAllUsers(user, roleIds); } + + @Override + @Transactional(rollbackFor = Exception.class) + public UserResponseBean updateUserDetails(HttpServletRequest request, Long userId, UpdateUserReqForBeneficiary userReq) { + return userDao.updateUserDetails(request , userId, userReq); + } } \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java index 6dc45bec..b5517cd6 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java @@ -47,7 +47,7 @@ public interface UserApi { return new ResponseEntity>(HttpStatus.NOT_IMPLEMENTED); } - @Operation(summary = "Api to update user", + @Operation(summary = "Api to update user (Only for super admin)", responses = { @ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { @@ -243,6 +243,24 @@ public interface UserApi { @RequestMapping("favicon.ico") @ResponseBody void returnNoFavicon(); + + @Operation(summary = "Api to update user", + responses = { + @ApiResponse(responseCode = "200", description = "OK"), + @ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { + @ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE)})), + @ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { + @ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE)})), + @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { + @ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE)}))}) + @RequestMapping(value = "/{userId}/update-details", + produces = {"application/json"}, + method = RequestMethod.PUT) + default ResponseEntity> updateUserDetails(HttpServletRequest request, + @Parameter(description = "The user id", required = true) @PathVariable("userId") Long userId, + @Parameter(description = "User request object", required = true) @Valid @RequestBody UpdateUserReqForBeneficiary userReq) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java index 0d649943..35088a3b 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java @@ -247,5 +247,21 @@ public class UserApiController implements UserApi { public void returnNoFavicon() { // Do nothing } - + + @Override + public ResponseEntity> updateUserDetails(HttpServletRequest request, + @PathVariable("userId") Long userId, + @Valid @RequestBody UpdateUserReqForBeneficiary userReq) { + log.info("Update User for Beneficiary- User ID: {}, Request Body: {}", userId, userReq); + + /** This code is responsible for "Updating user details by beneficiary" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.UPDATE) + .actionContext(UserActionContextEnum.UPDATE_USER_DETAILS).build()); + + UserResponseBean updatedUser = userService.updateUserDetails(request, userId, userReq); + + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(updatedUser, Status.SUCCESS, Translator.toLocale(GepafinConstant.USER_UPDATED_SUCCESS_MSG))); + } + } \ No newline at end of file