отображение забронированных слотов и тестовые НУ
This commit is contained in:
+15
@@ -1,6 +1,7 @@
|
||||
package space.nstart.pcp.slots_service.controller
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.format.annotation.DateTimeFormat
|
||||
import org.springframework.web.bind.annotation.DeleteMapping
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
@@ -28,6 +29,20 @@ class BookingController {
|
||||
|
||||
@GetMapping
|
||||
fun all() = slotService.allBooked()
|
||||
|
||||
@GetMapping("/search")
|
||||
fun search(
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) timeStart: LocalDateTime?,
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) timeStop: LocalDateTime?,
|
||||
@RequestParam(required = false) requestId: String?,
|
||||
@RequestParam(required = false) satelliteIds: List<Long>?
|
||||
) = slotService.searchBookedSlots(
|
||||
timeStart = timeStart,
|
||||
timeStop = timeStop,
|
||||
requestId = requestId,
|
||||
satelliteIds = satelliteIds
|
||||
)
|
||||
|
||||
@GetMapping("/{booked_slot_id}")
|
||||
fun byId(@PathVariable("booked_slot_id") id : Long) = slotService.bookedById(id)
|
||||
@GetMapping("/by-request/{request_id}")
|
||||
|
||||
+23
@@ -29,6 +29,29 @@ interface BookedSlotsRepository : JpaRepository<BookedSlotEntity, Long>{
|
||||
@EntityGraph(attributePaths = ["slot"])
|
||||
fun findAllByStatus(status: String): List<BookedSlotEntity>
|
||||
|
||||
@EntityGraph(attributePaths = ["slot", "requests"])
|
||||
@Query("""
|
||||
select distinct bookedSlot
|
||||
from BookedSlotEntity bookedSlot
|
||||
where bookedSlot.slot.satelliteId in :satelliteIds
|
||||
and bookedSlot.cycle between :cycleBegin and :cycleEnd
|
||||
""")
|
||||
fun findBookingDetailsBySatelliteIdsAndCycleBetween(
|
||||
@Param("satelliteIds") satelliteIds: Collection<Long>,
|
||||
@Param("cycleBegin") cycleBegin: Long,
|
||||
@Param("cycleEnd") cycleEnd: Long
|
||||
): List<BookedSlotEntity>
|
||||
|
||||
@EntityGraph(attributePaths = ["slot", "requests"])
|
||||
@Query("""
|
||||
select distinct bookedSlot
|
||||
from BookedSlotEntity bookedSlot
|
||||
where bookedSlot.slot.satelliteId in :satelliteIds
|
||||
""")
|
||||
fun findBookingDetailsBySatelliteIds(
|
||||
@Param("satelliteIds") satelliteIds: Collection<Long>
|
||||
): List<BookedSlotEntity>
|
||||
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("DELETE FROM booked_slot WHERE booked_slot_id =:id", nativeQuery = true)
|
||||
|
||||
+101
-8
@@ -47,6 +47,7 @@ import space.nstart.pcp.pcp_types_lib.dto.ballistics.RevolutionSign
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteICDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.StationDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TargetPositionDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.BookedSlotDetailsDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.requests.slots.*
|
||||
import space.nstart.pcp.pcp_types_lib.dto.satellite.SatelliteSlotAngleDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.satellite.SatelliteSlotProfileDTO
|
||||
@@ -1451,8 +1452,8 @@ class SlotService {
|
||||
val cycleWindows = selectedSatellites.associate { satellite ->
|
||||
satellite.id to SatelliteCycleWindow(
|
||||
satellite = satellite,
|
||||
cycleBegin = Duration.between(satellite.tnCalc, timeStart).toDays() / satellite.durationCalc,
|
||||
cycleEnd = Duration.between(satellite.tnCalc, timeStop).toDays() / satellite.durationCalc
|
||||
cycleBegin = Duration.between(satellite.tnCalc, timeStart!!).toDays() / satellite.durationCalc,
|
||||
cycleEnd = Duration.between(satellite.tnCalc, timeStop!!).toDays() / satellite.durationCalc
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1883,6 +1884,98 @@ class SlotService {
|
||||
@Transactional(readOnly = true)
|
||||
fun allBooked() = bookedSlotsRepository.findAll().map { it.toDTO() }
|
||||
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun searchBookedSlots(
|
||||
timeStart: LocalDateTime?,
|
||||
timeStop: LocalDateTime?,
|
||||
requestId: String?,
|
||||
satelliteIds: List<Long>?
|
||||
): List<BookedSlotDetailsDTO> {
|
||||
if ((timeStart == null) != (timeStop == null)) {
|
||||
throw CustomValidationException("Для фильтра по времени должны быть заданы timeStart и timeStop")
|
||||
}
|
||||
if (timeStart != null && timeStop != null && timeStop < timeStart) {
|
||||
throw CustomValidationException("Параметр timeStop должен быть больше или равен timeStart")
|
||||
}
|
||||
|
||||
val requestedSatelliteIds = satelliteIds.orEmpty().filter { it > 0 }.distinct()
|
||||
val satellites = if (requestedSatelliteIds.isEmpty()) {
|
||||
satelliteCatalogClient.allSatellites()
|
||||
} else {
|
||||
loadSatellites(requestedSatelliteIds)
|
||||
}
|
||||
if (satellites.isEmpty()) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val satellitesById = satellites.associateBy { it.id }
|
||||
val selectedSatelliteIds = satellites.map { it.id }
|
||||
val normalizedRequestId = requestId?.trim()?.takeIf { it.isNotEmpty() }
|
||||
val hasInterval = timeStart != null && timeStop != null
|
||||
|
||||
val bookedSlots = if (hasInterval) {
|
||||
val cycleWindows = satellites.associate { satellite ->
|
||||
val cycleBegin = Duration.between(satellite.tnCalc, timeStart!!).toDays() / satellite.durationCalc
|
||||
val cycleEnd = Duration.between(satellite.tnCalc, timeStop!!).toDays() / satellite.durationCalc
|
||||
satellite.id to (cycleBegin - 1 to cycleEnd + 1)
|
||||
}
|
||||
val minCycle = cycleWindows.values.minOf { it.first }
|
||||
val maxCycle = cycleWindows.values.maxOf { it.second }
|
||||
bookedSlotsRepository.findBookingDetailsBySatelliteIdsAndCycleBetween(
|
||||
satelliteIds = selectedSatelliteIds,
|
||||
cycleBegin = minCycle,
|
||||
cycleEnd = maxCycle
|
||||
)
|
||||
} else {
|
||||
bookedSlotsRepository.findBookingDetailsBySatelliteIds(selectedSatelliteIds)
|
||||
}
|
||||
|
||||
return bookedSlots
|
||||
.asSequence()
|
||||
.filter { booked -> normalizedRequestId == null || booked.requests.orEmpty().any { it.requestId == normalizedRequestId } }
|
||||
.mapNotNull { booked ->
|
||||
val satellite = satellitesById[booked.slot.satelliteId] ?: return@mapNotNull null
|
||||
booked.toDetails(satellite)
|
||||
}
|
||||
.filter { details ->
|
||||
if (!hasInterval) {
|
||||
true
|
||||
} else {
|
||||
val start = details.timeStart
|
||||
val stop = details.timeStop
|
||||
start != null && stop != null && stop > timeStart!! && start < timeStop!!
|
||||
}
|
||||
}
|
||||
.sortedWith(
|
||||
compareBy<BookedSlotDetailsDTO> { it.timeStart ?: LocalDateTime.MAX }
|
||||
.thenBy { it.satelliteId }
|
||||
.thenBy { it.slotNum }
|
||||
.thenBy { it.cycle }
|
||||
.thenBy { it.bookedSlotId }
|
||||
)
|
||||
.toList()
|
||||
}
|
||||
|
||||
private fun BookedSlotEntity.toDetails(satellite: AbstractSatellite): BookedSlotDetailsDTO {
|
||||
val timeStart = slot.tn.plusDays(cycle * satellite.durationCalc)
|
||||
val timeStop = slot.tk.plusDays(cycle * satellite.durationCalc)
|
||||
return BookedSlotDetailsDTO(
|
||||
bookedSlotId = bookedSlotId ?: 0,
|
||||
satelliteId = slot.satelliteId,
|
||||
slotNum = slot.slotNum,
|
||||
cycle = cycle,
|
||||
timeStart = timeStart,
|
||||
timeStop = timeStop,
|
||||
durationSeconds = Duration.between(timeStart, timeStop).seconds,
|
||||
roll = slot.roll,
|
||||
revolution = slot.revolution + cycle * satellite.cycleRevs,
|
||||
revolutionSign = slot.revolutionSign,
|
||||
status = status,
|
||||
requestIds = requests.orEmpty().map { it.requestId }.distinct().sorted()
|
||||
)
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun allByInterval(
|
||||
satelliteId: Long,
|
||||
@@ -1894,8 +1987,8 @@ class SlotService {
|
||||
}
|
||||
|
||||
val satellite = satelliteById(satelliteId)
|
||||
val startCycle = Duration.between(satellite.tnCalc, timeStart).toDays() / satellite.durationCalc
|
||||
val stopCycle = Duration.between(satellite.tnCalc, timeStop).toDays() / satellite.durationCalc
|
||||
val startCycle = Duration.between(satellite.tnCalc, timeStart!!).toDays() / satellite.durationCalc
|
||||
val stopCycle = Duration.between(satellite.tnCalc, timeStop!!).toDays() / satellite.durationCalc
|
||||
val cycleBegin = startCycle - 1
|
||||
val cycleEnd = stopCycle + 1
|
||||
|
||||
@@ -1957,8 +2050,8 @@ class SlotService {
|
||||
|
||||
val satellite = satelliteById(satelliteId)
|
||||
|
||||
val startCycle = Duration.between(satellite.tnCalc, timeStart).toDays() / satellite.durationCalc
|
||||
val stopCycle = Duration.between(satellite.tnCalc, timeStop).toDays() / satellite.durationCalc
|
||||
val startCycle = Duration.between(satellite.tnCalc, timeStart!!).toDays() / satellite.durationCalc
|
||||
val stopCycle = Duration.between(satellite.tnCalc, timeStop!!).toDays() / satellite.durationCalc
|
||||
val cycleBegin = startCycle - 1
|
||||
val cycleEnd = stopCycle + 1
|
||||
|
||||
@@ -1982,8 +2075,8 @@ class SlotService {
|
||||
val selectedSatellites = loadSatellites(satelliteIds)
|
||||
|
||||
val cycleWindows = selectedSatellites.associate { satellite ->
|
||||
val startCycle = Duration.between(satellite.tnCalc, timeStart).toDays() / satellite.durationCalc
|
||||
val stopCycle = Duration.between(satellite.tnCalc, timeStop).toDays() / satellite.durationCalc
|
||||
val startCycle = Duration.between(satellite.tnCalc, timeStart!!).toDays() / satellite.durationCalc
|
||||
val stopCycle = Duration.between(satellite.tnCalc, timeStop!!).toDays() / satellite.durationCalc
|
||||
satellite.id to (startCycle - 1 to stopCycle + 1)
|
||||
}
|
||||
val minCycle = cycleWindows.values.minOf { it.first }
|
||||
|
||||
Reference in New Issue
Block a user