[Schedule]
- Created schedule worker. (schedules are only in sys-rest-api) [HcmClient] - Added get system token to call hcm-rest-api
This commit is contained in:
parent
923b6d5aca
commit
6a7882a028
|
|
@ -14,6 +14,7 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.goi.erp.token.PermissionAuthenticationToken;
|
||||
import com.goi.erp.token.SystemTokenProvider;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
|
@ -24,53 +25,40 @@ import java.util.UUID;
|
|||
public class HcmEmployeeClient {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
private final SystemTokenProvider systemTokenProvider;
|
||||
|
||||
@Value("${hcm.api.base-url}")
|
||||
private String hcmBaseUrl;
|
||||
|
||||
public Long getEmpIdFromExternalId(String externalSource, String externalId) {
|
||||
|
||||
String url = hcmBaseUrl + "/employee/external" + "?solutionType=" + externalSource + "&externalId=" + externalId;
|
||||
String url = hcmBaseUrl + "/employee/external"
|
||||
+ "?solutionType=" + externalSource
|
||||
+ "&externalId=" + externalId;
|
||||
|
||||
try {
|
||||
// set token in header
|
||||
String jwt = getCurrentJwt();
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set("Authorization", "Bearer " + jwt);
|
||||
HttpEntity<Void> entity = new HttpEntity<>(headers);
|
||||
|
||||
// GET
|
||||
HttpEntity<Void> entity = new HttpEntity<>(systemHeaders());
|
||||
|
||||
ResponseEntity<Map<String, Object>> response =
|
||||
restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.GET,
|
||||
entity,
|
||||
new ParameterizedTypeReference<Map<String, Object>>() {}
|
||||
new ParameterizedTypeReference<>() {}
|
||||
);
|
||||
|
||||
Map<String, Object> body = response.getBody();
|
||||
//System.out.println("RESPONSE ➜ " + body);
|
||||
|
||||
if (body != null && body.get("eexEmpId") != null) {
|
||||
|
||||
Object raw = body.get("eexEmpId");
|
||||
|
||||
if (raw instanceof Number) {
|
||||
return ((Number) raw).longValue(); // 🔥 모든 숫자를 Long 변환
|
||||
}
|
||||
|
||||
// 예상 밖 타입일 경우
|
||||
Map<String, Object> body = response.getBody();
|
||||
if (body != null && body.get("eexEmpId") instanceof Number n) {
|
||||
return n.longValue();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error(
|
||||
"[EXTERNAL][GET] externalId lookup error: {}",
|
||||
e.getMessage()
|
||||
);
|
||||
log.error("[HCM][GET] externalId lookup error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Long getEmpIdFromUuid(UUID uuid) {
|
||||
|
||||
|
|
@ -124,6 +112,12 @@ public class HcmEmployeeClient {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private HttpHeaders systemHeaders() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setBearerAuth(systemTokenProvider.getToken());
|
||||
return headers;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ public class SecurityConfig {
|
|||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
|
||||
.requestMatchers("/ext/**").permitAll()
|
||||
.requestMatchers("/scheduler/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
) // 요청 권한 설정
|
||||
.addFilterBefore(new CorsFilter(corsConfigurationSource()), UsernamePasswordAuthenticationFilter.class) // JWT 필터 전에 CorsFilter 등록
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
package com.goi.erp.controller;
|
||||
|
||||
import com.goi.erp.service.ExtSamsaraInspectionProcessor;
|
||||
import com.goi.erp.service.VehicleDispatchAutoCloseService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/test")
|
||||
@RequiredArgsConstructor
|
||||
public class TestController {
|
||||
|
||||
private final ExtSamsaraInspectionProcessor processor;
|
||||
private final VehicleDispatchAutoCloseService autoCloseService;
|
||||
|
||||
@PostMapping("/process-samsara-inspection")
|
||||
public String process() {
|
||||
processor.processUnprocessed();
|
||||
return "OK";
|
||||
}
|
||||
|
||||
/**
|
||||
* 차량 배차 자동 종료 테스트 (오늘 날짜 기준)
|
||||
*/
|
||||
@PostMapping("/auto-close-dispatch")
|
||||
public String autoCloseDispatch() {
|
||||
|
||||
autoCloseService.processAutoClose(LocalDate.now());
|
||||
|
||||
return "AUTO CLOSE OK";
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@ import lombok.NoArgsConstructor;
|
|||
@Builder
|
||||
public class ExtIngestResult {
|
||||
private String source;
|
||||
private String recordType;
|
||||
private int received;
|
||||
private int inserted;
|
||||
private int updated;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import java.util.List;
|
|||
@Builder
|
||||
public class ExtSamsaraInspectionIngestCommand {
|
||||
private String source;
|
||||
private String recordType;
|
||||
private LocalDateTime fetchedAt;
|
||||
private List<ExtSamsaraInspectionRecordDto> records;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,9 +49,6 @@ public class ExtSamsaraRawInspection {
|
|||
@Column(name = "esri_source", nullable = false, length = 20)
|
||||
private String esriSource; // SAMSARA
|
||||
|
||||
@Column(name = "esri_record_type", nullable = false, length = 20)
|
||||
private String esriRecordType; // DVIR
|
||||
|
||||
@Column(name = "esri_external_id", nullable = false, length = 50)
|
||||
private String esriExternalId; // inspection id
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ public class ExtSamsaraInspectionIngestService {
|
|||
|
||||
return ExtIngestResult.builder()
|
||||
.source(command.getSource())
|
||||
.recordType(command.getRecordType())
|
||||
.received(command.getRecords().size())
|
||||
.inserted(inserted)
|
||||
.updated(updated)
|
||||
|
|
@ -90,7 +89,6 @@ public class ExtSamsaraInspectionIngestService {
|
|||
|
||||
ExtSamsaraRawInspection entity = ExtSamsaraRawInspection.builder()
|
||||
.esriSource(command.getSource())
|
||||
.esriRecordType(command.getRecordType())
|
||||
.esriExternalId(record.getExternalId())
|
||||
.esriVehicleExtId(record.getVehicleExternalId())
|
||||
.esriDriverExtId(record.getDriverExternalId())
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.goi.erp.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.goi.erp.dto.ProcessResultDto;
|
||||
import com.goi.erp.dto.VehicleInspectionDefectDto;
|
||||
import com.goi.erp.dto.VehicleInspectionDto;
|
||||
import com.goi.erp.entity.ExtSamsaraRawInspection;
|
||||
|
|
@ -11,6 +12,7 @@ import jakarta.transaction.Transactional;
|
|||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -25,43 +27,61 @@ public class ExtSamsaraInspectionProcessor {
|
|||
private final ExtSamsaraRawInspectionRepository rawRepo;
|
||||
private final VehicleInspectionService vehicleInspectionService;
|
||||
|
||||
@Transactional
|
||||
public void processUnprocessed() {
|
||||
public ProcessResultDto processUnprocessed() {
|
||||
|
||||
List<ExtSamsaraRawInspection> raws = rawRepo.findByEsriProcessedFalse();
|
||||
|
||||
if (raws.isEmpty()) {
|
||||
log.info("[DVIR_PROCESSOR] no unprocessed raw inspections");
|
||||
return;
|
||||
}
|
||||
// log 용
|
||||
int processed = 0;
|
||||
int failed = 0;
|
||||
|
||||
List<ExtSamsaraRawInspection> raws = rawRepo.findByEsriProcessedFalseAndEsriFetchedDate(LocalDate.now());
|
||||
|
||||
if (raws.isEmpty()) {
|
||||
log.info("[INSPECTION_PROCESSOR] no unprocessed raw inspections");
|
||||
return new ProcessResultDto(0, 0);
|
||||
}
|
||||
|
||||
for (ExtSamsaraRawInspection raw : raws) {
|
||||
try {
|
||||
processSingle(raw);
|
||||
processSingleTx(raw);
|
||||
processed++;
|
||||
} catch (Exception e) {
|
||||
failed++;
|
||||
log.error(
|
||||
"[DVIR_PROCESSOR] failed rawId={} externalId={} msg={}",
|
||||
raw.getEsriId(),
|
||||
raw.getEsriExternalId(),
|
||||
e.getMessage(),
|
||||
e
|
||||
);
|
||||
// markFailed(raw, e);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("[DVIR_PROCESSOR] done processed={} failed={}", processed, failed);
|
||||
log.info("[INSPECTION_PROCESSOR] done processed={} failed={}", processed, failed);
|
||||
return new ProcessResultDto(processed, failed);
|
||||
}
|
||||
|
||||
/**
|
||||
* raw 1건 단위 트랜잭션
|
||||
*/
|
||||
@Transactional
|
||||
protected void processSingleTx(ExtSamsaraRawInspection raw) {
|
||||
processSingle(raw);
|
||||
raw.setEsriProcessed(true);
|
||||
raw.setEsriProcessedAt(LocalDateTime.now());
|
||||
rawRepo.save(raw);
|
||||
}
|
||||
|
||||
// private void markFailed(ExtSamsaraRawInspection raw, Exception e) {
|
||||
// log.error(
|
||||
// "[INSPECTION_PROCESSOR] failed rawId={} externalId={} msg={}",
|
||||
// raw.getEsriId(),
|
||||
// raw.getEsriExternalId(),
|
||||
// e.getMessage(),
|
||||
// e
|
||||
// );
|
||||
//
|
||||
// raw.setEsriProcessError(e.getMessage());
|
||||
// raw.setEsriProcessFailedAt(LocalDateTime.now());
|
||||
// rawRepo.save(raw);
|
||||
// }
|
||||
|
||||
private void processSingle(ExtSamsaraRawInspection raw) {
|
||||
|
||||
JsonNode payload = raw.getEsriPayload();
|
||||
|
||||
// Inspection
|
||||
VehicleInspectionDto dto = new VehicleInspectionDto();
|
||||
dto.setSource("SAMSARA");
|
||||
dto.setSourceId(Long.valueOf(raw.getEsriExternalId()));
|
||||
|
|
@ -79,18 +99,11 @@ public class ExtSamsaraInspectionProcessor {
|
|||
dto.setEndAt(raw.getEsriEndTime());
|
||||
dto.setResult(payload.path("safetyStatus").asText(null));
|
||||
dto.setOdometer(payload.path("odometerMeters").asLong(0L));
|
||||
|
||||
log.info(
|
||||
"[DVIR] rawId={} odometerMeters node={} value={}",
|
||||
raw.getEsriExternalId(),
|
||||
payload.get("odometerMeters"),
|
||||
payload.path("odometerMeters").asLong(-1)
|
||||
);
|
||||
|
||||
// Defects
|
||||
// defects
|
||||
JsonNode defectsNode = payload.path("vehicleDefects");
|
||||
List<VehicleInspectionDefectDto> defectDtos = new ArrayList<>();
|
||||
|
||||
|
||||
if (defectsNode.isArray()) {
|
||||
for (JsonNode d : defectsNode) {
|
||||
VehicleInspectionDefectDto defectDto = new VehicleInspectionDefectDto();
|
||||
|
|
@ -98,33 +111,22 @@ public class ExtSamsaraInspectionProcessor {
|
|||
defectDto.setDefectType(d.path("defectType").asText(null));
|
||||
defectDto.setComment(d.path("comment").asText(null));
|
||||
defectDto.setIsResolved(d.path("isResolved").asBoolean(false));
|
||||
|
||||
JsonNode resolvedBy = d.path("resolvedBy");
|
||||
if (!resolvedBy.isMissingNode()) {
|
||||
defectDto.setResolvedByExternalId(resolvedBy.path("id").asText(null));
|
||||
}
|
||||
|
||||
defectDto.setResolvedAt(DateTimeUtil.parse(d.path("resolvedAtTime")));
|
||||
defectDto.setCreatedAt(DateTimeUtil.parse(d.path("createdAtTime")));
|
||||
defectDtos.add(defectDto);
|
||||
}
|
||||
}
|
||||
|
||||
dto.setDefects(defectDtos);
|
||||
dto.setHasDefect(!defectDtos.isEmpty());
|
||||
|
||||
log.info(
|
||||
"[DVIR DTO] sourceId={} result={} odometer={} hasDefect={} defects={}",
|
||||
dto.getSourceId(),
|
||||
dto.getResult(),
|
||||
dto.getOdometer(),
|
||||
dto.getHasDefect(),
|
||||
dto.getDefects() != null ? dto.getDefects().size() : null
|
||||
);
|
||||
|
||||
// inspection + defect 저장은 Service 에서
|
||||
vehicleInspectionService.saveInspection(dto);
|
||||
|
||||
// raw 처리 완료
|
||||
raw.setEsriProcessed(true);
|
||||
raw.setEsriProcessedAt(LocalDateTime.now());
|
||||
rawRepo.save(raw);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package com.goi.erp.service;
|
||||
|
||||
import com.goi.erp.client.SamsaraVehicleStatGpsClient;
|
||||
import com.goi.erp.client.SysConfigClient;
|
||||
import com.goi.erp.common.util.GeoUtil;
|
||||
import com.goi.erp.dto.ProcessResultDto;
|
||||
import com.goi.erp.dto.ScheduleWorkerRequestDto;
|
||||
import com.goi.erp.dto.VehicleStatGpsResponseDto;
|
||||
import com.goi.erp.entity.VehicleDispatch;
|
||||
import com.goi.erp.repository.VehicleDispatchRepository;
|
||||
|
|
@ -35,22 +36,38 @@ public class VehicleDispatchAutoCloseService {
|
|||
private final VehicleDispatchRepository vehicleDispatchRepository;
|
||||
private final VehicleExternalMapService vehicleExternalMapService;
|
||||
private final SamsaraVehicleStatGpsClient vehicleStatClient;
|
||||
private final SysConfigClient sysConfigClient;
|
||||
|
||||
@Transactional
|
||||
public void processAutoClose(LocalDate dispatchDate) {
|
||||
// config
|
||||
BigDecimal homeLat = sysConfigClient.getDecimal("SYS", "HOME_LATITUDE");
|
||||
BigDecimal homeLon = sysConfigClient.getDecimal("SYS", "HOME_LONGITUDE");
|
||||
Integer radiusMeters = sysConfigClient.getInt("OPR", "HOME_RADIUS_METERS");
|
||||
Integer pausedMinutes = sysConfigClient.getInt("OPR", "PAUSED_CLOSE_MINUTES");
|
||||
public ProcessResultDto processAutoClose(ScheduleWorkerRequestDto request) {
|
||||
|
||||
int processed = 0;
|
||||
int failed = 0;
|
||||
|
||||
// config
|
||||
Map<String, Map<String, String>> cfg = request.getConfig();
|
||||
|
||||
// 0. auto open check 먼저
|
||||
processAutoOpen(dispatchDate, homeLat, homeLon, radiusMeters);
|
||||
|
||||
// 1. 대상 vehicle_dispatch 조회 (C 제외)
|
||||
BigDecimal homeLat = new BigDecimal(cfg.get("SYS").get("HOME_LATITUDE"));
|
||||
BigDecimal homeLon = new BigDecimal(cfg.get("SYS").get("HOME_LONGITUDE"));
|
||||
Integer radiusMeters = Integer.valueOf(cfg.get("OPR").get("HOME_RADIUS_METERS"));
|
||||
Integer pausedCloseMinutes = Integer.valueOf(cfg.get("OPR").getOrDefault("PAUSED_CLOSE_MINUTES", "30"));
|
||||
|
||||
LocalDate dispatchDate = request.getFrom().toLocalDate();
|
||||
|
||||
// 0. auto open
|
||||
try {
|
||||
processAutoOpen(dispatchDate, homeLat, homeLon, radiusMeters);
|
||||
} catch (Exception e) {
|
||||
log.error("[AUTO-CLOSE] auto-open failed", e);
|
||||
failed++;
|
||||
}
|
||||
|
||||
// 1. 대상 조회
|
||||
List<VehicleDispatch> targets = vehicleDispatchRepository.findAllNotClosed(dispatchDate);
|
||||
if (targets.isEmpty()) return;
|
||||
|
||||
if (targets.isEmpty()) {
|
||||
log.info("[AUTO-CLOSE] no dispatch to process");
|
||||
return new ProcessResultDto(0, 0);
|
||||
}
|
||||
|
||||
// 2. external vehicleIds 수집
|
||||
List<Long> vehicleIds = targets.stream()
|
||||
|
|
@ -58,8 +75,10 @@ public class VehicleDispatchAutoCloseService {
|
|||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
if (vehicleIds.isEmpty()) return;
|
||||
|
||||
if (vehicleIds.isEmpty()) {
|
||||
log.info("[AUTO-CLOSE] no vehicles to process");
|
||||
return new ProcessResultDto(0, 0);
|
||||
}
|
||||
|
||||
// 3. internal vehicleId -> samsara externalId 매핑 bulk 조회
|
||||
Map<Long, String> vehicleIdToExternalId = vehicleExternalMapService.findExternalIdsByVehicleIds("SAMSARA", vehicleIds);
|
||||
|
|
@ -68,11 +87,17 @@ public class VehicleDispatchAutoCloseService {
|
|||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
if (externalIds.isEmpty()) return;
|
||||
if (externalIds.isEmpty()) {
|
||||
log.info("[AUTO-CLOSE] no external vehicles to process");
|
||||
return new ProcessResultDto(0, 0);
|
||||
}
|
||||
|
||||
// 4. call
|
||||
List<VehicleStatGpsResponseDto> stats = vehicleStatClient.fetchVehicleStats(externalIds);
|
||||
if (stats.isEmpty()) return;
|
||||
if (stats.isEmpty()) {
|
||||
log.info("[AUTO-CLOSE] no stats to process");
|
||||
return new ProcessResultDto(0, 0);
|
||||
}
|
||||
|
||||
// 5. response
|
||||
Map<String, VehicleStatGpsResponseDto> statMap = stats.stream()
|
||||
|
|
@ -81,64 +106,117 @@ public class VehicleDispatchAutoCloseService {
|
|||
s -> s,
|
||||
(a, b) -> a
|
||||
));
|
||||
|
||||
// 6. dispatch별 처리
|
||||
|
||||
|
||||
for (VehicleDispatch dispatch : targets) {
|
||||
|
||||
Long internalVehicleId = dispatch.getVedVehId();
|
||||
if (internalVehicleId == null) continue;
|
||||
|
||||
String externalId = vehicleIdToExternalId.get(internalVehicleId);
|
||||
if (externalId == null) continue;
|
||||
|
||||
VehicleStatGpsResponseDto stat = statMap.get(externalId);
|
||||
if (stat == null) continue;
|
||||
|
||||
// 관측값 계산
|
||||
boolean engineOn = Boolean.TRUE.equals(stat.getVesEngineOn());
|
||||
|
||||
double distanceMeters = GeoUtil.distanceMeters(
|
||||
homeLat.doubleValue(),
|
||||
homeLon.doubleValue(),
|
||||
stat.getVesLatitude().doubleValue(),
|
||||
stat.getVesLongitude().doubleValue()
|
||||
);
|
||||
|
||||
boolean isAtHome = distanceMeters <= radiusMeters;
|
||||
boolean isStoppedAtHome = !engineOn && isAtHome;
|
||||
|
||||
// 상태 변경
|
||||
String status = dispatch.getVedStatus();
|
||||
|
||||
// P → O (다시 출발)
|
||||
if ("P".equals(status) && !isStoppedAtHome) {
|
||||
transitionToOnRoute(dispatch);
|
||||
continue;
|
||||
}
|
||||
|
||||
// O -> P (도착 후 정차)
|
||||
if ("O".equals(status) && isStoppedAtHome) {
|
||||
transitionToPaused(dispatch);
|
||||
continue;
|
||||
}
|
||||
|
||||
// P -> C (장시간 정차)
|
||||
if ("P".equals(status) && isStoppedAtHome) {
|
||||
|
||||
if (dispatch.getVedPausedAt() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
long pausedMin = Duration.between(
|
||||
dispatch.getVedPausedAt(),
|
||||
LocalDateTime.now()
|
||||
).toMinutes();
|
||||
|
||||
if (pausedMin >= pausedMinutes) {
|
||||
transitionToClosed(dispatch, "AUTO_CLOSE_HOME_IDLE");
|
||||
try {
|
||||
boolean changed = processSingleDispatch(
|
||||
dispatch,
|
||||
vehicleIdToExternalId,
|
||||
statMap,
|
||||
homeLat,
|
||||
homeLon,
|
||||
radiusMeters,
|
||||
pausedCloseMinutes
|
||||
);
|
||||
if (changed) {
|
||||
processed++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
failed++;
|
||||
log.error(
|
||||
"[AUTO-CLOSE] failed dispatchId={} msg={}",
|
||||
dispatch.getVedId(),
|
||||
e.getMessage(),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("[AUTO-CLOSE] done processed={} failed={}", processed, failed);
|
||||
return new ProcessResultDto(processed, failed);
|
||||
}
|
||||
|
||||
|
||||
private boolean processSingleDispatch(
|
||||
VehicleDispatch dispatch,
|
||||
Map<Long, String> vehicleIdToExternalId,
|
||||
Map<String, VehicleStatGpsResponseDto> statMap,
|
||||
BigDecimal homeLat,
|
||||
BigDecimal homeLon,
|
||||
Integer radiusMeters,
|
||||
Integer pausedCloseMinutes
|
||||
) {
|
||||
Long internalVehicleId = dispatch.getVedVehId();
|
||||
if (internalVehicleId == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// internal → external vehicleId
|
||||
String externalId = vehicleIdToExternalId.get(internalVehicleId);
|
||||
if (externalId == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 외부 GPS 상태
|
||||
VehicleStatGpsResponseDto stat = statMap.get(externalId);
|
||||
if (stat == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean engineOn = Boolean.TRUE.equals(stat.getVesEngineOn());
|
||||
|
||||
double distanceMeters = GeoUtil.distanceMeters(
|
||||
homeLat.doubleValue(),
|
||||
homeLon.doubleValue(),
|
||||
stat.getVesLatitude().doubleValue(),
|
||||
stat.getVesLongitude().doubleValue()
|
||||
);
|
||||
|
||||
boolean isAtHome = distanceMeters <= radiusMeters;
|
||||
boolean isStoppedAtHome = !engineOn && isAtHome;
|
||||
|
||||
String status = dispatch.getVedStatus();
|
||||
|
||||
/*
|
||||
* 상태 전이 규칙
|
||||
*
|
||||
* O → P : HOME 근접 + engine OFF
|
||||
* P → O : HOME 이탈 or engine ON
|
||||
* P → C : HOME 근접 + engine OFF + paused_at ≥ N분
|
||||
*/
|
||||
|
||||
// P → O (다시 출발)
|
||||
if ("P".equals(status) && !isStoppedAtHome) {
|
||||
transitionToOnRoute(dispatch);
|
||||
return true;
|
||||
}
|
||||
|
||||
// O → P (도착 후 정차)
|
||||
if ("O".equals(status) && isStoppedAtHome) {
|
||||
transitionToPaused(dispatch);
|
||||
return true;
|
||||
}
|
||||
|
||||
// P → C (장시간 정차)
|
||||
if ("P".equals(status) && isStoppedAtHome) {
|
||||
|
||||
if (dispatch.getVedPausedAt() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long pausedMinutes = Duration.between(
|
||||
dispatch.getVedPausedAt(),
|
||||
LocalDateTime.now()
|
||||
).toMinutes();
|
||||
|
||||
if (pausedMinutes >= pausedCloseMinutes) {
|
||||
transitionToClosed(dispatch, "AUTO_CLOSE_HOME_IDLE");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void processAutoOpen(
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ application:
|
|||
expiration: 86400000 # a day
|
||||
refresh-token:
|
||||
expiration: 604800000 # 7 days
|
||||
system:
|
||||
client-id: opr-rest-api
|
||||
client-secret: ${SYSTEM_CLIENT_SECRET}
|
||||
pagination:
|
||||
default-page: 0
|
||||
default-size: 20
|
||||
|
|
@ -33,6 +36,9 @@ server:
|
|||
# ================================
|
||||
# ADD THIS
|
||||
# ================================
|
||||
auth:
|
||||
api:
|
||||
base-url: http://localhost:8080/auth-service
|
||||
hcm:
|
||||
api:
|
||||
base-url: http://localhost:8081/hcm-rest-api
|
||||
|
|
|
|||
Loading…
Reference in New Issue