From e8a59ce277e3ff2336c5aa957cf53c638709cba7 Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 18 Nov 2025 15:01:45 +0530 Subject: [PATCH 01/33] Resolved conflicts --- .../constants/GepafinConstant.java | 4 +- .../tendermanagement/dao/ApplicationDao.java | 61 +++++++++++++++++++ .../dao/ApplicationEvaluationDao.java | 10 +++ .../tendermanagement/dao/AppointmentDao.java | 4 +- .../dao/CompanyDocumentDao.java | 2 +- .../entities/ApplicationEntity.java | 3 + .../enums/UserActionContextEnum.java | 3 +- .../CompanyDocumentRepository.java | 2 +- .../service/ApplicationService.java | 2 +- .../service/impl/ApplicationServiceImpl.java | 6 ++ .../web/rest/api/ApplicationApi.java | 13 ++++ .../api/impl/ApplicationApiController.java | 11 ++++ .../db/changelog/db.changelog-1.0.0.xml | 6 ++ src/main/resources/message_en.properties | 3 + src/main/resources/message_it.properties | 2 + 15 files changed, 124 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 4a887ac0..8ff0c836 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -634,8 +634,8 @@ public class GepafinConstant { public static final String MAIL_SENT_SUCCESSFULLY="mail.send.successfully"; public static final String EMAIL_LOG_FETCHED="email.log.fetched"; public static final String APPLICATION_AMENDMENT_APPROPIATE_STATUS="amendment.appropiate.status"; - - + public static final String UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION_MSG="upload.company.document.to.application"; + public static final String COMPANY_DOCUMENT_NOT_FOUND_WITH_IDS="company.document.not.found.with.ids"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index d193c953..aa65357a 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -232,6 +232,15 @@ public class ApplicationDao { @Autowired private ApplicationContractRepository applicationContractRepository; + @Autowired + private CompanyDocumentRepository companyDocumentRepository; + + @Autowired + private AppointmentDao appointmentDao; + + @Autowired + private DocumentDao documentDao; + public final Random random = new Random(); public ApplicationResponseBean createApplication(HttpServletRequest request, ApplicationRequestBean applicationRequestBean, Long formId, Long applicationId) { @@ -2630,4 +2639,56 @@ public class ApplicationDao { } return Collections.emptyList(); } + public void uploadCompanyDocumentsToApplication( Long applicationId,List companyDocumentIds,UserEntity user) { + ApplicationEntity applicationEntity=validateApplication(applicationId); + ApplicationEntity oldApplication = Utils.getClonedEntityForData(applicationEntity); + List companyDocumentEntities=validateCompanyDocuments(companyDocumentIds); + List multipartFiles=new ArrayList<>(); + for(CompanyDocumentEntity companyDocumentEntity:companyDocumentEntities) { + try { + File localFile = appointmentDao.downloadFileFromS3(companyDocumentEntity.getFilePath()); + MultipartFile multipartFile = appointmentDao.convertFileToMultipartFile(localFile); + multipartFiles.add(multipartFile); + } catch (Exception e) { + throw new RuntimeException(e); + } + List documentResponseBeans=documentDao.uploadFiles(user.getId(),multipartFiles,applicationId,DocumentSourceTypeEnum.APPLICATION,DocumentTypeEnum.DOCUMENT); + List initialDocumentIds = documentResponseBeans.stream() + .map(DocumentResponseBean::getId) + .collect(Collectors.toList()); + String initialDocumentId = initialDocumentIds.stream() + .map(String::valueOf) + .collect(Collectors.joining(",")); + applicationEntity.setCompanyDocument(initialDocumentId); + applicationRepository.save(applicationEntity); + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplication).newData(applicationEntity).build()); + } + } + + public List validateCompanyDocuments(List ids) { + + List documents = + companyDocumentRepository.findByIdInAndIsDeletedFalseAndStatus(ids,CompanyDocumentStatusEnum.VALID.getValue()); + + Set foundIds = documents.stream() + .map(CompanyDocumentEntity::getId) + .collect(Collectors.toSet()); + + List missingIds = ids.stream() + .filter(id -> !foundIds.contains(id)) + .toList(); + + if (!missingIds.isEmpty()) { + log.warn("Company Document(s) not found with IDs {}", missingIds); + throw new ResourceNotFoundException( + Status.NOT_FOUND, + MessageFormat.format( + Translator.toLocale(GepafinConstant.COMPANY_DOCUMENT_NOT_FOUND_WITH_IDS), + missingIds + )); + } + + return documents; + } + } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index 121cd15e..a07cb582 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -630,6 +630,16 @@ public class ApplicationEvaluationDao { processedFieldIds.add(fieldResponse.getId()); }); + List companyDocuments=applicationAmendmentRequestDao.getDocumentResponseBean(applicationFormEntities.get(0).getApplication().getCompanyDocument()); + + for(DocumentResponseBean documentResponseBean:companyDocuments) { + FieldResponse companyFieldResponse = new FieldResponse(); + companyFieldResponse.setId("COMPANY"); + companyFieldResponse.setValid(Boolean.TRUE); + companyFieldResponse.setLabel(documentResponseBean.getName()); + companyFieldResponse.setFileDetail(List.of(documentResponseBean)); + validFieldResponses.add(companyFieldResponse); + } response.setFiles(validFieldResponses); } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 5b6bf8c1..aa81aab5 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -1355,13 +1355,13 @@ public class AppointmentDao { return input; } - public static MultipartFile convertFileToMultipartFile(File file) throws IOException { + public MultipartFile convertFileToMultipartFile(File file) throws IOException { FileInputStream input = new FileInputStream(file); return new MockMultipartFile(file.getName(), file.getName(), MediaType.APPLICATION_OCTET_STREAM_VALUE, input); } - private File downloadFileFromS3(String fileUrl) throws Exception { + public File downloadFileFromS3(String fileUrl) throws Exception { String key = amazonS3Service.extractS3KeyFromUrl(fileUrl); String fileName = extractFileName(key); String folderPath = key.substring(0, key.lastIndexOf("/")); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java index c034a985..687917df 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java @@ -354,7 +354,7 @@ public class CompanyDocumentDao { builder.equal(root.get("userWithCompany").get("userId"), userId) ); predicate = builder.and(predicate, builder.or(companyPredicate, personalPredicate)); - + predicate = builder.equal(root.get("status"), CompanyDocumentStatusEnum.VALID.getValue()); return predicate; }; } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationEntity.java index 8b8c64d7..7670d520 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationEntity.java @@ -87,4 +87,7 @@ public class ApplicationEntity extends BaseEntity { @Column(name = "REJECTED_DOCUMENT") private String rejectedDocument; + + @Column(name = "COMPANY_DOCUMENT") + private String companyDocument; } \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java index 9401834e..9092c769 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java @@ -232,7 +232,8 @@ public enum UserActionContextEnum { FETCH_APPLICATION_CONTRACT_BY_BENEFICIARY_USER_ID("FETCH_APPLICATION_CONTRACT_BY_BENEFICIARY_USER_ID"), SEND_PEC_MAIL("SEND_PEC_MAIL"), FETCH_EMAIL_LOG("FETCH_EMAIL_LOG"), - FETCH_ALL_EMAIL_LOG("FETCH_ALL_EMAIL_LOG"); + FETCH_ALL_EMAIL_LOG("FETCH_ALL_EMAIL_LOG"), + UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION("UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION"); private final String value; diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/CompanyDocumentRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/CompanyDocumentRepository.java index 30a49410..47e0a14f 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/CompanyDocumentRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/CompanyDocumentRepository.java @@ -35,7 +35,7 @@ public interface CompanyDocumentRepository extends JpaRepository findByCategoryEntityId(Long categoryId); - + List findByIdInAndIsDeletedFalseAndStatus(List ids,String status); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java index 9cc2ea22..a1206ee3 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java @@ -54,5 +54,5 @@ public interface ApplicationService { public byte[] downloadRankingCsv(HttpServletRequest request, Long callId); - + public void uploadCompanyDocumentsToApplication(HttpServletRequest request, Long applicationId, List companyDocumentIds); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java index e311340e..12769ac7 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java @@ -182,4 +182,10 @@ public class ApplicationServiceImpl implements ApplicationService { UserEntity userEntity = validator.validateUser(request); return applicationDao.downloadRankingCsv(callId,userEntity); } + + @Override + public void uploadCompanyDocumentsToApplication(HttpServletRequest request, Long applicationId, List companyDocumentIds) { + UserEntity userEntity = validator.validateUser(request); + applicationDao.uploadCompanyDocumentsToApplication(applicationId,companyDocumentIds,userEntity); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java index b64b3951..989088d5 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java @@ -267,6 +267,19 @@ public interface ApplicationApi { public ResponseEntity downloadRankingCsv( HttpServletRequest request, @Parameter(description = "The call id", required = true) @PathVariable(value = "callId", required = true) Long callId); + @Operation(summary = "Api to upload company documents in application", + 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)})) + }) + @GetMapping(value = "/{applicationId}/companyDocuments") + public ResponseEntity> uploadCompanyDocumentsToApplication( + HttpServletRequest request,@Parameter(description = "The application id", required = true) @PathVariable(value = "applicationId", required = true) Long applicationId, @Parameter(description = "The company document id", required = true) @RequestParam("companyDocumentIds") List companyDocumentIds); } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java index 76946420..c5817500 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java @@ -275,4 +275,15 @@ public class ApplicationApiController implements ApplicationApi { .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(csvBytes); } + + @Override + public ResponseEntity> uploadCompanyDocumentsToApplication(HttpServletRequest request, Long applicationId,List companyDocumentIds) { + loggingUtil.logUserAction( + UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.UPDATE).actionContext(UserActionContextEnum.UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION).build()); + + applicationService.uploadCompanyDocumentsToApplication(request, applicationId,companyDocumentIds); + + return ResponseEntity.status(HttpStatus.OK).body(new Response<>(null, Status.SUCCESS, Translator.toLocale(GepafinConstant.UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION_MSG))); + + } } 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 1f2ebb22..9c5aa1de 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 @@ -3167,4 +3167,10 @@ + + + + + + diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index 39cec228..7e930753 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -427,5 +427,8 @@ subject.body.required=Subject and body is required to create contract. mail.send.successfully=Mail sent succesfully. email.log.fetched=Email log fetched successfully. amendment.appropiate.status=Application amendment is not in appropiate status for this operation. +upload.company.document.to.application=Uploaded company document to application successfully. +company.document.not.found.with.ids=Company document not found. Missing IDs: {0} + diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 3cd42992..d88b196c 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -418,3 +418,5 @@ subject.body.required=Per creare un contratto sono necessari oggetto e corpo. mail.send.successfully=Email inviata con successo. email.log.fetched=Registro email recuperato correttamente. amendment.appropiate.status=L'emendamento dell'applicazione non � in stato appropriato per questa operazione. +upload.company.document.to.application=Documento aziendale caricato correttamente nell'applicazione. +company.document.not.found.with.ids=Documento aziendale non trovato. ID mancanti: {0} From feca1e86bf11cbc33c76adcf076c46de42466423 Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 18 Nov 2025 16:59:43 +0530 Subject: [PATCH 02/33] Fixed issue in company document get endpoint --- .../dao/CompanyDocumentDao.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java index 687917df..ca266679 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java @@ -333,6 +333,11 @@ public class CompanyDocumentDao { predicate = builder.and(predicate, builder.isFalse(root.get("isDeleted"))); + predicate = builder.and( + predicate, + builder.notEqual(root.get("status"), CompanyDocumentStatusEnum.EXPIRED.getValue()) + ); + if (typeEnum != null) { if (typeEnum == CompanyDocumentTypeEnum.COMPANY_DOCUMENT) { // Case 1: Fetch only COMPANY_DOCUMENT type documents for the given company @@ -346,15 +351,15 @@ public class CompanyDocumentDao { builder.equal(root.get("userWithCompany").get("userId"), userId) ); } + }else { + // Case 3: If typeEnum is null, fetch all documents for the company and personal documents for the user + Predicate companyPredicate = builder.equal(root.get("companyId"), companyId); + Predicate personalPredicate = builder.and( + builder.equal(root.get("type"), CompanyDocumentTypeEnum.PERSONAL_DOCUMENT.getValue()), + builder.equal(root.get("userWithCompany").get("userId"), userId) + ); + predicate = builder.and(predicate, builder.or(companyPredicate, personalPredicate)); } - // Case 3: If typeEnum is null, fetch all documents for the company and personal documents for the user - Predicate companyPredicate = builder.equal(root.get("companyId"), companyId); - Predicate personalPredicate = builder.and( - builder.equal(root.get("type"), CompanyDocumentTypeEnum.PERSONAL_DOCUMENT.getValue()), - builder.equal(root.get("userWithCompany").get("userId"), userId) - ); - predicate = builder.and(predicate, builder.or(companyPredicate, personalPredicate)); - predicate = builder.equal(root.get("status"), CompanyDocumentStatusEnum.VALID.getValue()); return predicate; }; } From d8538b0b358213259f2392a7b12990562c16d67c Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 18 Nov 2025 19:37:03 +0530 Subject: [PATCH 03/33] Disabled evaluation scheduler and increased evaluation duration --- .../gepafin/tendermanagement/dao/ApplicationEvaluationDao.java | 2 +- .../scheduler/ApplicationEvaluationScheduler.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index a07cb582..4379fbc8 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -170,7 +170,7 @@ public class ApplicationEvaluationDao { Long hubId = application.getHubId(); HubEntity hub = hubService.valdateHub(hubId); - Long initialDays = (hub != null) ? hub.getEvaluationExpirationDays() : 30L; + Long initialDays = (hub != null) ? hub.getEvaluationExpirationDays() : 365L; entity.setApplicationId(application.getId()); entity.setAssignedApplicationsEntity(assignedApplications); diff --git a/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationEvaluationScheduler.java b/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationEvaluationScheduler.java index 413efe37..dd32315f 100644 --- a/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationEvaluationScheduler.java +++ b/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationEvaluationScheduler.java @@ -45,7 +45,7 @@ public class ApplicationEvaluationScheduler { private static final Logger log = LoggerFactory.getLogger(ApplicationEvaluationScheduler.class); - @Scheduled(cron = "0 0 2 * * ?") // Runs daily at midnight +// @Scheduled(cron = "0 0 2 * * ?") // Runs daily at midnight public void updateExpiredEvaluations() { log.info("Starting the Application Evaluation Expiration scheduler..."); try { From b52b82d8de60bfecb62abd8adf6a3234f91724c4 Mon Sep 17 00:00:00 2001 From: rajesh Date: Wed, 19 Nov 2025 12:19:49 +0530 Subject: [PATCH 04/33] Added companyId in evaluation response --- .../gepafin/tendermanagement/dao/ApplicationEvaluationDao.java | 3 ++- .../model/response/ApplicationEvaluationFormResponse.java | 1 + .../model/response/ApplicationEvaluationResponse.java | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index 4379fbc8..cb052189 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -205,7 +205,7 @@ public class ApplicationEvaluationDao { CompanyEntity company=companyService.validateCompany(entity.getAssignedApplicationsEntity().getApplication().getCompanyId()); setAmendmentDetails(entity,response); - + response.setCompanyId(company.getId()); response.setCompanyVatNumber(company.getVatNumber()); response.setCompanyCodiceAteco(company.getCodiceAteco()); setCriteriaResponses(entity, response, evaluationCriterias); @@ -2434,6 +2434,7 @@ public class ApplicationEvaluationDao { if (evaluationFormEntity != null) { response.setApplicationEvaluationFormResponse(convertEvaluationFormToResponse(evaluationFormEntity, evaluationEntity)); } + response.setCompanyId(company.getId()); response.setCompanyVatNumber(company.getVatNumber()); response.setCompanyCodiceAteco(company.getCodiceAteco()); response.setSignedDocument(getApplicationSignedDocument(evaluationEntity)); diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationFormResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationFormResponse.java index 2e18339a..3903daed 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationFormResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationFormResponse.java @@ -15,6 +15,7 @@ public class ApplicationEvaluationFormResponse { private Long id; private Long applicationId; + private Long companyId; private ApplicationStatusTypeEnum applicationStatus; private Long assignedApplicationId; private String note; diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java index 742edae9..d05f5816 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java @@ -15,6 +15,7 @@ public class ApplicationEvaluationResponse { private Long id; private Long applicationId; + private Long companyId; private ApplicationStatusTypeEnum applicationStatus; private Long assignedApplicationId; private String note; From e69c6ba8e073f6a421e8ce7fcf19f76b1d1688f6 Mon Sep 17 00:00:00 2001 From: rajesh Date: Wed, 19 Nov 2025 13:06:44 +0530 Subject: [PATCH 05/33] Updated code for company document --- .../java/net/gepafin/tendermanagement/dao/ApplicationDao.java | 2 +- .../repositories/CompanyDocumentRepository.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index aa65357a..d7a5661a 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -2668,7 +2668,7 @@ public class ApplicationDao { public List validateCompanyDocuments(List ids) { List documents = - companyDocumentRepository.findByIdInAndIsDeletedFalseAndStatus(ids,CompanyDocumentStatusEnum.VALID.getValue()); + companyDocumentRepository.findByIdInAndIsDeletedFalseAndStatusNot(ids,CompanyDocumentStatusEnum.EXPIRED.getValue()); Set foundIds = documents.stream() .map(CompanyDocumentEntity::getId) diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/CompanyDocumentRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/CompanyDocumentRepository.java index 47e0a14f..c37b993a 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/CompanyDocumentRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/CompanyDocumentRepository.java @@ -35,7 +35,7 @@ public interface CompanyDocumentRepository extends JpaRepository findByCategoryEntityId(Long categoryId); - List findByIdInAndIsDeletedFalseAndStatus(List ids,String status); + List findByIdInAndIsDeletedFalseAndStatusNot(List ids, String status); } From 763aa8ab09b94c2afd5cc3ca21115ef4dd1b7544 Mon Sep 17 00:00:00 2001 From: rajesh Date: Wed, 19 Nov 2025 16:34:43 +0530 Subject: [PATCH 06/33] Fixed issue of email --- .../net/gepafin/tendermanagement/dao/EmailNotificationDao.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java index 4bf00449..117c3b4a 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java @@ -257,7 +257,7 @@ public class EmailNotificationDao { //SMTP emailLogRequest.setAttachments(attachmentRequests); EmailLogEntity emailLogEntity=emailLogDao.createEmailLog(emailLogRequest,urls); - sendMail(null, subject, body, List.of(rinaldoEmail), emailLogEntity); + sendMail(applicationEntity.getHubId(), subject, body, List.of(rinaldoEmail), emailLogEntity); } if (applicationEvaluationEntity.isPresent()) { Long preInstructorId = applicationEvaluationEntity.get().getUserId(); // Assuming UserEntity has an email field From 26e7430f9314a303ac03bf067c65e40035a984f7 Mon Sep 17 00:00:00 2001 From: rajesh Date: Wed, 19 Nov 2025 17:31:01 +0530 Subject: [PATCH 07/33] Disabled director profile feature --- .../dao/EmailNotificationDao.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java index 4bf00449..b0aec45d 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java @@ -423,14 +423,14 @@ public class EmailNotificationDao { Boolean isSendEmail=Boolean.TRUE; HubEntity hubEntity = hubRepository.findById(hubId).orElseThrow(() -> new IllegalArgumentException("Invalid Hub ID: " + hubId)); - if(Boolean.TRUE.equals(hubEntity.getUniqueUuid().equals(defaultHubUuid))){ - if(Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_TECHNICAL_EVALUATION_REJECTED.getValue())) - || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_ADMISSIBLE.getValue())) - || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_REJECTED.getValue())) - || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue()))) { - isSendEmail = Boolean.FALSE; - } - } +// if(Boolean.TRUE.equals(hubEntity.getUniqueUuid().equals(defaultHubUuid))){ +// if(Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_TECHNICAL_EVALUATION_REJECTED.getValue())) +// || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_ADMISSIBLE.getValue())) +// || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_REJECTED.getValue())) +// || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue()))) { +// isSendEmail = Boolean.FALSE; +// } +// } if (recipientEmails.stream().anyMatch(email -> email.equals(GepafinConstant.RINALDO_EMAIL))) { emailConfig.setEmailServiceType(EmailServiceTypeEnum.SYSTEM_EMAIL_SERVICE.getValue()); From 6d1b8dc0418d21c0d8fce3cece4aab7a7c2803df Mon Sep 17 00:00:00 2001 From: rajesh Date: Wed, 19 Nov 2025 15:07:43 +0530 Subject: [PATCH 08/33] Allowed permission to instructor for accessing company document API --- src/main/java/net/gepafin/tendermanagement/util/Validator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/net/gepafin/tendermanagement/util/Validator.java b/src/main/java/net/gepafin/tendermanagement/util/Validator.java index a68dc1bd..895e63d9 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Validator.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Validator.java @@ -92,6 +92,8 @@ public class Validator { return companyEntity; } else if (checkIsInstructorManager()) { return companyEntity; + }else if (checkIsPreInstructor()) { + return companyEntity; } Map userInfo = tokenProvider.getUserInfoAndUserIdFromToken(request); companyService.validateUserWithCompny(getUserId(userInfo), companyId); From 551c4b04dff7091656bea4a060dafe54de1ed997 Mon Sep 17 00:00:00 2001 From: rajesh Date: Thu, 20 Nov 2025 15:09:20 +0530 Subject: [PATCH 09/33] Enabled company document for director --- .../net/gepafin/tendermanagement/dao/CompanyDocumentDao.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java index ca266679..2eba35f5 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java @@ -314,7 +314,9 @@ public class CompanyDocumentDao { public List getAllCompanyDocument(UserEntity user , Long companyId, CompanyDocumentTypeEnum typeEnum){ log.info("Fetching all company documents for Company ID '{}', User ID '{}', Type '{}'", companyId, user.getId(), typeEnum); - validator.validateUserWithCompany(request, companyId); + if(Boolean.TRUE.equals(validator.checkIsBeneficiary())) { + validator.validateUserWithCompany(request, companyId); + } companyService.validateCompany(companyId); Specification spec = filterCompanyDocuments(companyId, user.getId(), typeEnum); From 0d0aafe31b0de03b1662313ee95ae2955f609d48 Mon Sep 17 00:00:00 2001 From: rajesh Date: Wed, 28 Jan 2026 20:30:25 +0530 Subject: [PATCH 10/33] Updated password of NDG appointment --- src/main/resources/application-local.properties | 4 ++-- src/main/resources/application-production.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index 9cd21534..b61da230 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -1,5 +1,5 @@ # DataSource Configuration -spring.datasource.url=jdbc:postgresql://localhost:5432/gepafin_local +spring.datasource.url=jdbc:postgresql://localhost:5432/postgres spring.datasource.username=postgres spring.datasource.password=root spring.datasource.driver-class-name=org.postgresql.Driver @@ -17,7 +17,7 @@ default.hub.uuid=p4lk3bcx1RStqTaIVVbXs appointment.base.url=https://demo.galileonetwork.it/gateway/rest appointment.portal.user=UtenzaAPIPortal@621 -appointment.portal.password=u13nzaAP1P0rtal! +appointment.portal.password=Sardegna2025! appointment.portal.source=GEPAFINPORTAL appointment.portal.context=GEPAFINPORTAL diff --git a/src/main/resources/application-production.properties b/src/main/resources/application-production.properties index b159155c..a38014af 100644 --- a/src/main/resources/application-production.properties +++ b/src/main/resources/application-production.properties @@ -26,7 +26,7 @@ default.hub.uuid=p4lk3bcx1RStqTaIVVbXs #Login to Odessa, Appointment Creation, Upload document Configuration appointment.base.url=https://prd.galileonetwork.it/gateway/rest appointment.portal.user=UtenzaAPIPortal@621 -appointment.portal.password=Valeria2016! +appointment.portal.password=Gepafin2025! appointment.portal.source=GEPAFINPORTAL appointment.portal.context=GEPAFINPORTAL From b75dcf6532c48246a31c5c9fc5d915466900be83 Mon Sep 17 00:00:00 2001 From: rajesh Date: Wed, 28 Jan 2026 20:37:24 +0530 Subject: [PATCH 11/33] Updated code --- src/main/resources/application-local.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index b61da230..3563166f 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -1,5 +1,5 @@ # DataSource Configuration -spring.datasource.url=jdbc:postgresql://localhost:5432/postgres +spring.datasource.url=jdbc:postgresql://localhost:5432/gepafin_local spring.datasource.username=postgres spring.datasource.password=root spring.datasource.driver-class-name=org.postgresql.Driver From c56ff7658cf761a13239ea9a67eec95aea50eb5b Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 3 Feb 2026 15:24:26 +0530 Subject: [PATCH 12/33] Removed condition of APPOINTMENT status --- .../gepafin/tendermanagement/dao/ApplicationEvaluationDao.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index cb052189..db30b057 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -1976,7 +1976,8 @@ public class ApplicationEvaluationDao { List responses = new ArrayList<>(); - if(newStatus.equals(ApplicationStatusForEvaluation.ADMISSIBLE) && Boolean.TRUE.equals(application.getStatus().equals(ApplicationStatusTypeEnum.APPOINTMENT.getValue()))){ +// if(newStatus.equals(ApplicationStatusForEvaluation.ADMISSIBLE) && Boolean.TRUE.equals(application.getStatus().equals(ApplicationStatusTypeEnum.APPOINTMENT.getValue()))){ + if(newStatus.equals(ApplicationStatusForEvaluation.ADMISSIBLE)){ application.setStatus(newStatus.getValue()); log.info("Status updated to ADMISSIBLE for applicationId: " + application.getId()); emailNotificationDao.sendAdmissibilityNotificationEmailForAdmissibleApplication(application); From ce0320ced6af3cb904ae8051091e6fcdc0f5cbba Mon Sep 17 00:00:00 2001 From: rajesh Date: Thu, 12 Feb 2026 14:51:32 +0530 Subject: [PATCH 13/33] Enabled the mail functionality for director profile --- .../dao/EmailNotificationDao.java | 16 ++++++++-------- .../tendermanagement/enums/RoleStatusEnum.java | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java index df18ef35..117c3b4a 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java @@ -423,14 +423,14 @@ public class EmailNotificationDao { Boolean isSendEmail=Boolean.TRUE; HubEntity hubEntity = hubRepository.findById(hubId).orElseThrow(() -> new IllegalArgumentException("Invalid Hub ID: " + hubId)); -// if(Boolean.TRUE.equals(hubEntity.getUniqueUuid().equals(defaultHubUuid))){ -// if(Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_TECHNICAL_EVALUATION_REJECTED.getValue())) -// || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_ADMISSIBLE.getValue())) -// || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_REJECTED.getValue())) -// || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue()))) { -// isSendEmail = Boolean.FALSE; -// } -// } + if(Boolean.TRUE.equals(hubEntity.getUniqueUuid().equals(defaultHubUuid))){ + if(Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_TECHNICAL_EVALUATION_REJECTED.getValue())) + || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_ADMISSIBLE.getValue())) + || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_REJECTED.getValue())) + || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue()))) { + isSendEmail = Boolean.FALSE; + } + } if (recipientEmails.stream().anyMatch(email -> email.equals(GepafinConstant.RINALDO_EMAIL))) { emailConfig.setEmailServiceType(EmailServiceTypeEnum.SYSTEM_EMAIL_SERVICE.getValue()); diff --git a/src/main/java/net/gepafin/tendermanagement/enums/RoleStatusEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/RoleStatusEnum.java index 0891dc93..e332583f 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/RoleStatusEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/RoleStatusEnum.java @@ -9,7 +9,8 @@ public enum RoleStatusEnum { ROLE_PRE_INSTRUCTOR("ROLE_PRE_INSTRUCTOR"), ROLE_GEPAFIN_OPERATOR("ROLE_GEPAFIN_OPERATOR"), ROLE_INSTRUCTOR_MANAGER("ROLE_INSTRUCTOR_MANAGER"), - ROLE_CONFIDI("ROLE_CONFIDI"); + ROLE_CONFIDI("ROLE_CONFIDI"), + ROLE_DIRECTOR("ROLE_DIRECTOR"); private String value; From 7a1f3dd1e8ea841c1e6385fb37f64559f08f137d Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 16 Feb 2026 21:10:34 +0530 Subject: [PATCH 14/33] Removed calculation logic from the evaluation form --- .../gepafin/tendermanagement/dao/ApplicationEvaluationDao.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index db30b057..4727893f 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -2277,7 +2277,7 @@ public class ApplicationEvaluationDao { } Utils.setIfUpdated(applicationEvaluationFormFieldEntity::getFieldId, applicationEvaluationFormFieldEntity::setFieldId, applicationFormFieldRequestBean.getFieldId()); List contentBeans = Utils.convertJsonStringToList(evaluationFormEntity.getContent(), ContentResponseBean.class); - calculationProcessForFormula(applicationEvaluationFormEntity,contentBeans,applicationFormFieldRequestBean,fieldValidator); +// calculationProcessForFormula(applicationEvaluationFormEntity,contentBeans,applicationFormFieldRequestBean,fieldValidator); if (applicationFormFieldRequestBean.getFieldValue() != null) { applicationEvaluationFormFieldEntity.setFieldValue(Utils.convertObjectToJsonString(applicationFormFieldRequestBean.getFieldValue())); } else { From 05f74b37281ee6ff698d7b1730f2aa17e53d5177 Mon Sep 17 00:00:00 2001 From: rajesh Date: Fri, 20 Feb 2026 16:43:20 +0530 Subject: [PATCH 15/33] Fixed document issue in mail sending API --- .../net/gepafin/tendermanagement/util/S3DocxProcessor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/util/S3DocxProcessor.java b/src/main/java/net/gepafin/tendermanagement/util/S3DocxProcessor.java index 86037d8f..999f44b8 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/S3DocxProcessor.java +++ b/src/main/java/net/gepafin/tendermanagement/util/S3DocxProcessor.java @@ -50,9 +50,9 @@ public class S3DocxProcessor { try (S3Object s3Object = s3Client.getObject(bucket, key); InputStream originalStream = new BufferedInputStream(s3Object.getObjectContent())) { byte[] updatedBytes=null; - if (isDocxFile(originalStream)) { - log.warn("Skipping non-DOCX file from S3: bucket={}, key={}", bucket, key); - updatedBytes = replacePlaceholders(originalStream, replacements); + if(Boolean.FALSE.equals(key.endsWith(".zip")) && (replacements!=null && Boolean.FALSE.equals(replacements.isEmpty())) && isDocxFile(originalStream)) { + log.warn("Skipping non-DOCX file from S3: bucket={}, key={}", bucket, key); + updatedBytes = replacePlaceholders(originalStream, replacements); }else { // non-DOCX → just copy raw stream updatedBytes = originalStream.readAllBytes(); From f0c15b928ebe29e8e779bcaaf473816aed8d2257 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 23 Feb 2026 12:53:06 +0530 Subject: [PATCH 16/33] Resolved conflict --- .../constants/GepafinConstant.java | 3 ++ .../dao/ApplicationAmendmentRequestDao.java | 7 ++++ .../dao/EmailNotificationDao.java | 8 +++- .../ApplicationAmendmentRequestEntity.java | 7 ++++ .../entities/SystemEmailTemplatesEntity.java | 3 +- .../enums/AmendmentDocumentTypeEnum.java | 4 +- .../enums/EmailScenarioTypeEnum.java | 1 + .../ApplicationAmendmentSpecialRequest.java | 4 ++ ...ApplicationAmendmentRequestRepository.java | 2 + .../service/impl/PecEmailService.java | 40 +++++++++++++------ .../db/changelog/db.changelog-1.0.0.xml | 21 ++++++++++ ...ecial_amendment_blue_tongue_23_02_2026.sql | 11 +++++ src/main/resources/message_en.properties | 3 +- src/main/resources/message_it.properties | 1 + 14 files changed, 98 insertions(+), 17 deletions(-) create mode 100644 src/main/resources/db/dump/insert_system_email_template_for_special_amendment_blue_tongue_23_02_2026.sql diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 8ff0c836..74b4e221 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -636,6 +636,9 @@ public class GepafinConstant { public static final String APPLICATION_AMENDMENT_APPROPIATE_STATUS="amendment.appropiate.status"; public static final String UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION_MSG="upload.company.document.to.application"; public static final String COMPANY_DOCUMENT_NOT_FOUND_WITH_IDS="company.document.not.found.with.ids"; + public static final String REQUIRED_AMOUNT_FIELD_NOT_PROVIDED = "amount.field.not.provided"; + + } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index d8243429..bb9a2b29 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -1859,6 +1859,11 @@ public class ApplicationAmendmentRequestDao { ApplicationEvaluationEntity oldApplicationEvaluationEntity = Utils.getClonedEntityForData(applicationEvaluationEntity); ApplicationEntity applicationEntity=applicationDao.validateApplication(applicationEvaluationEntity.getApplicationId()); ApplicationEntity oldApplicationEntity = Utils.getClonedEntityForData(applicationEntity); + if(Boolean.TRUE.equals(applicationAmendmentRequest.getAmendmentDocumentType().equals(AmendmentDocumentTypeEnum.BLUE_TONGUE))) { + if(applicationAmendmentRequest.getBlueTongueField1()==null || applicationAmendmentRequest.getBlueTongueField2()==null){ + throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.REQUIRED_AMOUNT_FIELD_NOT_PROVIDED)); + } + } if(Boolean.FALSE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.ADMISSIBLE.getValue()))) { throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.INVALID_APPLICATION_STATUS)); @@ -1922,6 +1927,8 @@ public class ApplicationAmendmentRequestDao { protocolDao.saveProtocolEntity(protocolEntity); applicationAmendmentRequestEntity.setProtocol(protocolEntity); applicationAmendmentRequestEntity.setAmendmentDocumentType(applicationAmendmentRequest.getAmendmentDocumentType().getValue()); + applicationAmendmentRequestEntity.setBlueTongueField1(applicationAmendmentRequest.getBlueTongueField1()); + applicationAmendmentRequestEntity.setBlueTongueField2(applicationAmendmentRequest.getBlueTongueField2()); ApplicationAmendmentRequestEntity applicationAmendment = saveApplicationAmendmentRequestEntity(applicationAmendmentRequestEntity, null, VersionActionTypeEnum.INSERT); log.info("Amendment request saved with ID={}", applicationAmendment.getId()); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java index 117c3b4a..7cfb73cc 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java @@ -145,7 +145,7 @@ public class EmailNotificationDao { List attachmentRequests =new ArrayList<>(); List urls=new ArrayList<>(); List documentEntities=new ArrayList<>(); - if(systemEmailTemplateResponse.getEmailScenario().equals(EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED)) { + if(systemEmailTemplateResponse.getEmailScenario().equals(EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED) || systemEmailTemplateResponse.getEmailScenario().equals(EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE)) { if(Boolean.TRUE.equals(AmendmentDocumentTypeEnum.ALTRE_GARANZIE.getValue().equals(applicationAmendmentRequest.getAmendmentDocumentType()))){ documentEntities=documentRepository.findBySourceInAndIsDeletedFalse(List.of(applicationAmendmentRequest.getAmendmentDocumentType(),"MODELLO_AUTOCERTIFICAZIONE","MODELLO_PRIVACY")); }else { @@ -517,7 +517,11 @@ public class EmailNotificationDao { public void sendMailforSpecialAmendment(ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity,ApplicationEntity applicationEntity) { Map bodyPlaceholders = prepareEmailPlaceholders(applicationEntity, applicationAmendmentRequestEntity); - sendEmail(applicationEntity, SystemEmailTemplatesEntity.SystemEmailTemplatesEntityTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED, bodyPlaceholders, null, + SystemEmailTemplatesEntity.SystemEmailTemplatesEntityTypeEnum systemEmailTemplatesEntityTypeEnum= SystemEmailTemplatesEntity.SystemEmailTemplatesEntityTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED; + if(applicationAmendmentRequestEntity.getAmendmentDocumentType().equals(AmendmentDocumentTypeEnum.BLUE_TONGUE.getValue())){ + systemEmailTemplatesEntityTypeEnum= SystemEmailTemplatesEntity.SystemEmailTemplatesEntityTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE; + } + sendEmail(applicationEntity,systemEmailTemplatesEntityTypeEnum, bodyPlaceholders, null, applicationAmendmentRequestEntity.getId(),null); } public void sendEmailForApplicationContracted(ApplicationEntity applicationEntity,ApplicationContractEntity applicationContractEntity,UserEntity user) { diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestEntity.java index 1ccd4eed..af7f6f24 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestEntity.java @@ -5,6 +5,7 @@ import lombok.Data; import org.hibernate.annotations.Where; import net.gepafin.tendermanagement.model.response.EmailSendResponse; +import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.List; @@ -77,4 +78,10 @@ public class ApplicationAmendmentRequestEntity extends BaseEntity { @Column(name = "AMENDMENT_INITIAL_DOCUMENT") private String amendmentInitialDocument; + @Column(name = "BLUE_TONGUE_FIELD_1") + private BigDecimal blueTongueField1; + + @Column(name = "BLUE_TONGUE_FIELD_2") + private BigDecimal blueTongueField2; + } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/SystemEmailTemplatesEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/SystemEmailTemplatesEntity.java index 0cc3c6fb..4d425442 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/SystemEmailTemplatesEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/SystemEmailTemplatesEntity.java @@ -57,7 +57,8 @@ public class SystemEmailTemplatesEntity extends BaseEntity { INADMISSIBILITY_TEMPLATE("INADMISSIBILITY_NOTIFICATION"), APPLICATION_SUBMISSION_FAILURE_NOTIFICATION("APPLICATION_SUBMISSION_FAILURE_NOTIFICATION"), INADMISSIBILITY_NOTIFICATION_DUE_TO_TECHNICAL_EVALUATION_FAILURE("INADMISSIBILITY_NOTIFICATION_DUE_TO_TECHNICAL_EVALUATION_FAILURE"), - SPECIAL_APPLICATION_AMENDMENT_REQUESTED("SPECIAL_APPLICATION_AMENDMENT_REQUESTED"); + SPECIAL_APPLICATION_AMENDMENT_REQUESTED("SPECIAL_APPLICATION_AMENDMENT_REQUESTED"), + SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE("SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE"); private String value; SystemEmailTemplatesEntityTypeEnum(String value) { diff --git a/src/main/java/net/gepafin/tendermanagement/enums/AmendmentDocumentTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/AmendmentDocumentTypeEnum.java index e1e97b63..8dd53ab8 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/AmendmentDocumentTypeEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/AmendmentDocumentTypeEnum.java @@ -10,7 +10,9 @@ public enum AmendmentDocumentTypeEnum { MCC_START_UP("MCC_START_UP"), - ALTRE_GARANZIE("ALTRE_GARANZIE"); + ALTRE_GARANZIE("ALTRE_GARANZIE"), + + BLUE_TONGUE("BLUE_TONGUE"); private final String value; diff --git a/src/main/java/net/gepafin/tendermanagement/enums/EmailScenarioTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/EmailScenarioTypeEnum.java index fe8d64b2..563e91e0 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/EmailScenarioTypeEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/EmailScenarioTypeEnum.java @@ -15,6 +15,7 @@ public enum EmailScenarioTypeEnum { APPLICATION_SUBMISSION_FAILURE("APPLICATION_SUBMISSION_FAILURE"), APPLICATION_TECHNICAL_EVALUATION_REJECTED("APPLICATION_TECHNICAL_EVALUATION_REJECTED"), SPECIAL_APPLICATION_AMENDMENT_REQUESTED("SPECIAL_APPLICATION_AMENDMENT_REQUESTED"), + SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE("SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE"), APPLICATION_CONTRACT_CREATED("APPLICATION_CONTRACT_CREATED"); private final String value; diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/ApplicationAmendmentSpecialRequest.java b/src/main/java/net/gepafin/tendermanagement/model/request/ApplicationAmendmentSpecialRequest.java index 3a971a7c..673a5afa 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/request/ApplicationAmendmentSpecialRequest.java +++ b/src/main/java/net/gepafin/tendermanagement/model/request/ApplicationAmendmentSpecialRequest.java @@ -13,4 +13,8 @@ public class ApplicationAmendmentSpecialRequest { private AmendmentDocumentTypeEnum amendmentDocumentType; private String pec; + + private BigDecimal blueTongueField1; + + private BigDecimal blueTongueField2; } diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java index dc03dd43..f0f0aca4 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java @@ -156,4 +156,6 @@ public interface ApplicationAmendmentRequestRepository extends JpaRepository statusList); + ApplicationAmendmentRequestEntity findByApplicationIdAndIsDeletedFalseAndAmendmentDocumentTypeAndType(Long applicationId,String amendmentDocumentType, String type); + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/PecEmailService.java b/src/main/java/net/gepafin/tendermanagement/service/impl/PecEmailService.java index 7f29d522..be6aeb02 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/PecEmailService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/PecEmailService.java @@ -10,14 +10,13 @@ import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.dao.ApplicationDao; import net.gepafin.tendermanagement.dao.EmailLogDao; import net.gepafin.tendermanagement.dao.NotificationDao; +import net.gepafin.tendermanagement.entities.ApplicationAmendmentRequestEntity; import net.gepafin.tendermanagement.entities.ApplicationEntity; import net.gepafin.tendermanagement.entities.CompanyEntity; import net.gepafin.tendermanagement.entities.EmailLogEntity; -import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum; -import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum; -import net.gepafin.tendermanagement.enums.NotificationTypeEnum; -import net.gepafin.tendermanagement.enums.StatusTypeEnum; +import net.gepafin.tendermanagement.enums.*; import net.gepafin.tendermanagement.model.request.*; +import net.gepafin.tendermanagement.repositories.ApplicationAmendmentRequestRepository; import net.gepafin.tendermanagement.repositories.EmailLogRepository; import net.gepafin.tendermanagement.service.CompanyService; import net.gepafin.tendermanagement.util.DateTimeUtil; @@ -68,6 +67,9 @@ public class PecEmailService implements EmailService { @Autowired private EmailLogRepository emailLogRepository; + @Autowired + private ApplicationAmendmentRequestRepository applicationAmendmentRequestRepository; + @Override public void sendEmail(String subject, String body, List recipientEmails, EmailConfig emailConfig, EmailLogEntity emailLogEntity, Boolean isSendEmail) { @@ -80,7 +82,7 @@ public class PecEmailService implements EmailService { S3DocxProcessor processor = new S3DocxProcessor(s3Client); List urls = Utils.convertJsonStringToList(emailLogEntity.getAttachments(), String.class); - if(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED.getValue())) { + if(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED.getValue()) || emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE.getValue()) ) { ApplicationEntity applicationEntity = applicationDao.validateApplication(emailLogEntity.getApplicationId()); CompanyEntity company = companyService.validateCompany(applicationEntity.getCompanyId()); String amount = Utils.convertToItalianFormat(String.valueOf(applicationEntity.getAmountAccepted())); @@ -88,13 +90,27 @@ public class PecEmailService implements EmailService { if (protocolNumber == null) { protocolNumber = String.valueOf(applicationEntity.getProtocol().getProtocolNumber()); } - replacements = Map.of( - "{call_name}", applicationEntity.getCall().getName(), - "{amount_accepted}", amount, - "{pec}", "bandi.gepafin@legalmail.it", - "{company_name}", company.getCompanyName(), - "{protocol_number}", protocolNumber - ); + + replacements.put("{call_name}", applicationEntity.getCall().getName()); + replacements.put("{amount_accepted}", amount); + replacements.put("{pec}", "bandi.gepafin@legalmail.it"); + replacements.put("{company_name}", company.getCompanyName()); + replacements.put("{protocol_number}", protocolNumber); + + if (emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE.getValue())){ + ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity=applicationAmendmentRequestRepository.findByApplicationIdAndIsDeletedFalseAndAmendmentDocumentTypeAndType(applicationEntity.getId(), AmendmentDocumentTypeEnum.BLUE_TONGUE.getValue(),ApplicationAmendmentRequestTypeEnum.SPECIAL.getValue()); + if(applicationAmendmentRequestEntity!=null){ + if (applicationAmendmentRequestEntity.getBlueTongueField1() != null) { + replacements.put("{blue_tongue_field_1}", + Utils.convertToItalianFormat(applicationAmendmentRequestEntity.getBlueTongueField1().toString())); + } + + if (applicationAmendmentRequestEntity.getBlueTongueField2() != null) { + replacements.put("{blue_tongue_field_2}", + Utils.convertToItalianFormat(applicationAmendmentRequestEntity.getBlueTongueField2().toString())); + } + } + } } if (urls!=null && Boolean.FALSE.equals(urls.isEmpty())) { Map processedFiles = null; 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 9c5aa1de..32c8690d 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 @@ -3173,4 +3173,25 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/db/dump/insert_system_email_template_for_special_amendment_blue_tongue_23_02_2026.sql b/src/main/resources/db/dump/insert_system_email_template_for_special_amendment_blue_tongue_23_02_2026.sql new file mode 100644 index 00000000..11bdcc02 --- /dev/null +++ b/src/main/resources/db/dump/insert_system_email_template_for_special_amendment_blue_tongue_23_02_2026.sql @@ -0,0 +1,11 @@ +INSERT INTO gepafin_schema.system_email_template +( template_name, "type", html_content, subject, "json", "system", is_deleted, created_date, updated_date, email_scenario, hub_id) +VALUES( 'Special Amendment Creation Email', 'SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE', ' + +
+

Buongiorno, vi invitiamo a prendere visione del documento allegato con cui vi informiamo dell avvenuta delibera a valere sull Avviso in oggetto.

+

Distinti Saluti,

+

{{email_signature}}

+
+ +', 'Comunicazione esito valutazione tecnica ed economico-finanziaria– Avviso {{call_name}} ', NULL, true, false, '2026-02-22 20:00:00.000', '2026-02-22 20:00:00.000', 'SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE', NULL); \ No newline at end of file diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index 7e930753..d21b41c1 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -428,7 +428,8 @@ mail.send.successfully=Mail sent succesfully. email.log.fetched=Email log fetched successfully. amendment.appropiate.status=Application amendment is not in appropiate status for this operation. upload.company.document.to.application=Uploaded company document to application successfully. -company.document.not.found.with.ids=Company document not found. Missing IDs: {0} +company.document.not.found.with.ids=Company document not found. Missing IDs: {0}. +amount.field.not.provided= Please provide the required amount fields. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index d88b196c..3595be62 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -420,3 +420,4 @@ email.log.fetched=Registro email recuperato correttamente. amendment.appropiate.status=L'emendamento dell'applicazione non � in stato appropriato per questa operazione. upload.company.document.to.application=Documento aziendale caricato correttamente nell'applicazione. company.document.not.found.with.ids=Documento aziendale non trovato. ID mancanti: {0} +amount.field.not.provided= Si prega di fornire i campi obbligatori per l'importo. From b65b3eb47cd475e63a51227a3f94d292303bef06 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 23 Feb 2026 14:34:31 +0530 Subject: [PATCH 17/33] Updated code --- .../tendermanagement/dao/ApplicationAmendmentRequestDao.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index bb9a2b29..45b867b2 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -1938,6 +1938,7 @@ public class ApplicationAmendmentRequestDao { ApplicationAmendmentRequestResponse applicationAmendmentRequestResponse = convertEntityToResponse(applicationAmendmentRequestEntity,false); if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())){ + log.info("Sending mail for the special amendment for amendment ID = {}", applicationAmendment.getId()); saveEmailSendResponse(emailSendResponse, applicationAmendmentRequestEntity); applicationAmendmentRequestResponse.setEmailSendResponse(responses); } From ccc6ac2c8f07bd71c6646f4cbfe4d80d321ceb71 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 23 Feb 2026 16:26:00 +0530 Subject: [PATCH 18/33] Updated application status setting flow --- .../gepafin/tendermanagement/dao/ApplicationEvaluationDao.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index 4727893f..d5edecb7 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -2653,7 +2653,6 @@ public class ApplicationEvaluationDao { if (criteriaJson != null && applicationEntity.getCall().getThreshold()!=null ){ BigDecimal totalScore = calculateTotalScore(evaluationEntity.getCriteria()); if (totalScore.compareTo(new BigDecimal(applicationEntity.getCall().getThreshold())) >= 0) { - applicationEntity.setStatus(status.getValue()); log.info("Status updated to AWAITING_TECHNICAL_EVALUATION for applicationId: {}", applicationId); } else{ @@ -2661,6 +2660,7 @@ public class ApplicationEvaluationDao { throw new CustomValidationException(Status.BAD_REQUEST,Translator.toLocale(GepafinConstant.INSUFFICIENT_SCORE_MESSAGE)); } } + applicationEntity.setStatus(status.getValue()); } public BigDecimal calculateTotalScore(String criteriaJson){ From 255ee536e1a8b953444ec36db2a13eb2713135a5 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 2 Mar 2026 17:55:55 +0530 Subject: [PATCH 19/33] Applied null check --- .../tendermanagement/dao/AppointmentDao.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index aa81aab5..ecff43b2 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -534,7 +534,7 @@ public class AppointmentDao { log.info("Scheduler shut down for applicationId: {}", applicationId); } - private void processNdgGeneration(ApplicationEntity application, CompanyEntity company, HubEntity hub) { + private void processNdgGeneration(ApplicationEntity application, CompanyEntity company, HubEntity hub) { // Validate application, company, and hub Long applicationId = application.getId(); log.info("Starting NDG generation process for applicationId: {}", applicationId); @@ -560,10 +560,12 @@ public class AppointmentDao { }else { ndgResponse = retrieveNdgByVatNumber(company.getVatNumber(), authorizationToken, hub, application,company); } - if (isNdgValid(ndgResponse.getNdg())) { - saveNdg(application, company, ndgResponse.getNdg()); - log.info("NDG successfully generated for applicationId: {}", applicationId); - } else { + if(ndgResponse!=null) { + if (isNdgValid(ndgResponse.getNdg())) { + saveNdg(application, company, ndgResponse.getNdg()); + log.info("NDG successfully generated for applicationId: {}", applicationId); + } + }else { log.info("Polling for NDG for applicationId: {}", applicationId); handleNdgPolling(application, company, hub, authorizationToken); } @@ -743,6 +745,9 @@ public class AppointmentDao { String responseJson = getNdgFromExternalService(vatNumber, authorizationToken); // Parse and return the NDG response AppointmentLoginResponse loginResponse=parseNdgResponse(responseJson); + if(loginResponse==null){ + return null; + } ObjectMapper objectMapper = new ObjectMapper(); JsonNode rootNode = null; try { From aa7ac4fef2c94549cc348712b640b39169749f35 Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 3 Mar 2026 12:14:48 +0530 Subject: [PATCH 20/33] Fixed NDG issue --- .../net/gepafin/tendermanagement/dao/AppointmentDao.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index aa81aab5..0bdc8d59 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -166,6 +166,13 @@ public class AppointmentDao { NdganagEntity ndganagEntity = ndganagRepository.findByVatNumber(company.getVatNumber()); if (ndganagEntity != null && ndganagEntity.getNdg() != null) { ndgResponse.setNdg(ndganagEntity.getNdg()); + company.setNdg(ndganagEntity.getNdg()); + application.setNdg(ndganagEntity.getNdg()); + application.setNdgStatus(GepafinConstant.NDG_GENERATED); + application.setStatus(ApplicationStatusTypeEnum.NDG.getValue()); + + companyRepository.save(company); + applicationRepository.save(application); return ndgResponse; } From aa34bf698e97cf2a50277b1c79e346c2e091a00f Mon Sep 17 00:00:00 2001 From: rajesh Date: Thu, 5 Mar 2026 15:42:03 +0530 Subject: [PATCH 21/33] Handled non-existent user login error --- .../gepafin/tendermanagement/constants/GepafinConstant.java | 1 + .../service/impl/AuthenticationService.java | 6 +++--- src/main/resources/message_en.properties | 1 + src/main/resources/message_it.properties | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 74b4e221..d312f062 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -9,6 +9,7 @@ public class GepafinConstant { public static final String USER_UPDATED_SUCCESS_MSG = "user.updated.success"; public static final String USER_DELETED_SUCCESS_MSG = "user.deleted.success"; public static final String USER_NOT_FOUND_MSG = "user.not.found"; + public static final String INVALID_USERNAME_AND_PASSWORD = "invalid.username.or.password"; public static final String CREATE_USER_ERROR_MSG = "create_user_error_msg"; public static final String UPDATE_USER_ERROR_MSG = "update_user_error_msg"; public static final String DELETE_USER_ERROR_MSG = "delete_user_error_msg"; diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java b/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java index 01ad155b..ed0e862d 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java @@ -96,7 +96,7 @@ public class AuthenticationService { RoleStatusEnum.ROLE_BENEFICIARY.getValue() ).orElseThrow(() -> new ResourceNotFoundException( Status.NOT_FOUND, - Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG) + Translator.toLocale(GepafinConstant.INVALID_USERNAME_AND_PASSWORD) )); String emailWithHubId = loginReq.getEmail()+":"+loginReq.getHubUuid(); @@ -115,7 +115,7 @@ public class AuthenticationService { createSuccessLoginAttempt(loginAttemptEntity); } catch (Exception e) { log.info("Authentication failed for email: {}", loginReq.getEmail()); - loginAttemptEntity.setUserId(user.getId()); +// loginAttemptEntity.setUserId(user.getId()); createFailedLoginAttempt(loginAttemptEntity, e.getMessage()); throw e; } @@ -238,7 +238,7 @@ public class AuthenticationService { return getJWTTokenBean(userEntity, Boolean.TRUE, loginAttempt.getId(),null); } catch (Exception e) { log.info("Authentication login failed for email: {}",e.getMessage()); - loginAttemptEntity.setUserId(userId); +// loginAttemptEntity.setUserId(userId); createFailedLoginAttempt(loginAttemptEntity, e.getMessage()); throw e; } diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index d21b41c1..b26ec2c2 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -2,6 +2,7 @@ user.created.success=User created successfully. user.updated.success=User updated successfully. user.deleted.success=User deleted successfully. user.not.found=User not found. +invalid.username.or.password= Invalid username or password. create_user_error_msg=An error occurred while creating the user. update_user_error_msg=An error occurred while updating the user. delete_user_error_msg=An error occurred while deleting the user. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 3595be62..041e08a2 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -2,6 +2,7 @@ user.created.success=Utente creato con successo. user.updated.success=Utente aggiornato con successo. user.deleted.success=Utente eliminato con successo. user.not.found=Utente non trovato. +invalid.username.or.password= Nome utente o password non validi. create_user_error_msg=Si ? verificato un errore durante la creazione dell'utente. update_user_error_msg=Si ? verificato un errore durante l'aggiornamento dell'utente. delete_user_error_msg=Si ? verificato un errore durante l'eliminazione dell'utente. From 0669d2c928ec5b37b8e173aed3dc3671582c8fc7 Mon Sep 17 00:00:00 2001 From: rajesh Date: Thu, 5 Mar 2026 16:53:51 +0530 Subject: [PATCH 22/33] Fixed upload document external system issue --- .../java/net/gepafin/tendermanagement/dao/AppointmentDao.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 7169eb08..069d823d 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -1240,9 +1240,9 @@ public class AppointmentDao { if (documentAttachmentId!=null) { // If the documentAttachmentId is already set, return the response - log.info("Document already uploaded with documentAttachmentId: {}", systemDoc.getDocumentAttachmentId()); + log.info("Document already uploaded with documentAttachmentId: {}", documentAttachmentId); DocumentUploadResponse response = new DocumentUploadResponse(); - response.setDocumentAttachmentId(systemDoc.getDocumentAttachmentId()); + response.setDocumentAttachmentId(documentAttachmentId); return response; } // Check if a thread is already running for this document upload From 2c6a64f4080b99eeb6d0261a70f036235fdf033b Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 9 Mar 2026 13:46:20 +0530 Subject: [PATCH 23/33] Added documentAttachmentId in response of evaluation --- .../java/net/gepafin/tendermanagement/dao/ApplicationDao.java | 1 + .../model/response/ApplicationSignedDocumentResponse.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index d7a5661a..7a351d08 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -1453,6 +1453,7 @@ public class ApplicationDao { applicationSignedDocumentResponse.setCreatedDate(applicationSignedDocument.getCreatedDate()); applicationSignedDocumentResponse.setUpdatedDate(applicationSignedDocument.getUpdatedDate()); applicationSignedDocumentResponse.setFileHash(applicationSignedDocument.getFileHash()); + applicationSignedDocumentResponse.setDocumentAttachmentId(applicationSignedDocument.getDocumentAttachmentId()); return applicationSignedDocumentResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationSignedDocumentResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationSignedDocumentResponse.java index 249ed7f8..a9ccc386 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationSignedDocumentResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationSignedDocumentResponse.java @@ -12,4 +12,5 @@ public class ApplicationSignedDocumentResponse extends BaseBean{ private String filePath; private ApplicationSignedDocumentStatusEnum status; private String fileHash; + private String documentAttachmentId; } From f0f904dabe77eea94e94c0d46597e3318bcb1c06 Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 10 Mar 2026 16:50:00 +0530 Subject: [PATCH 24/33] Managed company creation --- .../config/MessageSourceConfig.java | 2 +- .../config/WebSocketConfig.java | 16 ++++- .../constants/GepafinConstant.java | 3 +- .../tendermanagement/dao/AppointmentDao.java | 3 + .../tendermanagement/dao/CompanyDao.java | 65 ++++++++++++++++--- .../entities/CompanyEntity.java | 3 + src/main/resources/application-dev.properties | 4 +- .../resources/application-local.properties | 3 +- .../application-production.properties | 4 +- .../resources/application-testing.properties | 3 +- .../db/changelog/db.changelog-1.0.0.xml | 5 ++ src/main/resources/message_en.properties | 2 + src/main/resources/message_it.properties | 4 +- 13 files changed, 100 insertions(+), 17 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/config/MessageSourceConfig.java b/src/main/java/net/gepafin/tendermanagement/config/MessageSourceConfig.java index 79ef4d11..1159a0aa 100644 --- a/src/main/java/net/gepafin/tendermanagement/config/MessageSourceConfig.java +++ b/src/main/java/net/gepafin/tendermanagement/config/MessageSourceConfig.java @@ -14,7 +14,7 @@ public class MessageSourceConfig { public ResourceBundleMessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasenames("message"); - messageSource.setDefaultEncoding("UTF-8"); + messageSource.setDefaultEncoding("ISO-8859-1"); messageSource.setUseCodeAsDefaultMessage(true); return messageSource; } diff --git a/src/main/java/net/gepafin/tendermanagement/config/WebSocketConfig.java b/src/main/java/net/gepafin/tendermanagement/config/WebSocketConfig.java index 0212f720..1b9a9e36 100644 --- a/src/main/java/net/gepafin/tendermanagement/config/WebSocketConfig.java +++ b/src/main/java/net/gepafin/tendermanagement/config/WebSocketConfig.java @@ -23,10 +23,22 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Value("${spring.rabbitmq.password}") private String clientPassword; + @Value("${rabbitmq.enabled:false}") + private boolean rabbitmqEnabled; + @Override public void configureMessageBroker(MessageBrokerRegistry config) { - - config.enableStompBrokerRelay("/topic").setRelayHost(relayHost).setRelayPort(relayPort).setClientLogin(clientUserName).setClientPasscode(clientPassword); + if (rabbitmqEnabled) { + // Use external RabbitMQ broker + config.enableStompBrokerRelay("/topic") + .setRelayHost(relayHost) + .setRelayPort(relayPort) + .setClientLogin(clientUserName) + .setClientPasscode(clientPassword); + } else { + // Use in-memory simple broker + config.enableSimpleBroker("/topic"); + } config.setApplicationDestinationPrefixes("/app"); } diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index d312f062..46a8eb23 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -199,6 +199,7 @@ public class GepafinConstant { public static final String VALIDATION_ERROR_FILE_EMPTY = "validation.error.file.empty"; public static final String VALIDATION_ERROR_FILE_INVALIDTYPE = "validation.error.file.invalidType"; public static final String UPLOAD_ERROR_S3 = "upload.error.s3"; + public static final String VAT_OR_TAX_CODE_REQUIRED = "vat.or.tax.code.required"; public static final String CALL_NOT_STARTED_YET = "call.not.started.yet"; public static final String CALL_ALREADY_ENDED = "call.already.ended"; @@ -638,7 +639,7 @@ public class GepafinConstant { public static final String UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION_MSG="upload.company.document.to.application"; public static final String COMPANY_DOCUMENT_NOT_FOUND_WITH_IDS="company.document.not.found.with.ids"; public static final String REQUIRED_AMOUNT_FIELD_NOT_PROVIDED = "amount.field.not.provided"; - + public static final String PLEASE_PROVIDE_VALID_VAT_NUMBER="provide.valid.vat.number"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 069d823d..0e25e8d4 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -163,6 +163,9 @@ public class AppointmentDao { NdgResponse ndgResponse = new NdgResponse(); CompanyEntity company = companyService.validateCompany(application.getCompanyId()); + if(Boolean.FALSE.equals(company.getValidVat())){ + throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PLEASE_PROVIDE_VALID_VAT_NUMBER)); + } NdganagEntity ndganagEntity = ndganagRepository.findByVatNumber(company.getVatNumber()); if (ndganagEntity != null && ndganagEntity.getNdg() != null) { ndgResponse.setNdg(ndganagEntity.getNdg()); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java index 8b59eebe..8c6a8b1b 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java @@ -69,13 +69,26 @@ public class CompanyDao { @Autowired private HttpServletRequest request; + @Autowired + private VatCheckDao vatCheckDao; + private static final String NOT_FOUND_JSON = "{\"data\": \"not found\"}"; public CompanyResponse createCompany(UserEntity userEntity, CompanyRequest companyRequest) { log.info("Initiating company creation by userId: {}", userEntity.getId()); - CompanyEntity existingCompany = companyRepository.findByVatNumberAndHubId(companyRequest.getVatNumber(), userEntity.getHub().getId()); + Boolean validVat=Boolean.FALSE; + if(companyRequest.getVatNumber()!=null){ + VatCheckResponseBean vatCheckResponseBean=vatCheckDao.checkVatNumber(companyRequest.getVatNumber(), userEntity.getHub().getId()); + if(vatCheckResponseBean!=null && Boolean.TRUE.equals(vatCheckResponseBean.getValid())){ + validVat=Boolean.TRUE; + } + } + CompanyEntity existingCompany = null; + if (!StringUtils.isEmpty(companyRequest.getVatNumber())) { + existingCompany = companyRepository.findByVatNumberAndHubId(companyRequest.getVatNumber(), userEntity.getHub().getId()); + } UserWithCompanyEntity userWithCompanyEntity = null; if (existingCompany != null) { UserWithCompanyEntity existingRelation = userWithCompanyRepository.findByUserIdAndCompanyIdAndIsDeletedFalse(userEntity.getId(), existingCompany.getId()).orElse(null); @@ -93,6 +106,7 @@ public class CompanyDao { } else { validateCompany(userEntity, companyRequest); CompanyEntity companyEntity = convertCompanyRequestToCompanyEntity(userEntity, companyRequest); + companyEntity.setValidVat(validVat); CompanyEntity companyData = companyRepository.save(companyEntity); /** This code is responsible for adding a version history log for "creating company" operation. **/ @@ -112,12 +126,16 @@ public class CompanyDao { throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_EMAIL)); } - if (StringUtils.isEmpty(companyRequest.getVatNumber())) { + // At least one identifier required + if (StringUtils.isEmpty(companyRequest.getVatNumber()) + && StringUtils.isEmpty(companyRequest.getCodiceFiscale())) { throw new CustomValidationException(Status.VALIDATION_ERROR, - Translator.toLocale(GepafinConstant.VATNUMBER_MANDATORY)); + Translator.toLocale(GepafinConstant.VAT_OR_TAX_CODE_REQUIRED)); } - if (companyRepository.existsByVatNumberAndHubId(companyRequest.getVatNumber(), userEntity.getHub().getId())) { - throw new CustomValidationException(Status.VALIDATION_ERROR, + // Only check VAT uniqueness if VAT provided + if (!StringUtils.isEmpty(companyRequest.getVatNumber()) + && companyRepository.existsByVatNumberAndHubId(companyRequest.getVatNumber(), userEntity.getHub().getId())) { + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.VATNUMBER_ALREADY_EXISTS)); } } @@ -140,7 +158,7 @@ public class CompanyDao { UserWithCompanyEntity userWithCompany = userWithCompanyRepository.save(userWithCompanyEntity); /** This code is responsible for adding a version history log for the "adding user with company" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(userWithCompany).build()); - if (StringUtils.isEmpty(companyEntity.getJson())) { + if (StringUtils.isEmpty(companyEntity.getJson()) && companyRequest.getVatCheckResponse() != null) { companyEntity.setJson(Utils.convertMapIntoJsonString(companyRequest.getVatCheckResponse())); updateCodiceAtecoFieldWithNewJson(companyEntity); companyEntity = companyRepository.save(companyEntity); @@ -161,7 +179,11 @@ public class CompanyDao { private CompanyEntity convertCompanyRequestToCompanyEntity(UserEntity userEntity, CompanyRequest request) { CompanyEntity entity = new CompanyEntity(); entity.setCompanyName(request.getCompanyName()); - entity.setVatNumber(request.getVatNumber()); + if(request.getVatNumber()==null){ + entity.setVatNumber(request.getCodiceFiscale()); + }else { + entity.setVatNumber(request.getVatNumber()); + } entity.setCodiceFiscale(request.getCodiceFiscale()); entity.setAddress(request.getAddress()); entity.setPhoneNumber(request.getPhoneNumber()); @@ -182,7 +204,11 @@ public class CompanyDao { CompanyResponse response = new CompanyResponse(); response.setId(entity.getId()); response.setCompanyName(entity.getCompanyName()); - response.setVatNumber(entity.getVatNumber()); + if(entity.getVatNumber()==null){ + response.setVatNumber(entity.getCodiceFiscale()); + }else { + response.setVatNumber(entity.getVatNumber()); + } response.setCodiceFiscale(entity.getCodiceFiscale()); response.setAddress(entity.getAddress()); response.setPhoneNumber(entity.getPhoneNumber()); @@ -231,6 +257,29 @@ public class CompanyDao { // companyEntity.setVatNumber(companyRequest.getVatNumber()); // // } + + //allow adding VAT later + if(StringUtils.isNotBlank(companyRequest.getVatNumber()) + && StringUtils.isBlank(companyEntity.getVatNumber())) { + CompanyEntity existingCompany = companyRepository.findByVatNumberAndHubId(companyRequest.getVatNumber(), userEntity.getHub().getId()); + if(existingCompany!=null){ + throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.VATNUMBER_ALREADY_EXISTS)); + } + Boolean validVat=Boolean.FALSE; + if(companyRequest.getVatNumber()!=null){ + VatCheckResponseBean vatCheckResponseBean=vatCheckDao.checkVatNumber(companyRequest.getVatNumber(), userEntity.getHub().getId()); + if(vatCheckResponseBean!=null && Boolean.TRUE.equals(vatCheckResponseBean.getValid())){ + validVat=Boolean.TRUE; + } + } + companyEntity.setVatNumber(companyRequest.getVatNumber()); + companyEntity.setValidVat(validVat); + if(companyRequest.getVatCheckResponse() != null) { + String responseJson = Utils.convertMapIntoJsonString(companyRequest.getVatCheckResponse()); + companyEntity.setJson(responseJson); + updateCodiceAtecoFieldWithNewJson(companyEntity); + } + } companyRepository.save(companyEntity); log.info("Company updated and saved. companyId: {}", companyEntity.getId()); diff --git a/src/main/java/net/gepafin/tendermanagement/entities/CompanyEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/CompanyEntity.java index 8a6c94e1..0f47d5d9 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/CompanyEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/CompanyEntity.java @@ -64,4 +64,7 @@ public class CompanyEntity extends BaseEntity{ @Column(name = "PEC") private String pec; + + @Column(name = "VALID_VAT") + private Boolean validVat; } diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 356735fb..6db0a637 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -29,4 +29,6 @@ spring.rabbitmq.host=172.18.0.7 spring.rabbitmq.port=61613 spring.rabbitmq.username=guest spring.rabbitmq.password=guest -spring.rabbitmq.virtual-host=/ \ No newline at end of file +spring.rabbitmq.virtual-host=/ + +rabbitmq.enabled=false \ No newline at end of file diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index 3563166f..bcae6352 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -26,4 +26,5 @@ spring.rabbitmq.host=localhost spring.rabbitmq.port=61613 spring.rabbitmq.username=guest spring.rabbitmq.password=guest -spring.rabbitmq.virtual-host=/ \ No newline at end of file +spring.rabbitmq.virtual-host=/ +rabbitmq.enabled=false \ No newline at end of file diff --git a/src/main/resources/application-production.properties b/src/main/resources/application-production.properties index a38014af..bfb4a6c3 100644 --- a/src/main/resources/application-production.properties +++ b/src/main/resources/application-production.properties @@ -38,4 +38,6 @@ spring.rabbitmq.username=guest spring.rabbitmq.password=guest spring.rabbitmq.virtual-host=/ -isSviluppumbriaProtocolEnabled = false \ No newline at end of file +isSviluppumbriaProtocolEnabled = false + +rabbitmq.enabled=true \ No newline at end of file diff --git a/src/main/resources/application-testing.properties b/src/main/resources/application-testing.properties index 532deb3f..912727b9 100644 --- a/src/main/resources/application-testing.properties +++ b/src/main/resources/application-testing.properties @@ -24,4 +24,5 @@ spring.rabbitmq.host=rabbitmq.bflows.ai spring.rabbitmq.port=61613 spring.rabbitmq.username=guest spring.rabbitmq.password=guest -spring.rabbitmq.virtual-host=/ \ No newline at end of file +spring.rabbitmq.virtual-host=/ +rabbitmq.enabled=false \ No newline at end of file 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 32c8690d..36e1c630 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 @@ -3193,5 +3193,10 @@ + + + + + diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index b26ec2c2..64331f3d 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -431,6 +431,8 @@ amendment.appropiate.status=Application amendment is not in appropiate status fo upload.company.document.to.application=Uploaded company document to application successfully. company.document.not.found.with.ids=Company document not found. Missing IDs: {0}. amount.field.not.provided= Please provide the required amount fields. +vat.or.tax.code.required=VAT Number or Tax Code is required. +provide.valid.vat.number=Please provide a valid vat number to proceed NDG. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 041e08a2..5265325f 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -71,7 +71,7 @@ email.already.exists=Esiste gi? un utente con questa email. invalid_user=Validazione utente fallita. Controlla le informazioni, lo stato dell'account e la scadenza del token. #Global messages -common_message=qualcosa � andato storto. Per favore riprova +common_message=Qualcosa è andato storto. Riprova. invalid_signature=Gettone non valido. invalid_login=Nome utente o password errati req_validation_er=Errore di convalida @@ -422,3 +422,5 @@ amendment.appropiate.status=L'emendamento dell'applicazione non � in stato app upload.company.document.to.application=Documento aziendale caricato correttamente nell'applicazione. company.document.not.found.with.ids=Documento aziendale non trovato. ID mancanti: {0} amount.field.not.provided= Si prega di fornire i campi obbligatori per l'importo. +vat.or.tax.code.required=È obbligatorio il numero di partita IVA o il codice fiscale. +provide.valid.vat.number=Inserisci un numero di partita IVA valido per procedere con NDG. \ No newline at end of file From e2c73db9f748e6d79edde8bd736b2e8d74aab09d Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 10 Mar 2026 18:32:21 +0530 Subject: [PATCH 25/33] Updated code --- src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java index 8c6a8b1b..92c90f23 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java @@ -1,5 +1,6 @@ package net.gepafin.tendermanagement.dao; +import net.gepafin.tendermanagement.model.util.NanoIdUtils; import org.springframework.data.domain.Pageable; // Correct package import java.util.ArrayList; @@ -180,7 +181,7 @@ public class CompanyDao { CompanyEntity entity = new CompanyEntity(); entity.setCompanyName(request.getCompanyName()); if(request.getVatNumber()==null){ - entity.setVatNumber(request.getCodiceFiscale()); + entity.setVatNumber(NanoIdUtils.randomNanoId()); }else { entity.setVatNumber(request.getVatNumber()); } From 5fe2291a3ec1b067a3524db65bb4717c73af0862 Mon Sep 17 00:00:00 2001 From: rajesh Date: Wed, 11 Mar 2026 12:20:06 +0530 Subject: [PATCH 26/33] Created new endpoint to reject emails by director --- .../constants/GepafinConstant.java | 1 + .../tendermanagement/dao/PecMailDao.java | 18 ++++++++++++++++++ .../entities/EmailLogEntity.java | 3 +++ .../tendermanagement/enums/StatusTypeEnum.java | 3 ++- .../enums/UserActionContextEnum.java | 1 + .../model/response/PecEmailLogResponse.java | 2 ++ .../service/PecMailService.java | 2 ++ .../service/impl/PecMailSerivceImpl.java | 5 +++++ .../web/rest/api/PecMailApi.java | 11 +++++++++++ .../web/rest/api/impl/PecMailController.java | 11 +++++++++++ .../db/changelog/db.changelog-1.0.0.xml | 6 ++++++ src/main/resources/message_en.properties | 1 + src/main/resources/message_it.properties | 1 + 13 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 46a8eb23..f223d922 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -634,6 +634,7 @@ public class GepafinConstant { public static final String APPLICATION_NOT_APPROVED="application.not.approved"; public static final String SUBJECT_AND_BODY_REQUIRED="subject.body.required"; public static final String MAIL_SENT_SUCCESSFULLY="mail.send.successfully"; + public static final String PEC_EMAIL_REJECTED_SUCCESSFULLY="pec.email.rejected.successfully"; public static final String EMAIL_LOG_FETCHED="email.log.fetched"; public static final String APPLICATION_AMENDMENT_APPROPIATE_STATUS="amendment.appropiate.status"; public static final String UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION_MSG="upload.company.document.to.application"; diff --git a/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java index 18240044..fcaecbcc 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java @@ -15,6 +15,7 @@ import net.gepafin.tendermanagement.repositories.EmailLogRepository; import net.gepafin.tendermanagement.repositories.UserActionsRepository; import net.gepafin.tendermanagement.service.ApplicationService; import net.gepafin.tendermanagement.service.CallService; +import net.gepafin.tendermanagement.util.DateTimeUtil; import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.util.Validator; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; @@ -24,6 +25,7 @@ import org.checkerframework.checker.units.qual.A; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -74,6 +76,21 @@ public class PecMailDao { return pecMailResponses; } + public PecMailResponse rejectPecMail(HttpServletRequest request, Long userActionId, String motivation) { + List emailLogs = getEmailLogEntities(request, userActionId); + LocalDateTime rejectedAt = DateTimeUtil.DateServerToUTC(LocalDateTime.now()); + for (EmailLogEntity log : emailLogs) { + log.setSendStatus(StatusTypeEnum.REJECTED.getValue()); + log.setMotivation(motivation); + log.setSendDateTime(rejectedAt); + } + emailLogRepository.saveAll(emailLogs); + EmailLogEntity firstLog = emailLogs.get(0); + ApplicationEntity applicationEntity = applicationService.validateApplication(firstLog.getApplicationId()); + String callName = applicationEntity.getCall().getName(); + return createPecMailResponse(firstLog.getUserAction().getId(), firstLog, callName); + } + private List getEmailLogEntities(HttpServletRequest request, Long userActionId) { UserActionEntity userActionEntity = userActionsRepository.findUserActionByIdAndIsDeletedFalse(userActionId); if (userActionEntity == null) { @@ -117,6 +134,7 @@ public class PecMailDao { pecEmailLogResponse.setSubject(emailLogEntity.getEmailSubject()); pecEmailLogResponse.setHtmlContent(emailLogEntity.getEmailBody()); pecEmailLogResponse.setCallId(emailLogEntity.getCallId()); + pecEmailLogResponse.setMotivation(emailLogEntity.getMotivation()); return pecEmailLogResponse; } private PecMailResponse createPecMailResponse(Long userActionId, EmailLogEntity emailLogEntity, String callName) { diff --git a/src/main/java/net/gepafin/tendermanagement/entities/EmailLogEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/EmailLogEntity.java index 0a4dfc90..ba21ec3d 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/EmailLogEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/EmailLogEntity.java @@ -62,5 +62,8 @@ public class EmailLogEntity extends BaseEntity{ @Column(name = "ATTACHMENTS") private String attachments; + + @Column(name = "MOTIVATION", columnDefinition = "TEXT") + private String motivation; } diff --git a/src/main/java/net/gepafin/tendermanagement/enums/StatusTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/StatusTypeEnum.java index 738a6a17..65e9c262 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/StatusTypeEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/StatusTypeEnum.java @@ -5,7 +5,8 @@ import com.fasterxml.jackson.annotation.JsonValue; public enum StatusTypeEnum { PENDING ("PENDING"), SUCCESS ("SUCCESS"), - FAILED("FAILED"); + FAILED("FAILED"), + REJECTED("REJECTED"); private String value; diff --git a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java index 9092c769..8ada4d3c 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java @@ -231,6 +231,7 @@ public enum UserActionContextEnum { FETCH_APPLICATION_CONTRACT_BY_APPLICATION_ID("FETCH_APPLICATION_CONTRACT_BY_APPLICATION_ID"), FETCH_APPLICATION_CONTRACT_BY_BENEFICIARY_USER_ID("FETCH_APPLICATION_CONTRACT_BY_BENEFICIARY_USER_ID"), SEND_PEC_MAIL("SEND_PEC_MAIL"), + REJECT_PEC_MAIL("REJECT_PEC_MAIL"), FETCH_EMAIL_LOG("FETCH_EMAIL_LOG"), FETCH_ALL_EMAIL_LOG("FETCH_ALL_EMAIL_LOG"), UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION("UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION"); diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/PecEmailLogResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/PecEmailLogResponse.java index 6b0ada2f..7b646e84 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/PecEmailLogResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/PecEmailLogResponse.java @@ -27,4 +27,6 @@ public class PecEmailLogResponse { private Long callId; + private String motivation; + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/PecMailService.java b/src/main/java/net/gepafin/tendermanagement/service/PecMailService.java index 77339aae..2d26dec4 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/PecMailService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/PecMailService.java @@ -10,6 +10,8 @@ public interface PecMailService { public List sendPecMail(HttpServletRequest request, List userActionIds); + public PecMailResponse rejectPecMail(HttpServletRequest request, Long userActionId, String motivation); + public List getEmailLogByUserActionId(HttpServletRequest request, Long userActionId); public List getAllEmailLogs(HttpServletRequest request); diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/PecMailSerivceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/PecMailSerivceImpl.java index 8e0daef1..f87b74b8 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/PecMailSerivceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/PecMailSerivceImpl.java @@ -21,6 +21,11 @@ public class PecMailSerivceImpl implements PecMailService { return pecMailDao.sendPecMail(request,userActionIds); } + @Override + public PecMailResponse rejectPecMail(HttpServletRequest request, Long userActionId, String motivation) { + return pecMailDao.rejectPecMail(request, userActionId, motivation); + } + @Override public List getEmailLogByUserActionId(HttpServletRequest request, Long userActionId) { return pecMailDao.getEmailLogByUserActionId(request,userActionId); diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/PecMailApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/PecMailApi.java index 27fdcc27..461c3087 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/PecMailApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/PecMailApi.java @@ -31,6 +31,17 @@ public interface PecMailApi { ResponseEntity>> sendPecMail(HttpServletRequest request, @Parameter(description = "The user action id", required = true) @RequestParam("userActionIds") List userActionIds); + @Operation(summary = "Api to reject PEC email for a user action with motivation.", 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))) }) + @PostMapping(value = "/userAction/{userActionId}/reject", produces = "application/json") + ResponseEntity> rejectPecMail(HttpServletRequest request, + @Parameter(description = "The user action id", required = true) @PathVariable("userActionId") Long userActionId, + @Parameter(description = "Motivation for rejection", required = true) @RequestParam("motivation") String motivation); @Operation(summary = "Api to get email log by user action id", responses = { @ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = @ExampleObject(value = diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/PecMailController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/PecMailController.java index 41e8ed58..e22be37a 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/PecMailController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/PecMailController.java @@ -44,6 +44,17 @@ public class PecMailController implements PecMailApi { } + @Override + public ResponseEntity> rejectPecMail(HttpServletRequest request, Long userActionId, String motivation) { + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.EMAIL) + .actionContext(UserActionContextEnum.REJECT_PEC_MAIL).build()); + + PecMailResponse pecMailResponse = pecMailService.rejectPecMail(request, userActionId, motivation); + + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(pecMailResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.PEC_EMAIL_REJECTED_SUCCESSFULLY))); + } + @Override public ResponseEntity>> getEmailLogByUserActionId(HttpServletRequest request, Long userActionId) { loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.EMAIL) 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 36e1c630..7f005f1f 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 @@ -3199,4 +3199,10 @@ + + + + + + diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index 64331f3d..65b69eff 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -426,6 +426,7 @@ application.contract.already.exist=Application contract already exist for this a application.not.approved=Application is not approved. subject.body.required=Subject and body is required to create contract. mail.send.successfully=Mail sent succesfully. +pec.email.rejected.successfully=Email rejected successfully. email.log.fetched=Email log fetched successfully. amendment.appropiate.status=Application amendment is not in appropiate status for this operation. upload.company.document.to.application=Uploaded company document to application successfully. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 5265325f..2437fa0b 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -417,6 +417,7 @@ application.contract.already.exist=Il contratto di applicazione esiste gi� per application.not.approved=La domanda non � stata approvata. subject.body.required=Per creare un contratto sono necessari oggetto e corpo. mail.send.successfully=Email inviata con successo. +pec.email.rejected.successfully=Email rifiutata con successo. email.log.fetched=Registro email recuperato correttamente. amendment.appropiate.status=L'emendamento dell'applicazione non � in stato appropriato per questa operazione. upload.company.document.to.application=Documento aziendale caricato correttamente nell'applicazione. From 00080d6a6c27b0e294c8c5e400cf60939588db28 Mon Sep 17 00:00:00 2001 From: rajesh Date: Wed, 11 Mar 2026 16:20:35 +0530 Subject: [PATCH 27/33] Created new endpoint to update VAT number of company --- .../tendermanagement/dao/CompanyDao.java | 57 ++++++++++++------- .../enums/UserActionContextEnum.java | 1 + .../model/response/CompanyResponse.java | 1 + .../service/CompanyService.java | 2 + .../service/impl/CompanyServiceImpl.java | 8 +++ .../web/rest/api/CompanyApi.java | 13 +++++ .../rest/api/impl/CompanyApiController.java | 9 +++ 7 files changed, 69 insertions(+), 22 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java index 92c90f23..400d30f6 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java @@ -229,6 +229,7 @@ public class CompanyDao { response.setUpdatedDate(entity.getUpdatedDate()); response.setContactName(userWithCompanyEntity.getContactName()); response.setContactEmail(userWithCompanyEntity.getContactEmail()); + response.setValidVat(entity.getValidVat()); return response; } @@ -259,28 +260,6 @@ public class CompanyDao { // // } - //allow adding VAT later - if(StringUtils.isNotBlank(companyRequest.getVatNumber()) - && StringUtils.isBlank(companyEntity.getVatNumber())) { - CompanyEntity existingCompany = companyRepository.findByVatNumberAndHubId(companyRequest.getVatNumber(), userEntity.getHub().getId()); - if(existingCompany!=null){ - throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.VATNUMBER_ALREADY_EXISTS)); - } - Boolean validVat=Boolean.FALSE; - if(companyRequest.getVatNumber()!=null){ - VatCheckResponseBean vatCheckResponseBean=vatCheckDao.checkVatNumber(companyRequest.getVatNumber(), userEntity.getHub().getId()); - if(vatCheckResponseBean!=null && Boolean.TRUE.equals(vatCheckResponseBean.getValid())){ - validVat=Boolean.TRUE; - } - } - companyEntity.setVatNumber(companyRequest.getVatNumber()); - companyEntity.setValidVat(validVat); - if(companyRequest.getVatCheckResponse() != null) { - String responseJson = Utils.convertMapIntoJsonString(companyRequest.getVatCheckResponse()); - companyEntity.setJson(responseJson); - updateCodiceAtecoFieldWithNewJson(companyEntity); - } - } companyRepository.save(companyEntity); log.info("Company updated and saved. companyId: {}", companyEntity.getId()); @@ -311,6 +290,40 @@ public class CompanyDao { return convertCompanyEntityToCompanyResponse(companyEntity, userWithCompanyEntity); } + /** + * Updates only the VAT number for the given company: runs VAT check, sets validVat and json (vat check response), and updates codiceAteco from response. + */ + public CompanyResponse updateCompanyVatNumber(UserEntity userEntity, Long companyId, String vatNumber) { + log.info("Updating company VAT number. companyId: {}, userId: {}", companyId, userEntity.getId()); + if (StringUtils.isBlank(vatNumber)) { + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.VAT_OR_TAX_CODE_REQUIRED)); + } + CompanyEntity companyEntity = validateCompany(companyId); + Long hubId = userEntity.getHub().getId(); + CompanyEntity existingCompany = companyRepository.findByVatNumberAndHubId(vatNumber, hubId); + if (existingCompany != null && !existingCompany.getId().equals(companyId)) { + throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.VATNUMBER_ALREADY_EXISTS)); + } + VatCheckResponseBean vatCheckResponseBean = vatCheckDao.checkVatNumber(vatNumber, hubId); + Boolean validVat = Boolean.FALSE; + if (vatCheckResponseBean != null && Boolean.TRUE.equals(vatCheckResponseBean.getValid())) { + validVat = Boolean.TRUE; + } + CompanyEntity oldCompanyData = Utils.getClonedEntityForData(companyEntity); + companyEntity.setVatNumber(vatNumber); + companyEntity.setValidVat(validVat); + if (vatCheckResponseBean != null && vatCheckResponseBean.getVatCheckResponse() != null) { + companyEntity.setJson(Utils.convertMapIntoJsonString(vatCheckResponseBean.getVatCheckResponse())); + updateCodiceAtecoFieldWithNewJson(companyEntity); + } + companyRepository.save(companyEntity); + log.info("Company VAT number updated and saved. companyId: {}", companyEntity.getId()); + loggingUtil.addVersionHistory( + VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCompanyData).newData(companyEntity).build()); + UserWithCompanyEntity userWithCompanyEntity = getUserWithCompany(userEntity.getId(), companyId); + return convertCompanyEntityToCompanyResponse(companyEntity, userWithCompanyEntity); + } + public CompanyEntity validateCompany(Long companyId) { log.info("Validating company. companyId: {}", companyId); return companyRepository.findById(companyId).orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, diff --git a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java index 8ada4d3c..9dc8b16d 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java @@ -60,6 +60,7 @@ public enum UserActionContextEnum { CREATE_COMPANY("CREATE_COMPANY"), GET_COMPANY("GET_COMPANY"), UPDATE_COMPANY("UPDATE_COMPANY"), + UPDATE_COMPANY_VAT_NUMBER("UPDATE_COMPANY_VAT_NUMBER"), DELETE_COMPANY("DELETE_COMPANY"), UPLOAD_COMPANY_DELEGATION("UPLOAD_COMPANY_DELEGATION"), DOWNLOAD_COMPANY_DELEGATION_TEMPLATE("DOWNLOAD_COMPANY_DELEGATION_TEMPLATE"), diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/CompanyResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/CompanyResponse.java index ddd62f38..4752eed7 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/CompanyResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/CompanyResponse.java @@ -25,4 +25,5 @@ public class CompanyResponse extends BaseBean{ private String contactName; private String contactEmail; private String codiceAteco; + private Boolean validVat; } diff --git a/src/main/java/net/gepafin/tendermanagement/service/CompanyService.java b/src/main/java/net/gepafin/tendermanagement/service/CompanyService.java index 4c868f1e..6427341f 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/CompanyService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/CompanyService.java @@ -21,6 +21,8 @@ public interface CompanyService { CompanyResponse updateCompany(HttpServletRequest request, Long companyId, CompanyRequest companyRequest); + CompanyResponse updateCompanyVatNumber(HttpServletRequest request, Long companyId, String vatNumber); + CompanyResponse getCompany(HttpServletRequest request, Long companyId); void deleteCompany(HttpServletRequest request, Long companyId); diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java index f9a8b8c8..ba8779bb 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java @@ -56,6 +56,14 @@ public class CompanyServiceImpl implements CompanyService { validator.validateUserWithCompany(request, companyId); return companyDao.updateCompany(userEntity, companyId, companyRequest); } + + @Override + @Transactional(rollbackFor = Exception.class) + public CompanyResponse updateCompanyVatNumber(HttpServletRequest request, Long companyId, String vatNumber) { + UserEntity userEntity = validator.validateUser(request); + validator.validateUserWithCompany(request, companyId); + return companyDao.updateCompanyVatNumber(userEntity, companyId, vatNumber); + } @Override @Transactional(readOnly = true) diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/CompanyApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/CompanyApi.java index a30e18be..3f566b5d 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/CompanyApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/CompanyApi.java @@ -55,6 +55,19 @@ public interface CompanyApi { @Parameter(description = "The company id", required = true) @PathVariable("companyId") Long companyId, @Parameter(description = "Company request object", required = true) @RequestBody CompanyRequest companyRequest); + @Operation(summary = "Api to update only company VAT number", 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) })) }) + @PutMapping(value = "/{companyId}/vatNumber", produces = { "application/json" }) + ResponseEntity> updateCompanyVatNumber(HttpServletRequest request, + @Parameter(description = "The company id", required = true) @PathVariable("companyId") Long companyId, + @Parameter(description = "VAT number", required = true) @RequestParam("vatNumber") String vatNumber); + + @Operation(summary = "Api to delete company", 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) })), diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CompanyApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CompanyApiController.java index 08d34ccf..d798ccfb 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CompanyApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CompanyApiController.java @@ -73,6 +73,15 @@ public class CompanyApiController implements CompanyApi{ .body(new Response<>(data, Status.SUCCESS, Translator.toLocale(GepafinConstant.COMPANY_UPDATED_SUCCESS_MSG))); } + @Override + public ResponseEntity> updateCompanyVatNumber(HttpServletRequest request, Long companyId, String vatNumber) { + log.info("Update company VAT number with companyId: {}, vatNumber: {}", companyId, vatNumber); + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.UPDATE).actionContext(UserActionContextEnum.UPDATE_COMPANY_VAT_NUMBER).build()); + CompanyResponse data = companyService.updateCompanyVatNumber(request, companyId, vatNumber); + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(data, Status.SUCCESS, Translator.toLocale(GepafinConstant.COMPANY_UPDATED_SUCCESS_MSG))); + } + @Override public ResponseEntity> getCompany(HttpServletRequest request, Long companyId) { From bdb7b7d885214b801d6286b926424b063d639622 Mon Sep 17 00:00:00 2001 From: rajesh Date: Thu, 12 Mar 2026 16:30:22 +0530 Subject: [PATCH 28/33] Updated the update company API --- .../tendermanagement/dao/CompanyDao.java | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java index 400d30f6..dd487692 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java @@ -250,15 +250,26 @@ public class CompanyDao { setIfUpdated(companyEntity::getCountry, companyEntity::setCountry, companyRequest.getCountry()); setIfUpdated(companyEntity::getNumberOfEmployees, companyEntity::setNumberOfEmployees, companyRequest.getNumberOfEmployees()); setIfUpdated(companyEntity::getAnnualRevenue, companyEntity::setAnnualRevenue, companyRequest.getAnnualRevenue()); -// -// if(StringUtils.isNotBlank(companyRequest.getVatNumber())) { -// CompanyEntity existingCompany = companyRepository.findByVatNumberAndHubId(companyRequest.getVatNumber(), userEntity.getHub().getId()); -// if(existingCompany!=null){ -// throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.VATNUMBER_ALREADY_EXISTS)); -// } -// companyEntity.setVatNumber(companyRequest.getVatNumber()); -// -// } + + // Same VAT logic as updateCompanyVatNumber: run VAT check, set validVat, json, and codiceAteco when vatNumber is provided + if (StringUtils.isNotBlank(companyRequest.getVatNumber())) { + Long hubId = userEntity.getHub().getId(); + CompanyEntity existingCompany = companyRepository.findByVatNumberAndHubId(companyRequest.getVatNumber(), hubId); + if (existingCompany != null) { + throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.VATNUMBER_ALREADY_EXISTS)); + } + VatCheckResponseBean vatCheckResponseBean = vatCheckDao.checkVatNumber(companyRequest.getVatNumber(), hubId); + Boolean validVat = Boolean.FALSE; + if (vatCheckResponseBean != null && Boolean.TRUE.equals(vatCheckResponseBean.getValid())) { + validVat = Boolean.TRUE; + } + companyEntity.setVatNumber(companyRequest.getVatNumber()); + companyEntity.setValidVat(validVat); + if (vatCheckResponseBean != null && vatCheckResponseBean.getVatCheckResponse() != null) { + companyEntity.setJson(Utils.convertMapIntoJsonString(vatCheckResponseBean.getVatCheckResponse())); + updateCodiceAtecoFieldWithNewJson(companyEntity); + } + } companyRepository.save(companyEntity); log.info("Company updated and saved. companyId: {}", companyEntity.getId()); From 3410f6b45fe8d82ca34d766928baf313960a949f Mon Sep 17 00:00:00 2001 From: rajesh Date: Fri, 13 Mar 2026 20:26:04 +0530 Subject: [PATCH 29/33] Handled rejected email rollback cases --- .../dao/ApplicationAmendmentRequestDao.java | 31 ++++- .../tendermanagement/dao/PecMailDao.java | 120 ++++++++++++++++++ .../ApplicationAmendmentRequestEnum.java | 4 +- .../VersionHistoryRepository.java | 2 + 4 files changed, 152 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index 45b867b2..0c12eb8e 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -786,6 +786,10 @@ public class ApplicationAmendmentRequestDao { log.warn("Permission denied: Beneficiary tried to update amendment ID {} with status RESPONSE_RECEIVED", id); throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); } + if(Boolean.TRUE.equals(isBeneficiary) && existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.DRAFT.getValue())){ + log.warn("Permission denied: Beneficiary tried to update amendment ID {} with status DRAFT (only instructor can update)", id); + throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); + } if(Boolean.FALSE.equals(isBeneficiary) && existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())){ log.warn("Permission denied: Non-beneficiary tried to update amendment ID {} with status AWAITING", id); throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); @@ -1278,16 +1282,35 @@ public class ApplicationAmendmentRequestDao { log.info("Updating application amendment with status: {}", id); ApplicationAmendmentRequestEntity existingApplicationAmendment = validateApplicationAmendmentRequest(id); ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(existingApplicationAmendment); - if (Boolean.TRUE.equals(existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())) && Boolean.TRUE.equals(statusTypeEnum.equals(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED))) { + + if (ApplicationAmendmentRequestEnum.AWAITING.equals(statusTypeEnum)) { + // Only instructor can set status to AWAITING (e.g. after finishing edits post email rejection); beneficiary must not be allowed + if (Boolean.TRUE.equals(validator.checkIsBeneficiary()) || Boolean.TRUE.equals(validator.checkIsConfidi())) { + log.warn("Permission denied: Beneficiary/Confidi tried to set amendment ID {} status to AWAITING", id); + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); + } + validator.validatePreInstructor(request, existingApplicationAmendment.getApplicationEvaluationEntity().getUserId()); + // Allow transition to AWAITING only from DRAFT (e.g. after instructor finished edits post email rejection) + if (!ApplicationAmendmentRequestEnum.DRAFT.getValue().equals(existingApplicationAmendment.getStatus())) { + log.warn("Invalid status transition: amendment ID {} is not in DRAFT (current: {})", id, existingApplicationAmendment.getStatus()); + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_APPROPIATE_STATUS)); + } + log.info("Updating amendment ID {} status from DRAFT to AWAITING", id); + existingApplicationAmendment.setStatus(ApplicationAmendmentRequestEnum.AWAITING.getValue()); + existingApplicationAmendment.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); + applicationAmendmentRequestRepository.save(existingApplicationAmendment); + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationAmendmentEntity).newData(existingApplicationAmendment).build()); + // Send the same mail as when (normal) amendment was created; only normal amendments can be in DRAFT (special amendment emails are sent at creation, not held) + emailNotificationDao.sendMailToNotifyBeneficiaryRegardingNewAmendment(existingApplicationAmendment); + } else if (Boolean.TRUE.equals(existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())) && Boolean.TRUE.equals(statusTypeEnum.equals(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED))) { log.info("Updating amendment ID {} status from {} to {}", id, existingApplicationAmendment.getStatus(), statusTypeEnum); existingApplicationAmendment.setStatus(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED.getValue()); existingApplicationAmendment.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); applicationAmendmentRequestRepository.save(existingApplicationAmendment); - - /** This code is responsible for adding a version history log for the "Update Application Amendment" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationAmendmentEntity).newData(existingApplicationAmendment).build()); } - ApplicationAmendmentRequestResponse response = convertEntityToResponse(existingApplicationAmendment,false); + + ApplicationAmendmentRequestResponse response = convertEntityToResponse(existingApplicationAmendment, false); log.info("Amendment status updated successfully: {}", response); return response; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java index fcaecbcc..d25e1507 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java @@ -6,13 +6,22 @@ import lombok.extern.log4j.Log4j2; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.*; +import net.gepafin.tendermanagement.enums.ApplicationEvaluationStatusTypeEnum; +import net.gepafin.tendermanagement.enums.AssignedApplicationEnum; +import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum; import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum; import net.gepafin.tendermanagement.enums.StatusTypeEnum; import net.gepafin.tendermanagement.model.response.EmailLogResponse; import net.gepafin.tendermanagement.model.response.PecEmailLogResponse; import net.gepafin.tendermanagement.model.response.PecMailResponse; +import net.gepafin.tendermanagement.enums.ApplicationAmendmentRequestEnum; +import net.gepafin.tendermanagement.repositories.ApplicationAmendmentRequestRepository; +import net.gepafin.tendermanagement.repositories.ApplicationEvaluationRepository; +import net.gepafin.tendermanagement.repositories.ApplicationRepository; +import net.gepafin.tendermanagement.repositories.AssignedApplicationsRepository; import net.gepafin.tendermanagement.repositories.EmailLogRepository; import net.gepafin.tendermanagement.repositories.UserActionsRepository; +import net.gepafin.tendermanagement.repositories.VersionHistoryRepository; import net.gepafin.tendermanagement.service.ApplicationService; import net.gepafin.tendermanagement.service.CallService; import net.gepafin.tendermanagement.util.DateTimeUtil; @@ -28,6 +37,8 @@ import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Optional; @Component @Log4j2 @@ -51,6 +62,22 @@ public class PecMailDao { @Autowired private ApplicationService applicationService; + @Autowired + private ApplicationRepository applicationRepository; + + @Autowired + private ApplicationEvaluationRepository applicationEvaluationRepository; + + @Autowired + private AssignedApplicationsRepository assignedApplicationsRepository; + + @Autowired + private VersionHistoryRepository versionHistoryRepository; + + @Autowired + private ApplicationAmendmentRequestRepository applicationAmendmentRequestRepository; + + private static final String TABLE_APPLICATION = "APPLICATION"; public List sendPecMail(HttpServletRequest request, List userActionIds) { @@ -86,11 +113,104 @@ public class PecMailDao { } emailLogRepository.saveAll(emailLogs); EmailLogEntity firstLog = emailLogs.get(0); + + rollbackDomainChangesForRejectedEmail(firstLog, userActionId); + ApplicationEntity applicationEntity = applicationService.validateApplication(firstLog.getApplicationId()); String callName = applicationEntity.getCall().getName(); return createPecMailResponse(firstLog.getUserAction().getId(), firstLog, callName); } + /** + * Rolls back domain changes using version history (audit) for the user action that triggered the email. + * Restores application, application_evaluation, and assigned_applications from oldData in version history. + */ + private void rollbackDomainChangesForRejectedEmail(EmailLogEntity firstLog, Long userActionId) { + if (firstLog == null || firstLog.getApplicationId() == null || firstLog.getEmailType() == null || userActionId == null) { + return; + } + + String scenario = firstLog.getEmailType(); + Long applicationId = firstLog.getApplicationId(); + + // Only normal amendment emails are rejectable in PEC flow; set amendment to DRAFT so only instructor can update + if (EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue().equals(scenario)) { + Long amendmentId = firstLog.getAmendmentId(); + if (amendmentId != null) { + applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId).ifPresent(amendment -> { + amendment.setStatus(ApplicationAmendmentRequestEnum.DRAFT.getValue()); + applicationAmendmentRequestRepository.save(amendment); + log.info("Set amendment id={} to DRAFT after email rejected (userActionId={})", amendmentId, userActionId); + }); + } + return; + } + + // Only rollback for the three evaluation-outcome email scenarios + if (!EmailScenarioTypeEnum.APPLICATION_TECHNICAL_EVALUATION_REJECTED.getValue().equals(scenario) + && !EmailScenarioTypeEnum.APPLICATION_REJECTED.getValue().equals(scenario) + && !EmailScenarioTypeEnum.APPLICATION_ADMISSIBLE.getValue().equals(scenario)) { + return; + } + + List appHistory = versionHistoryRepository.findVersionHistoryByUserActionIdAndTableName(userActionId, TABLE_APPLICATION); + Optional applicationVersion = appHistory.stream() + .filter(v -> applicationId.equals(v.getRecordId()) && v.getOldData() != null && !v.getOldData().isEmpty()) + .findFirst(); + + ApplicationEntity applicationEntity = applicationService.validateApplication(applicationId); + if (applicationVersion.isPresent()) { + Map oldDataMap = Utils.convertJsonStringToMap(applicationVersion.get().getOldData()); + if (oldDataMap != null) { + String previousStatus = Utils.extractString(oldDataMap, "status"); + if (previousStatus != null) { + applicationEntity.setStatus(previousStatus); + } + Object dateRejectedObj = oldDataMap.get("dateRejected"); + applicationEntity.setDateRejected(parseLocalDateTimeFromAudit(dateRejectedObj)); + applicationRepository.save(applicationEntity); + log.info("Rolled back application id={} from version history (userActionId={})", applicationId, userActionId); + } + } else { + log.warn("No APPLICATION version history with oldData found for userActionId={}, applicationId={}; skipping application rollback", userActionId, applicationId); + } + + // Only set application_evaluation and assigned_applications to OPEN for REJECTED and TECHNICAL_EVALUATION_REJECTED (not for ADMISSIBLE) + boolean reopenEvaluationAndAssigned = EmailScenarioTypeEnum.APPLICATION_TECHNICAL_EVALUATION_REJECTED.getValue().equals(scenario) + || EmailScenarioTypeEnum.APPLICATION_REJECTED.getValue().equals(scenario); + if (!reopenEvaluationAndAssigned) { + return; + } + + applicationEvaluationRepository.findByApplicationIdAndIsDeletedFalse(applicationId).ifPresent(evaluation -> { + evaluation.setStatus(ApplicationEvaluationStatusTypeEnum.OPEN.getValue()); + evaluation.setClosingDate(null); + evaluation.setActiveDays(null); + applicationEvaluationRepository.save(evaluation); + log.info("Set application_evaluation id={} to OPEN (userActionId={})", evaluation.getId(), userActionId); + }); + + assignedApplicationsRepository.findByApplicationIdAndIsDeletedFalse(applicationId).ifPresent(assigned -> { + assigned.setStatus(AssignedApplicationEnum.OPEN.getValue()); + assignedApplicationsRepository.save(assigned); + log.info("Set assigned_applications id={} to OPEN (userActionId={})", assigned.getId(), userActionId); + }); + } + + private static LocalDateTime parseLocalDateTimeFromAudit(Object value) { + if (value == null) { + return null; + } + if (value instanceof String str && !str.isEmpty()) { + try { + return DateTimeUtil.parseStringToLocalDateTime(str); + } catch (Exception e) { + return null; + } + } + return null; + } + private List getEmailLogEntities(HttpServletRequest request, Long userActionId) { UserActionEntity userActionEntity = userActionsRepository.findUserActionByIdAndIsDeletedFalse(userActionId); if (userActionEntity == null) { diff --git a/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java index d25ef71d..eeee1100 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java @@ -6,7 +6,9 @@ public enum ApplicationAmendmentRequestEnum { AWAITING("AWAITING"), RESPONSE_RECEIVED("RESPONSE_RECEIVED"), CLOSE("CLOSE"), - EXPIRED("EXPIRED"); + EXPIRED("EXPIRED"), + /** Amendment PEC email was rejected; only instructor can update until status is set back to AWAITING. */ + DRAFT("DRAFT"); private String value; diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/VersionHistoryRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/VersionHistoryRepository.java index 853bb945..782a2cc6 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/VersionHistoryRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/VersionHistoryRepository.java @@ -13,4 +13,6 @@ public interface VersionHistoryRepository extends JpaRepository findVersionHistoryByUserActionIdAndUserIdNull(Long id); List findVersionHistoryByUserActionId(Long id); + + List findVersionHistoryByUserActionIdAndTableName(Long userActionId, String tableName); } From 94c86ebacd2398b0e210d4add4fe73f639f186d0 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 16 Mar 2026 16:38:53 +0530 Subject: [PATCH 30/33] Updated amendment rejection email flow and handled for special amendment --- .../dao/ApplicationAmendmentRequestDao.java | 25 +-------- .../dao/EmailNotificationDao.java | 4 +- .../tendermanagement/dao/PecMailDao.java | 54 +++++++++++++++---- .../ApplicationAmendmentRequestEnum.java | 4 +- .../db/changelog/db.changelog-1.0.0.xml | 4 ++ ..._template_special_amendment_16_03_2026.sql | 7 +++ 6 files changed, 62 insertions(+), 36 deletions(-) create mode 100644 src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.sql diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index 0c12eb8e..33e70a17 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -786,10 +786,6 @@ public class ApplicationAmendmentRequestDao { log.warn("Permission denied: Beneficiary tried to update amendment ID {} with status RESPONSE_RECEIVED", id); throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); } - if(Boolean.TRUE.equals(isBeneficiary) && existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.DRAFT.getValue())){ - log.warn("Permission denied: Beneficiary tried to update amendment ID {} with status DRAFT (only instructor can update)", id); - throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); - } if(Boolean.FALSE.equals(isBeneficiary) && existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())){ log.warn("Permission denied: Non-beneficiary tried to update amendment ID {} with status AWAITING", id); throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); @@ -1283,26 +1279,7 @@ public class ApplicationAmendmentRequestDao { ApplicationAmendmentRequestEntity existingApplicationAmendment = validateApplicationAmendmentRequest(id); ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(existingApplicationAmendment); - if (ApplicationAmendmentRequestEnum.AWAITING.equals(statusTypeEnum)) { - // Only instructor can set status to AWAITING (e.g. after finishing edits post email rejection); beneficiary must not be allowed - if (Boolean.TRUE.equals(validator.checkIsBeneficiary()) || Boolean.TRUE.equals(validator.checkIsConfidi())) { - log.warn("Permission denied: Beneficiary/Confidi tried to set amendment ID {} status to AWAITING", id); - throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); - } - validator.validatePreInstructor(request, existingApplicationAmendment.getApplicationEvaluationEntity().getUserId()); - // Allow transition to AWAITING only from DRAFT (e.g. after instructor finished edits post email rejection) - if (!ApplicationAmendmentRequestEnum.DRAFT.getValue().equals(existingApplicationAmendment.getStatus())) { - log.warn("Invalid status transition: amendment ID {} is not in DRAFT (current: {})", id, existingApplicationAmendment.getStatus()); - throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_APPROPIATE_STATUS)); - } - log.info("Updating amendment ID {} status from DRAFT to AWAITING", id); - existingApplicationAmendment.setStatus(ApplicationAmendmentRequestEnum.AWAITING.getValue()); - existingApplicationAmendment.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); - applicationAmendmentRequestRepository.save(existingApplicationAmendment); - loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationAmendmentEntity).newData(existingApplicationAmendment).build()); - // Send the same mail as when (normal) amendment was created; only normal amendments can be in DRAFT (special amendment emails are sent at creation, not held) - emailNotificationDao.sendMailToNotifyBeneficiaryRegardingNewAmendment(existingApplicationAmendment); - } else if (Boolean.TRUE.equals(existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())) && Boolean.TRUE.equals(statusTypeEnum.equals(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED))) { + if (Boolean.TRUE.equals(existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())) && Boolean.TRUE.equals(statusTypeEnum.equals(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED))) { log.info("Updating amendment ID {} status from {} to {}", id, existingApplicationAmendment.getStatus(), statusTypeEnum); existingApplicationAmendment.setStatus(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED.getValue()); existingApplicationAmendment.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java index 7cfb73cc..60d867bc 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java @@ -427,7 +427,9 @@ public class EmailNotificationDao { if(Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_TECHNICAL_EVALUATION_REJECTED.getValue())) || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_ADMISSIBLE.getValue())) || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_REJECTED.getValue())) - || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue()))) { + || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue())) + || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED.getValue())) + || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE.getValue()))) { isSendEmail = Boolean.FALSE; } } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java index d25e1507..73a352c6 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java @@ -7,6 +7,7 @@ import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.enums.ApplicationEvaluationStatusTypeEnum; +import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.AssignedApplicationEnum; import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum; import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum; @@ -133,16 +134,39 @@ public class PecMailDao { String scenario = firstLog.getEmailType(); Long applicationId = firstLog.getApplicationId(); - // Only normal amendment emails are rejectable in PEC flow; set amendment to DRAFT so only instructor can update - if (EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue().equals(scenario)) { - Long amendmentId = firstLog.getAmendmentId(); - if (amendmentId != null) { - applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId).ifPresent(amendment -> { - amendment.setStatus(ApplicationAmendmentRequestEnum.DRAFT.getValue()); - applicationAmendmentRequestRepository.save(amendment); - log.info("Set amendment id={} to DRAFT after email rejected (userActionId={})", amendmentId, userActionId); - }); + // Amendment email rejected (normal or special): revert application, then mark amendment REJECTED and soft-deleted + boolean isNormalAmendment = EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue().equals(scenario); + boolean isSpecialAmendment = EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED.getValue().equals(scenario) + || EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE.getValue().equals(scenario); + + if (isNormalAmendment || isSpecialAmendment) { + ApplicationEntity applicationEntity = applicationService.validateApplication(applicationId); + if (isNormalAmendment) { + List appHistory = versionHistoryRepository.findVersionHistoryByUserActionIdAndTableName(userActionId, TABLE_APPLICATION); + Optional applicationVersion = appHistory.stream() + .filter(v -> applicationId.equals(v.getRecordId()) && v.getOldData() != null && !v.getOldData().isEmpty()) + .findFirst(); + if (applicationVersion.isPresent()) { + Map oldDataMap = Utils.convertJsonStringToMap(applicationVersion.get().getOldData()); + if (oldDataMap != null) { + String previousStatus = Utils.extractString(oldDataMap, "status"); + if (previousStatus != null) { + applicationEntity.setStatus(previousStatus); + } + applicationRepository.save(applicationEntity); + log.info("Rolled back application id={} from version history after amendment email rejected (userActionId={})", applicationId, userActionId); + } + } else { + log.warn("No APPLICATION version history with oldData found for userActionId={}, applicationId={}; skipping application rollback", userActionId, applicationId); + } + } else { + applicationEntity.setStatus(ApplicationStatusTypeEnum.ADMISSIBLE.getValue()); + applicationEntity.setDateRejected(null); + applicationRepository.save(applicationEntity); + log.info("Set application id={} to ADMISSIBLE after special amendment email rejected (userActionId={})", applicationId, userActionId); } + + markAmendmentRejectedAndDeleted(firstLog.getAmendmentId(), userActionId); return; } @@ -197,6 +221,18 @@ public class PecMailDao { }); } + private void markAmendmentRejectedAndDeleted(Long amendmentId, Long userActionId) { + if (amendmentId == null) { + return; + } + applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId).ifPresent(amendment -> { + amendment.setStatus(ApplicationAmendmentRequestEnum.REJECTED.getValue()); + amendment.setIsDeleted(true); + applicationAmendmentRequestRepository.save(amendment); + log.info("Set amendment id={} to REJECTED and is_deleted=true after amendment email rejected (userActionId={})", amendmentId, userActionId); + }); + } + private static LocalDateTime parseLocalDateTimeFromAudit(Object value) { if (value == null) { return null; diff --git a/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java index eeee1100..13a6d8c4 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java @@ -7,8 +7,8 @@ public enum ApplicationAmendmentRequestEnum { RESPONSE_RECEIVED("RESPONSE_RECEIVED"), CLOSE("CLOSE"), EXPIRED("EXPIRED"), - /** Amendment PEC email was rejected; only instructor can update until status is set back to AWAITING. */ - DRAFT("DRAFT"); + /** Special amendment PEC email was rejected; amendment status set to REJECTED. */ + REJECTED("REJECTED"); private String value; 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 7f005f1f..8ce255b6 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 @@ -3205,4 +3205,8 @@ + + + + diff --git a/src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.sql b/src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.sql new file mode 100644 index 00000000..03cd457d --- /dev/null +++ b/src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.sql @@ -0,0 +1,7 @@ +UPDATE gepafin_schema.system_email_template +SET subject='Comunicazione esito valutazione tecnica ed economico-finanziaria– Avviso {{call_name}} ' +WHERE email_scenario='SPECIAL_APPLICATION_AMENDMENT_REQUESTED'; + +UPDATE gepafin_schema.system_email_template +SET subject='Comunicazione esito valutazione tecnica ed economico-finanziaria– Avviso {{call_name}} ' +WHERE email_scenario='SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE'; \ No newline at end of file From d0b05aae1129aaf124a3752e806f7751cafb88a7 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 16 Mar 2026 20:07:27 +0530 Subject: [PATCH 31/33] Updated code --- src/main/resources/db/changelog/db.changelog-1.0.0.xml | 4 ---- ..._system_email_template_special_amendment_16_03_2026.sql | 7 ------- 2 files changed, 11 deletions(-) delete mode 100644 src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.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 8ce255b6..7f005f1f 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 @@ -3205,8 +3205,4 @@ - - - - diff --git a/src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.sql b/src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.sql deleted file mode 100644 index 03cd457d..00000000 --- a/src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.sql +++ /dev/null @@ -1,7 +0,0 @@ -UPDATE gepafin_schema.system_email_template -SET subject='Comunicazione esito valutazione tecnica ed economico-finanziaria– Avviso {{call_name}} ' -WHERE email_scenario='SPECIAL_APPLICATION_AMENDMENT_REQUESTED'; - -UPDATE gepafin_schema.system_email_template -SET subject='Comunicazione esito valutazione tecnica ed economico-finanziaria– Avviso {{call_name}} ' -WHERE email_scenario='SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE'; \ No newline at end of file From b225b9f0423affac65d09e7ae0ca2a05be005c12 Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 17 Mar 2026 15:12:48 +0530 Subject: [PATCH 32/33] Resolved conflict --- .../constants/GepafinConstant.java | 1 + .../dao/ApplicationAmendmentRequestDao.java | 89 ++++++++++++++----- .../tendermanagement/dao/PecMailDao.java | 32 ++++++- .../ApplicationAmendmentRequestEnum.java | 3 + src/main/resources/message_en.properties | 1 + src/main/resources/message_it.properties | 1 + 6 files changed, 101 insertions(+), 26 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index f223d922..cf39a573 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -637,6 +637,7 @@ public class GepafinConstant { public static final String PEC_EMAIL_REJECTED_SUCCESSFULLY="pec.email.rejected.successfully"; public static final String EMAIL_LOG_FETCHED="email.log.fetched"; public static final String APPLICATION_AMENDMENT_APPROPIATE_STATUS="amendment.appropiate.status"; + public static final String AMENDMENT_MUST_BE_APPROVED_FIRST_MSG = "amendment.must.be.approved.first"; public static final String UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION_MSG="upload.company.document.to.application"; public static final String COMPANY_DOCUMENT_NOT_FOUND_WITH_IDS="company.document.not.found.with.ids"; public static final String REQUIRED_AMOUNT_FIELD_NOT_PROVIDED = "amount.field.not.provided"; diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index 45b867b2..c8313ffa 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -335,12 +335,12 @@ public class ApplicationAmendmentRequestDao { log.warn("Invalid responseDays received: {}", applicationAmendmentRequest.getResponseDays()); throw new CustomValidationException(Status.BAD_REQUEST,Translator.toLocale(GepafinConstant.RESPONSE_DAYS_NOT_NULL)); } - applicationAmendmentRequestEntity.setEndDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now()).plusDays(applicationAmendmentRequest.getResponseDays())); - applicationAmendmentRequestEntity.setIsEmail(applicationAmendmentRequest.getIsSendEmail()); applicationAmendmentRequestEntity.setIsNotification(applicationAmendmentRequest.getIsSendNotification()); - applicationAmendmentRequestEntity.setStartDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); - applicationAmendmentRequestEntity.setStatus(ApplicationAmendmentRequestEnum.AWAITING.getValue()); + // startDate and endDate set to null until director approves (sends PEC); status DRAFT until then + applicationAmendmentRequestEntity.setStartDate(null); + applicationAmendmentRequestEntity.setEndDate(null); + applicationAmendmentRequestEntity.setStatus(ApplicationAmendmentRequestEnum.DRAFT.getValue()); applicationAmendmentRequestEntity.setType(ApplicationAmendmentRequestTypeEnum.REGULAR.getValue()); ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(applicationEvaluationId); //cloned for old data entity @@ -367,20 +367,7 @@ public class ApplicationAmendmentRequestDao { applicationAmendmentRequestEntity.setFormFields(formFieldsJson); } List amendmentRequest = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse(applicationEvaluationEntity.getId()); - // Ensure startDate and initialDays are not null to avoid NullPointerException - if (amendmentRequest !=null && amendmentRequest.isEmpty()) { - if (applicationEvaluationEntity.getStartDate() != null && applicationEvaluationEntity.getInitialDays() != null) { - Long initialDays = applicationEvaluationEntity.getInitialDays(); - LocalDateTime startDate = applicationEvaluationEntity.getStartDate(); - LocalDateTime nowInUTC = DateTimeUtil.DateServerToUTC(LocalDateTime.now()); - // Calculate remaining days - Long remainingDays = initialDays - DAYS.between(startDate, nowInUTC); - // Set remaining days in the entity - applicationEvaluationEntity.setRemainingDays(remainingDays); - //Set stop date time in the entity becuase amendment has started - applicationEvaluationEntity.setStopDateTime(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); - } - } + // remainingDays/stopDateTime are set when director approves (see approveAmendment) boolean noneClosedOrExpired = amendmentRequest.stream() .noneMatch(amendment -> @@ -1221,7 +1208,8 @@ public class ApplicationAmendmentRequestDao { log.info("Extending response days for Application Amendment ID: {}, Additional Days: {}", id, newResponseDays); ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = validateApplicationAmendmentRequest(id); if(Boolean.TRUE.equals(applicationAmendmentRequestEntity.getStatus().equals(ApplicationAmendmentRequestEnum.CLOSE.getValue())) - || Boolean.TRUE.equals(applicationAmendmentRequestEntity.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue()))) { + || Boolean.TRUE.equals(applicationAmendmentRequestEntity.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())) + || Boolean.TRUE.equals(applicationAmendmentRequestEntity.getStatus().equals(ApplicationAmendmentRequestEnum.DRAFT.getValue()))) { throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_APPROPIATE_STATUS)); } log.info("Extending response days for Application Amendment ID: {}, Additional Days: {}", id, newResponseDays); @@ -1279,6 +1267,9 @@ public class ApplicationAmendmentRequestDao { ApplicationAmendmentRequestEntity existingApplicationAmendment = validateApplicationAmendmentRequest(id); ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(existingApplicationAmendment); if (Boolean.TRUE.equals(existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())) && Boolean.TRUE.equals(statusTypeEnum.equals(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED))) { + if (existingApplicationAmendment.getStartDate() == null) { + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.AMENDMENT_MUST_BE_APPROVED_FIRST_MSG)); + } log.info("Updating amendment ID {} status from {} to {}", id, existingApplicationAmendment.getStatus(), statusTypeEnum); existingApplicationAmendment.setStatus(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED.getValue()); existingApplicationAmendment.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); @@ -1292,12 +1283,63 @@ public class ApplicationAmendmentRequestDao { return response; } + /** + * Sets amendment startDate, endDate and status AWAITING when director sends PEC mail (approval). + * Called from PecMailDao after PEC send succeeds; amendment id comes from email log (user action). + * No-op if amendment not found, not DRAFT (or already has startDate set), or startDate already set. + */ + public void setAmendmentStartAndEndDateOnPecSent(Long amendmentId) { + if (amendmentId == null) { + return; + } + Optional optional = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId); + if (optional.isEmpty()) { + return; + } + ApplicationAmendmentRequestEntity amendment = optional.get(); + boolean isDraft = ApplicationAmendmentRequestEnum.DRAFT.getValue().equals(amendment.getStatus()); + boolean isAwaitingWithNoStart = ApplicationAmendmentRequestEnum.AWAITING.getValue().equals(amendment.getStatus()) && amendment.getStartDate() == null; + if ((!isDraft && !isAwaitingWithNoStart) || amendment.getStartDate() != null) { + return; + } + log.info("Setting amendment ID {} startDate/endDate and status AWAITING after PEC mail sent.", amendmentId); + Long responseDays = amendment.getResponseDays() != null ? amendment.getResponseDays() : 0L; + LocalDateTime nowUtc = DateTimeUtil.DateServerToUTC(LocalDateTime.now()); + ApplicationAmendmentRequestEntity oldEntity = Utils.getClonedEntityForData(amendment); + amendment.setStartDate(nowUtc); + amendment.setEndDate(nowUtc.plusDays(responseDays)); + amendment.setStatus(ApplicationAmendmentRequestEnum.AWAITING.getValue()); + amendment.setUpdatedDate(nowUtc); + + ApplicationEvaluationEntity evaluation = amendment.getApplicationEvaluationEntity(); + List allForEvaluation = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse(evaluation.getId()); + boolean isFirstApprovedAmendment = allForEvaluation.stream() + .filter(a -> !a.getId().equals(amendment.getId())) + .noneMatch(a -> a.getStartDate() != null); + + if (isFirstApprovedAmendment && evaluation.getStartDate() != null && evaluation.getInitialDays() != null) { + Long initialDays = evaluation.getInitialDays(); + LocalDateTime evalStartDate = evaluation.getStartDate(); + Long remainingDays = initialDays - DAYS.between(evalStartDate, nowUtc); + evaluation.setRemainingDays(remainingDays); + evaluation.setStopDateTime(nowUtc); + applicationEvaluationRepository.save(evaluation); + } + + applicationAmendmentRequestRepository.save(amendment); + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldEntity).newData(amendment).build()); + log.info("Amendment ID {} startDate and endDate set after PEC sent.", amendmentId); + } + public EmailReminderResponse sendReminderEmail(Long amendmentId) { log.info("Initiating reminder email process for Amendment ID: {}", amendmentId); ApplicationAmendmentRequestEntity amendment = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId) .orElseThrow(() -> { log.error("Amendment not found with ID: {}", amendmentId); return new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG)); }); + if (!ApplicationAmendmentRequestEnum.AWAITING.getValue().equals(amendment.getStatus())) { + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_APPROPIATE_STATUS)); + } Optional entityOptional = applicationEvaluationRepository.findByIdAndIsDeletedFalse(amendment.getApplicationEvaluationEntity().getId()); EmailReminderResponse emailReminderResponse = new EmailReminderResponse(); @@ -1875,11 +1917,12 @@ public class ApplicationAmendmentRequestDao { else { applicationAmendmentRequestEntity.setResponseDays(10l); } - applicationAmendmentRequestEntity.setEndDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now()).plusDays(applicationAmendmentRequestEntity.getResponseDays())); + // startDate and endDate set when director approves (see approveAmendment) + applicationAmendmentRequestEntity.setEndDate(null); applicationAmendmentRequestEntity.setIsEmail(Boolean.TRUE); applicationAmendmentRequestEntity.setIsNotification(Boolean.FALSE); - applicationAmendmentRequestEntity.setStartDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); - applicationAmendmentRequestEntity.setStatus(ApplicationAmendmentRequestEnum.AWAITING.getValue()); + applicationAmendmentRequestEntity.setStartDate(null); + applicationAmendmentRequestEntity.setStatus(ApplicationAmendmentRequestEnum.DRAFT.getValue()); // if ( applicationEvaluationEntity.getStartDate() != null && applicationEvaluationEntity.getInitialDays() != null ) { // Long initialDays = applicationEvaluationEntity.getInitialDays(); // LocalDateTime startDate = applicationEvaluationEntity.getStartDate(); @@ -1938,7 +1981,7 @@ public class ApplicationAmendmentRequestDao { ApplicationAmendmentRequestResponse applicationAmendmentRequestResponse = convertEntityToResponse(applicationAmendmentRequestEntity,false); if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())){ - log.info("Sending mail for the special amendment for amendment ID = {}", applicationAmendment.getId()); +// log.info("Sending mail for the special amendment for amendment ID = {}", applicationAmendment.getId()); saveEmailSendResponse(emailSendResponse, applicationAmendmentRequestEntity); applicationAmendmentRequestResponse.setEmailSendResponse(responses); } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java index fcaecbcc..ea1aef50 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java @@ -6,13 +6,13 @@ import lombok.extern.log4j.Log4j2; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.*; +import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum; import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum; import net.gepafin.tendermanagement.enums.StatusTypeEnum; import net.gepafin.tendermanagement.model.response.EmailLogResponse; import net.gepafin.tendermanagement.model.response.PecEmailLogResponse; import net.gepafin.tendermanagement.model.response.PecMailResponse; -import net.gepafin.tendermanagement.repositories.EmailLogRepository; -import net.gepafin.tendermanagement.repositories.UserActionsRepository; +import net.gepafin.tendermanagement.repositories.*; import net.gepafin.tendermanagement.service.ApplicationService; import net.gepafin.tendermanagement.service.CallService; import net.gepafin.tendermanagement.util.DateTimeUtil; @@ -51,6 +51,25 @@ public class PecMailDao { @Autowired private ApplicationService applicationService; + @Autowired + private ApplicationRepository applicationRepository; + + @Autowired + private ApplicationEvaluationRepository applicationEvaluationRepository; + + @Autowired + private AssignedApplicationsRepository assignedApplicationsRepository; + + @Autowired + private VersionHistoryRepository versionHistoryRepository; + + @Autowired + private ApplicationAmendmentRequestRepository applicationAmendmentRequestRepository; + + @Autowired + private ApplicationAmendmentRequestDao applicationAmendmentRequestDao; + + private static final String TABLE_APPLICATION = "APPLICATION"; public List sendPecMail(HttpServletRequest request, List userActionIds) { @@ -67,6 +86,13 @@ public class PecMailDao { recipients, log ); + // When PEC send succeeded and this is an amendment email (regular or special), set amendment startDate/endDate and status AWAITING + boolean isAmendmentEmail = EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue().equals(log.getEmailType()) + || EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED.getValue().equals(log.getEmailType()) + || EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE.getValue().equals(log.getEmailType()); + if (isAmendmentEmail && log.getAmendmentId() != null && StatusTypeEnum.SUCCESS.getValue().equals(log.getSendStatus())) { + applicationAmendmentRequestDao.setAmendmentStartAndEndDateOnPecSent(log.getAmendmentId()); + } ApplicationEntity applicationEntity=applicationService.validateApplication(log.getApplicationId()); String callName=applicationEntity.getCall().getName(); PecMailResponse pecMailResponse=createPecMailResponse(log.getUserAction().getId(),log,callName); @@ -115,7 +141,7 @@ public class PecMailDao { for(EmailLogEntity emailLogEntity:emailLogs) { PecEmailLogResponse pecEmailLogResponse = createPecEmailLogResponse(userActionId, emailLogEntity, callName); pecEmailLogResponses.add(pecEmailLogResponse); - } + } return pecEmailLogResponses; } diff --git a/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java index d25ef71d..98881c36 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java @@ -3,6 +3,9 @@ package net.gepafin.tendermanagement.enums; import com.fasterxml.jackson.annotation.JsonValue; public enum ApplicationAmendmentRequestEnum { + /** Created but not yet approved (PEC not sent by director). */ + DRAFT("DRAFT"), + /** Director sent PEC (approved); amendment is active and awaiting beneficiary response. */ AWAITING("AWAITING"), RESPONSE_RECEIVED("RESPONSE_RECEIVED"), CLOSE("CLOSE"), diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index 65b69eff..b223a21d 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -429,6 +429,7 @@ mail.send.successfully=Mail sent succesfully. pec.email.rejected.successfully=Email rejected successfully. email.log.fetched=Email log fetched successfully. amendment.appropiate.status=Application amendment is not in appropiate status for this operation. +amendment.must.be.approved.first=Amendment must be approved by the director before response can be recorded. upload.company.document.to.application=Uploaded company document to application successfully. company.document.not.found.with.ids=Company document not found. Missing IDs: {0}. amount.field.not.provided= Please provide the required amount fields. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 2437fa0b..bcff6a8f 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -420,6 +420,7 @@ mail.send.successfully=Email inviata con successo. pec.email.rejected.successfully=Email rifiutata con successo. email.log.fetched=Registro email recuperato correttamente. amendment.appropiate.status=L'emendamento dell'applicazione non � in stato appropriato per questa operazione. +amendment.must.be.approved.first=L'emendamento deve essere approvato dal direttore prima di poter registrare la risposta. upload.company.document.to.application=Documento aziendale caricato correttamente nell'applicazione. company.document.not.found.with.ids=Documento aziendale non trovato. ID mancanti: {0} amount.field.not.provided= Si prega di fornire i campi obbligatori per l'importo. From b644707f85fc42b8e76f4178c0ba80f8687b06cc Mon Sep 17 00:00:00 2001 From: rajesh Date: Thu, 9 Apr 2026 12:14:59 +0530 Subject: [PATCH 33/33] Resolved conflict --- src/main/resources/application.properties | 2 +- src/main/resources/db/changelog/db.changelog-1.0.0.xml | 3 +++ .../db/dump/update_email_config_for_mailgun_09_04_2026.sql | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/db/dump/update_email_config_for_mailgun_09_04_2026.sql diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 7fffc70b..f3798939 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -57,7 +57,7 @@ active.profile.folder=dev # MailGun API mailGun_base_url=https://api.eu.mailgun.net/ #Below credentials are only for sending mail to rinaldo -mailGun_apiKey= 398e3dea1911fe941af261906ec99362-07e2c238-8094421f +mailGun_apiKey= 541d407d4a8e2cd943d00cb4529f0fba-415ae7fb-7aded414 mailGun_user=comunicazione@paghiamoci.ai mailGun_domainName=paghiamoci.ai 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 7f005f1f..9c50da89 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 @@ -3205,4 +3205,7 @@ + + + diff --git a/src/main/resources/db/dump/update_email_config_for_mailgun_09_04_2026.sql b/src/main/resources/db/dump/update_email_config_for_mailgun_09_04_2026.sql new file mode 100644 index 00000000..bebf92a1 --- /dev/null +++ b/src/main/resources/db/dump/update_email_config_for_mailgun_09_04_2026.sql @@ -0,0 +1,4 @@ +UPDATE hub +SET + email_service_config = 'FgMmDkXJGSWaZIKaR/NyYcilihMOy7gDL/wbeTqYbJeNyUpj4J6ew2qAznFimoTePqoOriC9cyX9Jjlvr2QKsDCL6N2OmozX9uIhqmgvTRS2QLC6oVg4wvwvWJZig3i70YWQQrkXXZQ6f2pg9xzMxYJZ75KpnqFzqudjQ7BSnrzRyK1USODyN7rczkcDSVGn+3cbj0/mWMPWxF1St+DzFt27Sos0pTtoxvXqHorGe6PQauN540vXlUJNA4ouZAh+R3TL4G/vXu46LpqhvqTEDZ24XI8x6rhBHUMKKBLxMe3+ZfIbyCZ9COm5zvEaJ5cB' +WHERE UNIQUE_UUID = 't7jh5wfg9QXylNaTZkPoE'; \ No newline at end of file