diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 382ea8ca..4afb7238 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -433,6 +433,21 @@ public class GepafinConstant { public static final String FORMULA_AMOUNT_NOT_MATCHED="formula.amount.not.matches.requested.amount"; public static final String CRITERIA_TABLE_COLUMNS="criteria_table_columns"; + + 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_FETCHED_SUCCESSFULLY = "company.document.fetched.successfully"; + + public static final String DOCUMENT_CATEGORY_CREATE_SUCCESS = "document.category.success"; + public static final String DOCUMENT_CATEGORY_GET_SUCCESS = "document.category.get.success"; + public static final String DOCUMENT_CATEGORY_NOT_FOUND = "document.category.not.found"; + public static final String DOCUMENT_CATEGORY_DELETE_SUCCESS = "document.category.delete.success"; + public static final String DOCUMENT_CATEGORY_UPDATE_SUCCESS = "document.category.update.success"; + public static final String ERROR_MOVING_FILE_TO_DELETED_FOLDER = "error.moving.file.to.deleted.folder"; + + public static final String CATEGORY_CANNOT_BE_DELETED = "category.cannot.be.deleted"; + public static final String INVALID_EXPIRATION_DATE = "invalid.expiration.date"; public static final String LABEL="label"; public static final String FORMULA="formula"; public static final String VARIABLE="variable"; diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java new file mode 100644 index 00000000..a9f45b86 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java @@ -0,0 +1,334 @@ +package net.gepafin.tendermanagement.dao; + +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.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; + + public List uploadFileForCompany(HttpServletRequest request, Long userId, List files, Long companyId, Long documentCategoryId, CompanyDocumentTypeEnum companyDocumentSourceTypeEnum, LocalDateTime expirationDate){ + DocumentCategoryEntity categoryEntity = categoryDao.validateCategory(documentCategoryId); + validator.validateUserWithCompany(request,companyId); + UserWithCompanyEntity userWithCompanyEntity=companyService.getUserWithCompany(userId,companyId); + + LocalDateTime currentDate = LocalDateTime.now(); + if (expirationDate.isBefore(currentDate)) { + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_EXPIRATION_DATE)); + } + List companyDocumentEntities = new ArrayList<>(); + for (MultipartFile file : files){ + 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); + if (expirationDate.isBefore(currentDate.plusDays(7))) { + companyDocumentEntity.setStatus(CompanyDocumentStatusEnum.DUE.getValue()); + } else { + companyDocumentEntity.setStatus(CompanyDocumentStatusEnum.VALID.getValue()); + } + + companyDocumentEntity.setCategoryEntity(categoryEntity); + companyDocumentEntity.setUserWithCompany(userWithCompanyEntity); + companyDocumentEntity.setExpirationDate(expirationDate); + companyDocumentEntities.add(companyDocumentEntity); + } + } + companyDocumentRepository.saveAll(companyDocumentEntities); + + /** 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) { + 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) { + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.S3_PATH_GENERATION_ERROR_MSG)); + } + } + + public CompanyDocumentEntity validateCompanyDocument(Long id) { + return companyDocumentRepository.findByIdAndNotDeleted(id).orElseThrow(() -> 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.setName(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.setUserWithCompanyId(entity.getUserWithCompany().getId()); + responseBean.setCreatedDate(entity.getCreatedDate()); + responseBean.setUpdatedDate(entity.getUpdatedDate()); + return responseBean; + } + + public CompanyDocumentResponseBean updateCompanyDocument(HttpServletRequest request,Long companyDocumentId, CompanyDocumentRequest companyDocumentRequest){ + + 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)) { + 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()); + } else { + companyDocumentEntity.setStatus(CompanyDocumentStatusEnum.VALID.getValue()); + } + } + if (companyDocumentRequest.getCategoryId() != null && companyDocumentRequest.getCategoryId() >0) { + DocumentCategoryEntity categoryEntity = categoryDao.validateCategory(companyDocumentRequest.getCategoryId()); + setIfUpdated(companyDocumentEntity::getCategoryEntity, companyDocumentEntity::setCategoryEntity, categoryEntity); + } + companyDocumentRepository.save(companyDocumentEntity); + + /** 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) { + CompanyDocumentEntity companyDocumentEntity = validateCompanyDocument(companyDocumentId); + validator.validateUserWithCompany(request,companyDocumentEntity.getCompanyId()); + return convertToCompanyDocumentResponseBean(companyDocumentEntity); + } + + public void deleteCompanyFile(Long 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 validateAndDuplicateCompanyDocument(HttpServletRequest request , Long userId ,Long companyDocumentId , Long applicationId , DocumentTypeEnum documentTypeEnum){ + ApplicationEntity applicationEntity = applicationService.validateApplication(applicationId); + CompanyDocumentEntity companyDocumentEntity = validateCompanyDocument(companyDocumentId); + validator.validateUserWithCompany(request,companyDocumentEntity.getCompanyId()); + + String oldS3Path = companyDocumentEntity.getFilePath(); + String newS3Path = s3ConfigBean.generateDocumentPath(DocumentSourceTypeEnum.APPLICATION,applicationEntity.getCall().getId(),applicationId,0L); + + log.info("Original Paths - oldPath: {}, newPath: {}", oldS3Path, newS3Path); + + oldS3Path = amazonS3ServiceImpl.decodeS3Key(amazonS3ServiceImpl.cleanOldPath(oldS3Path)); + newS3Path = amazonS3ServiceImpl.cleanNewPath(oldS3Path, newS3Path); + log.info("Moving file from {} to {} in bucket {}", oldS3Path, newS3Path, bucketName); + + CopyObjectRequest copyRequest = new CopyObjectRequest(bucketName, oldS3Path, bucketName, newS3Path); + s3Client.copyObject(copyRequest); + log.info("File copied successfully from {} to {}", oldS3Path, newS3Path); + + DocumentEntity entity = new DocumentEntity(); + entity.setFilePath(newS3Path); + entity.setFileName(companyDocumentEntity.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 getAllCompanyDocument(UserEntity user , Long companyId, CompanyDocumentTypeEnum typeEnum){ + validator.validateUserWithCompany(request, companyId); + companyService.validateCompany(companyId); + + Specification spec = filterCompanyDocuments(companyId, user.getId(), typeEnum); + + List companyDocumentEntities = companyDocumentRepository.findAll(spec); + return companyDocumentEntities.stream() + .map(this::convertToCompanyDocumentResponseBean) + .collect(Collectors.toList()); + + } + + private Specification filterCompanyDocuments(Long companyId, Long userId, CompanyDocumentTypeEnum typeEnum) { + return (root, query, builder) -> { + Predicate predicate = builder.equal(root.get("companyId"), companyId); + + 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) + ); + } + } + // 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; + }; + } + + + + +} diff --git a/src/main/java/net/gepafin/tendermanagement/dao/DocumentCategoryDao.java b/src/main/java/net/gepafin/tendermanagement/dao/DocumentCategoryDao.java new file mode 100644 index 00000000..5dc799fb --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/dao/DocumentCategoryDao.java @@ -0,0 +1,111 @@ +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.DocumentCategoryEntity; +import net.gepafin.tendermanagement.entities.CompanyDocumentEntity; +import net.gepafin.tendermanagement.enums.VersionActionTypeEnum; +import net.gepafin.tendermanagement.model.request.DocumentCategoryRequest; +import net.gepafin.tendermanagement.model.request.VersionHistoryRequest; +import net.gepafin.tendermanagement.model.response.DocumentCategoryResponse; +import net.gepafin.tendermanagement.repositories.DocumentCategoryRepository; +import net.gepafin.tendermanagement.repositories.CompanyDocumentRepository; +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.ResourceNotFoundException; +import net.gepafin.tendermanagement.web.rest.api.errors.Status; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +import static net.gepafin.tendermanagement.util.Utils.setIfUpdated; + +@Component +public class DocumentCategoryDao { + + @Autowired + private DocumentCategoryRepository categoryRepository; + + @Autowired + private LoggingUtil loggingUtil; + + @Autowired + private HttpServletRequest request; + + @Autowired + private CompanyDocumentRepository companyDocumentRepository; + + public DocumentCategoryResponse createDocumentCategory(HttpServletRequest request, DocumentCategoryRequest categoryRequest){ + + DocumentCategoryEntity entity = createCategoryEntity(new DocumentCategoryEntity(),categoryRequest); + categoryRepository.save(entity); + + /** This code is responsible for adding a version history log for the "Create Company Document Category" operation. **/ + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(entity).build()); + + return convertToResponseBean(entity); + } + + public DocumentCategoryEntity createCategoryEntity(DocumentCategoryEntity entity, DocumentCategoryRequest companyDocumentCategoryRequest){ + entity.setCategoryName(companyDocumentCategoryRequest.getCategoryName()); + entity.setDescription(companyDocumentCategoryRequest.getDescription()); + entity.setIsDeleted(false); + return entity; + } + + public DocumentCategoryResponse convertToResponseBean(DocumentCategoryEntity entity){ + DocumentCategoryResponse response = new DocumentCategoryResponse(); + response.setId(entity.getId()); + response.setCategoryName(entity.getCategoryName()); + response.setDescription(entity.getDescription()); + response.setCreatedDate(entity.getCreatedDate()); + response.setUpdatedDate(entity.getUpdatedDate()); + return response; + } + + public DocumentCategoryResponse getDocumentCategoryById(HttpServletRequest request, Long id){ + return convertToResponseBean(validateCategory(id)); + } + + public DocumentCategoryEntity validateCategory(Long id) { + return categoryRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.DOCUMENT_CATEGORY_NOT_FOUND))); + } + + public void deleteDocumentCategory(HttpServletRequest request,Long id) { + DocumentCategoryEntity entity = validateCategory(id); + + List companyDocumentEntities = companyDocumentRepository.findByCategoryEntityId(id); + if (!companyDocumentEntities.isEmpty()){ + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.CATEGORY_CANNOT_BE_DELETED)); + } + DocumentCategoryEntity oldCategoryEntity = Utils.getClonedEntityForData(entity); + entity.setIsDeleted(true); + categoryRepository.save(entity); + + /** This code is responsible for adding a version history log for the "soft delete category" operation **/ + loggingUtil.addVersionHistory( + VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.SOFT_DELETE).oldData(oldCategoryEntity).newData(entity).build()); + } + + public DocumentCategoryResponse updateDocumentCategory(HttpServletRequest request, Long id , DocumentCategoryRequest categoryRequest){ + DocumentCategoryEntity entity = validateCategory(id); + DocumentCategoryEntity oldCategoryEntity = Utils.getClonedEntityForData(entity); + DocumentCategoryEntity newCategoryEntity = updateCategoryEntity(entity, categoryRequest); + + /** This code is responsible for adding a version history log for the "Update Category" operation. **/ + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCategoryEntity).newData(newCategoryEntity).build()); + return convertToResponseBean(entity); + } + + public DocumentCategoryEntity updateCategoryEntity(DocumentCategoryEntity entity , DocumentCategoryRequest categoryRequest){ + setIfUpdated(entity::getCategoryName, entity::setCategoryName, categoryRequest.getCategoryName()); + setIfUpdated(entity::getDescription, entity::setDescription, categoryRequest.getDescription()); + + return entity; + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/dao/DocumentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/DocumentDao.java index e1dbe853..81400797 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/DocumentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/DocumentDao.java @@ -316,7 +316,7 @@ public class DocumentDao { log.info("File for document ID {} successfully moved to deleted folder.", documentEntity.getId()); } catch (Exception e) { log.error("Error moving file for document ID {} to deleted folder: {}", documentEntity.getId(), e.getMessage()); - throw new CustomValidationException(Status.VALIDATION_ERROR, "Error occurred while moving file to deleted folder."); + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.ERROR_MOVING_FILE_TO_DELETED_FOLDER)); } } } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/NotificationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/NotificationDao.java index 81eced77..3a32373c 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/NotificationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/NotificationDao.java @@ -8,12 +8,7 @@ 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.ApplicationEntity; -import net.gepafin.tendermanagement.entities.ApplicationEvaluationEntity; -import net.gepafin.tendermanagement.entities.NotificationEntity; -import net.gepafin.tendermanagement.entities.NotificationTypeEntity; -import net.gepafin.tendermanagement.entities.UserEntity; -import net.gepafin.tendermanagement.entities.UserWithCompanyEntity; +import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.enums.NotificationEnum; import net.gepafin.tendermanagement.enums.NotificationTypeEnum; import net.gepafin.tendermanagement.enums.RoleStatusEnum; @@ -28,6 +23,7 @@ import net.gepafin.tendermanagement.repositories.NotificationTypeRepository; import net.gepafin.tendermanagement.repositories.UserRepository; import net.gepafin.tendermanagement.repositories.UserWithCompanyRepository; import net.gepafin.tendermanagement.service.ApplicationService; +import net.gepafin.tendermanagement.service.CompanyService; import net.gepafin.tendermanagement.util.DateTimeUtil; import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; @@ -81,6 +77,9 @@ public class NotificationDao { @Autowired private UserDao userDao; + @Autowired + private CompanyService companyService; + public NotificationResponse sendNotification(NotificationReq notificationReq) { // Ensure userId is properly set in notificationReq if not already @@ -416,6 +415,18 @@ public class NotificationDao { return predicates; } + public void sendNotificationToBeneficiaryForDocumentExpiration(CompanyDocumentEntity companyDocumentEntity, NotificationTypeEnum notificationTypeEnum) { + + CompanyEntity companyEntity = companyService.validateCompany(companyDocumentEntity.getCompanyId()); + Map placeHolders = new HashMap<>(); + placeHolders.put("{{file_name}}", companyDocumentEntity.getFileName()); + placeHolders.put("{{company_name}}", companyEntity.getCompanyName()); + placeHolders.put("{{expiration_date}}", companyDocumentEntity.getExpirationDate().toString()); + NotificationReq notificationReq = createNotificationReq(notificationTypeEnum.getValue(), placeHolders, companyDocumentEntity.getUserWithCompany().getUserId(), companyDocumentEntity.getUserWithCompany(), + listOf(companyDocumentEntity.getCompanyId())); + sendNotification(notificationReq); + } + public PageableResponseBean> getNotificationsByUserIdAndCompanyIdByPagination(Long userId, Long companyId, NotificationRequestBean notificationRequestBean) { UserWithCompanyEntity userWithCompany; if (companyId != null) { diff --git a/src/main/java/net/gepafin/tendermanagement/dao/S3PathConfig.java b/src/main/java/net/gepafin/tendermanagement/dao/S3PathConfig.java index 1db01f11..9b55eda1 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/S3PathConfig.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/S3PathConfig.java @@ -1,6 +1,8 @@ package net.gepafin.tendermanagement.dao; import net.gepafin.tendermanagement.entities.S3ConfigEntity; +import net.gepafin.tendermanagement.enums.CompanyDocSourceTypeEnum; +import net.gepafin.tendermanagement.enums.CompanyDocumentTypeEnum; import net.gepafin.tendermanagement.enums.DocOtherSourceTypeEnum; import net.gepafin.tendermanagement.enums.DocumentSourceTypeEnum; import net.gepafin.tendermanagement.repositories.S3ConfigRepository; @@ -49,4 +51,29 @@ public class S3PathConfig { public String getBucketNameForCallAppType(DocumentSourceTypeEnum type){ return s3ConfigRepository.getBucketNameByType(type); } + + public String generateCompanyDocumentPath(CompanyDocumentTypeEnum type, Long companyId) { + S3ConfigEntity config = getCompanyDocumentPath(type); + return config.getParentFolder() + "/" + buildCompanyDocumentS3Path(config.getPath(), companyId); + } + + private String buildCompanyDocumentS3Path(String pathTemplate, Long companyId) { + return pathTemplate + .replace("{company_id}", companyId != null && companyId != 0L ? "company_" + companyId : ""); + } + + private S3ConfigEntity getCompanyDocumentPath(CompanyDocumentTypeEnum type) { + return s3ConfigRepository.getPathByType(type.name()).orElseThrow(() -> new IllegalArgumentException("No path configuration found for type: " + type)); + } + + private S3ConfigEntity getCompanyDocumentPathForOther(CompanyDocSourceTypeEnum type) { + + return s3ConfigRepository.getPathByType(type.name()).orElseThrow(() -> new IllegalArgumentException("No path configuration found for type: " + type)); + } + + public String generateCompanyDocumentPathForOther(CompanyDocSourceTypeEnum type, Long companyId) { + + S3ConfigEntity config = getCompanyDocumentPathForOther(type); + return config.getParentFolder() + "/" + buildCompanyDocumentS3Path(config.getPath(),companyId); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/CompanyDocumentEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/CompanyDocumentEntity.java new file mode 100644 index 00000000..7308a270 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/CompanyDocumentEntity.java @@ -0,0 +1,46 @@ +package net.gepafin.tendermanagement.entities; + +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "COMPANY_DOCUMENT") +@Data +public class CompanyDocumentEntity extends BaseEntity { + + @Column(name = "FILE_NAME") + private String fileName; + + @Column(name = "FILE_PATH") + private String filePath; + + @Column(name="TYPE") + private String type; + + @Column(name="COMPANY_ID") + private Long companyId; + + @Column(name ="IS_DELETED") + private Boolean isDeleted = false; + + @Column(name="UPLOADED_BY") + private Long uploadedBy; + + @Column(name = "EXPIRATION_DATE") + private LocalDateTime expirationDate; + + @Column(name ="STATUS") + private String status; + + @ManyToOne + @JoinColumn(name = "USER_WITH_COMPANY_ID") + private UserWithCompanyEntity userWithCompany; + + @ManyToOne + @JoinColumn(name = "DOCUMENT_CATEGORY_ID") + private DocumentCategoryEntity categoryEntity; + + +} diff --git a/src/main/java/net/gepafin/tendermanagement/entities/DocumentCategoryEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/DocumentCategoryEntity.java new file mode 100644 index 00000000..25a25d6d --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/DocumentCategoryEntity.java @@ -0,0 +1,22 @@ +package net.gepafin.tendermanagement.entities; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import lombok.Data; + +@Entity +@Table(name = "document_category") +@Data +public class DocumentCategoryEntity extends BaseEntity { + + @Column(name = "CATEGORY_NAME") + private String categoryName; + + @Column(name = "DESCRIPTION") + private String description; + + @Column(name ="IS_DELETED") + private Boolean isDeleted = false; + +} diff --git a/src/main/java/net/gepafin/tendermanagement/enums/CompanyDocSourceTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/CompanyDocSourceTypeEnum.java new file mode 100644 index 00000000..bb78960c --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/enums/CompanyDocSourceTypeEnum.java @@ -0,0 +1,19 @@ +package net.gepafin.tendermanagement.enums; + + +public enum CompanyDocSourceTypeEnum { + + DELETED_PERSONAL_DOCUMENT("DELETED_PERSONAL_DOCUMENT"), + DELETED_COMPANY_DOCUMENT("DELETED_COMPANY_DOCUMENT"); + + + private String value; + + CompanyDocSourceTypeEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/enums/CompanyDocumentStatusEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/CompanyDocumentStatusEnum.java new file mode 100644 index 00000000..b3a1782f --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/enums/CompanyDocumentStatusEnum.java @@ -0,0 +1,17 @@ +package net.gepafin.tendermanagement.enums; + +public enum CompanyDocumentStatusEnum { + VALID("VALID"), + DUE("DUE"), + EXPIRED("EXPIRED"); + + private String value; + + CompanyDocumentStatusEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/enums/CompanyDocumentTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/CompanyDocumentTypeEnum.java new file mode 100644 index 00000000..9b163da0 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/enums/CompanyDocumentTypeEnum.java @@ -0,0 +1,16 @@ +package net.gepafin.tendermanagement.enums; + +public enum CompanyDocumentTypeEnum { + COMPANY_DOCUMENT("COMPANY_DOCUMENT"), + PERSONAL_DOCUMENT("PERSONAL_DOCUMENT"); + + private String value; + + CompanyDocumentTypeEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/enums/ExpirationTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/ExpirationTypeEnum.java index 2aaa1ae2..91ebfc25 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/ExpirationTypeEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/ExpirationTypeEnum.java @@ -5,7 +5,8 @@ import com.fasterxml.jackson.annotation.JsonValue; public enum ExpirationTypeEnum { AMENDMENT("AMENDMENT"), - EVALUATION("EVALUATION"); + EVALUATION("EVALUATION"), + COMPANY_DOCUMENT("COMPANY_DOCUMENT"); private String value; diff --git a/src/main/java/net/gepafin/tendermanagement/enums/NotificationTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/NotificationTypeEnum.java index 96d89e91..8957c03b 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/NotificationTypeEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/NotificationTypeEnum.java @@ -13,7 +13,8 @@ public enum NotificationTypeEnum { EVALUATION_CREATION("EVALUATION_CREATION"), EVALUATION_EXPIRED("EVALUATION_EXPIRED"), AMENDMENT_EXPIRATION_REMINDER("AMENDMENT_EXPIRATION_REMINDER"), - EVALUATION_EXPIRATION_REMINDER("EVALUATION_EXPIRATION_REMINDER"); + EVALUATION_EXPIRATION_REMINDER("EVALUATION_EXPIRATION_REMINDER"), + COMPANY_DOCUMENT_EXPIRATION_REMINDER("COMPANY_DOCUMENT_EXPIRATION_REMINDER"); private final String value; diff --git a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java index 4b7cf497..1029d9b1 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java @@ -193,6 +193,21 @@ public enum UserActionContextEnum { GET_USER_ACTION("GET_USER_ACTION"), GET_ACTION_CONTEXT_LABELS("GET_ACTION_CONTEXT_LABELS"), + + GET_COMPANY_DOCUMENT("GET_COMPANY_DOCUMENT"), + DELETE_COMPANY_DOCUMENT("DELETE_COMPANY_DOCUMENT"), + UPLOAD_COMPANY_DOCUMENT("UPLOAD_COMPANY_DOCUMENT"), + UPLOAD_COMPANY_PERSONAL_DOCUMENT("UPLOAD_COMPANY_PERSONAL_DOCUMENT"), + GET_ALL_COMPANY_DOCUMENT("GET_ALL_COMPANY_DOCUMENT"), + UPDATE_COMPANY_DOCUMENT("UPDATE_COMPANY_DOCUMENT"), + DUPLICATE_COMPANY_DOCUMENT("DUPLICATE_COMPANY_DOCUMENT"), + + CREATE_DOCUMENT_CATEGORY("CREATE_DOCUMENT_CATEGORY"), + GET_DOCUMENT_CATEGORY("GET_DOCUMENT_CATEGORY"), + DELETE_DOCUMENT_CATEGORY("DELETE_DOCUMENT_CATEGORY"), + UPDATE_DOCUMENT_CATEGORY("UPDATE_DOCUMENT_CATEGORY"), + COMPANY_DOCUMENT_EXPIRATION_SCHEDULER("COMPANY_DOCUMENT_EXPIRATION_SCHEDULER"), + GET_ALL_ASSIGNED_APPLICATION_BY_PAGINATION("GET_ALL_ASSIGNED_APPLICATION_BY_PAGINATION"), GET_ALL_APPLICATION_AMENDMENT_BY_PAGINATION("GET_ALL_APPLICATION_AMENDMENT_BY_PAGINATION"), GET_ALL_USER_ACTION_BY_PAGINATION("GET_ALL_USER_ACTION_BY_PAGINATION"), diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/CompanyDocumentRequest.java b/src/main/java/net/gepafin/tendermanagement/model/request/CompanyDocumentRequest.java new file mode 100644 index 00000000..41d167ca --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/request/CompanyDocumentRequest.java @@ -0,0 +1,12 @@ +package net.gepafin.tendermanagement.model.request; + +import lombok.Data; + +import java.time.LocalDateTime; + + +@Data +public class CompanyDocumentRequest { + private Long categoryId; + private LocalDateTime expirationDate; +} diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/DocumentCategoryRequest.java b/src/main/java/net/gepafin/tendermanagement/model/request/DocumentCategoryRequest.java new file mode 100644 index 00000000..25fdb219 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/request/DocumentCategoryRequest.java @@ -0,0 +1,9 @@ +package net.gepafin.tendermanagement.model.request; + +import lombok.Data; + +@Data +public class DocumentCategoryRequest { + private String categoryName; + private String description; +} diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/CompanyDocumentResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/CompanyDocumentResponseBean.java new file mode 100644 index 00000000..576cc324 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/CompanyDocumentResponseBean.java @@ -0,0 +1,29 @@ +package net.gepafin.tendermanagement.model.response; + +import lombok.Data; +import net.gepafin.tendermanagement.enums.CompanyDocumentTypeEnum; +import net.gepafin.tendermanagement.model.BaseBean; +import java.time.LocalDateTime; + +@Data +public class CompanyDocumentResponseBean extends BaseBean { + + private String name; + + private String filePath; + + private CompanyDocumentTypeEnum type; + + private Long companyId; + + private String status; + + private LocalDateTime expirationDate; + + private Long uploadedBy; + + private Long userWithCompanyId; + + private DocumentCategoryResponse category; + +} diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/DocumentCategoryResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/DocumentCategoryResponse.java new file mode 100644 index 00000000..3b5512e9 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/DocumentCategoryResponse.java @@ -0,0 +1,11 @@ +package net.gepafin.tendermanagement.model.response; + +import lombok.Data; +import net.gepafin.tendermanagement.model.BaseBean; + +@Data +public class DocumentCategoryResponse extends BaseBean { + private String categoryName; + private String description; + +} diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/CompanyDocumentRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/CompanyDocumentRepository.java new file mode 100644 index 00000000..30a49410 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/repositories/CompanyDocumentRepository.java @@ -0,0 +1,41 @@ +package net.gepafin.tendermanagement.repositories; + +import feign.Param; +import net.gepafin.tendermanagement.entities.ApplicationAmendmentRequestEntity; +import net.gepafin.tendermanagement.entities.CompanyDocumentEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +@Repository +public interface CompanyDocumentRepository extends JpaRepository, JpaSpecificationExecutor { + + @Query("SELECT c FROM CompanyDocumentEntity c WHERE c.id = :id AND c.isDeleted = false") + Optional findByIdAndNotDeleted(@Param("id") Long id); + + @Query("SELECT d FROM CompanyDocumentEntity d " + + "WHERE d.isDeleted = false " + + "AND d.expirationDate BETWEEN :startTime AND :endTime") + List findExpiringBetween(LocalDateTime startTime, LocalDateTime endTime); + + @Query("SELECT c FROM CompanyDocumentEntity c " + + "WHERE c.isDeleted = false " + + "AND c.expirationDate < :now") + List findByExpirationDateBeforeAndIsDeletedFalse(LocalDateTime now); + + @Query("SELECT c FROM CompanyDocumentEntity c " + + "WHERE c.companyId = :companyId " + + "AND c.isDeleted = false") + List findByCompanyId(Long companyId); + + List findByCategoryEntityId(Long categoryId); + + + + +} diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/DocumentCategoryRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/DocumentCategoryRepository.java new file mode 100644 index 00000000..3b09eb60 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/repositories/DocumentCategoryRepository.java @@ -0,0 +1,9 @@ +package net.gepafin.tendermanagement.repositories; + +import net.gepafin.tendermanagement.entities.DocumentCategoryEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface DocumentCategoryRepository extends JpaRepository { +} diff --git a/src/main/java/net/gepafin/tendermanagement/scheduler/CompanyDocumentExpirationScheduler.java b/src/main/java/net/gepafin/tendermanagement/scheduler/CompanyDocumentExpirationScheduler.java new file mode 100644 index 00000000..e5a40408 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/scheduler/CompanyDocumentExpirationScheduler.java @@ -0,0 +1,113 @@ +package net.gepafin.tendermanagement.scheduler; + +import jakarta.servlet.http.HttpServletRequest; +import net.gepafin.tendermanagement.dao.NotificationDao; +import net.gepafin.tendermanagement.entities.CompanyDocumentEntity; +import net.gepafin.tendermanagement.entities.ExpirationConfigEntity; +import net.gepafin.tendermanagement.enums.*; +import net.gepafin.tendermanagement.model.request.UserActionRequest; +import net.gepafin.tendermanagement.model.request.VersionHistoryRequest; +import net.gepafin.tendermanagement.repositories.CompanyDocumentRepository; +import net.gepafin.tendermanagement.repositories.ExpirationConfigRepository; +import net.gepafin.tendermanagement.util.LoggingUtil; +import net.gepafin.tendermanagement.util.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.List; + +@Component +public class CompanyDocumentExpirationScheduler { + + @Autowired + private CompanyDocumentRepository companyDocumentRepository; + + @Autowired + private NotificationDao notificationDao; + + @Autowired + private LoggingUtil loggingUtil; + + @Autowired + private HttpServletRequest request; + + @Autowired + private ExpirationConfigRepository expirationConfigRepository; + + private static final Logger log = LoggerFactory.getLogger(ExpirationScheduler.class); + + @Scheduled(cron = "0 0 4 * * ?") + public void processDocumentExpiration(){ + log.info("Starting the Document Expiration scheduler..."); + + try { + Utils.setHttpServletRequestForScheduler(); + + // Logging user action for the scheduler operation + loggingUtil.logUserActionWithoutToken( + UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.SCHEDULER) + .actionContext(UserActionContextEnum.COMPANY_DOCUMENT_EXPIRATION_SCHEDULER).build()); + + + log.info("Starting processing expiration notifications for document"); + processExpirationReminder(ExpirationTypeEnum.COMPANY_DOCUMENT); + updateExpiredDocuments(); + + log.info("Expiration scheduler completed successfully."); + } + catch (Exception e){ + log.error("An error occurred during the Notification Expiration Scheduler of Document: {}", e.getMessage(), e); + } + } + + private void processExpirationReminder(ExpirationTypeEnum typeEnum){ + List configEntities = expirationConfigRepository.findByTypeAndIsDeletedFalse(typeEnum.getValue()); + + for (ExpirationConfigEntity config : configEntities){ + Long daysBefore = config.getIntervalDays(); + LocalDateTime now = LocalDateTime.now(); + LocalDateTime startDate = now.plusDays(daysBefore).withHour(0).withMinute(0).withSecond(0).withNano(2); + LocalDateTime endDate = startDate.plusDays(1).minusNanos(2); + + processDocumentExpiration(startDate, endDate, daysBefore); + } + } + + private void processDocumentExpiration(LocalDateTime startDate, LocalDateTime endDate, Long daysBefore){ + List expiringDocuments = companyDocumentRepository.findExpiringBetween(startDate, endDate); + + for (CompanyDocumentEntity document : expiringDocuments) { + notificationDao.sendNotificationToBeneficiaryForDocumentExpiration(document, NotificationTypeEnum.COMPANY_DOCUMENT_EXPIRATION_REMINDER); + updateDocumentStatus(document, CompanyDocumentStatusEnum.DUE.getValue()); + } + } + + + private void updateDocumentStatus(CompanyDocumentEntity companyDocument,String status) { + CompanyDocumentEntity oldCompanyDocumentEntity = Utils.getClonedEntityForData(companyDocument); + companyDocument.setStatus(status); + companyDocumentRepository.save(companyDocument); + + // Logging version history for the update operation + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request) + .actionType(VersionActionTypeEnum.UPDATE).oldData(oldCompanyDocumentEntity) + .newData(companyDocument).build()); + + log.info("Updated document status for document: {}", companyDocument.getFileName()); + } + + + private void updateExpiredDocuments() { + LocalDateTime now = LocalDateTime.now(); + List expiredDocuments = companyDocumentRepository.findByExpirationDateBeforeAndIsDeletedFalse(now); + + for (CompanyDocumentEntity document : expiredDocuments) { + updateDocumentStatus(document, CompanyDocumentStatusEnum.EXPIRED.getValue()); + } + } + +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/CompanyDocumentService.java b/src/main/java/net/gepafin/tendermanagement/service/CompanyDocumentService.java new file mode 100644 index 00000000..dd469fe8 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/service/CompanyDocumentService.java @@ -0,0 +1,29 @@ +package net.gepafin.tendermanagement.service; + +import jakarta.servlet.http.HttpServletRequest; +import net.gepafin.tendermanagement.enums.CompanyDocumentTypeEnum; +import net.gepafin.tendermanagement.enums.DocumentTypeEnum; +import net.gepafin.tendermanagement.model.request.CompanyDocumentRequest; +import net.gepafin.tendermanagement.model.response.CompanyDocumentResponseBean; +import net.gepafin.tendermanagement.model.response.DocumentResponseBean; +import org.springframework.web.multipart.MultipartFile; + +import java.time.LocalDateTime; +import java.util.List; + +public interface CompanyDocumentService { + List uploadFileForCompany(HttpServletRequest request, List files, Long companyId, Long documentCategoryId, CompanyDocumentTypeEnum documentSourceTypeEnum, LocalDateTime expirationDate); + + CompanyDocumentResponseBean updateCompanyDocument(HttpServletRequest httpServletRequest, Long companyDocumentId, CompanyDocumentRequest companyDocumentRequest); + + CompanyDocumentResponseBean getCompanyDocument(HttpServletRequest request, Long companyDocumentId); + + void deleteCompanyFile(HttpServletRequest request,Long companyDocumentId); + + DocumentResponseBean validateAndDuplicateCompanyDocument(HttpServletRequest request, Long companyDocumentId, Long applicationId, DocumentTypeEnum typeEnum); + + List getAllCompanyDocument(HttpServletRequest request ,Long companyId , CompanyDocumentTypeEnum typeEnum); + + + +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/DocumentCategoryService.java b/src/main/java/net/gepafin/tendermanagement/service/DocumentCategoryService.java new file mode 100644 index 00000000..f742c5f2 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/service/DocumentCategoryService.java @@ -0,0 +1,13 @@ +package net.gepafin.tendermanagement.service; + +import jakarta.servlet.http.HttpServletRequest; +import net.gepafin.tendermanagement.model.request.DocumentCategoryRequest; +import net.gepafin.tendermanagement.model.response.DocumentCategoryResponse; + +public interface DocumentCategoryService { + + DocumentCategoryResponse createDocumentCategory(HttpServletRequest request, DocumentCategoryRequest categoryRequest); + DocumentCategoryResponse getDocumentCategoryById(HttpServletRequest request, Long id); + void deleteDocumentCategory(HttpServletRequest request,Long id); + DocumentCategoryResponse updateDocumentCategory(HttpServletRequest request, Long id, DocumentCategoryRequest categoryRequest); +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java index 9909f732..bff95344 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java @@ -153,7 +153,7 @@ public class AmazonS3ServiceImpl implements AmazonS3Service { } } - private String decodeS3Key(String key) { + public String decodeS3Key(String key) { return URLDecoder.decode(key, StandardCharsets.UTF_8); } @@ -186,11 +186,11 @@ public class AmazonS3ServiceImpl implements AmazonS3Service { } } - private String cleanNewPath(String oldPath, String newPath) { + public String cleanNewPath(String oldPath, String newPath) { return newPath + "/" + oldPath.substring(oldPath.lastIndexOf("/") + 1); } - private String cleanOldPath(String oldPath) { + public String cleanOldPath(String oldPath) { return oldPath.replace(s3Url, ""); } } \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyDocumentServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyDocumentServiceImpl.java new file mode 100644 index 00000000..8fa169d8 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyDocumentServiceImpl.java @@ -0,0 +1,66 @@ +package net.gepafin.tendermanagement.service.impl; + +import jakarta.servlet.http.HttpServletRequest; +import net.gepafin.tendermanagement.dao.CompanyDocumentDao; +import net.gepafin.tendermanagement.entities.UserEntity; +import net.gepafin.tendermanagement.enums.CompanyDocumentTypeEnum; +import net.gepafin.tendermanagement.enums.DocumentTypeEnum; +import net.gepafin.tendermanagement.model.request.CompanyDocumentRequest; +import net.gepafin.tendermanagement.model.response.CompanyDocumentResponseBean; +import net.gepafin.tendermanagement.model.response.DocumentResponseBean; +import net.gepafin.tendermanagement.service.CompanyDocumentService; +import net.gepafin.tendermanagement.util.Validator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +@Service +public class CompanyDocumentServiceImpl implements CompanyDocumentService { + + @Autowired + private Validator validator; + + @Autowired + private CompanyDocumentDao companyDocumentDao; + + @Override + public List uploadFileForCompany(HttpServletRequest request, List files, Long companyId, Long documentCategoryId , CompanyDocumentTypeEnum documentSourceTypeEnum, LocalDateTime expirationDate) { + Map userInfo = validator.getUserInfoFromToken(request); + Long userId = validator.getUserId(userInfo); + return companyDocumentDao.uploadFileForCompany(request,userId,files,companyId,documentCategoryId,documentSourceTypeEnum,expirationDate); + } + + @Override + public CompanyDocumentResponseBean updateCompanyDocument(HttpServletRequest request, Long companyDocumentId, CompanyDocumentRequest companyDocumentRequest) { + validator.validateUser(request); + return companyDocumentDao.updateCompanyDocument(request,companyDocumentId, companyDocumentRequest); + } + + @Override + public CompanyDocumentResponseBean getCompanyDocument(HttpServletRequest request, Long companyDocumentId) { + UserEntity user = validator.validateUser(request); + return companyDocumentDao.getCompanyDocument(user , companyDocumentId); + } + + @Override + public void deleteCompanyFile(HttpServletRequest request,Long companyDocumentId) { + validator.validateUser(request); + companyDocumentDao.deleteCompanyFile(companyDocumentId); + } + + @Override + public DocumentResponseBean validateAndDuplicateCompanyDocument(HttpServletRequest request, Long companyDocumentId, Long applicationId, DocumentTypeEnum typeEnum) { + UserEntity user = validator.validateUser(request); + return companyDocumentDao.validateAndDuplicateCompanyDocument(request, user.getId(), companyDocumentId,applicationId,typeEnum); + } + + @Override + public List getAllCompanyDocument(HttpServletRequest request, Long companyId, CompanyDocumentTypeEnum typeEnum) { + UserEntity user = validator.validateUser(request); + return companyDocumentDao.getAllCompanyDocument(user,companyId,typeEnum); + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/DocumentCategoryServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/DocumentCategoryServiceImpl.java new file mode 100644 index 00000000..bbb757e7 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/DocumentCategoryServiceImpl.java @@ -0,0 +1,51 @@ +package net.gepafin.tendermanagement.service.impl; + +import jakarta.servlet.http.HttpServletRequest; +import net.gepafin.tendermanagement.dao.DocumentCategoryDao; +import net.gepafin.tendermanagement.model.request.DocumentCategoryRequest; +import net.gepafin.tendermanagement.model.response.DocumentCategoryResponse; +import net.gepafin.tendermanagement.service.DocumentCategoryService; +import net.gepafin.tendermanagement.util.Validator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class DocumentCategoryServiceImpl implements DocumentCategoryService { + + @Autowired + DocumentCategoryDao categoryDao; + + @Autowired + private Validator validator; + + @Override + @Transactional(rollbackFor = Exception.class) + public DocumentCategoryResponse createDocumentCategory(HttpServletRequest request, DocumentCategoryRequest categoryRequest) { + validator.validateUser(request); + return categoryDao.createDocumentCategory(request,categoryRequest); + } + + @Override + @Transactional(readOnly = true) + public DocumentCategoryResponse getDocumentCategoryById(HttpServletRequest request, Long id) { + validator.validateUser(request); + return categoryDao.getDocumentCategoryById(request,id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteDocumentCategory(HttpServletRequest request, Long id) { + validator.validateUser(request); + categoryDao.deleteDocumentCategory(request,id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public DocumentCategoryResponse updateDocumentCategory(HttpServletRequest request, Long id, DocumentCategoryRequest categoryRequest) { + validator.validateUser(request); + return categoryDao.updateDocumentCategory(request,id,categoryRequest); + } + + +} diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/CompanyDocumentApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/CompanyDocumentApi.java new file mode 100644 index 00000000..ba3409d5 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/CompanyDocumentApi.java @@ -0,0 +1,122 @@ +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.enums.CompanyDocumentTypeEnum; +import net.gepafin.tendermanagement.enums.DocumentTypeEnum; +import net.gepafin.tendermanagement.model.request.CompanyDocumentRequest; +import net.gepafin.tendermanagement.model.request.FormRequest; +import net.gepafin.tendermanagement.model.response.CompanyDocumentResponseBean; +import net.gepafin.tendermanagement.model.response.DocumentResponseBean; +import net.gepafin.tendermanagement.model.util.Response; +import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.time.LocalDateTime; +import java.util.List; + +@Validated +public interface CompanyDocumentApi { + @Operation(summary = "Api to upload a file for company", + responses = { + @ApiResponse(responseCode = "200", description = "OK"), + @ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { + @ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE) })), + @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 = "/company/{companyId}/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + default ResponseEntity>> uploadFileForCompany(HttpServletRequest httpServletRequest, + @Parameter(description = "Company Id", required = true) @PathVariable("companyId") Long companyId, + @Parameter(description = "The Document Category id", required = true) @RequestParam(value = "documentCategoryId", required = false) Long documentCategoryId, + @RequestParam("documentType") CompanyDocumentTypeEnum documentTypeEnum, + @RequestParam("expirationDate") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime expirationDate, + @RequestParam("file") List files) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + + @Operation(summary = "Api to update company document", + 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 = "/{id}",produces = "application/json") + default ResponseEntity> updateCompanyDocument(HttpServletRequest httpServletRequest, @Parameter(description = "Company Document Id", required = true) @PathVariable("id") Long companyDocumentId,@Valid @RequestBody CompanyDocumentRequest companyDocumentRequest) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + + @Operation(summary = "API to get company document 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) })) + }) + @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) + ResponseEntity> getCompanyDocumentById(HttpServletRequest request, + @Parameter(description = "Company Document Id", required = true) + @PathVariable("id") Long id); + + @Operation(summary = "API to delete a file by company document id", + responses = { + @ApiResponse(responseCode = "200", description = "File deleted successfully"), + @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) })) + }) + @DeleteMapping(value = "") + default ResponseEntity> deleteCompanyFile(HttpServletRequest httpServletRequest, + @RequestParam( "id") Long id) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + + + @Operation(summary = "Api to copy a company document", + 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 = "/{id}/document/upload", produces = MediaType.APPLICATION_JSON_VALUE) + default ResponseEntity> validateAndDuplicateCompanyDocument (HttpServletRequest httpServletRequest, @Parameter(description = "Company Document Id", required = true) @PathVariable("id") Long companyDocumentId, + @Parameter(description = "Application Id", required = true) @RequestParam Long applicationId, + @RequestParam("documentType") DocumentTypeEnum documentTypeEnum) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + + @Operation(summary = "API to get all company documents", + 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) })) + }) + @GetMapping(value = "/company/{companyId}", produces = MediaType.APPLICATION_JSON_VALUE) + ResponseEntity>> getAllCompanyDocuments(HttpServletRequest request, + @Parameter(description = "Company Id", required = true) + @PathVariable("companyId") Long companyId , @RequestParam(value = "documentType", required = false) CompanyDocumentTypeEnum documentTypeEnum); +} diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/DocumentCategoryApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/DocumentCategoryApi.java new file mode 100644 index 00000000..11d571bb --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/DocumentCategoryApi.java @@ -0,0 +1,82 @@ +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.DocumentCategoryRequest; +import net.gepafin.tendermanagement.model.response.DocumentCategoryResponse; +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.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +@Validated +public interface DocumentCategoryApi { + + @Operation(summary = "Api to create document category", 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 = "", produces = "application/json") + ResponseEntity> createDocumentCategory(HttpServletRequest request, + @Parameter(description = "Company Document Category request object", required = true) + @Valid @RequestBody DocumentCategoryRequest categoryRequest); + + + @Operation(summary = "Api to get document category 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 = "/{id}", produces = "application/json") + ResponseEntity> getDocumentCategoryById(HttpServletRequest request, + @Parameter(description = "The document category id", required = true) + @PathVariable("id") Long id); + + + @Operation(summary = "Api to delete a document category", 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) })) + }) + @DeleteMapping(value = "/{id}") + ResponseEntity> deleteDocumentCategory(HttpServletRequest request, + @Parameter(description = "The document category id", required = true) + @PathVariable("id") Long id); + + + @Operation(summary = "API to update a document category", 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 = "/{id}", produces = "application/json") + ResponseEntity> updateDocumentCategory(HttpServletRequest request, + @Parameter(description = "The document category id", required = true) + @PathVariable("id") Long id, + @Parameter(description = "Category request object", required = true) + @Valid @RequestBody DocumentCategoryRequest categoryRequest); +} diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CompanyDocumentApiControlller.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CompanyDocumentApiControlller.java new file mode 100644 index 00000000..8fd555c2 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CompanyDocumentApiControlller.java @@ -0,0 +1,118 @@ +package net.gepafin.tendermanagement.web.rest.api.impl; + +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.dao.CompanyDocumentDao; +import net.gepafin.tendermanagement.enums.*; +import net.gepafin.tendermanagement.model.request.CompanyDocumentRequest; +import net.gepafin.tendermanagement.model.request.UserActionRequest; +import net.gepafin.tendermanagement.model.response.CompanyDocumentResponseBean; +import net.gepafin.tendermanagement.model.response.DocumentResponseBean; +import net.gepafin.tendermanagement.model.util.Response; +import net.gepafin.tendermanagement.service.CompanyDocumentService; +import net.gepafin.tendermanagement.util.LoggingUtil; +import net.gepafin.tendermanagement.web.rest.api.CompanyDocumentApi; +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.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.time.LocalDateTime; +import java.util.List; + +@RestController +@RequestMapping("${openapi.gepafin.base-path:/v1/companyDocument}") +@Slf4j +public class CompanyDocumentApiControlller implements CompanyDocumentApi { + + @Autowired + private CompanyDocumentService companyDocumentService; + + @Autowired + private LoggingUtil loggingUtil; + + @Autowired + private CompanyDocumentDao companyDocumentDao; + + @Override + public ResponseEntity>> uploadFileForCompany(HttpServletRequest request, Long companyId, Long documentCategoryId, CompanyDocumentTypeEnum companyDocumentSourceTypeEnum, LocalDateTime expirationDate, + List files) { + try { + UserActionContextEnum userActionContext = companyDocumentDao.getUserActionContextEnum(companyDocumentSourceTypeEnum); + + /** This code is responsible for creating user action logs for the "upload document for company" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.UPLOAD).actionContext(userActionContext).build()); + + List responseBeans = companyDocumentService.uploadFileForCompany(request,files, companyId, documentCategoryId ,companyDocumentSourceTypeEnum,expirationDate); + return ResponseEntity.status(HttpStatus.CREATED) + .body(new Response>(responseBeans, Status.SUCCESS, Translator.toLocale(GepafinConstant.FILES_UPLOADED_MSG))); + } catch (CustomValidationException ex) { + throw ex; + } + } + + + @Override + public ResponseEntity> updateCompanyDocument(HttpServletRequest httpServletRequest, Long companyDocumentId, CompanyDocumentRequest companyDocumentRequest) { + + /** This code is responsible for creating user action logs for the "update company document" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(httpServletRequest).actionType(UserActionLogsEnum.UPDATE).actionContext(UserActionContextEnum.UPDATE_COMPANY_DOCUMENT).build()); + + CompanyDocumentResponseBean responseBeans = companyDocumentService.updateCompanyDocument(httpServletRequest, companyDocumentId, companyDocumentRequest); + return ResponseEntity.status(HttpStatus.CREATED) + .body(new Response(responseBeans, Status.SUCCESS, Translator.toLocale(GepafinConstant.COMPANY_DOCUMENT_UPDATED_SUCCESSFULLY))); + } + + @Override + public ResponseEntity> getCompanyDocumentById(HttpServletRequest request, Long id) { + /** This code is responsible for creating user action logs for the "Get Company Document" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW).actionContext(UserActionContextEnum.GET_COMPANY_DOCUMENT).build()); + + CompanyDocumentResponseBean companyDocumentResponseBean = companyDocumentService.getCompanyDocument(request, id); + return ResponseEntity.status(HttpStatus.CREATED) + .body(new Response(companyDocumentResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.COMPANY_DOCUMENT_FETCHED_SUCCESSFULLY))); + } + + @Override + public ResponseEntity> deleteCompanyFile(HttpServletRequest request, Long companyDocumentId) { + + /** This code is responsible for creating user action logs for the "delete company document" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.DELETE).actionContext(UserActionContextEnum.DELETE_COMPANY_DOCUMENT).build()); + + companyDocumentService.deleteCompanyFile(request,companyDocumentId); + return ResponseEntity.status(HttpStatus.CREATED) + .body(new Response(null, Status.SUCCESS, Translator.toLocale(GepafinConstant.FILE_DELETED_SUCCESSFULLY_MSG))); + } + + @Override + public ResponseEntity> validateAndDuplicateCompanyDocument(HttpServletRequest httpServletRequest, Long companyDocumentId , Long applicationId,DocumentTypeEnum typeEnum) { + + /** This code is responsible for creating user action logs for the "duplicate company document" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(httpServletRequest).actionType(UserActionLogsEnum.UPDATE).actionContext(UserActionContextEnum.DUPLICATE_COMPANY_DOCUMENT).build()); + + DocumentResponseBean responseBeans = companyDocumentService.validateAndDuplicateCompanyDocument(httpServletRequest, companyDocumentId,applicationId,typeEnum); + return ResponseEntity.status(HttpStatus.CREATED) + .body(new Response(responseBeans, Status.SUCCESS, Translator.toLocale(GepafinConstant.COMPANY_DOCUMENT_COPIED_SUCCESSFULLY))); + } + + @Override + public ResponseEntity>> getAllCompanyDocuments(HttpServletRequest request, Long companyId, CompanyDocumentTypeEnum typeEnum) { + log.info("Get All Company Document"); + + /** This code is responsible for creating user action logs for the "get all Company Document" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW) + .actionContext(UserActionContextEnum.GET_ALL_COMPANY_DOCUMENT).build()); + + List companyDocumentResponseBeans = companyDocumentService.getAllCompanyDocument(request,companyId,typeEnum); + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(companyDocumentResponseBeans, Status.SUCCESS, Translator.toLocale(GepafinConstant.COMPANY_DOCUMENT_FETCHED_SUCCESSFULLY))); + } + + +} diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/DocumentCategoryApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/DocumentCategoryApiController.java new file mode 100644 index 00000000..f1e99706 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/DocumentCategoryApiController.java @@ -0,0 +1,82 @@ +package net.gepafin.tendermanagement.web.rest.api.impl; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +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.DocumentCategoryRequest; +import net.gepafin.tendermanagement.model.request.UserActionRequest; +import net.gepafin.tendermanagement.model.response.DocumentCategoryResponse; +import net.gepafin.tendermanagement.model.util.Response; +import net.gepafin.tendermanagement.service.DocumentCategoryService; +import net.gepafin.tendermanagement.util.LoggingUtil; +import net.gepafin.tendermanagement.web.rest.api.DocumentCategoryApi; +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; + +@RestController +@RequestMapping("${openapi.gepafin.base-path:/v1/documentCategory}") +public class DocumentCategoryApiController implements DocumentCategoryApi { + + @Autowired + LoggingUtil loggingUtil; + + @Autowired + DocumentCategoryService categoryService; + + public ResponseEntity> createDocumentCategory(HttpServletRequest request, @Valid DocumentCategoryRequest categoryRequest){ + + /** This code is responsible for creating user action logs for the "Create Document category" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.INSERT) + .actionContext(UserActionContextEnum.CREATE_DOCUMENT_CATEGORY).build()); + + DocumentCategoryResponse categoryResponse = categoryService.createDocumentCategory(request,categoryRequest); + + return ResponseEntity.status(HttpStatus.CREATED) + .body(new Response<>(categoryResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.DOCUMENT_CATEGORY_CREATE_SUCCESS))); + + } + + @Override + public ResponseEntity> getDocumentCategoryById(HttpServletRequest request, Long id) { + + /** This code is responsible for creating user action logs for the "get document category by id" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW) + .actionContext(UserActionContextEnum.GET_DOCUMENT_CATEGORY).build()); + + DocumentCategoryResponse categoryResponse = categoryService.getDocumentCategoryById(request,id); + + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(categoryResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.DOCUMENT_CATEGORY_GET_SUCCESS))); + } + + @Override + public ResponseEntity> deleteDocumentCategory(HttpServletRequest request, Long id) { + + /** This code is responsible for creating user action logs for the "Delete category" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.DELETE).actionContext(UserActionContextEnum.DELETE_DOCUMENT_CATEGORY).build()); + + categoryService.deleteDocumentCategory(request,id); + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(null, Status.SUCCESS, Translator.toLocale(GepafinConstant.DOCUMENT_CATEGORY_DELETE_SUCCESS))); + } + + @Override + public ResponseEntity> updateDocumentCategory(HttpServletRequest request, Long id, DocumentCategoryRequest categoryRequest) { + + /** This code is responsible for "Updating Category details" operation. **/ + loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.UPDATE) + .actionContext(UserActionContextEnum.UPDATE_DOCUMENT_CATEGORY).build()); + + DocumentCategoryResponse categoryResponse = categoryService.updateDocumentCategory(request,id, categoryRequest); + + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(categoryResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.DOCUMENT_CATEGORY_UPDATE_SUCCESS))); + } +} diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index aacc398a..e4232f22 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2429,6 +2429,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +