AssignmentServiceImpl.java
package com.nashtech.rookie.asset_management_0701.services.assignment;
import java.time.LocalDate;
import java.util.Map;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.nashtech.rookie.asset_management_0701.dtos.filters.AssignmentFilter;
import com.nashtech.rookie.asset_management_0701.dtos.requests.assignment.AssignmentCreateDto;
import com.nashtech.rookie.asset_management_0701.dtos.requests.assignment.AssignmentUpdateDto;
import com.nashtech.rookie.asset_management_0701.dtos.responses.PaginationResponse;
import com.nashtech.rookie.asset_management_0701.dtos.responses.assigment.AssignmentHistory;
import com.nashtech.rookie.asset_management_0701.dtos.responses.assigment.AssignmentResponse;
import com.nashtech.rookie.asset_management_0701.dtos.responses.assigment.AssignmentResponseDto;
import com.nashtech.rookie.asset_management_0701.entities.Asset;
import com.nashtech.rookie.asset_management_0701.entities.Assignment;
import com.nashtech.rookie.asset_management_0701.entities.Location;
import com.nashtech.rookie.asset_management_0701.entities.User;
import com.nashtech.rookie.asset_management_0701.enums.EAssetState;
import com.nashtech.rookie.asset_management_0701.enums.EAssignmentState;
import com.nashtech.rookie.asset_management_0701.enums.EUserStatus;
import com.nashtech.rookie.asset_management_0701.exceptions.AppException;
import com.nashtech.rookie.asset_management_0701.exceptions.ErrorCode;
import com.nashtech.rookie.asset_management_0701.mappers.AssignmentMapper;
import com.nashtech.rookie.asset_management_0701.repositories.AssetRepository;
import com.nashtech.rookie.asset_management_0701.repositories.AssignmentRepository;
import com.nashtech.rookie.asset_management_0701.repositories.UserRepository;
import com.nashtech.rookie.asset_management_0701.utils.PageSortUtil;
import com.nashtech.rookie.asset_management_0701.utils.auth_util.AuthUtil;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AssignmentServiceImpl implements AssignmentService {
private static final String ASSIGNED_DATE = "assignedDate";
private final AssetRepository assetRepository;
private final AssignmentRepository assignmentRepository;
private final AssignmentMapper assignmentMapper;
private final UserRepository userRepository;
private final AuthUtil authUtil;
private final Map<String, String> sortBy = Map.ofEntries(
Map.entry("assetName", "asset_name"),
Map.entry("assetCode", "asset_assetCode"),
Map.entry("assignedTo", "assignTo_username"),
Map.entry("assignedBy", "assignBy_username"),
Map.entry(ASSIGNED_DATE, ASSIGNED_DATE),
Map.entry("state", "state"),
Map.entry("id", "id"),
Map.entry("category", "asset_category_name")
);
@Override
public PaginationResponse<AssignmentHistory> getAssignmentHistory (Long assetId, Integer page, Integer size) {
Asset asset = assetRepository.findById(assetId)
.orElseThrow(() -> new AppException(ErrorCode.ASSET_NOT_FOUND));
Sort sort = Sort.by(Sort.Direction.DESC, ASSIGNED_DATE);
Pageable pageable = PageSortUtil.createPageRequest(page, size, sort);
Page<Assignment> assignments = assignmentRepository.findAllByAsset(asset, pageable);
return PaginationResponse.<AssignmentHistory>builder()
.page(pageable.getPageNumber() + 1)
.total(assignments.getTotalElements())
.itemsPerPage(pageable.getPageSize())
.data(assignments.map(assignmentMapper::toAssignmentHistory).toList())
.build();
}
@Override
@Transactional
public void deleteAssignment (Long id) {
Assignment assignment = assignmentRepository.findById(id)
.orElseThrow(() -> new AppException(ErrorCode.ASSIGNMENT_NOT_FOUND));
if (assignment.getState() == EAssignmentState.ACCEPTED) {
throw new AppException(ErrorCode.ASSIGNMENT_CANNOT_DELETE);
}
Asset asset = assignment.getAsset();
asset.setState(EAssetState.AVAILABLE);
assetRepository.save(asset);
assignmentRepository.delete(assignment);
}
@Override
@Transactional
public AssignmentResponseDto changeState (Long assignmentId, EAssignmentState state) {
Assignment assignment = assignmentRepository.findByIdAndAssignToUsername(
assignmentId, authUtil.getCurrentUserName())
.orElseThrow(() -> new AppException(ErrorCode.ASSIGNMENT_NOT_FOUND));
switch (state) {
case EAssignmentState.ACCEPTED -> assignment.setState(EAssignmentState.ACCEPTED);
case EAssignmentState.DECLINED -> {
assignment.setState(EAssignmentState.DECLINED);
assignment.getAsset().setState(EAssetState.AVAILABLE);
}
default -> assignment.setState(EAssignmentState.WAITING);
}
return assignmentMapper.toAssignmentResponseDto(assignment);
}
@Override
public AssignmentResponse getAssignment (Long id) {
return assignmentRepository.findById(id)
.map(assignmentMapper::toAssignmentResponse)
.orElseThrow(() -> new AppException(ErrorCode.ASSIGNMENT_NOT_FOUND));
}
@Override
@Transactional
public AssignmentResponseDto createAssignment (AssignmentCreateDto assignmentCreateDto) {
User currentUser = authUtil.getCurrentUser();
User user = getUserById(assignmentCreateDto.getUserId());
Asset asset = getAssetById(assignmentCreateDto.getAssetId());
validateAssetState(asset);
validateLocationAsset(asset, currentUser);
validateLocationUser(user, currentUser);
Assignment assignment = assignmentMapper.toAssignment(assignmentCreateDto);
assignment.setState(EAssignmentState.WAITING);
assignment.setAssignBy(currentUser);
assignment.setAssignTo(user);
asset.setState(EAssetState.ASSIGNED);
assignment.setAsset(asset);
Assignment savedAssignment = assignmentRepository.save(assignment);
assetRepository.save(asset);
return assignmentMapper.toAssignmentResponseDto(savedAssignment);
}
@Override
@Transactional
public AssignmentResponseDto updateAssignment (Long id, AssignmentUpdateDto assignmentUpdateDto) {
Assignment updateAssignment = assignmentRepository.findById(id)
.orElseThrow(() -> new AppException(ErrorCode.ASSIGNMENT_NOT_FOUND));
User currentUser = authUtil.getCurrentUser();
if (!updateAssignment.getAssignBy().equals(currentUser)) {
throw new AppException(ErrorCode.ASSIGMENT_NOT_BELONG_TO_YOU);
}
if (updateAssignment.getState() != EAssignmentState.WAITING) {
throw new AppException(ErrorCode.ASSIGMENT_CANNOT_UPDATE);
}
Asset oldAsset = updateAssignment.getAsset();
oldAsset.setState(EAssetState.AVAILABLE);
assetRepository.save(oldAsset);
User user = getUserById(assignmentUpdateDto.getUserId());
Asset asset = getAssetById(assignmentUpdateDto.getAssetId());
validateAssetState(asset);
validateLocationAsset(asset, currentUser);
validateLocationUser(user, currentUser);
updateAssignment = assignmentMapper.updateEntity(updateAssignment, assignmentUpdateDto);
asset.setState(EAssetState.ASSIGNED);
updateAssignment.setAssignTo(user);
updateAssignment.setAsset(asset);
assetRepository.save(asset);
assignmentRepository.save(updateAssignment);
return assignmentMapper.toAssignmentResponseDto(updateAssignment);
}
private User getUserById (Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new AppException(ErrorCode.USER_NOT_FOUND));
if (user.getStatus().equals(EUserStatus.DISABLED)){
throw new AppException(ErrorCode.USER_NOT_FOUND);
}
return user;
}
private Asset getAssetById (Long assetId) {
return assetRepository.findById(assetId)
.orElseThrow(() -> new AppException(ErrorCode.ASSET_NOT_FOUND));
}
private void validateAssetState (Asset asset) {
if (!EAssetState.AVAILABLE.equals(asset.getState())) {
throw new AppException(ErrorCode.ASSET_STATE_NOT_AVAILABLE);
}
}
private void validateLocationUser (User entity, User currentUser) {
if (!entity.getLocation().equals(currentUser.getLocation())) {
throw new AppException(ErrorCode.USER_LOCATION_INVALID_WITH_ADMIN);
}
}
private void validateLocationAsset (Asset entity, User currentUser) {
if (!entity.getLocation().equals(currentUser.getLocation())) {
throw new AppException(ErrorCode.ASSET_LOCATION_INVALID_WITH_ADMIN);
}
}
public PaginationResponse<AssignmentResponseDto> getMyAssignments (AssignmentFilter assignmentFilter) {
Sort sort = Sort.by(PageSortUtil.parseSortDirection(assignmentFilter.getSortDir()),
sortBy.get(assignmentFilter.getOrderBy()));
Pageable pageable = PageSortUtil.createPageRequest(assignmentFilter.getPageNumber(),
assignmentFilter.getPageSize(), sort);
LocalDate currentDate = LocalDate.now();
Page<Assignment> assignments = assignmentRepository.findAll(
Specification.where(AssignmentSpecification.assignToIdEquals(authUtil.getCurrentUser().getId())
.and(AssignmentSpecification.assignedDateLessThanEqual(currentDate)))
.and(AssignmentSpecification.notStateReturned())
.and(AssignmentSpecification.notStateDeclined())
, pageable);
return PaginationResponse.<AssignmentResponseDto>builder()
.page(pageable.getPageNumber() + 1)
.total(assignments.getTotalElements())
.itemsPerPage(pageable.getPageSize())
.data(assignments.map(assignmentMapper::toAssignmentResponseDto).toList())
.build();
}
public PaginationResponse<AssignmentResponseDto> getAllAssignments (AssignmentFilter filter) {
Sort sort = Sort.by(PageSortUtil.parseSortDirection(filter.getSortDir()), sortBy.get(filter.getOrderBy()));
Pageable pageable = PageSortUtil.createPageRequest(filter.getPageNumber()
, filter.getPageSize(), sort);
Location currentLocation = authUtil.getCurrentUser().getLocation();
Page<Assignment> assignments = assignmentRepository.findAll(
Specification.where(AssignmentSpecification.hasAssetName(filter.getSearchString())
.or(AssignmentSpecification.hasAssetCode(filter.getSearchString()))
.or(AssignmentSpecification.hasAssigneeUsername(filter.getSearchString()))
.and(AssignmentSpecification.hasStates(filter.getStates()))
.and(AssignmentSpecification.assignOnDate(filter.getAssignDate()))
.and(AssignmentSpecification.hasLocation(currentLocation))
.and(AssignmentSpecification.notStateReturned()))
.and(AssignmentSpecification.joinFetch("returningRequest"))
.and(AssignmentSpecification.joinFetch("asset"))
.and(AssignmentSpecification.joinFetch("assignBy"))
.and(AssignmentSpecification.joinFetch("assignTo"))
, pageable);
return PaginationResponse.<AssignmentResponseDto>builder()
.page(pageable.getPageNumber() + 1)
.total(assignments.getTotalElements())
.itemsPerPage(pageable.getPageSize())
.data(assignments.map(assignmentMapper::toAssignmentResponseDto).toList())
.build();
}
}