package com.goi.erp.controller; import com.goi.erp.common.permission.PermissionSet; import com.goi.erp.dto.VehicleDispatchRequestDto; import com.goi.erp.entity.VehicleDispatch; import com.goi.erp.repository.VehicleDispatchRepository; import com.goi.erp.common.permission.PermissionChecker; import com.goi.erp.token.PermissionAuthenticationToken; import com.goi.erp.service.VehicleDispatchService; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import java.math.BigDecimal; import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import java.util.UUID; @RestController @RequestMapping("/api/vehicle-dispatch") @RequiredArgsConstructor public class VehicleDispatchController { private final VehicleDispatchService dispatchService; private final VehicleDispatchRepository dispatchRepository; // 기본값 private final int defaultPage = 0; private final int defaultSize = 50; private final int maxSize = 500; /* ============================================================ CREATE (MANUAL) ============================================================ */ @PostMapping("/manual") public ResponseEntity createManualDispatch( @RequestBody VehicleDispatchRequestDto requestDto ) { PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); if (auth == null || auth.getPermissionSet() == null) { throw new AccessDeniedException("Permission information is missing"); } PermissionSet permissionSet = auth.getPermissionSet(); if (!PermissionChecker.canCreateOPR(permissionSet)) { throw new AccessDeniedException("You do not have permission to create dispatch"); } VehicleDispatch created = dispatchService.createManualDispatch(requestDto, auth.getName()); return new ResponseEntity<>(created, HttpStatus.CREATED); } /* ============================================================ PATCH (MANUAL) ============================================================ */ @PatchMapping("/manual/{uuid}") public ResponseEntity patchManualDispatch( @PathVariable UUID uuid, @RequestBody VehicleDispatchRequestDto requestDto ) { PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); if (auth == null || auth.getPermissionSet() == null) { throw new AccessDeniedException("Permission information is missing"); } PermissionSet permissionSet = auth.getPermissionSet(); if (!PermissionChecker.canUpdateOPR(permissionSet)) { throw new AccessDeniedException("You do not have permission to update dispatch"); } VehicleDispatch updated = dispatchService.patchManualDispatch(uuid, requestDto, auth.getName()); return ResponseEntity.ok(updated); } /* ============================================================ STATE CHANGE (MANUAL) ============================================================ */ @PostMapping("/{uuid}/pause") public ResponseEntity pauseDispatch( @PathVariable UUID uuid, @RequestParam(required = false) LocalDateTime pausedAt ) { PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); if (auth == null || auth.getPermissionSet() == null) { throw new AccessDeniedException("Permission information is missing"); } PermissionSet permissionSet = auth.getPermissionSet(); if (!PermissionChecker.canUpdateOPR(permissionSet)) { throw new AccessDeniedException("You do not have permission to update dispatch"); } dispatchService.pauseDispatch(uuid, pausedAt); return ResponseEntity.ok().build(); } @PostMapping("/{uuid}/close") public ResponseEntity closeDispatch( @PathVariable UUID uuid, @RequestParam(required = false) LocalDateTime endAt, @RequestParam(required = false) BigDecimal endOdometerEnd, // DB: ved_odometer_end 로 저장 @RequestParam(required = false) String reason ) { PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); if (auth == null || auth.getPermissionSet() == null) { throw new AccessDeniedException("Permission information is missing"); } PermissionSet permissionSet = auth.getPermissionSet(); if (!PermissionChecker.canUpdateOPR(permissionSet)) { throw new AccessDeniedException("You do not have permission to update dispatch"); } dispatchService.closeDispatch( uuid, endAt, endOdometerEnd, (reason == null || reason.isBlank()) ? "MANUAL_CLOSE" : reason ); return ResponseEntity.ok().build(); } /* ============================================================ READ ONE ============================================================ */ @GetMapping("/{uuid}") public ResponseEntity getOne( @PathVariable UUID uuid ) { PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); if (auth == null || auth.getPermissionSet() == null) { throw new AccessDeniedException("Permission information is missing"); } PermissionSet permissionSet = auth.getPermissionSet(); if (!PermissionChecker.canReadOPRAll(permissionSet)) { throw new AccessDeniedException("You do not have permission to read dispatch data"); } return dispatchRepository.findByVedUuid(uuid) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } /* ============================================================ READ ALL (Paged) ============================================================ */ @GetMapping public ResponseEntity> getAll( @RequestParam(required = false) Integer page, @RequestParam(required = false) Integer size ) { PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); if (auth == null || auth.getPermissionSet() == null) { throw new AccessDeniedException("Permission information is missing"); } PermissionSet permissionSet = auth.getPermissionSet(); if (!PermissionChecker.canReadOPRAll(permissionSet)) { throw new AccessDeniedException("You do not have permission to read dispatch data"); } int p = (page == null) ? defaultPage : page; int s = (size == null) ? defaultSize : size; if (s > maxSize) s = maxSize; Pageable pageable = PageRequest.of(p, s); return ResponseEntity.ok(dispatchRepository.findAll(pageable)); } /* ============================================================ READ BY DATE (가장 자주 쓰는 API) - date만: 그날 전체 - date + vehId: 그 차량의 그날 - date + driverId: 그 기사 그날 ============================================================ */ @GetMapping("/by-date") public ResponseEntity> getByDate( @RequestParam LocalDate date, @RequestParam(required = false) Long vehId, @RequestParam(required = false) Long driverId ) { PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); if (auth == null || auth.getPermissionSet() == null) { throw new AccessDeniedException("Permission information is missing"); } PermissionSet permissionSet = auth.getPermissionSet(); if (!PermissionChecker.canReadOPRAll(permissionSet)) { throw new AccessDeniedException("You do not have permission to read dispatch data"); } if (vehId != null && driverId != null) { // 둘 다 넣는 케이스가 있을까 throw new IllegalArgumentException("Use either vehId or driverId, not both"); } if (vehId != null) { return ResponseEntity.ok( dispatchRepository.findByVedVehIdAndVedDispatchDate(vehId, date) ); } if (driverId != null) { return ResponseEntity.ok( dispatchRepository.findByVedDriverIdAndVedDispatchDate(driverId, date) ); } return ResponseEntity.ok( dispatchRepository.findByVedDispatchDate(date) ); } /* ============================================================ JOB TRIGGER - paused to closed ============================================================ */ @PostMapping("/jobs/close-paused") public ResponseEntity closePaused( @RequestParam(defaultValue = "60") long minutes ) { PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); if (auth == null || auth.getPermissionSet() == null) { throw new AccessDeniedException("Permission information is missing"); } PermissionSet permissionSet = auth.getPermissionSet(); if (!PermissionChecker.canUpdateOPR(permissionSet)) { throw new AccessDeniedException("You do not have permission to update dispatch"); } dispatchService.closePausedDispatches(Duration.ofMinutes(minutes)); return ResponseEntity.ok().build(); } }