API 수정

This commit is contained in:
2026-02-09 18:21:02 +09:00
parent 14ba981675
commit 66a1f0f69f
7 changed files with 1100 additions and 44 deletions

View File

@@ -3055,8 +3055,68 @@ ORDER BY COALESCE(T.REVISION, '1.0')
SELECT
P.OBJID::VARCHAR AS CODE_ID
,P.PROJECT_NO AS CODE_NAME
,(SELECT SUPPLY_NAME FROM SUPPLY_MNG SM WHERE SM.OBJID::VARCHAR = P.CUSTOMER_OBJID) || ' ' || P.PROJECT_NO || ' ' || C.PROJECT_NAME AS PROJ_INFO
,P.REQ_DEL_DATE
,(SELECT CLIENT_NM FROM CLIENT_MNG SM WHERE 'C_' || SM.OBJID::VARCHAR = P.CUSTOMER_OBJID) || ' ' || P.PROJECT_NO AS PROJ_INFO
,P.DUE_DATE
FROM PROJECT_MGMT P
INNER JOIN CONTRACT_MGMT C
ON C.OBJID = P.CONTRACT_OBJID
LEFT OUTER JOIN (
SELECT
T.CONTRACT_OBJID,
CASE
WHEN COUNT(CASE WHEN PARENT_OBJID IS NOT NULL AND PARENT_OBJID != '' THEN 1 END) = 0 THEN 0
ELSE ROUND((
COUNT(CASE WHEN SETUP_ACT_END != '' AND SETUP_ACT_END IS NOT NULL AND PARENT_OBJID IS NOT NULL AND PARENT_OBJID != '' THEN 1 END)::FLOAT
/
COUNT(CASE WHEN PARENT_OBJID IS NOT NULL AND PARENT_OBJID != '' THEN 1 END)
* 100
)::numeric, 1)
END AS SETUP_RATETOTAL
FROM
SETUP_WBS_TASK T
GROUP BY
T.CONTRACT_OBJID
) ST ON ST.CONTRACT_OBJID = P.OBJID
LEFT OUTER JOIN (
SELECT
CONTRACT_OBJID,
COUNT(CASE WHEN DESIGN_act_start IS NOT NULL AND DESIGN_act_start!='' THEN 1 END) AS DESIGN_START_COUNT
FROM
PMS_WBS_TASK
GROUP BY
CONTRACT_OBJID
) WT ON WT.CONTRACT_OBJID = P.OBJID
WHERE (C.CONTRACT_RESULT = '0000964' or C.CONTRACT_RESULT = '0000968')
<if test="SEARCH_PROJECT_YEAR != null and SEARCH_PROJECT_YEAR !=''">
<!-- AND #{SEARCH_PROJECT_YEAR} BETWEEN
(SELECT
LEAST(
MIN(TO_CHAR(TO_DATE(NULLIF(PURCHASE_PLAN_START, ''), 'YYYY'), 'YYYY')),
MIN(TO_CHAR(TO_DATE(NULLIF(PRODUCE_PLAN_START , ''), 'YYYY'), 'YYYY')),
MIN(TO_CHAR(TO_DATE(NULLIF(DESIGN_PLAN_START , ''), 'YYYY'), 'YYYY')),
MIN(TO_CHAR(TO_DATE(NULLIF(SETUP_PLAN_START , ''), 'YYYY'), 'YYYY'))
)
FROM PMS_WBS_TASK O
WHERE O.CONTRACT_OBJID=P.OBJID)
AND (SELECT
GREATEST(
MAX(TO_CHAR(TO_DATE(NULLIF(PURCHASE_PLAN_END, ''), 'YYYY'), 'YYYY')),
MAX(TO_CHAR(TO_DATE(NULLIF(PRODUCE_PLAN_END , ''), 'YYYY'), 'YYYY')),
MAX(TO_CHAR(TO_DATE(NULLIF(DESIGN_PLAN_END , ''), 'YYYY'), 'YYYY')),
MAX(TO_CHAR(TO_DATE(NULLIF(SETUP_PLAN_END , ''), 'YYYY'), 'YYYY'))
)
FROM PMS_WBS_TASK O
WHERE O.CONTRACT_OBJID=P.OBJID) -->
</if>
ORDER BY SUBSTRING(P.PROJECT_NO,POSITION('-' IN P.PROJECT_NO)+1) DESC
</select>
<select id="getProgressProjectNoList_old" parameterType="map" resultType="map">
SELECT
P.OBJID::VARCHAR AS CODE_ID
,P.PROJECT_NO AS CODE_NAME
,(SELECT CLIENT_NM FROM CLIENT_MNG SM WHERE 'C_' || SM.OBJID::VARCHAR = P.CUSTOMER_OBJID) || ' ' || P.PROJECT_NO AS PROJ_INFO
,P.DUE_DATE
FROM PROJECT_MGMT P
INNER JOIN CONTRACT_MGMT C
ON C.OBJID = P.CONTRACT_OBJID
@@ -3117,7 +3177,7 @@ ORDER BY COALESCE(T.REVISION, '1.0')
-->
ORDER BY SUBSTRING(P.PROJECT_NO,POSITION('-' IN P.PROJECT_NO)+1) DESC
</select>
<!-- //유저 ID 조회 -->
<select id="getUserInfo" resultType="map" parameterType="map">
SELECT

View File

@@ -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 ? '<pre style="text-align:left;max-height:200px;overflow-y:auto;">' + data.errors + '</pre>' : 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 삭제 중 오류가 발생했습니다.'
});
}
});
}
});
}
*/
</script>
</head>
<body class="backcolor">
@@ -550,11 +763,14 @@ String connector = person.getUserId();
<!--
<input type="button" value="삭제" class="plm_btns" id="btnDelete">
-->
<input type="button" value="도면 다중 업로드" class="plm_btns" id="btnDrawingUpload">
<input type="button" value="조회" class="plm_btns" id="btnSearch">
<input type="button" value="Excel Download" class="plm_btns excelIcon" id="btnExcel">
<input type="button" value="ERP 전송" class="plm_btns" id="btnSendErp" style="background-color:#4CAF50;color:white;">
<input type="file" id="drawingFiles" multiple style="display:none;" accept=".stp,.step,.dwg,.dxf,.pdf">
<input type="button" value="도면 다중 업로드" class="plm_btns" id="btnDrawingUpload">
<input type="button" value="조회" class="plm_btns" id="btnSearch">
<input type="button" value="Excel Download" class="plm_btns excelIcon" id="btnExcel">
<input type="button" value="ERP 전송" class="plm_btns" id="btnSendErp" style="background-color:#4CAF50;color:white;">
<input type="button" value="ERP 단건 수정" class="plm_btns" id="btnUpdateSingleErp" style="background-color:#2196F3;color:white;">
<input type="button" value="ERP 전체 수정" class="plm_btns" id="btnUpdateAllErp" style="background-color:#1976D2;color:white;">
<!-- <input type="button" value="ERP 삭제" class="plm_btns" id="btnDeleteErp" style="background-color:#f44336;color:white;"> -->
<input type="file" id="drawingFiles" multiple style="display:none;" accept=".stp,.step,.dwg,.dxf,.pdf">
</div>
</div>
<div id="plmSearchZon">

View File

@@ -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("\"");

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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<String, Object> deletePartFromErp(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
Map<String, Object> resultMap = new HashMap<String, Object>();
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<String, Object> updatePartToErp(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
Map<String, Object> resultMap = new HashMap<String, Object>();
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<String, Object> updateAllPartsToErp(HttpServletRequest request) {
Map<String, Object> resultMap = new HashMap<String, Object>();
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;
}
}

View File

@@ -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<String, Object> deletePartFromErp(String partNo) {
Map<String, Object> result = new HashMap<String, Object>();
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<String, Object> updatePartToErp(String partObjid) {
Map<String, Object> result = new HashMap<String, Object>();
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
try {
String baseUrl = "https://erp.rps-korea.com";
// DB에서 PART 정보 조회
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("objid", partObjid);
Map<String, Object> 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<String, Object> updateAllPartsToErp() {
Map<String, Object> result = new HashMap<String, Object>();
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<Map<String, Object>> 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<String, Object> 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;
}
}