251 lines
9.5 KiB
Java
251 lines
9.5 KiB
Java
/************************************************************
|
|
*
|
|
* @packageName : io.company.localhost.service
|
|
* @fileName : localvacaService.java
|
|
* @author : 서지희
|
|
* @date : 25.02.06
|
|
* @description :
|
|
*
|
|
* ===========================================================
|
|
* DATE AUTHOR NOTE
|
|
* -----------------------------------------------------------
|
|
* 25.02.06 서지희 최초 생성
|
|
*
|
|
*************************************************************/
|
|
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);
|
|
}
|
|
}
|