Files
bflows-bandi-be/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java
2025-11-19 12:28:11 +05:30

371 lines
20 KiB
Java

package net.gepafin.tendermanagement.dao;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CopyObjectRequest;
import jakarta.persistence.criteria.Predicate;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import net.gepafin.tendermanagement.config.Translator;
import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.entities.*;
import net.gepafin.tendermanagement.enums.*;
import net.gepafin.tendermanagement.model.request.CompanyDocumentRequest;
import net.gepafin.tendermanagement.model.request.VersionHistoryRequest;
import net.gepafin.tendermanagement.model.response.DocumentCategoryResponse;
import net.gepafin.tendermanagement.model.response.CompanyDocumentResponseBean;
import net.gepafin.tendermanagement.model.response.DocumentResponseBean;
import net.gepafin.tendermanagement.model.response.UploadFileOnAmazonS3Response;
import net.gepafin.tendermanagement.repositories.CompanyDocumentRepository;
import net.gepafin.tendermanagement.repositories.DocumentRepository;
import net.gepafin.tendermanagement.service.AmazonS3Service;
import net.gepafin.tendermanagement.service.ApplicationService;
import net.gepafin.tendermanagement.service.CompanyService;
import net.gepafin.tendermanagement.service.impl.AmazonS3ServiceImpl;
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.ResourceNotFoundException;
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static net.gepafin.tendermanagement.util.Utils.setIfUpdated;
@Slf4j
@Component
public class CompanyDocumentDao {
@Autowired
private S3PathConfig s3ConfigBean;
@Autowired
private AmazonS3Service amazonS3Service;
@Autowired
private CompanyDocumentRepository companyDocumentRepository;
@Autowired
private LoggingUtil loggingUtil;
@Autowired
private HttpServletRequest request;
@Autowired
private DocumentCategoryDao categoryDao;
@Autowired
private CompanyService companyService;
@Value("${aws.s3.bucket.name}")
private String bucketName;
@Autowired
private AmazonS3Client s3Client;
@Autowired
private DocumentRepository documentRepository;
@Autowired
private CallDao callDao;
@Autowired
private ApplicationService applicationService;
@Autowired
private AmazonS3ServiceImpl amazonS3ServiceImpl;
@Autowired
private Validator validator;
@Autowired
private AmazonS3 amazonS3;
public List<CompanyDocumentResponseBean> uploadFileForCompany(Long userId, List<MultipartFile> files, Long companyId, Long documentCategoryId, CompanyDocumentTypeEnum companyDocumentSourceTypeEnum, LocalDateTime expirationDate,String name){
log.info("Uploading files for company. userId={}, companyId={}, documentCategoryId={}", userId, companyId, documentCategoryId);
DocumentCategoryEntity categoryEntity = categoryDao.validateCategory(documentCategoryId);
UserWithCompanyEntity userWithCompanyEntity=companyService.getUserWithCompany(userId,companyId);
LocalDateTime currentDate = LocalDateTime.now();
if (expirationDate.isBefore(currentDate)) {
log.warn("Expiration date {} is before current time {}", expirationDate, currentDate);
throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_EXPIRATION_DATE));
}
List<CompanyDocumentEntity> companyDocumentEntities = new ArrayList<>();
for (MultipartFile file : files){
log.info("Uploading file '{}' for companyId={}", file.getOriginalFilename(), companyId);
UploadFileOnAmazonS3Response uploadFileOnAmazonS3Response = uploadFileOnAmazonS3(file, companyDocumentSourceTypeEnum, companyId);
if (uploadFileOnAmazonS3Response != null) {
CompanyDocumentEntity companyDocumentEntity = new CompanyDocumentEntity();
companyDocumentEntity.setFileName(uploadFileOnAmazonS3Response.getFileName());
companyDocumentEntity.setCompanyId(companyId);
companyDocumentEntity.setType(companyDocumentSourceTypeEnum.getValue());
companyDocumentEntity.setFilePath(uploadFileOnAmazonS3Response.getFilePath());
companyDocumentEntity.setIsDeleted(false);
companyDocumentEntity.setUploadedBy(userId);
companyDocumentEntity.setName(name);
if (expirationDate.isBefore(currentDate.plusDays(7))) {
companyDocumentEntity.setStatus(CompanyDocumentStatusEnum.DUE.getValue());
log.info("Document '{}' marked as DUE (expires within 7 days).", uploadFileOnAmazonS3Response.getFileName());
} else {
companyDocumentEntity.setStatus(CompanyDocumentStatusEnum.VALID.getValue());
log.info("Document '{}' marked as VALID.", uploadFileOnAmazonS3Response.getFileName());
}
companyDocumentEntity.setCategoryEntity(categoryEntity);
companyDocumentEntity.setUserWithCompany(userWithCompanyEntity);
companyDocumentEntity.setExpirationDate(expirationDate);
companyDocumentEntities.add(companyDocumentEntity);
}
}
companyDocumentRepository.saveAll(companyDocumentEntities);
log.info("Saved {} documents for companyId={}", companyDocumentEntities.size(), companyId);
/** This code is responsible for adding a version history log for the "Upload company document" operation. **/
companyDocumentEntities.forEach(entity -> loggingUtil.addVersionHistory(
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(entity).build()));
return companyDocumentEntities.stream()
.map(this::convertToCompanyDocumentResponseBean)
.collect(Collectors.toList());
}
private UploadFileOnAmazonS3Response uploadFileOnAmazonS3(MultipartFile file, CompanyDocumentTypeEnum type, Long companyId) {
try {
String s3Path = generateS3PathForCompany(type,companyId);
log.info("Generated S3 path {}", s3Path);
return amazonS3Service.uploadFileOnAmazonS3(s3Path, file);
} catch (Exception e) {
log.error("Error occurred while uploading file '{}' for Company ID '{}': {}", file.getOriginalFilename(), companyId, e.getMessage());
throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.UPLOAD_ERROR_S3));
}
}
public String generateS3PathForCompany(CompanyDocumentTypeEnum typeOfDocument, Long companyId) {
try {
return s3ConfigBean.generateCompanyDocumentPath(typeOfDocument, companyId);
} catch (IllegalArgumentException e) {
log.error("Failed to generate S3 path for Company ID '{}' and Document Type '{}': {}", companyId, typeOfDocument, e.getMessage());
throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.S3_PATH_GENERATION_ERROR_MSG));
}
}
public CompanyDocumentEntity validateCompanyDocument(Long id) {
return companyDocumentRepository.findByIdAndNotDeleted(id).orElseThrow(() -> {
log.warn("Company Document not found with ID '{}'", id);
return new ResourceNotFoundException(Status.NOT_FOUND,
Translator.toLocale(GepafinConstant.COMPANY_DOCUMENT_NOT_FOUND));
});
}
public CompanyDocumentResponseBean convertToCompanyDocumentResponseBean(CompanyDocumentEntity entity) {
CompanyDocumentResponseBean responseBean = new CompanyDocumentResponseBean();
DocumentCategoryEntity categoryEntity = entity.getCategoryEntity();
DocumentCategoryResponse responseCategory = categoryDao.convertToResponseBean(categoryEntity);
responseBean.setId(entity.getId());
responseBean.setFileName(entity.getFileName());
responseBean.setType(CompanyDocumentTypeEnum.valueOf(entity.getType()));
responseBean.setFilePath(entity.getFilePath());
responseBean.setCompanyId(entity.getCompanyId());
responseBean.setExpirationDate(entity.getExpirationDate());
responseBean.setStatus(entity.getStatus());
responseBean.setUploadedBy(entity.getUploadedBy());
responseBean.setCategory(responseCategory);
responseBean.setName(entity.getName());
responseBean.setUserWithCompanyId(entity.getUserWithCompany().getId());
responseBean.setCreatedDate(entity.getCreatedDate());
responseBean.setUpdatedDate(entity.getUpdatedDate());
return responseBean;
}
public CompanyDocumentResponseBean updateCompanyDocument(HttpServletRequest request,Long companyDocumentId, CompanyDocumentRequest companyDocumentRequest){
log.info("Start: Updating company document with ID: {}", companyDocumentId);
CompanyDocumentEntity companyDocumentEntity = validateCompanyDocument(companyDocumentId);
validator.validateUserWithCompany(request,companyDocumentEntity.getCompanyId());
CompanyDocumentEntity oldCompanyDocumentData = Utils.getClonedEntityForData(companyDocumentEntity);
LocalDateTime currentDate = LocalDateTime.now();
if (companyDocumentRequest.getExpirationDate() != null) {
if (companyDocumentRequest.getExpirationDate().isBefore(currentDate)) {
log.warn("Invalid expiration date: {}", companyDocumentRequest.getExpirationDate());
throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_EXPIRATION_DATE));
}
companyDocumentEntity.setExpirationDate(companyDocumentRequest.getExpirationDate());
if (companyDocumentRequest.getExpirationDate().isBefore(currentDate.plusDays(7))) {
companyDocumentEntity.setStatus(CompanyDocumentStatusEnum.DUE.getValue());
log.info("Document '{}' marked as DUE.", companyDocumentEntity.getName());
} else {
companyDocumentEntity.setStatus(CompanyDocumentStatusEnum.VALID.getValue());
log.info("Document '{}' marked as VALID (expiration is beyond 7 days).", companyDocumentEntity.getName());
}
}
if (companyDocumentRequest.getCategoryId() != null && companyDocumentRequest.getCategoryId() >0) {
DocumentCategoryEntity categoryEntity = categoryDao.validateCategory(companyDocumentRequest.getCategoryId());
setIfUpdated(companyDocumentEntity::getCategoryEntity, companyDocumentEntity::setCategoryEntity, categoryEntity);
}
setIfUpdated(companyDocumentEntity::getName, companyDocumentEntity::setName, companyDocumentRequest.getName());
companyDocumentRepository.save(companyDocumentEntity);
log.info("Saved updates for Company Document ID '{}'", companyDocumentId);
/** This code is responsible for adding a version history log for the "updating company document" operation. **/
loggingUtil.addVersionHistory(
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCompanyDocumentData).newData(companyDocumentEntity).build());
return convertToCompanyDocumentResponseBean(companyDocumentEntity);
}
public CompanyDocumentResponseBean getCompanyDocument(UserEntity user ,Long companyDocumentId) {
log.info("Fetching company document with ID '{}' for user '{}'", companyDocumentId, user.getId());
CompanyDocumentEntity companyDocumentEntity = validateCompanyDocument(companyDocumentId);
validator.validateUserWithCompany(request,companyDocumentEntity.getCompanyId());
return convertToCompanyDocumentResponseBean(companyDocumentEntity);
}
public void deleteCompanyFile(Long companyDocumentId){
log.info("Deleting file for company document ID '{}'", companyDocumentId);
CompanyDocumentEntity companyDocumentEntity = validateCompanyDocument(companyDocumentId);
deleteCompanyFileFromS3(companyDocumentEntity);
}
public void deleteCompanyFileFromS3(CompanyDocumentEntity companyDocumentEntity){
try {
CompanyDocumentEntity oldCompanyDocumentEntity = Utils.getClonedEntityForData(companyDocumentEntity);
validator.validateUserWithCompany(request,companyDocumentEntity.getCompanyId());
String oldCompanyDocumentPath = companyDocumentEntity.getFilePath();
String newS3Path = s3ConfigBean.generateCompanyDocumentPathForOther(CompanyDocSourceTypeEnum.valueOf("DELETED_" + companyDocumentEntity.getType().toUpperCase()), companyDocumentEntity.getCompanyId());
UploadFileOnAmazonS3Response response = amazonS3Service.moveFile(companyDocumentEntity.getFileName(), oldCompanyDocumentPath, newS3Path);
companyDocumentEntity.setFileName(response.getFileName());
companyDocumentEntity.setFilePath(response.getFilePath());
companyDocumentEntity.setIsDeleted(true);
companyDocumentRepository.save(companyDocumentEntity);
/** This code is responsible for adding a version history log for the "Soft delete document" operation. **/
loggingUtil.addVersionHistory(
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.SOFT_DELETE).oldData(oldCompanyDocumentEntity).newData(companyDocumentEntity).build());
log.info("File for company document ID {} successfully moved to deleted folder.", companyDocumentEntity.getId());
}
catch (Exception e) {
log.error("Error moving file for company document ID {} to deleted folder: {}", companyDocumentEntity.getId(), e.getMessage());
throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.ERROR_MOVING_FILE_TO_DELETED_FOLDER));
}
}
public UserActionContextEnum getUserActionContextEnum(CompanyDocumentTypeEnum type){
UserActionContextEnum userActionContext = null;
if (type.equals(CompanyDocumentTypeEnum.COMPANY_DOCUMENT)){
userActionContext = UserActionContextEnum.UPLOAD_COMPANY_DOCUMENT;
}
else if(type.equals(CompanyDocumentTypeEnum.PERSONAL_DOCUMENT)){
userActionContext = UserActionContextEnum.UPLOAD_COMPANY_PERSONAL_DOCUMENT;
}
return userActionContext;
}
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);
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());
DocumentResponseBean responseBean = callDao.convertToDocumentResponseBean(entity);
return responseBean;
}
public List<CompanyDocumentResponseBean> 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);
companyService.validateCompany(companyId);
Specification<CompanyDocumentEntity> spec = filterCompanyDocuments(companyId, user.getId(), typeEnum);
List<CompanyDocumentEntity> companyDocumentEntities = companyDocumentRepository.findAll(spec);
log.info("Retrieved all documents for Company ID '{}'", companyId);
return companyDocumentEntities.stream()
.map(this::convertToCompanyDocumentResponseBean)
.collect(Collectors.toList());
}
private Specification<CompanyDocumentEntity> filterCompanyDocuments(Long companyId, Long userId, CompanyDocumentTypeEnum typeEnum) {
return (root, query, builder) -> {
Predicate predicate = builder.equal(root.get("companyId"), companyId);
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
predicate = builder.and(predicate, builder.equal(root.get("type"), CompanyDocumentTypeEnum.COMPANY_DOCUMENT.getValue()));
} else if (typeEnum == CompanyDocumentTypeEnum.PERSONAL_DOCUMENT) {
// Case 2: Fetch only PERSONAL_DOCUMENT type documents for the logged-in user
predicate = builder.and(
predicate,
builder.equal(root.get("type"), CompanyDocumentTypeEnum.PERSONAL_DOCUMENT.getValue()),
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));
}
return predicate;
};
}
}