localhost-back/src/main/java/io/company/localhost/service/localvacaService.java
2025-02-24 11:07:24 +09:00

244 lines
9.2 KiB
Java

package io.company.localhost.service;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import io.company.localhost.common.dto.MapDto;
import io.company.localhost.mapper.localvacaMapper;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class localvacaService {
private final localvacaMapper localvacaMapper;
private final RestTemplate restTemplate = new RestTemplate();
@Value("${api.public-holiday.key}")
private String serviceKey;
public void insertVacation(MapDto vacation) {
// 필요한 경우 데이터 검증/전처리 후 매퍼 호출
localvacaMapper.insertVacation(vacation);
}
public void deleteVacation(Long vacationId) {
localvacaMapper.deleteVacation(vacationId);
}
public List<MapDto> selectVacationList(int year, int month) {
return localvacaMapper.selectVacations(year, month);
}
/**
* 🔹 특정 연월에 대한 공휴일 데이터 조회
*/
public List<MapDto> selectHolidays(int year, int month) {
// ✅ ServiceKey를 디코딩해서 사용
String decodedServiceKey = URLDecoder.decode(serviceKey, StandardCharsets.UTF_8);
System.out.println("📌 디코딩된 ServiceKey: " + decodedServiceKey);
// ✅ URI를 직접 문자열로 구성하여 ServiceKey가 다시 인코딩되지 않도록 함
String url = "http://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/getRestDeInfo"
+ "?solYear=" + year
+ "&solMonth=" + String.format("%02d", month)
+ "&ServiceKey=" + decodedServiceKey // ✅ 디코딩된 상태로 직접 추가
+ "&_type=json";
System.out.println("📌 API 요청 URL: " + url);
// ✅ API 요청 헤더 추가 (User-Agent 포함)
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
HttpEntity<String> entity = new HttpEntity<>(headers);
// ✅ `exchange` 메서드를 사용하여 요청
ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.GET, entity, Map.class);
System.out.println("📌 API 응답 데이터: " + response.getBody());
return parseResponse(response.getBody());
}
/**
* 🔹 공휴일 데이터를 MapDto로 변환
*/
private List<MapDto> parseResponse(Map<String, Object> response) {
List<MapDto> holidays = new ArrayList<>();
if (response == null || !response.containsKey("response")) {
System.out.println("📌 응답이 비어 있음.");
return holidays;
}
Map<String, Object> responseBody = (Map<String, Object>) response.get("response");
System.out.println("📌 responseBody: " + responseBody);
if (responseBody == null || !responseBody.containsKey("body")) {
System.out.println("📌 API 응답 데이터에서 'body' 필드 없음.");
return holidays;
}
Map<String, Object> body = (Map<String, Object>) responseBody.get("body");
System.out.println("📌 body: " + body);
if (body == null || !body.containsKey("items")) {
System.out.println("📌 API 응답 데이터에서 'items' 필드 없음.");
return holidays;
}
Object items = body.get("items");
System.out.println("📌 items: " + items);
// ✅ 'items'가 Map 타입인지 확인 후 처리
if (items instanceof Map) {
Map<String, Object> itemMap = (Map<String, Object>) items;
if (itemMap.containsKey("item")) {
Object itemData = itemMap.get("item");
System.out.println("📌 itemData: " + itemData);
// ✅ 'item'이 리스트인지 단일 객체인지 확인 후 변환
if (itemData instanceof List) {
for (Map<String, Object> item : (List<Map<String, Object>>) itemData) {
holidays.add(convertToMapDto(item));
}
} else if (itemData instanceof Map) {
holidays.add(convertToMapDto((Map<String, Object>) itemData));
}
}
}
System.out.println("📌 최종 holidays: " + holidays);
return holidays;
}
/**
* 🔹 공휴일 데이터를 MapDto로 변환
*/
private MapDto convertToMapDto(Map<String, Object> item) {
MapDto dto = new MapDto();
// ✅ locdate를 안전하게 변환 (int, long, double 등 다양한 형태 대응)
String locdateStr = String.valueOf(item.get("locdate"));
if (locdateStr.contains(".")) {
locdateStr = locdateStr.split("\\.")[0]; // 소수점 제거
}
// ✅ YYYY-MM-DD 형식으로 변환
if (locdateStr.length() == 8) {
String formattedDate = locdateStr.substring(0, 4) + "-" + locdateStr.substring(4, 6) + "-" + locdateStr.substring(6, 8);
dto.put("date", formattedDate);
} else {
dto.put("date", locdateStr); // 변환 불가능한 경우 원본 저장
}
dto.put("name", item.get("dateName"));
return dto;
}
/**
* 내 연차 사용 내역 조회 (사용한 연차 & 받은 연차)
*/
public Map<String, List<MapDto>> selectUserVacationHistory(Long userId, int year) {
List<MapDto> usedVacations = localvacaMapper.selectUsedVacations(userId,year);
List<MapDto> receivedVacations = localvacaMapper.selectReceivedVacations(userId,year);
Map<String, List<MapDto>> history = new HashMap<>();
history.put("usedVacations", usedVacations);
history.put("receivedVacations", receivedVacations);
return history;
}
/**
* 사원별 남은 연차 개수 조회
*/
public List<MapDto> selectEmployeeRemainingVacation() {
List<MapDto> employeeVacations = localvacaMapper.selectEmployeeRemainingVacation();
return employeeVacations.stream().map(emp -> {
// 🔹 hireDate 변환 (포맷 정규화)
String hireDateString = emp.get("hireDate").toString().split("\\.")[0]; // .0 제거
LocalDate hireDate;
try {
if (hireDateString.contains("T")) {
hireDate = LocalDateTime.parse(hireDateString, DateTimeFormatter.ISO_LOCAL_DATE_TIME).toLocalDate();
} else {
hireDate = LocalDate.parse(hireDateString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
} catch (Exception e) {
throw new RuntimeException("🚨 입사일 변환 오류: " + hireDateString, e);
}
// 🔹 총 연차 개수 계산
int totalVacation = procCalculateTotalVacation(hireDate);
// 🔹 사용한 연차 개수 처리 (null 방지)
double usedVacation = emp.get("used_quota") != null ? ((Number) emp.get("used_quota")).doubleValue() : 0.0;
// 🔹 받은 연차 개수 처리 (null 방지)
double receivedVacation = emp.get("received_quota") != null ? ((Number) emp.get("received_quota")).doubleValue() : 0.0;
// 🔹 남은 연차 개수 계산 (반차 포함)
double remainingVacation = totalVacation - usedVacation + receivedVacation;
// 🔹 값 업데이트
emp.put("totalQuota", totalVacation);
emp.put("remainingQuota", remainingVacation);
emp.put("usedQuota", usedVacation);
emp.put("receivedQuota", receivedVacation);
return emp;
}).collect(Collectors.toList());
}
/**
* 총 연차 계산 로직
*/
private int procCalculateTotalVacation(LocalDate hireDate) {
LocalDate today = LocalDate.now();
int yearsWorked = hireDate.until(today).getYears();
// 🔹 1년 미만: 연간 12개 지급
if (yearsWorked < 1) {
return 12;
}
// 🔹 1년 이상 기본 15개
int totalVacation = 15;
LocalDate nextIncreaseDate = hireDate.plusYears(2).withMonth(1).withDayOfMonth(1);
// 🔹 2년마다 1개 추가
while (nextIncreaseDate.isBefore(today) || nextIncreaseDate.isEqual(today)) {
totalVacation += 1;
nextIncreaseDate = nextIncreaseDate.plusYears(2);
}
return totalVacation;
}
public List<MapDto> selectSentVacationCount(MapDto map) {
return localvacaMapper.selectSentVacationCount(map);
}
}