diff --git a/src/com/pms/api/WarehouseApiClient.java b/src/com/pms/api/WarehouseApiClient.java new file mode 100644 index 0000000..8b6c8d6 --- /dev/null +++ b/src/com/pms/api/WarehouseApiClient.java @@ -0,0 +1,533 @@ +package com.pms.api; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.cert.X509Certificate; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import org.apache.commons.codec.binary.Base64; +import java.util.Random; + +/** + * 창고 정보 조회 API 클라이언트 + * 회사의 창고정보를 조회하는 API를 호출합니다. + */ +public class WarehouseApiClient { + + private static final String API_URL = "~/apiproxy/api20A00S00801"; + // 실제 키값 (기존 API 클라이언트와 동일) + private static final String CALLER_NAME = "API_gcmsAmaranth40578"; + private static final String ACCESS_TOKEN = "MN5KzKBWRAa92BPxDlRLl3GcsxeZXc"; + private static final String HASH_KEY = "22519103205540290721741689643674301018832465"; + private static final String GROUP_SEQ = "gcmsAmaranth40578"; + + /** + * 창고 정보를 조회합니다. + * + * @param baseUrl API 서버의 기본 URL (예: https://erp.rps-korea.com) + * @param coCd 회사코드 (4자리, 필수) + * @param baselocFg 기준위치구분 (0: 전체, 1: 기준위치만) + * @return API 응답 결과 (JSON 문자열) + * @throws Exception API 호출 중 발생하는 예외 + */ + public String getWarehouseList(String baseUrl, String coCd, String baselocFg) throws Exception { + if (coCd == null || coCd.trim().isEmpty()) { + throw new IllegalArgumentException("회사코드(coCd)는 필수입니다."); + } + + // JDK 1.7에서 TLS 1.2 활성화 + System.setProperty("https.protocols", "TLSv1.2"); + + // SSL 인증서 검증 우회 (개발 환경용) + TrustManager[] trustAllCerts = new TrustManager[] { + new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + public void checkClientTrusted(X509Certificate[] certs, String authType) { + } + public void checkServerTrusted(X509Certificate[] certs, String authType) { + } + } + }; + + SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() { + public boolean verify(String hostname, javax.net.ssl.SSLSession session) { + return true; + } + }); + + // API URL 구성 + String urlPath = API_URL.replace("~", ""); + // baseUrl 끝에 슬래시가 있으면 제거 + String cleanBaseUrl = baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl; + String fullUrl = cleanBaseUrl + urlPath; + URL url = new URL(fullUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + // 연결 타임아웃 설정 (30초) + connection.setConnectTimeout(30000); + connection.setReadTimeout(30000); + + // 리다이렉트 자동 따라가기 비활성화 (수동 처리) + connection.setInstanceFollowRedirects(false); + + try { + // HTTP 메서드 설정 + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); + connection.setRequestProperty("Accept", "application/json"); + + // 인증 프로토콜 가이드에 따른 헤더 설정 + // 1. callerName: 호출 구분명 + connection.setRequestProperty("callerName", CALLER_NAME); + + // 2. Authorization: Bearer + accessToken + connection.setRequestProperty("Authorization", "Bearer " + ACCESS_TOKEN); + + // 3. transaction-id: 32자리 랜덤 문자열 + String transactionId = generateTransactionId(); + connection.setRequestProperty("transaction-id", transactionId); + + // 4. timestamp: Unix timestamp (초 단위) + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + connection.setRequestProperty("timestamp", timestamp); + + // 5. groupSeq: Amaranth10 그룹시퀀스 + connection.setRequestProperty("groupSeq", GROUP_SEQ); + + // 6. wehago-sign: HMacSHA256 생성 + String wehagoSign = generateWehagoSign(ACCESS_TOKEN, transactionId, timestamp, urlPath); + connection.setRequestProperty("wehago-sign", wehagoSign); + + // 요청 본문 작성 + String requestBody = buildRequestBody(coCd, baselocFg); + + // 요청 전송 설정 + connection.setDoOutput(true); + connection.setDoInput(true); + + // 요청 본문 전송 + OutputStreamWriter writer = new OutputStreamWriter( + connection.getOutputStream(), StandardCharsets.UTF_8); + writer.write(requestBody); + writer.flush(); + writer.close(); + + // 응답 코드 확인 + int responseCode = connection.getResponseCode(); + + // 리다이렉트 처리 (301, 302, 303, 307, 308) + if (responseCode == 301 || responseCode == 302 || responseCode == 303 || + responseCode == 307 || responseCode == 308) { + String location = connection.getHeaderField("Location"); + connection.disconnect(); + + if (location != null) { + // 리다이렉트 URL로 재시도 + URL redirectUrl = new URL(location); + connection = (HttpURLConnection) redirectUrl.openConnection(); + connection.setConnectTimeout(30000); + connection.setReadTimeout(30000); + connection.setInstanceFollowRedirects(false); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); + connection.setRequestProperty("Accept", "application/json"); + + // 리다이렉트 시에도 동일한 인증 헤더 재설정 + connection.setRequestProperty("callerName", CALLER_NAME); + connection.setRequestProperty("Authorization", "Bearer " + ACCESS_TOKEN); + connection.setRequestProperty("transaction-id", transactionId); + connection.setRequestProperty("timestamp", timestamp); + connection.setRequestProperty("groupSeq", GROUP_SEQ); + connection.setRequestProperty("wehago-sign", wehagoSign); + + // 동일한 요청 본문 재사용 + connection.setDoOutput(true); + connection.setDoInput(true); + + OutputStreamWriter redirectWriter = new OutputStreamWriter( + connection.getOutputStream(), StandardCharsets.UTF_8); + redirectWriter.write(requestBody); + redirectWriter.flush(); + redirectWriter.close(); + + responseCode = connection.getResponseCode(); + } + } + + // 응답 읽기 + BufferedReader reader = null; + StringBuilder response = new StringBuilder(); + + try { + if (responseCode >= 200 && responseCode < 300) { + reader = new BufferedReader(new InputStreamReader( + connection.getInputStream(), StandardCharsets.UTF_8)); + } else { + // 에러 스트림이 null일 수 있으므로 체크 + java.io.InputStream errorStream = connection.getErrorStream(); + if (errorStream != null) { + reader = new BufferedReader(new InputStreamReader( + errorStream, StandardCharsets.UTF_8)); + } else { + // 에러 스트림이 없으면 응답 코드만 반환 + throw new Exception("API 호출 실패: HTTP " + responseCode + " (에러 응답 본문 없음)"); + } + } + + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } + } finally { + if (reader != null) { + reader.close(); + } + } + + if (responseCode >= 200 && responseCode < 300) { + return response.toString(); + } else { + throw new Exception("API 호출 실패: HTTP " + responseCode + " - " + response.toString()); + } + + } finally { + connection.disconnect(); + } + } + + /** + * 요청 본문 JSON을 생성합니다. + * + * @param coCd 회사코드 + * @param baselocFg 기준위치구분 + * @return JSON 문자열 + */ + private String buildRequestBody(String coCd, String baselocFg) { + StringBuilder json = new StringBuilder(); + json.append("{"); + json.append("\"coCd\":\"").append(escapeJson(coCd)).append("\""); + + if (baselocFg != null && !baselocFg.trim().isEmpty()) { + json.append(",\"baselocFg\":\"").append(escapeJson(baselocFg)).append("\""); + } + + json.append("}"); + return json.toString(); + } + + /** + * JSON 문자열 이스케이프 처리 + * + * @param value 원본 문자열 + * @return 이스케이프된 문자열 + */ + private String escapeJson(String value) { + if (value == null) { + return ""; + } + return value.replace("\\", "\\\\") + .replace("\"", "\\\"") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\t", "\\t"); + } + + /** + * 32자리 랜덤 transaction-id 생성 + * + * @return 32자리 랜덤 문자열 + */ + private String generateTransactionId() { + String chars = "0123456789abcdef"; + Random random = new Random(); + StringBuilder sb = new StringBuilder(32); + for (int i = 0; i < 32; i++) { + sb.append(chars.charAt(random.nextInt(chars.length()))); + } + return sb.toString(); + } + + /** + * Wehago-sign 생성 + * HMacSHA256(key=hashKey, value=accessToken+transactionId+timestamp+url) 후 Base64 인코딩 + * + * @param accessToken 접근 토큰 + * @param transactionId 트랜잭션 ID + * @param timestamp 타임스탬프 + * @param urlPath URL 경로 + * @return Base64 인코딩된 서명 + * @throws Exception 서명 생성 중 발생하는 예외 + */ + private String generateWehagoSign(String accessToken, String transactionId, + String timestamp, String urlPath) throws Exception { + try { + // value = accessToken + transactionId + timestamp + url + String value = accessToken + transactionId + timestamp + urlPath; + + // HMacSHA256 생성 + SecretKeySpec keySpec = new SecretKeySpec( + HASH_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(keySpec); + byte[] encrypted = mac.doFinal(value.getBytes(StandardCharsets.UTF_8)); + + // Base64 인코딩 + String base64Binary = Base64.encodeBase64String(encrypted); + return base64Binary; + + } catch (Exception e) { + System.err.println("Wehago-sign 생성 오류: " + e.getMessage()); + e.printStackTrace(); + throw e; + } + } + + /** + * JSON 응답을 읽기 쉬운 텍스트 형식으로 출력 + * + * @param jsonResponse JSON 응답 문자열 + */ + private static void printWarehouseList(String jsonResponse) { + try { + // 간단한 JSON 파싱 (JDK 1.7 호환) + if (jsonResponse == null || jsonResponse.trim().isEmpty()) { + System.out.println("응답 데이터가 없습니다."); + return; + } + + // resultData 배열 찾기 + int dataStart = jsonResponse.indexOf("\"resultData\":["); + if (dataStart == -1) { + System.out.println("창고 데이터를 찾을 수 없습니다."); + System.out.println("원본 응답: " + jsonResponse); + return; + } + + // resultCode 확인 + int codeStart = jsonResponse.indexOf("\"resultCode\":"); + if (codeStart != -1) { + int codeEnd = jsonResponse.indexOf(",", codeStart); + if (codeEnd == -1) codeEnd = jsonResponse.indexOf("}", codeStart); + String resultCode = jsonResponse.substring(codeStart + 13, codeEnd).trim(); + System.out.println("결과 코드: " + resultCode); + } + + // resultMsg 확인 + int msgStart = jsonResponse.indexOf("\"resultMsg\":\""); + if (msgStart != -1) { + int msgEnd = jsonResponse.indexOf("\"", msgStart + 13); + String resultMsg = jsonResponse.substring(msgStart + 13, msgEnd); + System.out.println("결과 메시지: " + resultMsg); + System.out.println(); + } + + // 창고 정보 파싱 및 출력 + String dataSection = jsonResponse.substring(dataStart + 14); + int bracketCount = 0; + int startIdx = -1; + int warehouseCount = 0; + + System.out.println("===================================="); + System.out.println("창고 목록"); + System.out.println("===================================="); + System.out.println(); + + for (int i = 0; i < dataSection.length(); i++) { + char c = dataSection.charAt(i); + + if (c == '{') { + if (bracketCount == 0) { + startIdx = i; + } + bracketCount++; + } else if (c == '}') { + bracketCount--; + if (bracketCount == 0 && startIdx != -1) { + // 창고 객체 추출 + String warehouseJson = dataSection.substring(startIdx, i + 1); + printWarehouseInfo(warehouseJson, ++warehouseCount); + startIdx = -1; + } + } + } + + System.out.println(); + System.out.println("===================================="); + System.out.println("총 " + warehouseCount + "개 창고"); + System.out.println("===================================="); + + } catch (Exception e) { + System.err.println("출력 중 오류 발생: " + e.getMessage()); + System.out.println("원본 응답: " + jsonResponse); + } + } + + /** + * 개별 창고 정보를 읽기 쉬운 형식으로 출력 + * + * @param warehouseJson 창고 JSON 문자열 + * @param index 순번 + */ + private static void printWarehouseInfo(String warehouseJson, int index) { + System.out.println("[" + index + "] 창고 정보"); + System.out.println("------------------------------------"); + + // API 문서 기준 필드 추출 + String coCd = extractJsonValue(warehouseJson, "coCd"); + String baselocCd = extractJsonValue(warehouseJson, "baselocCd"); + String baselocNm = extractJsonValue(warehouseJson, "baselocNm"); + String baselocFg = extractJsonValue(warehouseJson, "baselocFg"); + String divCd = extractJsonValue(warehouseJson, "divCd"); + String inlocCd = extractJsonValue(warehouseJson, "inlocCd"); + String inlocNm = extractJsonValue(warehouseJson, "inlocNm"); + String outlocCd = extractJsonValue(warehouseJson, "outlocCd"); + String outlocNm = extractJsonValue(warehouseJson, "outlocNm"); + String baselocDc = extractJsonValue(warehouseJson, "baselocDc"); + String useYn = extractJsonValue(warehouseJson, "useYn"); + String useYnNm = extractJsonValue(warehouseJson, "useYnNm"); + + System.out.println(" 회사코드: " + (coCd.isEmpty() ? "-" : coCd)); + System.out.println(" 창고코드: " + (baselocCd.isEmpty() ? "-" : baselocCd)); + System.out.println(" 창고명: " + (baselocNm.isEmpty() ? "-" : baselocNm)); + + // 구분코드 해석 + String baselocFgNm = "-"; + if ("0".equals(baselocFg)) baselocFgNm = "창고"; + else if ("1".equals(baselocFg)) baselocFgNm = "생산공정"; + else if ("2".equals(baselocFg)) baselocFgNm = "외주공정"; + System.out.println(" 구분: " + baselocFgNm + " (" + baselocFg + ")"); + + if (!divCd.isEmpty()) { + System.out.println(" 사업장코드: " + divCd); + } + if (!inlocCd.isEmpty()) { + System.out.println(" 입고기본장소: " + inlocCd + (inlocNm.isEmpty() ? "" : " (" + inlocNm + ")")); + } + if (!outlocCd.isEmpty()) { + System.out.println(" 출고기본장소: " + outlocCd + (outlocNm.isEmpty() ? "" : " (" + outlocNm + ")")); + } + if (!baselocDc.isEmpty()) { + System.out.println(" 비고: " + baselocDc); + } + if (!useYnNm.isEmpty()) { + System.out.println(" 사용여부: " + useYnNm); + } else if (!useYn.isEmpty()) { + System.out.println(" 사용여부: " + (useYn.equals("1") ? "사용" : "미사용")); + } + + System.out.println(); + } + + /** + * JSON 문자열에서 특정 필드의 값을 추출 + * + * @param json JSON 문자열 + * @param fieldName 필드명 + * @return 필드 값 (없으면 빈 문자열) + */ + private static String extractJsonValue(String json, String fieldName) { + String searchKey = "\"" + fieldName + "\":"; + int startIdx = json.indexOf(searchKey); + if (startIdx == -1) { + return ""; + } + + startIdx += searchKey.length(); + + // 공백 제거 + while (startIdx < json.length() && Character.isWhitespace(json.charAt(startIdx))) { + startIdx++; + } + + if (startIdx >= json.length()) { + return ""; + } + + char firstChar = json.charAt(startIdx); + + // 문자열 값인 경우 + if (firstChar == '"') { + int endIdx = json.indexOf('"', startIdx + 1); + if (endIdx == -1) return ""; + return json.substring(startIdx + 1, endIdx); + } + // 숫자나 null인 경우 + else { + int endIdx = startIdx; + while (endIdx < json.length() && + (Character.isDigit(json.charAt(endIdx)) || + json.charAt(endIdx) == '.' || + json.charAt(endIdx) == '-' || + json.charAt(endIdx) == 'n' || // null + json.charAt(endIdx) == 'u' || + json.charAt(endIdx) == 'l')) { + endIdx++; + } + String value = json.substring(startIdx, endIdx).trim(); + // null 체크 + if (value.startsWith("null")) { + return ""; + } + return value; + } + } + + /** + * 테스트 메인 메서드 + */ + public static void main(String[] args) { + // JDK 1.7에서 TLS 1.2 활성화 + System.setProperty("https.protocols", "TLSv1.2"); + + WarehouseApiClient client = new WarehouseApiClient(); + + try { + System.out.println("===================================="); + System.out.println("창고 조회 API 호출 테스트"); + System.out.println("===================================="); + System.out.println(); + + String baseUrl = "https://erp.rps-korea.com"; + String apiEndpoint = API_URL.replace("~", ""); // ~ 제거 + System.out.println("API 서버: " + baseUrl); + System.out.println("API 엔드포인트: " + apiEndpoint); + System.out.println(); + + // 회사코드 1000, baselocFg=0 으로 창고 조회 + System.out.println("[1] 회사코드 1000, baselocFg=0 으로 창고 조회"); + System.out.println("------------------------------------"); + String response = client.getWarehouseList( + baseUrl, + "1000", // 회사코드 + "0" // baselocFg: 0 (창고) + ); + + // 원본 응답 출력 + System.out.println("원본 응답: " + response); + System.out.println(); + + // JSON 응답을 읽기 쉬운 텍스트 형식으로 출력 + printWarehouseList(response); + System.out.println(); + + } catch (Exception e) { + System.err.println("===================================="); + System.err.println("오류 발생: " + e.getMessage()); + System.err.println("===================================="); + e.printStackTrace(); + } + } +} diff --git a/src/com/pms/controller/AdminController.java b/src/com/pms/controller/AdminController.java index b0f933c..498528d 100644 --- a/src/com/pms/controller/AdminController.java +++ b/src/com/pms/controller/AdminController.java @@ -5281,4 +5281,31 @@ public String clientImportFileProc(HttpServletRequest request, HttpSession sessi return resultMap; } + + /** + * ERP 창고 정보 동기화 수동 실행 + * @param request + * @param paramMap + * @return + */ + @RequestMapping("/admin/syncWarehouseDataManual.do") + @ResponseBody + public Map syncWarehouseDataManual(HttpServletRequest request, @RequestParam Map paramMap) { + Map resultMap = new HashMap(); + + try { + System.out.println("===================================="); + System.out.println("관리자 수동 ERP 창고 동기화 실행 요청"); + System.out.println("===================================="); + + resultMap = batchService.syncWarehouseDataManual(); + + } catch (Exception e) { + e.printStackTrace(); + resultMap.put("success", false); + resultMap.put("message", "창고 동기화 실행 중 오류가 발생했습니다: " + e.getMessage()); + } + + return resultMap; + } } diff --git a/src/com/pms/mapper/batch.xml b/src/com/pms/mapper/batch.xml index e066a5f..43bd0a4 100644 --- a/src/com/pms/mapper/batch.xml +++ b/src/com/pms/mapper/batch.xml @@ -178,5 +178,61 @@ END, data_type = #{data_type} + + + + INSERT INTO warehouse_location ( + objid, + location_code, + location_name, + location_description, + out_code, + out_co_name, + fit_status, + available_status, + use_status, + base_loc_cd, + co_cd, + loc_nmk, + attr_nmk, + insert_id, + writer, + regdate, + status + ) VALUES ( + #{location_code}, + #{location_code}, + #{location_name}, + #{location_description}, + #{out_code}, + #{out_co_name}, + #{fit_status}, + #{available_status}, + #{use_status}, + #{base_loc_cd}, + #{co_cd}, + #{loc_nmk}, + #{attr_nmk}, + #{insert_id}, + #{writer}, + NOW(), + #{status} + ) ON CONFLICT (location_code) DO + UPDATE SET + location_name = #{location_name}, + location_description = #{location_description}, + out_code = #{out_code}, + out_co_name = #{out_co_name}, + fit_status = #{fit_status}, + available_status = #{available_status}, + use_status = #{use_status}, + base_loc_cd = #{base_loc_cd}, + co_cd = #{co_cd}, + loc_nmk = #{loc_nmk}, + attr_nmk = #{attr_nmk}, + modify_id = #{insert_id}, + modify_dt = NOW(), + status = #{status} + diff --git a/src/com/pms/service/BatchService.java b/src/com/pms/service/BatchService.java index 86fe072..6a9fe8a 100644 --- a/src/com/pms/service/BatchService.java +++ b/src/com/pms/service/BatchService.java @@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestParam; import com.pms.api.CustomerApiClient; import com.pms.api.DepartmentApiClient; import com.pms.api.EmployeeApiClient; +import com.pms.api.WarehouseApiClient; import com.pms.common.Message; import com.pms.common.SqlMapConfig; import com.pms.common.bean.PersonBean; @@ -285,6 +286,41 @@ public class BatchService extends BaseService { return result; } + /** + * 창고 정보만 동기화 (수동 실행) + * @return 성공 여부 Map + */ + public Map syncWarehouseDataManual() { + Map result = new HashMap(); + SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession(false); + + System.out.println("===================================="); + System.out.println("ERP 창고 정보 동기화 시작 (수동)"); + System.out.println("===================================="); + + try { + String baseUrl = "https://erp.rps-korea.com"; + String coCd = "1000"; + + syncWarehouseData(sqlSession, baseUrl, coCd); + + sqlSession.commit(); + result.put("success", true); + result.put("message", "창고 정보 동기화가 완료되었습니다."); + System.out.println("ERP 창고 정보 동기화 완료"); + } catch (Exception e) { + sqlSession.rollback(); + result.put("success", false); + result.put("message", "창고 정보 동기화 중 오류가 발생했습니다: " + e.getMessage()); + System.err.println("창고 정보 동기화 오류: " + e.getMessage()); + e.printStackTrace(); + } finally { + sqlSession.close(); + } + + return result; + } + /** * ERP 데이터 동기화 실제 실행 로직 */ @@ -305,6 +341,9 @@ public class BatchService extends BaseService { // 3. 사원 정보 동기화 syncEmployeeData(sqlSession, baseUrl, coCd); + // 4. 창고 정보 동기화 + syncWarehouseData(sqlSession, baseUrl, coCd); + sqlSession.commit(); System.out.println("ERP 데이터 동기화 배치 완료"); @@ -458,6 +497,51 @@ public class BatchService extends BaseService { } } + /** + * 창고 정보 동기화 + */ + private void syncWarehouseData(SqlSession sqlSession, String baseUrl, String coCd) { + try { + System.out.println("창고 정보 동기화 시작..."); + + WarehouseApiClient warehouseClient = new WarehouseApiClient(); + String jsonResponse = warehouseClient.getWarehouseList(baseUrl, coCd, "0"); + + // JSON 파싱 및 DB 저장 + List> warehouseList = parseWarehouseJson(jsonResponse); + + int processCount = 0; + + // 처음 10건 로그 출력 + System.out.println("===================================="); + System.out.println("창고 데이터 샘플 (최대 10건)"); + System.out.println("===================================="); + + for (Map warehouse : warehouseList) { + // 처음 10건만 로그 출력 + if (processCount < 10) { + System.out.println("[창고 " + (processCount + 1) + "]"); + System.out.println(" - LOCATION_CODE: " + warehouse.get("location_code")); + System.out.println(" - LOCATION_NAME: " + warehouse.get("location_name")); + System.out.println(" - OUT_CODE: " + warehouse.get("out_code")); + System.out.println(" - USE_STATUS: " + warehouse.get("use_status")); + System.out.println("---"); + } + + // UPSERT 실행 + sqlSession.insert("batch.upsertWarehouse", warehouse); + processCount++; + } + + System.out.println("===================================="); + System.out.println("창고 정보 동기화 완료 - 처리: " + processCount + "건"); + + } catch (Exception e) { + System.err.println("창고 정보 동기화 실패: " + e.getMessage()); + throw new RuntimeException(e); + } + } + /** * 거래처 JSON 파싱 */ @@ -813,6 +897,89 @@ public class BatchService extends BaseService { return value; } } + + /** + * 창고 JSON 파싱 + */ + private List> parseWarehouseJson(String jsonResponse) { + List> warehouseList = new ArrayList>(); + + try { + // resultData 배열 찾기 + int dataStart = jsonResponse.indexOf("\"resultData\":["); + if (dataStart == -1) { + return warehouseList; + } + + String dataSection = jsonResponse.substring(dataStart + 14); + int bracketCount = 0; + int startIdx = -1; + + for (int i = 0; i < dataSection.length(); i++) { + char c = dataSection.charAt(i); + + if (c == '{') { + if (bracketCount == 0) { + startIdx = i; + } + bracketCount++; + } else if (c == '}') { + bracketCount--; + if (bracketCount == 0 && startIdx != -1) { + String warehouseJson = dataSection.substring(startIdx, i + 1); + Map warehouse = parseWarehouseObject(warehouseJson); + if (warehouse != null) { + warehouseList.add(warehouse); + } + startIdx = -1; + } + } + } + } catch (Exception e) { + System.err.println("창고 JSON 파싱 오류: " + e.getMessage()); + } + + return warehouseList; + } + + /** + * 창고 객체 파싱 + */ + private Map parseWarehouseObject(String json) { + Map warehouse = new HashMap(); + + // location_code를 objid에도 동일하게 저장 + String locationCode = extractJsonValue(json, "baselocCd"); + warehouse.put("objid", locationCode); + warehouse.put("location_code", locationCode); + + // 기본 정보 + warehouse.put("location_name", extractJsonValue(json, "baselocNm")); + warehouse.put("location_description", extractJsonValue(json, "baselocDc")); + warehouse.put("out_code", extractJsonValue(json, "outlocCd")); + warehouse.put("out_co_name", extractJsonValue(json, "outlocNm")); + + // 상태 정보 + String baselocFg = extractJsonValue(json, "baselocFg"); + warehouse.put("fit_status", baselocFg); + + String useYn = extractJsonValue(json, "useYn"); + warehouse.put("available_status", useYn); + warehouse.put("use_status", "1".equals(useYn) ? "Y" : "N"); + + // 추가 정보 + warehouse.put("base_loc_cd", extractJsonValue(json, "baselocCd")); + warehouse.put("co_cd", extractJsonValue(json, "coCd")); + warehouse.put("loc_nmk", extractJsonValue(json, "baselocNm")); + warehouse.put("attr_nmk", extractJsonValue(json, "inlocNm")); + + // 시스템 정보 + warehouse.put("insert_id", "batch_system"); + warehouse.put("writer", "batch_system"); + warehouse.put("status", "active"); + + return warehouse; + } }