diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index cf39a573..a2c0f8c1 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -445,6 +445,7 @@ public class GepafinConstant { public static final String COMPANY_DOCUMENT_NOT_FOUND = "company.document.not.found"; public static final String COMPANY_DOCUMENT_UPDATED_SUCCESSFULLY = "company.document.updated.successfully"; public static final String COMPANY_DOCUMENT_COPIED_SUCCESSFULLY = "company.document.copied.successfully"; + public static final String COMPANY_DOCUMENT_COPY_EVALUATION_REQUIRES_APPLICATION_EVALUATION = "company.document.copy.evaluation.requires.application.evaluation"; public static final String COMPANY_DOCUMENT_FETCHED_SUCCESSFULLY = "company.document.fetched.successfully"; public static final String DOCUMENT_CATEGORY_CREATE_SUCCESS = "document.category.success"; diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java index c8e87f88..b24736b3 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java @@ -33,6 +33,7 @@ import net.gepafin.tendermanagement.util.LoggingUtil; import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.util.Validator; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; +import net.gepafin.tendermanagement.web.rest.api.errors.ForbiddenAccessException; import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundException; import net.gepafin.tendermanagement.web.rest.api.errors.Status; import org.springframework.beans.factory.annotation.Autowired; @@ -123,7 +124,7 @@ public class CompanyDocumentDao { log.warn("Expiration date {} is before current time {}", expirationDate, currentDate); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_EXPIRATION_DATE)); } - CompanyDocumentTypeEnum storedType = CompanyDocumentTypeEnum.APPLICATION_DOCUMENT; + CompanyDocumentTypeEnum storedType = CompanyDocumentTypeEnum.COMPANY_DOCUMENT; List companyDocumentEntities = new ArrayList<>(); for (MultipartFile file : files) { log.info("Uploading instructor company document '{}' for companyId={}, applicationId={}", file.getOriginalFilename(), companyId, applicationId); @@ -348,42 +349,118 @@ public class CompanyDocumentDao { return userActionContext; } + /** + * Beneficiary or confidi: duplicate into application storage. Super admin, pre-instructor (instructor), or + * instructor manager: evaluation S3 folder + {@link ApplicationEvaluationEntity#getEvaluationDocument()} merge. + * Other roles are not allowed. + */ public DocumentResponseBean createDuplicateCompanyDocument(HttpServletRequest request , Long userId ,Long companyDocumentId , Long applicationId , DocumentTypeEnum documentTypeEnum){ log.info("Creating duplicate of company document ID '{}' for application ID '{}'", companyDocumentId, applicationId); - ApplicationEntity applicationEntity = applicationService.validateApplication(applicationId); CompanyDocumentEntity companyDocumentEntity = validateCompanyDocument(companyDocumentId); - validator.validateUserWithCompany(request,companyDocumentEntity.getCompanyId()); - String companyDocumentPath = companyDocumentEntity.getFilePath(); - String documentPath = s3ConfigBean.generateDocumentPath(DocumentSourceTypeEnum.APPLICATION,applicationEntity.getCall().getId(),applicationId,0L,0L,0L); + boolean beneficiaryOrConfidi = Boolean.TRUE.equals(validator.checkIsBeneficiary()) + || Boolean.TRUE.equals(validator.checkIsConfidi()); + boolean staffEvaluationRoles = Boolean.TRUE.equals(validator.checkIsSuperAdmin()) + || Boolean.TRUE.equals(validator.checkIsPreInstructor()) + || Boolean.TRUE.equals(validator.checkIsInstructorManager()); - log.info("Original Paths - oldPath: {}, newPath: {}", companyDocumentPath, documentPath); + if (beneficiaryOrConfidi) { + ApplicationEntity applicationEntity = applicationService.validateApplication(applicationId); + validator.validateUserWithCompany(request, companyDocumentEntity.getCompanyId()); - UploadFileOnAmazonS3Response response; - try { - response = amazonS3ServiceImpl.copyFile(companyDocumentEntity.getName(), companyDocumentPath, documentPath); - } catch (Exception e) { - log.error("Error occurred while uploading file from Amazon S3: {} for application ID '{}' and company Document ID '{}' ", e,applicationId,companyDocumentId); + String companyDocumentPath = companyDocumentEntity.getFilePath(); + String documentPath = s3ConfigBean.generateDocumentPath(DocumentSourceTypeEnum.APPLICATION, applicationEntity.getCall().getId(), applicationId, 0L, 0L, 0L); + + log.info("Original Paths - oldPath: {}, newPath: {}", companyDocumentPath, documentPath); + + UploadFileOnAmazonS3Response response; + try { + response = amazonS3ServiceImpl.copyFile(companyDocumentEntity.getName(), companyDocumentPath, documentPath); + } catch (Exception e) { + log.error("Error occurred while uploading file from Amazon S3: {} for application ID '{}' and company Document ID '{}' ", e, applicationId, companyDocumentId); + throw new CustomValidationException(Status.VALIDATION_ERROR, + Translator.toLocale(GepafinConstant.UPLOAD_ERROR_S3)); + } + + DocumentEntity entity = new DocumentEntity(); + entity.setFilePath(response.getFilePath()); + entity.setFileName(response.getFileName()); + entity.setSource(DocumentSourceTypeEnum.APPLICATION.getValue()); + entity.setType(documentTypeEnum.getValue()); + entity.setSourceId(applicationId); + entity.setUploadedBy(userId); + + documentRepository.save(entity); + + /** This code is responsible for adding a version history log for the "inserting data" operation. **/ + loggingUtil.addVersionHistory( + VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(entity).build()); + + return callDao.convertToDocumentResponseBean(entity); + } + + if (staffEvaluationRoles) { + ApplicationEntity applicationEntity = applicationService.validateApplicationWithCompany(applicationId, companyDocumentEntity.getCompanyId()); + CompanyEntity companyEntity = companyService.validateCompany(companyDocumentEntity.getCompanyId()); + validator.validateHubId(request, companyEntity.getHub().getId()); + return addCompanyDocumentToEvaluation(applicationEntity, companyDocumentEntity, userId); + } + + throw new ForbiddenAccessException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); + } + + /** + * Copies one company document into the evaluation S3 folder, persists a {@link DocumentEntity} with source + * {@link DocumentSourceTypeEnum#EVALUATION}, and appends the corresponding entry to + * {@link ApplicationEvaluationEntity#getEvaluationDocument()} (same JSON shape as instructor upload). + */ + private DocumentResponseBean addCompanyDocumentToEvaluation(ApplicationEntity application, + CompanyDocumentEntity companyDoc, Long userId) { + Long evaluationId = application.getApplicationEvaluationId(); + if (evaluationId == null || evaluationId <= 0) { + throw new CustomValidationException(Status.VALIDATION_ERROR, + Translator.toLocale(GepafinConstant.COMPANY_DOCUMENT_COPY_EVALUATION_REQUIRES_APPLICATION_EVALUATION)); + } + Optional evaluationOpt = + applicationEvaluationRepository.findByIdAndIsDeletedFalse(evaluationId); + if (evaluationOpt.isEmpty()) { + throw new CustomValidationException(Status.VALIDATION_ERROR, + Translator.toLocale(GepafinConstant.APPLICATION_EVALUATION_NOT_FOUND, evaluationId)); + } + + Long callId = application.getCall().getId(); + Long applicationId = application.getId(); + String evaluationFolderPath = s3ConfigBean.generateDocumentPath( + DocumentSourceTypeEnum.EVALUATION, callId, applicationId, evaluationId, 0L, 0L); + + DocumentEntity saved = persistInstructorCompanyDocumentAsEvaluationDocument( + companyDoc, evaluationFolderPath, evaluationId, userId); + EvaluationDocumentRequest entry = buildEvaluationDocumentEntry(companyDoc, saved); + if (entry == null) { throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.UPLOAD_ERROR_S3)); } - DocumentEntity entity = new DocumentEntity(); - entity.setFilePath(response.getFilePath()); - entity.setFileName(response.getFileName()); - entity.setSource(DocumentSourceTypeEnum.APPLICATION.getValue()); - entity.setType(documentTypeEnum.getValue()); - entity.setSourceId(applicationId); - entity.setUploadedBy(userId); + ApplicationEvaluationEntity evaluation = evaluationOpt.get(); + List merged = new ArrayList<>(parseEvaluationDocumentJson(evaluation.getEvaluationDocument())); + merged.add(entry); + evaluation.setEvaluationDocument(Utils.convertObjectToJson(merged)); + applicationEvaluationRepository.save(evaluation); - documentRepository.save(entity); + return callDao.convertToDocumentResponseBean(saved); + } - /** This code is responsible for adding a version history log for the "inserting data" operation. **/ - loggingUtil.addVersionHistory( - VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(entity).build()); - - DocumentResponseBean responseBean = callDao.convertToDocumentResponseBean(entity); - return responseBean; + private EvaluationDocumentRequest buildEvaluationDocumentEntry(CompanyDocumentEntity companyDoc, DocumentEntity saved) { + if (saved == null || saved.getId() == null) { + return null; + } + EvaluationDocumentRequest entry = new EvaluationDocumentRequest(); + SecureRandom random = new SecureRandom(); + entry.setFieldId(NanoIdUtils.randomNanoId(random, NanoIdUtils.DEFAULT_ALPHABET, 10)); + entry.setNameValue(instructorDocumentDisplayName(companyDoc)); + entry.setFileValue(String.valueOf(saved.getId())); + entry.setValid(null); + return entry; } /** @@ -417,22 +494,10 @@ public class CompanyDocumentDao { for (CompanyDocumentEntity companyDoc : instructorCompanyDocuments) { DocumentEntity saved = persistInstructorCompanyDocumentAsEvaluationDocument( companyDoc, evaluationFolderPath, evaluationId, userId); - if (saved.getId() == null) { - continue; + EvaluationDocumentRequest entry = buildEvaluationDocumentEntry(companyDoc, saved); + if (entry != null) { + newEntries.add(entry); } - EvaluationDocumentRequest entry = new EvaluationDocumentRequest(); - SecureRandom random = new SecureRandom(); - - String key = NanoIdUtils.randomNanoId( - random, - NanoIdUtils.DEFAULT_ALPHABET, - 10 - ); - entry.setFieldId(key); - entry.setNameValue(instructorDocumentDisplayName(companyDoc)); - entry.setFileValue(String.valueOf(saved.getId())); - entry.setValid(null); - newEntries.add(entry); } if (newEntries.isEmpty()) { return; diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index b223a21d..5cb20603 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -389,6 +389,7 @@ company.document.fetched.successfully = Company Document fetched successfully. company.document.updated.successfully = Company Document Updated successfully. category.cannot.be.deleted = Category cannot be deleted as it is associated with company documents. company.document.copied.successfully = Company Document Copied successfully. +company.document.copy.evaluation.requires.application.evaluation=Copy to evaluation requires an application evaluation linked to this application. invalid.expiration.date = Invalid Expiration Date diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index bcff6a8f..1f210422 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -374,6 +374,7 @@ document.category.not.found = Categoria documento non trovata. document.category.get.success = Categoria del documento recuperata correttamente. document.category.success =Categoria documento creata correttamente. company.document.copied.successfully = Documento aziendale copiato correttamente. +company.document.copy.evaluation.requires.application.evaluation=La copia nella valutazione richiede una valutazione dell'applicazione collegata a questa domanda. error.moving.file.to.deleted.folder = Si รจ verificato un errore durante lo spostamento del file aziendale nella cartella eliminata.ss company.document.fetched.successfully = Documento aziendale recuperato con successo.