SELECT
diff --git a/WebContent/WEB-INF/view/partMng/partMngList.jsp b/WebContent/WEB-INF/view/partMng/partMngList.jsp
index daa1064..5ab3b5e 100644
--- a/WebContent/WEB-INF/view/partMng/partMngList.jsp
+++ b/WebContent/WEB-INF/view/partMng/partMngList.jsp
@@ -53,10 +53,27 @@ String connector = person.getUserId();
fn_partMngDeploy();
});
- //ERP 전송
- $("#btnSendErp").click(function(){
- fn_sendErp();
- });
+ //ERP 전송
+ $("#btnSendErp").click(function(){
+ fn_sendErp();
+ });
+
+ //ERP 단건 수정
+ $("#btnUpdateSingleErp").click(function(){
+ fn_updateSingleErp();
+ });
+
+ //ERP 전체 수정
+ $("#btnUpdateAllErp").click(function(){
+ fn_updateAllErp();
+ });
+
+ //ERP 삭제
+ /*
+ $("#btnDeleteErp").click(function(){
+ fn_deleteErp();
+ });
+ */
//image src encoding
$("img").each(function(i) {
@@ -524,10 +541,206 @@ String connector = person.getUserId();
text: 'PART 전송 중 오류가 발생했습니다.'
});
}
+ });
+ }
+}
+
+// ERP 단건 수정 (선택한 PART 1개만 수정)
+function fn_updateSingleErp(){
+ var selectedData = _tabulGrid.getSelectedData();
+
+ if(!selectedData || selectedData.length == 0){
+ Swal.fire("선택된 PART가 없습니다.");
+ return;
+ }
+
+ if(selectedData.length > 1){
+ Swal.fire("하나의 PART만 선택해주세요.");
+ return;
+ }
+
+ var partObjid = selectedData[0].OBJID;
+ var partNo = selectedData[0].PART_NO;
+
+ Swal.fire({
+ title: 'ERP 단건 수정',
+ text: partNo + '을(를) ERP에 수정 전송하시겠습니까?',
+ icon: 'question',
+ showCancelButton: true,
+ confirmButtonText: '수정',
+ cancelButtonText: '취소',
+ confirmButtonColor: '#2196F3'
+ }).then((result) => {
+ if (result.isConfirmed) {
+ Swal.fire({
+ title: '수정 중...',
+ text: 'PART 정보를 ERP에 수정 전송하고 있습니다.',
+ allowOutsideClick: false,
+ didOpen: () => {
+ Swal.showLoading();
+ }
+ });
+
+ $.ajax({
+ type : "POST",
+ url : "/admin/updatePartToErp.do",
+ data : {partObjid: partObjid},
+ dataType:"json",
+ success:function(data){
+ Swal.close();
+ if(data.success){
+ Swal.fire({
+ icon: 'success',
+ title: '수정 완료',
+ text: data.message
+ });
+ } else {
+ Swal.fire({
+ icon: 'error',
+ title: '수정 실패',
+ text: data.message
+ });
+ }
+ },
+ error: function(jqxhr, status, error){
+ Swal.close();
+ Swal.fire({
+ icon: 'error',
+ title: '오류 발생',
+ text: 'PART 수정 중 오류가 발생했습니다.'
+ });
+ }
});
}
+ });
+}
+
+// ERP 전체 수정 (DB의 모든 release 상태 PART를 전부 수정)
+function fn_updateAllErp(){
+ Swal.fire({
+ title: 'ERP 전체 수정',
+ text: '모든 PART 정보를 ERP에 수정 전송하시겠습니까?',
+ icon: 'warning',
+ showCancelButton: true,
+ confirmButtonText: '전체 수정',
+ cancelButtonText: '취소',
+ confirmButtonColor: '#1976D2'
+ }).then((result) => {
+ if (result.isConfirmed) {
+ Swal.fire({
+ title: '전체 수정 중...',
+ text: '모든 PART 정보를 ERP에 수정 전송하고 있습니다. 시간이 걸릴 수 있습니다.',
+ allowOutsideClick: false,
+ didOpen: () => {
+ Swal.showLoading();
+ }
+ });
+
+ $.ajax({
+ type : "POST",
+ url : "/admin/updateAllPartsToErp.do",
+ dataType:"json",
+ success:function(data){
+ Swal.close();
+ if(data.success){
+ Swal.fire({
+ icon: 'success',
+ title: '전체 수정 완료',
+ text: data.message,
+ html: data.errors ? '' + data.errors + ' ' : data.message
+ });
+ } else {
+ Swal.fire({
+ icon: 'error',
+ title: '전체 수정 실패',
+ text: data.message
+ });
+ }
+ },
+ error: function(jqxhr, status, error){
+ Swal.close();
+ Swal.fire({
+ icon: 'error',
+ title: '오류 발생',
+ text: 'PART 전체 수정 중 오류가 발생했습니다.'
+ });
+ }
+ });
+ }
+ });
+}
+
+/*
+// ERP 삭제 (주석처리: ERP 전송된 데이터는 삭제하면 안됨)
+function fn_deleteErp(){
+ var selectedData = _tabulGrid.getSelectedData();
+
+ if(!selectedData || selectedData.length == 0){
+ Swal.fire("선택된 PART가 없습니다.");
+ return;
}
+ if(selectedData.length > 1){
+ Swal.fire("하나의 PART만 선택해주세요.");
+ return;
+ }
+
+ var partNo = selectedData[0].PART_NO;
+
+ Swal.fire({
+ title: 'ERP 삭제',
+ text: partNo + '을(를) ERP에서 삭제하시겠습니까?',
+ icon: 'warning',
+ showCancelButton: true,
+ confirmButtonText: '삭제',
+ cancelButtonText: '취소',
+ confirmButtonColor: '#d33'
+ }).then((result) => {
+ if (result.isConfirmed) {
+ Swal.fire({
+ title: '삭제 중...',
+ text: 'PART 정보를 ERP에서 삭제하고 있습니다.',
+ allowOutsideClick: false,
+ didOpen: () => {
+ Swal.showLoading();
+ }
+ });
+
+ $.ajax({
+ type : "POST",
+ url : "/admin/deletePartFromErp.do",
+ data : {partNo: partNo},
+ dataType:"json",
+ success:function(data){
+ Swal.close();
+ if(data.success){
+ Swal.fire({
+ icon: 'success',
+ title: '삭제 완료',
+ text: data.message
+ });
+ } else {
+ Swal.fire({
+ icon: 'error',
+ title: '삭제 실패',
+ text: data.message
+ });
+ }
+ },
+ error: function(jqxhr, status, error){
+ Swal.close();
+ Swal.fire({
+ icon: 'error',
+ title: '오류 발생',
+ text: 'PART 삭제 중 오류가 발생했습니다.'
+ });
+ }
+ });
+ }
+ });
+}
+*/
+
@@ -550,11 +763,14 @@ String connector = person.getUserId();
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/src/com/pms/api/PartErpApiClient.java b/src/com/pms/api/PartErpApiClient.java
index dae45a8..a61683c 100644
--- a/src/com/pms/api/PartErpApiClient.java
+++ b/src/com/pms/api/PartErpApiClient.java
@@ -48,7 +48,7 @@ public class PartErpApiClient {
* @return API 응답 결과 (JSON 문자열)
* @throws Exception API 호출 중 발생하는 예외
*/
- public String sendPartToErp(String baseUrl, String coCd, String itemCd, String itemNm,
+ public String sendPartToErp(String baseUrl, String coCd, String itemCd, String itemNm, String itemDc,
String acctFg, String odrFg, String unitDc, String unitmangDc,
int unitchngNb, String lotFg, String qcFg, String reqFg,
String setitemFg, String useYn) throws Exception {
@@ -125,7 +125,7 @@ public class PartErpApiClient {
connection.setRequestProperty("wehago-sign", wehagoSign);
// 요청 본문 작성
- String requestBody = buildRequestBody(coCd, itemCd, itemNm, acctFg, odrFg,
+ String requestBody = buildRequestBody(coCd, itemCd, itemNm, itemDc, acctFg, odrFg,
unitDc, unitmangDc, unitchngNb, lotFg, qcFg, reqFg, setitemFg, useYn);
connection.setDoOutput(true);
@@ -217,7 +217,7 @@ public class PartErpApiClient {
/**
* 요청 본문 JSON 생성
*/
- private String buildRequestBody(String coCd, String itemCd, String itemNm,
+ private String buildRequestBody(String coCd, String itemCd, String itemNm, String itemDc,
String acctFg, String odrFg, String unitDc,
String unitmangDc, int unitchngNb, String lotFg,
String qcFg, String reqFg, String setitemFg, String useYn) {
@@ -226,6 +226,9 @@ public class PartErpApiClient {
json.append("\"coCd\":\"").append(escapeJson(coCd)).append("\"");
json.append(",\"itemCd\":\"").append(escapeJson(itemCd)).append("\"");
json.append(",\"itemNm\":\"").append(escapeJson(itemNm)).append("\"");
+ if (itemDc != null && !itemDc.trim().isEmpty()) {
+ json.append(",\"itemDc\":\"").append(escapeJson(itemDc)).append("\"");
+ }
json.append(",\"acctFg\":\"").append(escapeJson(acctFg)).append("\"");
json.append(",\"odrFg\":\"").append(escapeJson(odrFg)).append("\"");
json.append(",\"unitDc\":\"").append(escapeJson(unitDc)).append("\"");
diff --git a/src/com/pms/api/PartErpDeleteApiClient.java b/src/com/pms/api/PartErpDeleteApiClient.java
new file mode 100644
index 0000000..29deb01
--- /dev/null
+++ b/src/com/pms/api/PartErpDeleteApiClient.java
@@ -0,0 +1,212 @@
+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;
+
+/**
+ * PART 정보 ERP 삭제 API 클라이언트
+ */
+public class PartErpDeleteApiClient {
+
+ private static final String API_URL = "~/apiproxy/api20A00D00701";
+ 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";
+
+ /**
+ * PART 정보를 ERP에서 삭제합니다.
+ */
+ public String deletePartFromErp(String baseUrl, String coCd, String itemCd) throws Exception {
+ if (coCd == null || coCd.trim().isEmpty()) {
+ throw new IllegalArgumentException("회사코드(coCd)는 필수입니다.");
+ }
+ if (itemCd == null || itemCd.trim().isEmpty()) {
+ throw new IllegalArgumentException("품번(itemCd)는 필수입니다.");
+ }
+
+ // 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("~", "");
+ 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();
+
+ connection.setConnectTimeout(30000);
+ connection.setReadTimeout(30000);
+ connection.setInstanceFollowRedirects(false);
+
+ try {
+ 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);
+
+ String transactionId = generateTransactionId();
+ connection.setRequestProperty("transaction-id", transactionId);
+
+ String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
+ connection.setRequestProperty("timestamp", timestamp);
+
+ connection.setRequestProperty("groupSeq", GROUP_SEQ);
+
+ String wehagoSign = generateWehagoSign(ACCESS_TOKEN, transactionId, timestamp, urlPath);
+ connection.setRequestProperty("wehago-sign", wehagoSign);
+
+ // 요청 본문 작성
+ String requestBody = buildRequestBody(coCd, itemCd);
+
+ 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();
+
+ // 응답 읽기
+ BufferedReader reader = null;
+ StringBuilder response = new StringBuilder();
+
+ try {
+ if (responseCode >= 200 && responseCode < 300) {
+ reader = new BufferedReader(new InputStreamReader(
+ connection.getInputStream(), StandardCharsets.UTF_8));
+ } else {
+ 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 생성
+ */
+ private String buildRequestBody(String coCd, String itemCd) {
+ StringBuilder json = new StringBuilder();
+ json.append("{");
+ json.append("\"coCd\":\"").append(escapeJson(coCd)).append("\"");
+ json.append(",\"itemCd\":\"").append(escapeJson(itemCd)).append("\"");
+ json.append("}");
+ return json.toString();
+ }
+
+ /**
+ * JSON 문자열 이스케이프 처리
+ */
+ 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 생성
+ */
+ 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 생성
+ */
+ private String generateWehagoSign(String accessToken, String transactionId,
+ String timestamp, String urlPath) throws Exception {
+ try {
+ String value = accessToken + transactionId + timestamp + urlPath;
+
+ 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));
+
+ String base64Binary = Base64.encodeBase64String(encrypted);
+ return base64Binary;
+
+ } catch (Exception e) {
+ System.err.println("Wehago-sign 생성 오류: " + e.getMessage());
+ e.printStackTrace();
+ throw e;
+ }
+ }
+}
diff --git a/src/com/pms/api/PartErpUpdateApiClient.java b/src/com/pms/api/PartErpUpdateApiClient.java
new file mode 100644
index 0000000..93b6cb4
--- /dev/null
+++ b/src/com/pms/api/PartErpUpdateApiClient.java
@@ -0,0 +1,242 @@
+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;
+
+/**
+ * PART 정보 ERP 수정 API 클라이언트
+ */
+public class PartErpUpdateApiClient {
+
+ private static final String API_URL = "~/apiproxy/api20A00U00701";
+ 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";
+
+ /**
+ * PART 정보를 ERP에서 수정합니다.
+ */
+ public String updatePartToErp(String baseUrl, String coCd, String itemCd, String itemNm, String itemDc,
+ String acctFg, String odrFg, String unitDc, String unitmangDc,
+ int unitchngNb, String lotFg, String qcFg, String reqFg,
+ String setitemFg, String useYn) throws Exception {
+ if (coCd == null || coCd.trim().isEmpty()) {
+ throw new IllegalArgumentException("회사코드(coCd)는 필수입니다.");
+ }
+ if (itemCd == null || itemCd.trim().isEmpty()) {
+ throw new IllegalArgumentException("품번(itemCd)는 필수입니다.");
+ }
+ if (itemNm == null || itemNm.trim().isEmpty()) {
+ throw new IllegalArgumentException("품명(itemNm)는 필수입니다.");
+ }
+ if (acctFg == null || acctFg.trim().isEmpty()) {
+ throw new IllegalArgumentException("계정구분(acctFg)는 필수입니다.");
+ }
+ if (odrFg == null || odrFg.trim().isEmpty()) {
+ throw new IllegalArgumentException("조달구분(odrFg)는 필수입니다.");
+ }
+
+ // 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("~", "");
+ 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();
+
+ connection.setConnectTimeout(30000);
+ connection.setReadTimeout(30000);
+ connection.setInstanceFollowRedirects(false);
+
+ try {
+ 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);
+
+ String transactionId = generateTransactionId();
+ connection.setRequestProperty("transaction-id", transactionId);
+
+ String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
+ connection.setRequestProperty("timestamp", timestamp);
+
+ connection.setRequestProperty("groupSeq", GROUP_SEQ);
+
+ String wehagoSign = generateWehagoSign(ACCESS_TOKEN, transactionId, timestamp, urlPath);
+ connection.setRequestProperty("wehago-sign", wehagoSign);
+
+ // 요청 본문 작성
+ String requestBody = buildRequestBody(coCd, itemCd, itemNm, itemDc, acctFg, odrFg,
+ unitDc, unitmangDc, unitchngNb, lotFg, qcFg, reqFg, setitemFg, useYn);
+
+ 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();
+
+ // 응답 읽기
+ BufferedReader reader = null;
+ StringBuilder response = new StringBuilder();
+
+ try {
+ if (responseCode >= 200 && responseCode < 300) {
+ reader = new BufferedReader(new InputStreamReader(
+ connection.getInputStream(), StandardCharsets.UTF_8));
+ } else {
+ 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 생성
+ */
+ private String buildRequestBody(String coCd, String itemCd, String itemNm, String itemDc,
+ String acctFg, String odrFg, String unitDc,
+ String unitmangDc, int unitchngNb, String lotFg,
+ String qcFg, String reqFg, String setitemFg, String useYn) {
+ StringBuilder json = new StringBuilder();
+ json.append("{");
+ json.append("\"coCd\":\"").append(escapeJson(coCd)).append("\"");
+ json.append(",\"itemCd\":\"").append(escapeJson(itemCd)).append("\"");
+ json.append(",\"itemNm\":\"").append(escapeJson(itemNm)).append("\"");
+ if (itemDc != null && !itemDc.trim().isEmpty()) {
+ json.append(",\"itemDc\":\"").append(escapeJson(itemDc)).append("\"");
+ }
+ json.append(",\"acctFg\":\"").append(escapeJson(acctFg)).append("\"");
+ json.append(",\"odrFg\":\"").append(escapeJson(odrFg)).append("\"");
+ json.append(",\"unitDc\":\"").append(escapeJson(unitDc)).append("\"");
+ json.append(",\"unitmangDc\":\"").append(escapeJson(unitmangDc)).append("\"");
+ json.append(",\"unitchngNb\":").append(unitchngNb);
+ json.append(",\"lotFg\":\"").append(escapeJson(lotFg)).append("\"");
+ json.append(",\"qcFg\":\"").append(escapeJson(qcFg)).append("\"");
+ json.append(",\"reqFg\":\"").append(escapeJson(reqFg)).append("\"");
+ json.append(",\"setitemFg\":\"").append(escapeJson(setitemFg)).append("\"");
+ json.append(",\"useYn\":\"").append(escapeJson(useYn)).append("\"");
+ json.append("}");
+ return json.toString();
+ }
+
+ /**
+ * JSON 문자열 이스케이프 처리
+ */
+ 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 생성
+ */
+ 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 생성
+ */
+ private String generateWehagoSign(String accessToken, String transactionId,
+ String timestamp, String urlPath) throws Exception {
+ try {
+ String value = accessToken + transactionId + timestamp + urlPath;
+
+ 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));
+
+ String base64Binary = Base64.encodeBase64String(encrypted);
+ return base64Binary;
+
+ } catch (Exception e) {
+ System.err.println("Wehago-sign 생성 오류: " + e.getMessage());
+ e.printStackTrace();
+ throw e;
+ }
+ }
+}
diff --git a/src/com/pms/controller/AdminController.java b/src/com/pms/controller/AdminController.java
index 3395dc5..f923059 100644
--- a/src/com/pms/controller/AdminController.java
+++ b/src/com/pms/controller/AdminController.java
@@ -15,6 +15,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@@ -5370,4 +5371,92 @@ public String clientImportFileProc(HttpServletRequest request, HttpSession sessi
return resultMap;
}
+
+ /*
+ // ERP에서 PART 삭제 (주석처리: ERP 전송된 데이터는 삭제하면 안됨)
+ @RequestMapping(value = "/admin/deletePartFromErp.do", method = RequestMethod.POST)
+ @ResponseBody
+ public Map deletePartFromErp(HttpServletRequest request, @RequestParam Map paramMap) {
+ Map resultMap = new HashMap();
+
+ try {
+ String partNo = CommonUtils.checkNull(paramMap.get("partNo"));
+
+ if (partNo.isEmpty()) {
+ resultMap.put("success", false);
+ resultMap.put("message", "PART 번호가 없습니다.");
+ return resultMap;
+ }
+
+ System.out.println("====================================");
+ System.out.println("ERP PART 삭제 요청: " + partNo);
+ System.out.println("====================================");
+
+ resultMap = batchService.deletePartFromErp(partNo);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ resultMap.put("success", false);
+ resultMap.put("message", "PART 삭제 중 오류가 발생했습니다: " + e.getMessage());
+ }
+
+ return resultMap;
+ }
+ */
+
+ /**
+ * ERP에 PART 단건 수정
+ */
+ @RequestMapping(value = "/admin/updatePartToErp.do", method = RequestMethod.POST)
+ @ResponseBody
+ public Map updatePartToErp(HttpServletRequest request, @RequestParam Map paramMap) {
+ Map resultMap = new HashMap();
+
+ try {
+ String partObjid = CommonUtils.checkNull(paramMap.get("partObjid"));
+
+ if (partObjid.isEmpty()) {
+ resultMap.put("success", false);
+ resultMap.put("message", "PART OBJID가 없습니다.");
+ return resultMap;
+ }
+
+ System.out.println("====================================");
+ System.out.println("ERP PART 단건 수정 요청: " + partObjid);
+ System.out.println("====================================");
+
+ resultMap = batchService.updatePartToErp(partObjid);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ resultMap.put("success", false);
+ resultMap.put("message", "PART 수정 중 오류가 발생했습니다: " + e.getMessage());
+ }
+
+ return resultMap;
+ }
+
+ /**
+ * ERP에 모든 PART 전체 수정
+ */
+ @RequestMapping(value = "/admin/updateAllPartsToErp.do", method = RequestMethod.POST)
+ @ResponseBody
+ public Map updateAllPartsToErp(HttpServletRequest request) {
+ Map resultMap = new HashMap();
+
+ try {
+ System.out.println("====================================");
+ System.out.println("ERP 전체 PART 수정 시작");
+ System.out.println("====================================");
+
+ resultMap = batchService.updateAllPartsToErp();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ resultMap.put("success", false);
+ resultMap.put("message", "전체 PART 수정 중 오류가 발생했습니다: " + e.getMessage());
+ }
+
+ return resultMap;
+ }
}
diff --git a/src/com/pms/service/BatchService.java b/src/com/pms/service/BatchService.java
index ef3fde4..193fca2 100644
--- a/src/com/pms/service/BatchService.java
+++ b/src/com/pms/service/BatchService.java
@@ -22,6 +22,8 @@ import com.pms.api.DepartmentApiClient;
import com.pms.api.EmployeeApiClient;
import com.pms.api.WarehouseApiClient;
import com.pms.api.PartErpApiClient;
+import com.pms.api.PartErpDeleteApiClient;
+import com.pms.api.PartErpUpdateApiClient;
import com.pms.common.Message;
import com.pms.common.SqlMapConfig;
import com.pms.common.bean.PersonBean;
@@ -1021,6 +1023,7 @@ public class BatchService extends BaseService {
String itemNm = CommonUtils.checkNull(part.get("part_name"));
String acctFg = CommonUtils.checkNull(part.get("acctfg"));
String odrFg = CommonUtils.checkNull(part.get("odrfg"));
+ String itemDc = CommonUtils.checkNull(part.get("spec"));
// 하드코딩 고정값
String coCd = "1000"; // 회사코드
@@ -1045,7 +1048,7 @@ public class BatchService extends BaseService {
}
// ERP로 전송
- String response = partErpClient.sendPartToErp(baseUrl, coCd, itemCd, itemNm,
+ String response = partErpClient.sendPartToErp(baseUrl, coCd, itemCd, itemNm,itemDc,
acctFg, odrFg, unitDc, unitmangDc, unitchngNb, lotFg, qcFg, reqFg, setitemFg, useYn);
// 응답 확인
@@ -1112,34 +1115,35 @@ public class BatchService extends BaseService {
return result;
}
- // DB에서 가져온 값
- String itemCd = CommonUtils.checkNull(part.get("part_no"));
- String itemNm = CommonUtils.checkNull(part.get("part_name"));
- String acctFg = CommonUtils.checkNull(part.get("acctfg"));
- String odrFg = CommonUtils.checkNull(part.get("odrfg"));
-
- // 하드코딩 고정값
- String coCd = "1000"; // 회사코드
- String unitDc = "1"; // 단위
- String unitmangDc = "1"; // 단위관리
- int unitchngNb = 1; // 단위변환
- String lotFg = "0"; // LOT구분
- String qcFg = "0"; // 검사구분
- String reqFg = "0"; // 청구구분
- String setitemFg = "0"; // 세트품목구분
- String useYn = "1"; // 사용여부
-
- // 필수값 체크
- if (itemCd.isEmpty() || itemNm.isEmpty()) {
- result.put("success", false);
- result.put("message", "품번 또는 품명이 없습니다.");
- return result;
- }
-
- // ERP로 전송
- PartErpApiClient partErpClient = new PartErpApiClient();
- String response = partErpClient.sendPartToErp(baseUrl, coCd, itemCd, itemNm,
- acctFg, odrFg, unitDc, unitmangDc, unitchngNb, lotFg, qcFg, reqFg, setitemFg, useYn);
+ // DB에서 가져온 값
+ String itemCd = CommonUtils.checkNull(part.get("part_no"));
+ String itemNm = CommonUtils.checkNull(part.get("part_name"));
+ String acctFg = CommonUtils.checkNull(part.get("acctfg"));
+ String odrFg = CommonUtils.checkNull(part.get("odrfg"));
+ String itemDc = CommonUtils.checkNull(part.get("spec"));
+
+ // 하드코딩 고정값
+ String coCd = "1000"; // 회사코드
+ String unitDc = "1"; // 단위
+ String unitmangDc = "1"; // 단위관리
+ int unitchngNb = 1; // 단위변환
+ String lotFg = "0"; // LOT구분
+ String qcFg = "0"; // 검사구분
+ String reqFg = "0"; // 청구구분
+ String setitemFg = "0"; // 세트품목구분
+ String useYn = "1"; // 사용여부
+
+ // 필수값 체크
+ if (itemCd.isEmpty() || itemNm.isEmpty()) {
+ result.put("success", false);
+ result.put("message", "품번 또는 품명이 없습니다.");
+ return result;
+ }
+
+ // ERP로 전송
+ PartErpApiClient partErpClient = new PartErpApiClient();
+ String response = partErpClient.sendPartToErp(baseUrl, coCd, itemCd, itemNm, itemDc,
+ acctFg, odrFg, unitDc, unitmangDc, unitchngNb, lotFg, qcFg, reqFg, setitemFg, useYn);
// 응답 확인
if (response.contains("\"resultCode\":0") || response.contains("\"resultCode\":\"0\"")) {
@@ -1200,6 +1204,236 @@ public class BatchService extends BaseService {
return "0"; // 기본값: 구매
}
+
+ /*
+ // ERP에서 PART 정보 삭제 (주석처리: ERP 전송된 데이터는 삭제하면 안됨)
+ public Map deletePartFromErp(String partNo) {
+ Map result = new HashMap();
+
+ try {
+ String baseUrl = "https://erp.rps-korea.com";
+ String coCd = "1000";
+
+ if (partNo == null || partNo.trim().isEmpty()) {
+ result.put("success", false);
+ result.put("message", "품번이 없습니다.");
+ return result;
+ }
+
+ // ERP에서 삭제
+ PartErpDeleteApiClient deleteClient = new PartErpDeleteApiClient();
+ String response = deleteClient.deletePartFromErp(baseUrl, coCd, partNo);
+
+ // 응답 확인
+ if (response.contains("\"resultCode\":0") || response.contains("\"resultCode\":\"0\"")) {
+ result.put("success", true);
+ result.put("message", "PART 정보가 ERP에서 삭제되었습니다.");
+ System.out.println("ERP PART 삭제 성공: " + partNo);
+ } else {
+ result.put("success", false);
+ result.put("message", "ERP 삭제 실패: " + response);
+ System.err.println("ERP PART 삭제 실패: " + partNo + " - " + response);
+ }
+
+ } catch (Exception e) {
+ result.put("success", false);
+ result.put("message", "PART 삭제 중 오류가 발생했습니다: " + e.getMessage());
+ System.err.println("PART 삭제 오류: " + e.getMessage());
+ e.printStackTrace();
+ }
+
+ return result;
+ }
+ */
+
+ /**
+ * ERP에 PART 단건 수정
+ * @param partObjid PART OBJID
+ * @return 성공 여부 Map
+ */
+ public Map updatePartToErp(String partObjid) {
+ Map result = new HashMap();
+ SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
+
+ try {
+ String baseUrl = "https://erp.rps-korea.com";
+
+ // DB에서 PART 정보 조회
+ Map paramMap = new HashMap();
+ paramMap.put("objid", partObjid);
+ Map part = sqlSession.selectOne("partMng.selectPartByObjid", paramMap);
+
+ if (part == null) {
+ result.put("success", false);
+ result.put("message", "PART 정보를 찾을 수 없습니다.");
+ return result;
+ }
+
+ // DB에서 가져온 값
+ String itemCd = CommonUtils.checkNull(part.get("part_no"));
+ String itemNm = CommonUtils.checkNull(part.get("part_name"));
+ String acctFg = CommonUtils.checkNull(part.get("acctfg"));
+ String odrFg = CommonUtils.checkNull(part.get("odrfg"));
+ String itemDc = CommonUtils.checkNull(part.get("spec"));
+
+ // 하드코딩 고정값
+ String coCd = "1000"; // 회사코드
+ String unitDc = "1"; // 단위
+ String unitmangDc = "1"; // 단위관리
+ int unitchngNb = 1; // 단위변환
+ String lotFg = "0"; // LOT구분
+ String qcFg = "0"; // 검사구분
+ String reqFg = "0"; // 청구구분
+ String setitemFg = "0"; // 세트품목구분
+ String useYn = "1"; // 사용여부
+
+ // 필수값 체크
+ if (itemCd.isEmpty() || itemNm.isEmpty()) {
+ result.put("success", false);
+ result.put("message", "품번 또는 품명이 없습니다.");
+ return result;
+ }
+
+ // ERP로 수정 전송
+ PartErpUpdateApiClient updateClient = new PartErpUpdateApiClient();
+ String response = updateClient.updatePartToErp(baseUrl, coCd, itemCd, itemNm, itemDc,
+ acctFg, odrFg, unitDc, unitmangDc, unitchngNb, lotFg, qcFg, reqFg, setitemFg, useYn);
+
+ // 응답 확인
+ if (response.contains("\"resultCode\":0") || response.contains("\"resultCode\":\"0\"")) {
+ result.put("success", true);
+ result.put("message", "PART 정보가 ERP에서 수정되었습니다.");
+ System.out.println("ERP PART 단건 수정 성공: " + itemCd);
+ } else {
+ result.put("success", false);
+ result.put("message", "ERP 수정 실패: " + response);
+ System.err.println("ERP PART 단건 수정 실패: " + itemCd + " - " + response);
+ }
+
+ } catch (Exception e) {
+ result.put("success", false);
+ result.put("message", "PART 수정 중 오류가 발생했습니다: " + e.getMessage());
+ System.err.println("PART 단건 수정 오류: " + e.getMessage());
+ e.printStackTrace();
+ } finally {
+ sqlSession.close();
+ }
+
+ return result;
+ }
+
+ /**
+ * ERP에 모든 PART 전체 수정 (DB의 모든 release 상태 PART)
+ * @return 성공 여부 Map
+ */
+ public Map updateAllPartsToErp() {
+ Map result = new HashMap();
+ SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
+
+ try {
+ String baseUrl = "https://erp.rps-korea.com";
+
+ System.out.println("====================================");
+ System.out.println("전체 PART 정보 ERP 수정 시작");
+ System.out.println("====================================");
+
+ // DB에서 모든 release 상태 PART 조회
+ List> partList = sqlSession.selectList("partMng.selectAllPartListForErp");
+
+ if (partList == null || partList.isEmpty()) {
+ result.put("success", false);
+ result.put("message", "수정할 PART가 없습니다.");
+ return result;
+ }
+
+ System.out.println("총 " + partList.size() + "건의 PART를 ERP에 수정 전송합니다.");
+
+ int successCount = 0;
+ int failCount = 0;
+ StringBuilder errorMessages = new StringBuilder();
+
+ // 하드코딩 고정값
+ String coCd = "1000";
+ String unitDc = "1";
+ String unitmangDc = "1";
+ int unitchngNb = 1;
+ String lotFg = "0";
+ String qcFg = "0";
+ String reqFg = "0";
+ String setitemFg = "0";
+ String useYn = "1";
+
+ PartErpUpdateApiClient updateClient = new PartErpUpdateApiClient();
+
+ for (int i = 0; i < partList.size(); i++) {
+ Map part = partList.get(i);
+
+ try {
+ // DB에서 가져온 값
+ String itemCd = CommonUtils.checkNull(part.get("part_no"));
+ String itemNm = CommonUtils.checkNull(part.get("part_name"));
+ String acctFg = CommonUtils.checkNull(part.get("acctfg"));
+ String odrFg = CommonUtils.checkNull(part.get("odrfg"));
+ String itemDc = CommonUtils.checkNull(part.get("spec"));
+
+ // 100건마다 진행 상황 출력
+ if ((i + 1) % 100 == 0) {
+ System.out.println("진행 중: " + (i + 1) + "/" + partList.size() + " (성공: " + successCount + ", 실패: " + failCount + ")");
+ }
+
+ // 필수값 체크
+ if (itemCd.isEmpty() || itemNm.isEmpty()) {
+ failCount++;
+ if (failCount <= 5) {
+ errorMessages.append(itemCd).append(": 품번 또는 품명이 없습니다.\n");
+ }
+ continue;
+ }
+
+ // ERP로 수정 전송
+ String response = updateClient.updatePartToErp(baseUrl, coCd, itemCd, itemNm, itemDc,
+ acctFg, odrFg, unitDc, unitmangDc, unitchngNb, lotFg, qcFg, reqFg, setitemFg, useYn);
+
+ // 응답 확인
+ if (response.contains("\"resultCode\":0") || response.contains("\"resultCode\":\"0\"")) {
+ successCount++;
+ } else {
+ failCount++;
+ if (failCount <= 5) {
+ errorMessages.append(itemCd).append(": ").append(response).append("\n");
+ }
+ }
+
+ } catch (Exception e) {
+ failCount++;
+ if (failCount <= 5) {
+ errorMessages.append(CommonUtils.checkNull(part.get("part_no"))).append(": ")
+ .append(e.getMessage()).append("\n");
+ }
+ }
+ }
+
+ result.put("success", true);
+ result.put("message", "PART 전체 수정 완료 - 성공: " + successCount + "건, 실패: " + failCount + "건");
+ if (errorMessages.length() > 0) {
+ result.put("errors", errorMessages.toString());
+ }
+
+ System.out.println("====================================");
+ System.out.println("PART 전체 수정 완료 - 성공: " + successCount + "건, 실패: " + failCount + "건");
+ System.out.println("====================================");
+
+ } catch (Exception e) {
+ result.put("success", false);
+ result.put("message", "PART 전체 수정 중 오류가 발생했습니다: " + e.getMessage());
+ System.err.println("PART 전체 수정 오류: " + e.getMessage());
+ e.printStackTrace();
+ } finally {
+ sqlSession.close();
+ }
+
+ return result;
+ }
}