Done ticket GEPAFINBE-6143

This commit is contained in:
rajesh
2025-11-04 16:46:25 +05:30
parent fcee98a228
commit 5171c69df4
30 changed files with 837 additions and 44 deletions

View File

@@ -623,7 +623,14 @@ public class GepafinConstant {
public static final List<String> MANUAL_EMAIL_KEYS = Arrays.asList(SUBJECT, MESSAGE);
public static final String INVALID_EMAIL_JSON = "invalid.email.json";
public static final String MORE_FIELDS_REQUIRED_FOR_REJECTION="more.fields.required";
public static final String CREATE_APPLICATION_CONTRACT="create.application.contract";
public static final String APPLICATION_CONTRACT_NOT_FOUND="application.contract.not.found";
public static final String APPLICATION_CONTRACT_FETCHED="application.contract.fetched";
public static final String APPLICATION_CONTRACT_UPDATED="application.contract.updated";
public static final String FILES_REQUIRED_FOR_CONTRACT="files.required.for.contract";
public static final String APPLICATION_CONTRACT_ALREADY_EXIST="application.contract.already.exist";
public static final String APPLICATION_NOT_APPROVED="application.not.approved";
public static final String SUBJECT_AND_BODY_REQUIRED="subject.body.required";
}

View File

@@ -662,7 +662,7 @@ public class ApplicationAmendmentRequestDao {
response.setApplicationFormFields(fileDetails);
}
private List<DocumentResponseBean> getDocumentResponseBean(String documentId) {
public List<DocumentResponseBean> getDocumentResponseBean(String documentId) {
List<Long> documentIds = extractIds(documentId);
List<DocumentResponseBean> documentResponseBeans = documentIds.stream()
.map(id -> {

View File

@@ -0,0 +1,220 @@
package net.gepafin.tendermanagement.dao;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.config.Translator;
import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.entities.ApplicationContractEntity;
import net.gepafin.tendermanagement.entities.ApplicationEntity;
import net.gepafin.tendermanagement.entities.ApplicationEvaluationEntity;
import net.gepafin.tendermanagement.entities.UserEntity;
import net.gepafin.tendermanagement.enums.*;
import net.gepafin.tendermanagement.model.request.ApplicationContractRequest;
import net.gepafin.tendermanagement.model.request.VersionHistoryRequest;
import net.gepafin.tendermanagement.model.response.ApplicationContractResponse;
import net.gepafin.tendermanagement.model.response.DocumentResponseBean;
import net.gepafin.tendermanagement.repositories.ApplicationContractRepository;
import net.gepafin.tendermanagement.repositories.ApplicationRepository;
import net.gepafin.tendermanagement.util.DateTimeUtil;
import net.gepafin.tendermanagement.util.LoggingUtil;
import net.gepafin.tendermanagement.util.Utils;
import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException;
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class ApplicationContractDao {
@Autowired
private ApplicationDao applicationDao;
@Autowired
private DocumentDao documentDao;
@Autowired
private ApplicationContractRepository applicationContractRepository;
@Autowired
private ApplicationRepository applicationRepository;
@Autowired
private HttpServletRequest request;
@Autowired
private LoggingUtil loggingUtil;
@Autowired
private ApplicationAmendmentRequestDao applicationAmendmentRequestDao;
@Autowired
private EmailNotificationDao emailNotificationDao;
@Autowired
private ApplicationEvaluationDao applicationEvaluationDao;
@Autowired
private NotificationDao notificationDao;
public ApplicationContractResponse createApplicationContract(Long applicationId, List<MultipartFile> contractDocuments, ApplicationContractRequest applicationContractRequest, UserEntity user) {
ApplicationEntity applicationEntity = applicationDao.validateApplication(applicationId);
if (Boolean.FALSE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.APPROVED.getValue()))) {
throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.APPLICATION_NOT_APPROVED));
}
if (applicationContractRequest.getSubject() == null || applicationContractRequest.getText() == null) {
throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.SUBJECT_AND_BODY_REQUIRED));
}
ApplicationEntity oldApplicationData = Utils.getClonedEntityForData(applicationEntity);
ApplicationContractEntity existingApplicationContractEntity = applicationContractRepository.findByApplicationIdAndIsDeletedFalse(applicationId);
if (existingApplicationContractEntity != null) {
throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.APPLICATION_CONTRACT_ALREADY_EXIST));
}
ApplicationContractEntity applicationContractEntity = createApplicationContractEntity(applicationContractRequest, user, applicationEntity);
loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(applicationContractEntity).build());
List<DocumentResponseBean> documentResponseBeans = setContractDocuments(contractDocuments, user, applicationContractEntity);
applicationEntity.setStatus(ApplicationStatusTypeEnum.AWAITING_CONTRACT.getValue());
applicationRepository.save(applicationEntity);
loggingUtil.addVersionHistory(
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationData).newData(applicationEntity).build());
emailNotificationDao.sendEmailForApplicationContracted(applicationEntity, applicationContractEntity, user);
return createApplicationContractResponse(applicationContractEntity, documentResponseBeans, null);
}
private ApplicationContractResponse createApplicationContractResponse(ApplicationContractEntity applicationContractEntity, List<DocumentResponseBean> instructorDocuments, List<DocumentResponseBean> beneficiaryDocuments) {
ApplicationContractResponse applicationContractResponse = new ApplicationContractResponse();
applicationContractResponse.setId(applicationContractEntity.getId());
applicationContractResponse.setText(applicationContractEntity.getText());
applicationContractResponse.setSubject(applicationContractEntity.getSubject());
applicationContractResponse.setInstructorId(applicationContractEntity.getInstructorId());
applicationContractResponse.setStatus(ApplicationContractStatusEnum.valueOf(applicationContractEntity.getStatus()));
applicationContractResponse.setInstructorDocuments(instructorDocuments);
applicationContractResponse.setBeneficiaryDocuments(beneficiaryDocuments);
applicationContractResponse.setCompletionDate(applicationContractEntity.getCompletionDate());
applicationContractResponse.setBeneficiaryUserId(applicationContractEntity.getBeneficiaryUserId());
return applicationContractResponse;
}
private List<DocumentResponseBean> setContractDocuments(List<MultipartFile> contractDocuments, UserEntity user, ApplicationContractEntity applicationContractEntity) {
List<DocumentResponseBean> documentResponseBeans = uploadContractDocument(user.getId(), contractDocuments, applicationContractEntity.getId());
List<Long> contractDocumentIds = documentResponseBeans.stream()
.map(DocumentResponseBean::getId)
.collect(Collectors.toList());
String contractDocumentId = contractDocumentIds.stream()
.map(String::valueOf)
.collect(Collectors.joining(","));
applicationContractEntity.setInstructorDocument(contractDocumentId);
applicationContractRepository.save(applicationContractEntity);
return documentResponseBeans;
}
private ApplicationContractEntity createApplicationContractEntity(ApplicationContractRequest applicationContractRequest, UserEntity user, ApplicationEntity applicationEntity) {
ApplicationContractEntity applicationContractEntity = new ApplicationContractEntity();
applicationContractEntity.setSubject(applicationContractRequest.getSubject());
applicationContractEntity.setText(applicationContractRequest.getText());
applicationContractEntity.setApplicationId(applicationEntity.getId());
applicationContractEntity.setInstructorId(user.getId());
applicationContractEntity.setIsDeleted(Boolean.FALSE);
applicationContractEntity.setApplicationId(applicationEntity.getId());
applicationContractEntity.setStatus(ApplicationContractStatusEnum.DRAFT.getValue());
applicationContractEntity.setBeneficiaryUserId(applicationEntity.getUserId());
applicationContractRepository.save(applicationContractEntity);
return applicationContractEntity;
}
public List<DocumentResponseBean> uploadContractDocument(Long userId, List<MultipartFile> files, Long applicationContractId) {
if (files != null) {
return documentDao.uploadFiles(userId, files, applicationContractId, DocumentSourceTypeEnum.CONTRACT, DocumentTypeEnum.DOCUMENT);
}
return new ArrayList<>();
}
public ApplicationContractResponse updateApplicationContract(Long applicationContractId, List<MultipartFile> beneficiaryContractDocuments, UserEntity user) {
ApplicationContractEntity applicationContractEntity = validateApplicationContract(applicationContractId);
ApplicationContractEntity oldApplicationContract = Utils.getClonedEntityForData(applicationContractEntity);
applicationContractEntity.setCompletionDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now()));
applicationContractEntity.setStatus(ApplicationContractStatusEnum.SIGNED.getValue());
List<DocumentResponseBean> beneficiaryContractDocuments1 = setBeneficiaryContractDocuments(beneficiaryContractDocuments, user, applicationContractEntity);
List<DocumentResponseBean> documentResponseBeans = applicationAmendmentRequestDao.getDocumentResponseBean(applicationContractEntity.getInstructorDocument());
loggingUtil.addVersionHistory(
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationContract).newData(applicationContractEntity).build());
ApplicationEntity applicationEntity = applicationDao.validateApplication(applicationContractEntity.getApplicationId());
ApplicationEntity oldApplicationData = Utils.getClonedEntityForData(applicationEntity);
ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationDao.validateApplicationEvaluation(applicationEntity.getApplicationEvaluationId());
applicationEntity.setStatus(ApplicationStatusTypeEnum.CONTRACT_SIGNED.getValue());
applicationRepository.save(applicationEntity);
loggingUtil.addVersionHistory(
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationData).newData(applicationEntity).build());
Map<String, String> placeHolders = new HashMap<>();
placeHolders.put("{{call_name}}", applicationEntity.getCall().getName());
String protocolNumber = applicationEntity.getProtocol().getExternalProtocolNumber();
if (protocolNumber == null) {
protocolNumber = String.valueOf(applicationEntity.getProtocol().getProtocolNumber());
}
placeHolders.put("{{protocol_number}}", protocolNumber);
notificationDao.sendNotificationToInstructor(placeHolders, applicationEvaluationEntity, NotificationTypeEnum.CONTRACT_UPLOAD);
return createApplicationContractResponse(applicationContractEntity, documentResponseBeans, beneficiaryContractDocuments1);
}
public ApplicationContractEntity validateApplicationContract(Long applicationContractId) {
ApplicationContractEntity applicationContractEntity = applicationContractRepository.findByIdAndIsDeletedFalse(applicationContractId);
if (applicationContractEntity == null) {
throw new CustomValidationException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_CONTRACT_NOT_FOUND));
}
return applicationContractEntity;
}
private List<DocumentResponseBean> setBeneficiaryContractDocuments(List<MultipartFile> contractDocuments, UserEntity user, ApplicationContractEntity applicationContractEntity) {
List<DocumentResponseBean> documentResponseBeans = uploadContractDocument(user.getId(), contractDocuments, applicationContractEntity.getId());
List<Long> contractDocumentIds = documentResponseBeans.stream()
.map(DocumentResponseBean::getId)
.collect(Collectors.toList());
String contractDocumentId = contractDocumentIds.stream()
.map(String::valueOf)
.collect(Collectors.joining(","));
applicationContractEntity.setBeneficiaryDocument(contractDocumentId);
applicationContractRepository.save(applicationContractEntity);
return documentResponseBeans;
}
public ApplicationContractResponse getContractById(Long contractId) {
ApplicationContractEntity applicationContractEntity = validateApplicationContract(contractId);
return createApplicationContractResponseFromEntity(applicationContractEntity);
}
private ApplicationContractResponse createApplicationContractResponseFromEntity(ApplicationContractEntity applicationContractEntity) {
List<DocumentResponseBean> instructorDocuments = applicationAmendmentRequestDao.getDocumentResponseBean(applicationContractEntity.getInstructorDocument());
List<DocumentResponseBean> beneficiaryDocuments = applicationAmendmentRequestDao.getDocumentResponseBean(applicationContractEntity.getBeneficiaryDocument());
return createApplicationContractResponse(applicationContractEntity, instructorDocuments, beneficiaryDocuments);
}
public ApplicationContractResponse getContractByApplicationId(Long applicationId) {
ApplicationContractEntity applicationContractEntity = applicationContractRepository.findByApplicationIdAndIsDeletedFalse(applicationId);
if (applicationContractEntity == null) {
return null;
}
return createApplicationContractResponseFromEntity(applicationContractEntity);
}
public List<ApplicationContractResponse> getContractByBeneficiaryUserId(UserEntity user) {
List<ApplicationContractEntity> applicationContractEntities = applicationContractRepository.findByBeneficiaryUserIdAndStatusAndIsDeletedFalse(user.getId(), ApplicationContractStatusEnum.DRAFT.getValue());
if (applicationContractEntities.isEmpty()) {
return null;
}
List<ApplicationContractResponse> applicationContractResponses = new ArrayList<>();
for (ApplicationContractEntity applicationContractEntity : applicationContractEntities) {
ApplicationContractResponse applicationContractResponse = createApplicationContractResponseFromEntity(applicationContractEntity);
applicationContractResponses.add(applicationContractResponse);
}
return applicationContractResponses;
}
}

View File

@@ -229,6 +229,9 @@ public class ApplicationDao {
@Autowired
private SystemEmailTemplatesDao systemEmailTemplatesDao;
@Autowired
private ApplicationContractRepository applicationContractRepository;
public final Random random = new Random();
public ApplicationResponseBean createApplication(HttpServletRequest request, ApplicationRequestBean applicationRequestBean, Long formId, Long applicationId) {
@@ -1383,7 +1386,7 @@ public class ApplicationDao {
ApplicationSignedDocumentEntity oldApplicationSignedDocument = Utils.getClonedEntityForData(applicationSignedDocumentEntity);
String oldS3Path = applicationSignedDocumentEntity.getFilePath();
log.debug("Old S3 path: {} ", oldS3Path);
String newS3Path = s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.DELETED_USER_SIGNED_DOCUMENT,applicationSignedDocumentEntity.getApplication().getCall().getId(),applicationSignedDocumentEntity.getApplication().getId(),0L,0L);
String newS3Path = s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.DELETED_USER_SIGNED_DOCUMENT,applicationSignedDocumentEntity.getApplication().getCall().getId(),applicationSignedDocumentEntity.getApplication().getId(),0L,0L,0l);
log.debug("Generated new S3 path for deleted document: {}", newS3Path);
UploadFileOnAmazonS3Response response = amazonS3Service.moveFile(applicationSignedDocumentEntity.getFileName(), oldS3Path, newS3Path);
@@ -1418,7 +1421,7 @@ public class ApplicationDao {
}
private String generateS3PathForDelegation(Long callId, Long applicationId) {
try {
return s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.USER_SIGNED_DOCUMENT, callId, applicationId,0L,0L);
return s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.USER_SIGNED_DOCUMENT, callId, applicationId,0L,0L,0L);
} catch (IllegalArgumentException e) {
log.error("Failed to generate S3 path for delegation | callId: {}, applicationId: {}, error: {}", callId, applicationId, e.getMessage(), e);
throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.S3_PATH_GENERATION_ERROR_MSG));
@@ -1541,11 +1544,12 @@ public class ApplicationDao {
List<DocumentEntity> amendmentDocuments = fetchAmendmentDocuments(applicationId);
List<DocumentEntity> evaluationDocuments = fetchEvaluationDocuments(applicationId);
List<DocumentEntity> communicationnDocuments = fetchCommunicationDocuments(applicationId);
List<DocumentEntity> contractDocuments=fetchContractDocuments(applicationId);
if (documents.isEmpty() && signedDocument == null && amendmentDocuments.isEmpty() && evaluationDocuments.isEmpty()) {
log.warn("No documents found for applicationId: {}", applicationId);
throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.DOCUMENT_NOT_FOUND));
}
return createZipWithDocuments(applicationEntity, documents, signedDocument, amendmentDocuments, evaluationDocuments, applicationId,communicationnDocuments);
return createZipWithDocuments(applicationEntity, documents, signedDocument, amendmentDocuments, evaluationDocuments, applicationId,communicationnDocuments,contractDocuments);
}
private void validateAssignedUser(HttpServletRequest request, Long applicationId) {
@@ -1637,12 +1641,12 @@ public class ApplicationDao {
}
}
private byte[] createZipWithDocuments(ApplicationEntity applicationEntity, List<DocumentEntity> documents, ApplicationSignedDocumentEntity signedDocument,
List<DocumentEntity> amendmentDocuments, List<DocumentEntity> evaluationDocuments, Long applicationId,List<DocumentEntity> communicationDocuments) {
List<DocumentEntity> amendmentDocuments, List<DocumentEntity> evaluationDocuments, Long applicationId,List<DocumentEntity> communicationDocuments,List<DocumentEntity> contractDocuments) {
try (ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream(); ZipOutputStream zos = new ZipOutputStream(zipOutputStream)) {
Long callId = applicationEntity.getCall().getId();
// Add Application Documents
String appS3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.APPLICATION, callId, applicationId, 0L,0L);
String appS3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.APPLICATION, callId, applicationId, 0L,0L,0L);
for (DocumentEntity document : documents) {
String fileName = Utils.extractFileName(document.getFilePath());
addDocumentToZip(zos, appS3Folder, document.getFilePath(), fileName);
@@ -1650,7 +1654,7 @@ public class ApplicationDao {
// Add Signed Document
if (signedDocument != null) {
String signedFolder = "SIGNED_DOCUMENT/";
String signedDocS3Folder = s3PathConfig.generateDocumentPathForOther(DocOtherSourceTypeEnum.USER_SIGNED_DOCUMENT, callId, applicationId, 0L,0L);
String signedDocS3Folder = s3PathConfig.generateDocumentPathForOther(DocOtherSourceTypeEnum.USER_SIGNED_DOCUMENT, callId, applicationId, 0L,0L,0L);
String fileName = signedDocument.getFileName();
addDocumentToZip(zos, signedDocS3Folder, signedDocument.getFilePath(), signedFolder + fileName);
}
@@ -1658,23 +1662,30 @@ public class ApplicationDao {
for (DocumentEntity amendmentDocument : amendmentDocuments) {
String protocolNumber = fetchProtocolNumberForAmendment(amendmentDocument.getSourceId());
String amendmentFolder = "SOCCORSO_" + protocolNumber + "/";
String amendmentS3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.AMENDMENT, callId, applicationId, amendmentDocument.getSourceId(),0L);
String amendmentS3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.AMENDMENT, callId, applicationId, amendmentDocument.getSourceId(),0L,0L);
String fileName = Utils.extractFileName(amendmentDocument.getFilePath());
addDocumentToZip(zos, amendmentS3Folder, amendmentDocument.getFilePath(), amendmentFolder + fileName);
}
// Add Evaluation Documents
for (DocumentEntity evaluationDocument : evaluationDocuments) {
String evaluationFolder = "EVALUATION/";
String evaluationS3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.EVALUATION, callId, applicationId, evaluationDocument.getSourceId(),0L);
String evaluationS3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.EVALUATION, callId, applicationId, evaluationDocument.getSourceId(),0L,0L);
String fileName = Utils.extractFileName(evaluationDocument.getFilePath());
addDocumentToZip(zos, evaluationS3Folder, evaluationDocument.getFilePath(), evaluationFolder + fileName);
}
for (DocumentEntity communicationDocument : communicationDocuments) {
Optional<CommunicationEntity> communicationEntity=communicationRepository.findByIdAndIsDeletedFalse(communicationDocument.getSourceId());
String evaluationFolder = "COMMUNICATION/";
String evaluationS3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.COMMUNICATION, callId, applicationId, communicationEntity.get().getApplicationAmendmentRequest().getId(),communicationDocument.getSourceId());
String communicationFolder = "COMMUNICATION/";
String communicationS3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.COMMUNICATION, callId, applicationId, communicationEntity.get().getApplicationAmendmentRequest().getId(),communicationDocument.getSourceId(),0L);
String fileName = Utils.extractFileName(communicationDocument.getFilePath());
addDocumentToZip(zos, evaluationS3Folder, communicationDocument.getFilePath(), evaluationFolder + fileName);
addDocumentToZip(zos, communicationS3Folder, communicationDocument.getFilePath(), communicationFolder + fileName);
}
for (DocumentEntity contractDocument : contractDocuments) {
ApplicationContractEntity applicationContractEntity=applicationContractRepository.findByIdAndIsDeletedFalse(contractDocument.getSourceId());
String contractFolder = "CONTRACT/";
String contractS3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.CONTRACT, callId, applicationId, 0L,contractDocument.getSourceId(),applicationContractEntity.getApplicationId());
String fileName = Utils.extractFileName(contractDocument.getFilePath());
addDocumentToZip(zos, contractS3Folder, contractDocument.getFilePath(), contractFolder + fileName);
}
zos.finish();
return zipOutputStream.toByteArray();
@@ -2599,5 +2610,18 @@ public class ApplicationDao {
return out.toByteArray();
}
private List<DocumentEntity> fetchContractDocuments(Long applicationId) {
log.info("Fetching contract documents for applicationId: {}", applicationId);
ApplicationContractEntity applicationContractEntity=applicationContractRepository.findByApplicationIdAndIsDeletedFalse(applicationId);
List<DocumentEntity> documentEntities=new ArrayList<>();
if(applicationContractEntity!=null){
Long contractId = applicationContractEntity.getId();
log.debug("Found contract entity with id: {}", contractId);
List<DocumentEntity> communicationDocuments= documentRepository.findBySourceIdInAndSourceAndIsDeletedFalse(Collections.singleton(contractId), DocumentSourceTypeEnum.CONTRACT.getValue());
documentEntities.addAll(communicationDocuments);
return documentEntities;
}
return Collections.emptyList();
}
}

View File

@@ -155,7 +155,7 @@ public class CallDao {
for (DocumentEntity document : documents) {
log.info("Adding document to ZIP: documentId={}, fileName={}", document.getId(), document.getFileName());
String s3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.CALL, callId, 0L,0L,0L);
String s3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.CALL, callId, 0L,0L,0L,0L);
try (InputStream fileInputStream = amazonS3Service.getFile(s3Folder, document.getFilePath())) {
String fileName = Utils.extractFileName(document.getFilePath());
ZipEntry zipEntry = new ZipEntry(fileName);

View File

@@ -281,7 +281,7 @@ public class CompanyDocumentDao {
validator.validateUserWithCompany(request,companyDocumentEntity.getCompanyId());
String companyDocumentPath = companyDocumentEntity.getFilePath();
String documentPath = s3ConfigBean.generateDocumentPath(DocumentSourceTypeEnum.APPLICATION,applicationEntity.getCall().getId(),applicationId,0L,0L);
String documentPath = s3ConfigBean.generateDocumentPath(DocumentSourceTypeEnum.APPLICATION,applicationEntity.getCall().getId(),applicationId,0L,0L,0L);
log.info("Original Paths - oldPath: {}, newPath: {}", companyDocumentPath, documentPath);

View File

@@ -92,7 +92,7 @@ public class DelegationDao {
public ByteArrayOutputStream generateDocument(Map<String, String> placeholders, String templateName) {
try {
String s3Folder = s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.TEMPLATE, 0L, 0L,0L,0L);
String s3Folder = s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.TEMPLATE, 0L, 0L,0L,0L,0L);
InputStream templateStream = amazonS3Service.getFile(s3Folder ,templateName);
XWPFDocument doc = loadTemplate(templateStream);
replacePlaceholders(doc, placeholders);

View File

@@ -93,6 +93,9 @@ public class DocumentDao {
@Autowired
private CommunicationRepository communicationRepository;
@Autowired
private ApplicationContractRepository applicationContractRepository;
// @Value("${aws.s3.url.folder}")
// private String s3Folder;
@@ -172,6 +175,7 @@ public class DocumentDao {
Long amendmentId = 0L;
Long evaluationId = 0L;
Long communicationId = 0L;
Long contractId=0L;
Long callId = sourceId;
if (type == DocumentSourceTypeEnum.APPLICATION) {
applicationId = sourceId;
@@ -197,9 +201,16 @@ public class DocumentDao {
applicationId=applicationAmendmentRequestEntity.get().getApplicationId();
callId = applicationAmendmentRequestEntity.get().getApplicationEvaluationEntity().getAssignedApplicationsEntity().getApplication().getCall().getId();
log.info("Processing document of type COMMUNICATION .Resolved evaluationId={}, applicationId={}, callId={}", evaluationId, applicationId, callId);
}else if (type == DocumentSourceTypeEnum.CONTRACT) {
contractId = sourceId;
ApplicationContractEntity applicationContractEntity=applicationContractRepository.findByIdAndIsDeletedFalse(contractId);
ApplicationEntity applicationEntity=applicationService.validateApplication(applicationContractEntity.getApplicationId());
applicationId=applicationEntity.getId();
callId = applicationEntity.getCall().getId();
log.info("Processing document of type CONTRACT .Resolved evaluationId={}, applicationId={}, callId={}, contractId={}", evaluationId, applicationId, callId,contractId);
}
try {
String s3Path = generateS3Path(type, callId, applicationId, amendmentId,communicationId);
String s3Path = generateS3Path(type, callId, applicationId, amendmentId,communicationId,contractId);
log.info("Generated S3 path {}", s3Path);
return amazonS3Service.uploadFileOnAmazonS3(s3Path, file);
} catch (Exception e) {
@@ -210,9 +221,9 @@ public class DocumentDao {
}
public String generateS3Path(DocumentSourceTypeEnum typeOfDocument, Long callId, Long applicationId, Long amendmentId,Long communicationId) {
public String generateS3Path(DocumentSourceTypeEnum typeOfDocument, Long callId, Long applicationId, Long amendmentId,Long communicationId,Long contractId) {
try {
return s3ConfigBean.generateDocumentPath(typeOfDocument, callId, applicationId, amendmentId,communicationId);
return s3ConfigBean.generateDocumentPath(typeOfDocument, callId, applicationId, amendmentId,communicationId,contractId);
} catch (IllegalArgumentException e) {
throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.S3_PATH_GENERATION_ERROR_MSG));
}
@@ -245,6 +256,7 @@ public class DocumentDao {
Long amendmentId = null;
Long evaluationId = null;
Long communicationId=null;
Long contractId=null;
if (DocumentSourceTypeEnum.CALL.getValue().equalsIgnoreCase(documentEntity.getSource())) {
callId = documentEntity.getSourceId();
@@ -340,9 +352,20 @@ public class DocumentDao {
communicationEntity1.setDocuments(updatedValue);
communicationRepository.save(communicationEntity1);
}
}
else if(DocumentSourceTypeEnum.CONTRACT.getValue().equalsIgnoreCase(documentEntity.getSource())) {
contractId = documentEntity.getSourceId();
ApplicationContractEntity applicationContractEntity=applicationContractRepository.findByIdAndIsDeletedFalse(contractId);
ApplicationEntity applicationEntity=applicationService.validateApplication(applicationContractEntity.getApplicationId());
String beneficiaryDocument=applicationContractEntity.getBeneficiaryDocument();
if(beneficiaryDocument!=null) {
String updatedValue = removeDocumentIdFromFieldValue(beneficiaryDocument, documentId);
applicationContractEntity.setBeneficiaryDocument(updatedValue);
applicationContractRepository.save(applicationContractEntity);
}
}
deleteFileFromS3(documentEntity, callId, applicationId,amendmentId,communicationId);
deleteFileFromS3(documentEntity, callId, applicationId,amendmentId,communicationId,contractId);
log.info("Successfully deleted file from S3 for documentId={}", documentId);
}
@@ -387,6 +410,7 @@ public class DocumentDao {
Long amendmentId=null;
Long evaluationId=null;
Long communicationId=null;
Long contractId=null;
if (type.equals(DocumentSourceTypeEnum.APPLICATION)) {
callId = applicationRepository.findCallIdById(id);
applicationId = id;
@@ -412,6 +436,13 @@ public class DocumentDao {
applicationId=applicationAmendmentRequestEntity.get().getApplicationId();
callId = applicationAmendmentRequestEntity.get().getApplicationEvaluationEntity().getAssignedApplicationsEntity().getApplication().getCall().getId();
log.info("Processing document of type EVALUATION .Resolved evaluationId={}, applicationId={}, callId={}", evaluationId, applicationId, callId);
}else if (type == DocumentSourceTypeEnum.CONTRACT) {
contractId = id;
ApplicationContractEntity applicationContractEntity=applicationContractRepository.findByIdAndIsDeletedFalse(contractId);
ApplicationEntity applicationEntity=applicationService.validateApplication(applicationContractEntity.getApplicationId());
applicationId=applicationContractEntity.getApplicationId();
callId = applicationEntity.getCall().getId();
log.info("Processing document of type CONTRACT .Resolved evaluationId={}, applicationId={}, callId={}, contractId={}", evaluationId, applicationId, callId,contractId);
}
else {
@@ -419,7 +450,7 @@ public class DocumentDao {
applicationId = 0L;
log.info("Processing document of type CALL . Resolved callId={}", callId);
}
String s3Path = generateS3Path(type, callId, applicationId,amendmentId,communicationId);
String s3Path = generateS3Path(type, callId, applicationId,amendmentId,communicationId,contractId);
log.info("Generated S3 path {}", s3Path);
return amazonS3Service.uploadFileOnAmazonS3(s3Path, file);
} catch (Exception e) {
@@ -432,12 +463,12 @@ public class DocumentDao {
return callDao.convertToDocumentResponseBean(documentEntity);
}
public void deleteFileFromS3(DocumentEntity documentEntity, Long callId, Long applicationId,Long amendmentId,Long communicationId) {
public void deleteFileFromS3(DocumentEntity documentEntity, Long callId, Long applicationId,Long amendmentId,Long communicationId,Long contractId) {
try {
DocumentEntity oldDocumentEntity = Utils.getClonedEntityForData(documentEntity);
String oldS3Path = documentEntity.getFilePath();
String newS3Path = s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.valueOf("DELETED_" + documentEntity.getSource().toUpperCase()), callId, applicationId,amendmentId,communicationId);
String newS3Path = s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.valueOf("DELETED_" + documentEntity.getSource().toUpperCase()), callId, applicationId,amendmentId,communicationId,contractId);
log.info("Moving file to deleted path: oldS3Path={}, newS3Path={}", oldS3Path, newS3Path);
UploadFileOnAmazonS3Response response = amazonS3Service.moveFile(documentEntity.getFileName(), oldS3Path, newS3Path);
documentEntity.setFileName(response.getFileName());

View File

@@ -97,6 +97,9 @@ public class EmailNotificationDao {
@Autowired
private ApplicationDao applicationDao;
@Autowired
private ApplicationContractDao applicationContractDao;
public void sendEmail(ApplicationEntity applicationEntity, SystemEmailTemplatesEntity.SystemEmailTemplatesEntityTypeEnum templateType, Map<String, String> bodyPlaceholders,
List<String> additionalRecipients, Long amendmentId,String emailType) {
@@ -106,7 +109,7 @@ public class EmailNotificationDao {
EmailContentResponse emailContent = prepareEmailContent(applicationEntity, templateType, hubEntity, bodyPlaceholders,emailType);
UserEntity userEntity = userService.validateUser(applicationEntity.getUserId());
sendEmails(applicationEntity, userEntity, additionalRecipients,amendmentId,emailContent.getSystemEmailTemplateResponse(),emailContent.getSubject(),emailContent.getBody());
sendEmails(applicationEntity, userEntity, additionalRecipients,amendmentId,emailContent.getSystemEmailTemplateResponse(),emailContent.getSubject(),emailContent.getBody(),null);
}
public EmailContentResponse prepareEmailContent(
@@ -131,7 +134,7 @@ public class EmailNotificationDao {
return new EmailContentResponse(subject, body, systemEmailTemplateResponse);
}
private void sendEmails(ApplicationEntity applicationEntity, UserEntity userEntity, List<String> additionalRecipients,Long amendmentId,SystemEmailTemplateResponse systemEmailTemplateResponse,String subject,String body) {
private void sendEmails(ApplicationEntity applicationEntity, UserEntity userEntity, List<String> additionalRecipients,Long amendmentId,SystemEmailTemplateResponse systemEmailTemplateResponse,String subject,String body,Long contractId) {
Optional<ApplicationEvaluationEntity> applicationEvaluationEntity = applicationEvaluationRepository.findByApplicationIdAndIsDeletedFalse(applicationEntity.getId());
CompanyEntity company = companyService.validateCompany(applicationEntity.getCompanyId());
@@ -177,6 +180,14 @@ public class EmailNotificationDao {
: new HashSet<>(documentIds);
documentEntities=documentRepository.findAllByIdInAndIsDeletedFalse(setOfDocumentIds);
}
if(Boolean.TRUE.equals(userEntity.getHub().getUniqueUuid().equals(defaultHubUuid)) && Boolean.TRUE.equals(systemEmailTemplateResponse.getEmailScenario().equals(EmailScenarioTypeEnum.APPLICATION_CONTRACT_CREATED))) {
ApplicationContractEntity applicationContractEntity=applicationContractDao.validateApplicationContract(contractId);
List<Long> documentIds=applicationDao.validateDocumentIds(applicationContractEntity.getInstructorDocument());
Set<Long> setOfDocumentIds = (documentIds == null)
? Collections.emptySet()
: new HashSet<>(documentIds);
documentEntities=documentRepository.findAllByIdInAndIsDeletedFalse(setOfDocumentIds);
}
urls = documentEntities.stream()
.map(DocumentEntity::getFilePath) // or getUrl()
@@ -225,7 +236,7 @@ public class EmailNotificationDao {
}
}
if (userEntity.getBeneficiary().getEmail() != null) {
if (userEntity.getBeneficiary()!= null) {
String beneficiaryEmail = null;
RecipientTypeEnum recipientTypeEnum=RecipientTypeEnum.BENEFICIARY;
if (Boolean.TRUE.equals(userEntity.getHub().getUniqueUuid().equals(defaultHubUuid))){
@@ -514,4 +525,33 @@ public class EmailNotificationDao {
sendEmail(applicationEntity, SystemEmailTemplatesEntity.SystemEmailTemplatesEntityTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED, bodyPlaceholders, null,
applicationAmendmentRequestEntity.getId(),null);
}
public void sendEmailForApplicationContracted(ApplicationEntity applicationEntity,ApplicationContractEntity applicationContractEntity,UserEntity user) {
Map<String, String> bodyPlaceholders = new HashMap<>();
bodyPlaceholders.put("{{call_name}}", applicationEntity.getCall().getName());
String protocolNumber=applicationEntity.getProtocol().getExternalProtocolNumber();
if(protocolNumber==null){
protocolNumber= String.valueOf(applicationEntity.getProtocol().getProtocolNumber());
}
bodyPlaceholders.put("{{protocol_number}}", protocolNumber);
String protocolDate= DateTimeUtil.formatLocalDateTime(applicationEntity.getProtocol().getCreatedDate(), GepafinConstant.DD_MM_YYYY);
if(applicationEntity.getProtocol().getExternalProtocolDate()!=null){
protocolDate= DateTimeUtil.formatLocalDateTime(applicationEntity.getProtocol().getExternalProtocolDate(), GepafinConstant.DD_MM_YYYY);
}
bodyPlaceholders.put("{{protocol_date}}", protocolDate);
bodyPlaceholders.put("{{protocol_time}}", DateTimeUtil.parseLocalTimeToString(applicationEntity.getProtocol().getTime(), GepafinConstant.HH_MM_SS));
HubEntity hubEntity = hubService.valdateHub(applicationEntity.getHubId());
Map<String, String> subjectPlaceholders = new HashMap<>();
CompanyEntity company = companyService.validateCompany(applicationEntity.getCompanyId());
subjectPlaceholders.put("{{call_name}}", applicationEntity.getCall().getName());
subjectPlaceholders.put("{{company_name}}", company.getCompanyName());
// bodyPlaceholders.put("{{legal_mail}}", legalMail);
String subject = Utils.replacePlaceholders(applicationContractEntity.getSubject(), subjectPlaceholders);
String body = Utils.replacePlaceholders(applicationContractEntity.getText(), bodyPlaceholders);
SystemEmailTemplateResponse systemEmailTemplateResponse=new SystemEmailTemplateResponse();
systemEmailTemplateResponse.setSubject(subject);
systemEmailTemplateResponse.setHtmlContent(body);
systemEmailTemplateResponse.setEmailScenario(EmailScenarioTypeEnum.APPLICATION_CONTRACT_CREATED);
EmailContentResponse emailContentResponse= new EmailContentResponse(subject, body, systemEmailTemplateResponse);
sendEmails(applicationEntity, user, null,null,emailContentResponse.getSystemEmailTemplateResponse(),emailContentResponse.getSubject(),emailContentResponse.getBody(),applicationContractEntity.getId());
}
}

View File

@@ -15,27 +15,28 @@ public class S3PathConfig {
@Autowired
S3ConfigRepository s3ConfigRepository;
public String generateDocumentPath(DocumentSourceTypeEnum type, Long callId, Long applicationId,Long amendmentId,Long communicationId) {
public String generateDocumentPath(DocumentSourceTypeEnum type, Long callId, Long applicationId,Long amendmentId,Long communicationId,Long contractId) {
S3ConfigEntity config = getDocumentPath(type);
return config.getParentFolder() + "/" + buildS3Path(config.getPath(), callId, applicationId,amendmentId,communicationId);
return config.getParentFolder() + "/" + buildS3Path(config.getPath(), callId, applicationId,amendmentId,communicationId,contractId);
}
public String generateDocumentPathForOther(DocOtherSourceTypeEnum type, Long callId, Long applicationId,Long amendmentId,Long communicationId) {
public String generateDocumentPathForOther(DocOtherSourceTypeEnum type, Long callId, Long applicationId,Long amendmentId,Long communicationId,Long contractId) {
S3ConfigEntity config = getDocumentPathForOther(type);
return config.getParentFolder() + "/" + buildS3Path(config.getPath(), callId, applicationId,amendmentId,communicationId);
return config.getParentFolder() + "/" + buildS3Path(config.getPath(), callId, applicationId,amendmentId,communicationId,contractId);
}
public String generateDocumentPathForDelegationAndSignedDocument(DocOtherSourceTypeEnum type) {
S3ConfigEntity config = getDocumentPathForOther(type);
return config.getParentFolder() + "/" + config.getPath();
}
private String buildS3Path(String pathTemplate, Long callId, Long applicationId, Long amendmentId,Long communicationId) {
private String buildS3Path(String pathTemplate, Long callId, Long applicationId, Long amendmentId,Long communicationId,Long contractId) {
return pathTemplate
.replace("{call_id}", callId != null && callId != 0L ? "call_" + callId : "")
.replace("{application_id}", applicationId != null && applicationId != 0L ? "application_" + applicationId : "")
.replace("{amendment_id}", amendmentId != null && amendmentId != 0L ? "amendment_" + amendmentId : "")
.replace("{communication_id}", communicationId != null && communicationId != 0L ? "communication_" + communicationId : "");
.replace("{communication_id}", communicationId != null && communicationId != 0L ? "communication_" + communicationId : "")
.replace("{contract_id}", contractId != null && contractId != 0L ? "contract_" + contractId : "");
}
private S3ConfigEntity getDocumentPath(DocumentSourceTypeEnum type) {

View File

@@ -0,0 +1,46 @@
package net.gepafin.tendermanagement.entities;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.Data;
import org.hibernate.annotations.Where;
import java.time.LocalDateTime;
@Entity
@Table(name = "APPLICATION_CONTRACT")
@Data
@Where(clause = "is_deleted = false")
public class ApplicationContractEntity extends BaseEntity{
@Column(name = "SUBJECT")
private String subject;
@Column(name = "TEXT")
private String text;
@Column(name = "INSTRUCTOR_DOCUMENT")
private String instructorDocument;
@Column(name = "STATUS")
private String status;
@Column(name = "BENEFICIARY_DOCUMENT")
private String beneficiaryDocument;
@Column(name = "BENEFICIARY_USER_ID")
private Long beneficiaryUserId;
@Column(name = "INSTRUCTOR_ID")
private Long instructorId;
@Column(name = "IS_DELETED")
private Boolean isDeleted;
@Column(name = "COMPLETION_DATE")
private LocalDateTime completionDate;
@Column(name = "APPLICATION_ID")
private Long applicationId;
}

View File

@@ -0,0 +1,22 @@
package net.gepafin.tendermanagement.enums;
import com.fasterxml.jackson.annotation.JsonValue;
public enum ApplicationContractStatusEnum {
DRAFT("DRAFT"),
SIGNED("SIGNED");
private final String value;
ApplicationContractStatusEnum(String value) {
this.value = value;
}
@JsonValue
public String getValue() {
return value;
}
}

View File

@@ -18,7 +18,9 @@ public enum ApplicationStatusTypeEnum {
ADMISSIBLE("ADMISSIBLE"),
TECHNICAL_EVALUATION("TECHNICAL_EVALUATION"),
TECHNICAL_EVALUATION_REJECTED("TECHNICAL_EVALUATION_REJECTED"),
AWAITING_TECHNICAL_EVALUATION("AWAITING_TECHNICAL_EVALUATION") ;
AWAITING_TECHNICAL_EVALUATION("AWAITING_TECHNICAL_EVALUATION"),
AWAITING_CONTRACT("AWAITING_CONTRACT"),
CONTRACT_SIGNED("CONTRACT_SIGNED");
private String value;

View File

@@ -6,7 +6,8 @@ public enum DocumentSourceTypeEnum {
APPLICATION("APPLICATION"),
EVALUATION("EVALUATION"),
AMENDMENT("AMENDMENT"),
COMMUNICATION("COMMUNICATION");
COMMUNICATION("COMMUNICATION"),
CONTRACT("CONTRACT");
private String value;

View File

@@ -14,7 +14,8 @@ public enum EmailScenarioTypeEnum {
APPLICATION_REJECTED("APPLICATION_REJECTED"),
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("SPECIAL_APPLICATION_AMENDMENT_REQUESTED"),
APPLICATION_CONTRACT_CREATED("APPLICATION_CONTRACT_CREATED");
private final String value;

View File

@@ -15,7 +15,8 @@ public enum NotificationTypeEnum {
AMENDMENT_EXPIRATION_REMINDER("AMENDMENT_EXPIRATION_REMINDER"),
EVALUATION_EXPIRATION_REMINDER("EVALUATION_EXPIRATION_REMINDER"),
COMPANY_DOCUMENT_EXPIRATION_REMINDER("COMPANY_DOCUMENT_EXPIRATION_REMINDER"),
PEC_EMAIL_SENDING_FAILURE("PEC_EMAIL_SENDING_FAILURE");
PEC_EMAIL_SENDING_FAILURE("PEC_EMAIL_SENDING_FAILURE"),
CONTRACT_UPLOAD("CONTRACT_UPLOAD");
private final String value;

View File

@@ -224,7 +224,13 @@ public enum UserActionContextEnum {
RESEND_EMAIL("RESEND_EMAIL"),
SEND_REMINDER_EMAIL("SEND_REMINDER_EMAIL"),
CREATE_SPECIAL_AMENDMENT("CREATE_SPECIAL_AMENDMENT"),
UPDATE_APPLICATION_TO_TECHNICAL_EVALUATION_REJECTED("UPDATE_APPLICATION_TO_TECHNICAL_EVALUATION_REJECTED");
UPDATE_APPLICATION_TO_TECHNICAL_EVALUATION_REJECTED("UPDATE_APPLICATION_TO_TECHNICAL_EVALUATION_REJECTED"),
CREATE_CONTRACT_FOR_APPLICATION("CREATE_CONTRACT_FOR_APPLICATION"),
UPDATE_APPLICATION_CONTRACT("UPDATE_APPLICATION_CONTRACT"),
FETCH_APPLICATION_CONTRACT("FETCH_APPLICATION_CONTRACT"),
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");
private final String value;

View File

@@ -0,0 +1,10 @@
package net.gepafin.tendermanagement.model.request;
import lombok.Data;
@Data
public class ApplicationContractRequest {
private String subject;
private String text;
}

View File

@@ -0,0 +1,30 @@
package net.gepafin.tendermanagement.model.response;
import lombok.Data;
import net.gepafin.tendermanagement.enums.ApplicationContractStatusEnum;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class ApplicationContractResponse {
private Long id;
private String subject;
private String text;
private ApplicationContractStatusEnum status;
private List<DocumentResponseBean> instructorDocuments;
private Long instructorId;
private List<DocumentResponseBean> beneficiaryDocuments;
private Long beneficiaryUserId;
private LocalDateTime completionDate;
}

View File

@@ -0,0 +1,18 @@
package net.gepafin.tendermanagement.repositories;
import net.gepafin.tendermanagement.entities.ApplicationContractEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ApplicationContractRepository extends JpaRepository<ApplicationContractEntity,Long> {
ApplicationContractEntity findByIdAndIsDeletedFalse(Long id);
ApplicationContractEntity findByApplicationIdAndIsDeletedFalse(Long applicationId);
List<ApplicationContractEntity> findByBeneficiaryUserIdAndStatusAndIsDeletedFalse(Long applicationId,String status);
}

View File

@@ -0,0 +1,21 @@
package net.gepafin.tendermanagement.service;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.model.request.ApplicationContractRequest;
import net.gepafin.tendermanagement.model.response.ApplicationContractResponse;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
public interface ApplicationContractService {
public ApplicationContractResponse createApplicationContract(HttpServletRequest httpServletRequest, Long applicationId, List<MultipartFile> contractDocuments, ApplicationContractRequest applicationContractRequest);
public ApplicationContractResponse updateApplicationContract(HttpServletRequest httpServletRequest, Long applicationContractId,List<MultipartFile> beneficiaryContractDocuments);
public ApplicationContractResponse getContractById(Long contractId);
public ApplicationContractResponse getContractByApplicationId(Long applicationContractId);
List<ApplicationContractResponse> getContractByBeneficiaryUserId(Long beneficiaryUserId);
}

View File

@@ -0,0 +1,68 @@
package net.gepafin.tendermanagement.service.impl;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.config.Translator;
import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.dao.ApplicationContractDao;
import net.gepafin.tendermanagement.dao.UserDao;
import net.gepafin.tendermanagement.entities.UserEntity;
import net.gepafin.tendermanagement.model.request.ApplicationContractRequest;
import net.gepafin.tendermanagement.model.response.ApplicationContractResponse;
import net.gepafin.tendermanagement.service.ApplicationContractService;
import net.gepafin.tendermanagement.util.Utils;
import net.gepafin.tendermanagement.util.Validator;
import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException;
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
@Service
public class ApplicationContractServiceImpl implements ApplicationContractService {
@Autowired
private ApplicationContractDao applicationContractDao;
@Autowired
private Validator validator;
@Autowired
private UserDao userDao;
@Override
public ApplicationContractResponse createApplicationContract(HttpServletRequest httpServletRequest, Long applicationId, List<MultipartFile> contractDocuments, ApplicationContractRequest applicationContractRequest) {
UserEntity user= validator.validateUser(httpServletRequest);
if(contractDocuments==null) {
throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.FILES_REQUIRED_FOR_CONTRACT));
}
contractDocuments.forEach(Utils::validateFileType);
return applicationContractDao.createApplicationContract(applicationId,contractDocuments,applicationContractRequest,user);
}
@Override
public ApplicationContractResponse updateApplicationContract(HttpServletRequest httpServletRequest, Long applicationContractId, List<MultipartFile> beneficiaryContractDocuments) {
UserEntity user= validator.validateUser(httpServletRequest);
if(beneficiaryContractDocuments==null) {
throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.FILES_REQUIRED_FOR_CONTRACT));
}
return applicationContractDao.updateApplicationContract(applicationContractId,beneficiaryContractDocuments,user);
}
@Override
public ApplicationContractResponse getContractById(Long contractId) {
return applicationContractDao.getContractById(contractId);
}
@Override
public ApplicationContractResponse getContractByApplicationId(Long applicationId) {
return applicationContractDao.getContractByApplicationId(applicationId);
}
@Override
public List<ApplicationContractResponse> getContractByBeneficiaryUserId(Long beneficiaryUserId) {
UserEntity user=userDao.validateUser(beneficiaryUserId);
return applicationContractDao.getContractByBeneficiaryUserId(user);
}
}

View File

@@ -9,6 +9,7 @@ import com.amazonaws.services.s3.model.ObjectMetadata;
import lombok.extern.slf4j.Slf4j;
import net.gepafin.tendermanagement.dao.DocumentDao;
import net.gepafin.tendermanagement.dao.S3PathConfig;
import net.gepafin.tendermanagement.entities.ApplicationContractEntity;
import net.gepafin.tendermanagement.entities.ApplicationEntity;
import net.gepafin.tendermanagement.entities.CommunicationEntity;
import net.gepafin.tendermanagement.entities.DocumentEntity;
@@ -81,6 +82,9 @@ public class S3ReUploadMigrationService {
@Autowired
private DocumentDao documentDao;
@Autowired
private ApplicationContractRepository applicationContractRepository;
private boolean migrationCompleted = false;
@@ -114,6 +118,7 @@ public class S3ReUploadMigrationService {
Long amendmentId = null;
Long evaluationId = null;
Long communicationId=null;
Long contractId=null;
if (DocumentSourceTypeEnum.CALL.getValue().equalsIgnoreCase(document.getSource())) {
callId = document.getSourceId();
} else if (DocumentSourceTypeEnum.APPLICATION.getValue().equalsIgnoreCase(document.getSource())) {
@@ -138,9 +143,15 @@ public class S3ReUploadMigrationService {
applicationId = applicationEntity.getId();
callId = applicationEntity.getCall().getId();
}
else if(DocumentSourceTypeEnum.CONTRACT.getValue().equalsIgnoreCase(document.getSource())){
contractId = document.getSourceId();
ApplicationContractEntity applicationContractEntity=applicationContractRepository.findByIdAndIsDeletedFalse(contractId);
ApplicationEntity applicationEntity=applicationService.validateApplication(applicationContractEntity.getApplicationId());
applicationId = applicationEntity.getId();
callId = applicationEntity.getCall().getId();
}
documentDao.deleteFileFromS3(document,callId,applicationId,amendmentId,communicationId);
documentDao.deleteFileFromS3(document,callId,applicationId,amendmentId,communicationId,contractId);
processDocuments++;
} catch (Exception e) {
@@ -231,10 +242,10 @@ public class S3ReUploadMigrationService {
Long callId;
if (sourceType.equals(DocumentSourceTypeEnum.CALL)) {
return s3ConfigBean.generateDocumentPath(sourceType, document.getSourceId(), 0L,0L,0L);
return s3ConfigBean.generateDocumentPath(sourceType, document.getSourceId(), 0L,0L,0L,0L);
} else {
callId = applicationRepository.findCallIdById(document.getSourceId());
return s3ConfigBean.generateDocumentPath(sourceType, callId, document.getSourceId(),0L,0L);
return s3ConfigBean.generateDocumentPath(sourceType, callId, document.getSourceId(),0L,0L,0L);
}
}

View File

@@ -139,7 +139,7 @@ public class UserSignedAndDelegationServiceImpl {
private String generateNewS3PathForDelegationDoc() {
return s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.USER_DELEGATION, 0L, 0L,0L,0L);
return s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.USER_DELEGATION, 0L, 0L,0L,0L,0L);
}
private String generateNewS3PathForUserSignedDoc(ApplicationSignedDocumentEntity document) {

View File

@@ -0,0 +1,96 @@
package net.gepafin.tendermanagement.web.rest.api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import net.gepafin.tendermanagement.model.request.ApplicationAmendmentSpecialRequest;
import net.gepafin.tendermanagement.model.request.ApplicationContractRequest;
import net.gepafin.tendermanagement.model.request.ApplicationEvaluationRequest;
import net.gepafin.tendermanagement.model.response.ApplicationAmendmentRequestResponse;
import net.gepafin.tendermanagement.model.response.ApplicationContractResponse;
import net.gepafin.tendermanagement.model.util.Response;
import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@Validated
public interface ApplicationContractApi {
@Operation(summary = "Api to create application contract",
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 = "/application/{applicationId}", produces = "application/json", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@PreAuthorize("hasRole('ROLE_SUPER_ADMIN') || hasRole('ROLE_INSTRUCTOR_MANAGER')|| hasRole('ROLE_PRE_INSTRUCTOR')")
ResponseEntity<Response<ApplicationContractResponse>> createApplicationContract(HttpServletRequest request,
@Parameter(description = "Application ID", required = true) @PathVariable("applicationId") Long applicationId, @Parameter(description = "List of files to upload", required = true)
@RequestPart(required = true) List<MultipartFile> contractDocuments,
@Parameter(description = "Application Contract Request Body", required = true) @RequestPart ApplicationContractRequest applicationContractRequest);
@Operation(summary = "Api to update application contract from beneficiary side",
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 = "{applicationContractId}", produces = "application/json", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@PreAuthorize( "hasRole('ROLE_SUPER_ADMIN') || hasRole('ROLE_BENEFICIARY') || hasRole('ROLE_CONFIDI')")
ResponseEntity<Response<ApplicationContractResponse>> updateApplicationContract(HttpServletRequest request,
@Parameter(description = "Application Contract ID", required = true) @PathVariable("applicationContractId") Long applicationContractId, @Parameter(description = "List of files to upload", required = true)
@RequestPart(required = true) List<MultipartFile> beneficiaryContractDocuments);
@Operation(summary = "Api to get an application contract by id",
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 = "{applicationContractId}", produces = "application/json")
ResponseEntity<Response<ApplicationContractResponse>> getApplicationContractById(HttpServletRequest request,@Parameter(description = "The application contract id", required = true) @RequestParam(value = "id", required = true) Long id);
@Operation(summary = "Api to get an application contract by application id",
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 = "/application/{applicationId}", produces = "application/json")
ResponseEntity<Response<ApplicationContractResponse>> getApplicationContractByApplicationId(HttpServletRequest request,@Parameter(description = "The application id", required = true) @RequestParam(value = "applicationId", required = true) Long applicationId);
@Operation(summary = "Api to get an application contract by beneficiary user id",
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 = "/user/{userId}", produces = "application/json")
ResponseEntity<Response< List<ApplicationContractResponse>>> getApplicationContractByBeneficiaryUserId(HttpServletRequest request,@Parameter(description = "The user id", required = true) @RequestParam(value = "userId", required = true) Long userId);
}

View File

@@ -0,0 +1,86 @@
package net.gepafin.tendermanagement.web.rest.api.impl;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.config.Translator;
import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.enums.UserActionContextEnum;
import net.gepafin.tendermanagement.enums.UserActionLogsEnum;
import net.gepafin.tendermanagement.model.request.ApplicationContractRequest;
import net.gepafin.tendermanagement.model.request.UserActionRequest;
import net.gepafin.tendermanagement.model.response.ApplicationContractResponse;
import net.gepafin.tendermanagement.model.util.Response;
import net.gepafin.tendermanagement.service.ApplicationContractService;
import net.gepafin.tendermanagement.util.LoggingUtil;
import net.gepafin.tendermanagement.web.rest.api.ApplicationContractApi;
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@RestController
@RequestMapping("${openapi.gepafin.base-path:/v1/applicationContract}")
public class ApplicationContractApiController implements ApplicationContractApi {
@Autowired
private LoggingUtil loggingUtil;
@Autowired
private ApplicationContractService applicationContractService;
@Override
public ResponseEntity<Response<ApplicationContractResponse>> createApplicationContract(HttpServletRequest request, Long applicationId, List<MultipartFile> contractDocuments, ApplicationContractRequest applicationContractRequest) {
loggingUtil.logUserAction(
UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.INSERT).actionContext(UserActionContextEnum.CREATE_CONTRACT_FOR_APPLICATION).build());
ApplicationContractResponse applicationContractResponse=applicationContractService.createApplicationContract(request,applicationId,contractDocuments,applicationContractRequest);
return ResponseEntity.status(HttpStatus.OK)
.body(new Response<>(applicationContractResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.CREATE_APPLICATION_CONTRACT)));
}
@Override
public ResponseEntity<Response<ApplicationContractResponse>> updateApplicationContract(HttpServletRequest request, Long applicationId, List<MultipartFile> beneficiaryContractDocuments) {
loggingUtil.logUserAction(
UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.UPDATE).actionContext(UserActionContextEnum.UPDATE_APPLICATION_CONTRACT).build());
ApplicationContractResponse applicationContractResponse=applicationContractService.updateApplicationContract(request,applicationId,beneficiaryContractDocuments);
return ResponseEntity.status(HttpStatus.OK)
.body(new Response<>(applicationContractResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.APPLICATION_CONTRACT_UPDATED)));
}
@Override
public ResponseEntity<Response<ApplicationContractResponse>> getApplicationContractById(HttpServletRequest request, Long id) {
loggingUtil.logUserAction(
UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW).actionContext(UserActionContextEnum.FETCH_APPLICATION_CONTRACT).build());
ApplicationContractResponse applicationContractResponse=applicationContractService.getContractById(id);
return ResponseEntity.status(HttpStatus.OK)
.body(new Response<>(applicationContractResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.APPLICATION_CONTRACT_FETCHED)));
}
@Override
public ResponseEntity<Response<ApplicationContractResponse>> getApplicationContractByApplicationId(HttpServletRequest request, Long applicationId) {
loggingUtil.logUserAction(
UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW).actionContext(UserActionContextEnum.FETCH_APPLICATION_CONTRACT_BY_APPLICATION_ID).build());
ApplicationContractResponse applicationContractResponse=applicationContractService.getContractByApplicationId(applicationId);
return ResponseEntity.status(HttpStatus.OK)
.body(new Response<>(applicationContractResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.APPLICATION_CONTRACT_FETCHED)));
}
@Override
public ResponseEntity<Response<List<ApplicationContractResponse>>> getApplicationContractByBeneficiaryUserId(HttpServletRequest request, Long beneficiaryUserId) {
loggingUtil.logUserAction(
UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW).actionContext(UserActionContextEnum.FETCH_APPLICATION_CONTRACT_BY_BENEFICIARY_USER_ID).build());
List<ApplicationContractResponse> applicationContractResponse=applicationContractService.getContractByBeneficiaryUserId(beneficiaryUserId);
return ResponseEntity.status(HttpStatus.OK)
.body(new Response<>(applicationContractResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.APPLICATION_CONTRACT_FETCHED)));
}
}

View File

@@ -3100,4 +3100,39 @@
<changeSet id="23-10-2025_RK_151527" author="Rajesh Khore">
<sqlFile dbms="postgresql" path="db/dump/update_document_for_special_amendment_23-10-2025.sql"/>
</changeSet>
<changeSet id="29-10-2025_RK_164154" author="Rajesh Khore">
<createTable tableName="application_contract">
<column name="id" type="INTEGER" autoIncrement="true">
<constraints primaryKey="true" primaryKeyName="application_contract_pkey" nullable="false"/>
</column>
<column name="subject" type="VARCHAR(255)"/>
<column name="text" type="VARCHAR(255)"/>
<column name="instructor_document" type="VARCHAR(255)"/>
<column name="status" type="VARCHAR(255)"/>
<column name="beneficiary_document" type="VARCHAR(255)"/>
<column name="beneficiary_user_id" type="INTEGER"/>
<column name="instructor_id" type="INTEGER"/>
<column name="application_id" type="INTEGER"/>
<column name="is_deleted" type="BOOLEAN"/>
<column name="completion_date" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="created_date" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="updated_date" type="TIMESTAMP WITHOUT TIME ZONE"/>
</createTable>
</changeSet>
<changeSet id="02-11-2025_RK_204924" author="Rajesh Khore">
<insert tableName="s3_path_configuration">
<column name="type" value="CONTRACT"/>
<column name="path" value="call/{call_id}/application/{application_id}/contract/{contract_id}/"/>
<column name="bucket_name" value="mementoresources"/>
<column name="created_date" value="2025-11-03 00:00:00"/>
<column name="updated_date" value="2025-11-03 00:00:00"/>
<column name="parent_folder" value="gepafin/staging"/>
</insert>
</changeSet>
<changeSet id="04-11-2025_RK_151527" author="Rajesh Khore">
<sqlFile dbms="postgresql" path="db/dump/insert_notification_template_for_contract_upload.sql"/>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,2 @@
INSERT INTO notification_type (notification_name,title, json_template,created_date,updated_date,is_deleted) VALUES
('CONTRACT_UPLOAD', 'Documento caricato per contratto','La richiesta in {{call_name}} con protocollo n. {{protocol_number}} ha caricato un documento per il contratto.','2025-11-04T15:16:26.472Z','2025-11-04T15:16:26.472Z','false');

View File

@@ -416,5 +416,11 @@ pec.email.required=PEC email is required.
application.technical.evaluation.rejected.success=Application changes to status application technical evaluation rejected successfully.
invalid.email.json=Invalid email json.
more.fields.required=Subject, reason, and motivation are required when rejecting the application.
create.application.contract=Application contract created successfully.
application.contract.not.found=Application contract not found.
application.contract.fetched=Application contract fetched successfully.
application.contract.updated=Application contract updated successfully.
files.required.for.contract=Files are required for contract.
application.contract.already.exist=Application contract already exist for this application.
application.not.approved=Application is not approved.
subject.body.required=Subject and body is required to create contract.

View File

@@ -407,3 +407,11 @@ pec.email.required=Obbligatorio l'indirizzo e-mail PEC.
application.technical.evaluation.rejected.success=Lo stato dell'applicazione cambia: valutazione tecnica dell'applicazione rifiutata con successo.
invalid.email.json=Codice email json non valido.
more.fields.required=Per rifiutare la domanda sono richiesti oggetto, motivo e motivazione.
create.application.contract=Contratto di candidatura creato con successo.
application.contract.not.found=Contratto di candidatura non trovato.
application.contract.fetched=Contratto di candidatura recuperato con successo.
application.contract.updated=Contratto di candidatura aggiornato con successo.
files.required.for.contract=I file sono necessari per il contratto.
application.contract.already.exist=Il contratto di applicazione esiste già per questa applicazione.
application.not.approved=La domanda non è stata approvata.
subject.body.required=Per creare un contratto sono necessari oggetto e corpo.