From 58319f620f20dd7023bff926fa64a54e514341e1 Mon Sep 17 00:00:00 2001 From: itfirst Date: Fri, 22 May 2026 23:54:45 +0900 Subject: [PATCH 01/18] Update Jenkinsfile --- Jenkinsfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index d9f98f0..e4245b6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -11,7 +11,7 @@ pipeline { // 앱 정보 APP_NAME = 'gcone_batch' - TOMCAT_HOME = '/usr/local/tomcat' + TOMCAT_HOME = '/usr/local/tomcat_dev' DEPLOY_PATH = "${TOMCAT_HOME}/webapps" BACKUP_PATH = "${TOMCAT_HOME}/backup" DEPLOY_FILE = "${TOMCAT_HOME}/webapps/${APP_NAME}.war" @@ -24,7 +24,7 @@ pipeline { stages { stage('Checkout') { steps { - git branch: 'master', + git branch: 'dev', credentialsId: 'itfirst', url: 'http://115.68.207.90:3000/itfirst/sake_batch.git' } @@ -90,7 +90,7 @@ pipeline { post { success { - echo '✅ sake_batch 배포 완료' + echo '✅ sake_batch 개발 배포 완료' } failure { script { @@ -112,7 +112,7 @@ pipeline { fi """ } - echo '❌ 배포 실패 - 롤백 처리됨' + echo '❌ 게빌 배포 실패 - 롤백 처리됨' } } } From 933a7e65e46ea78ba89c3b0f2de60d8218873593 Mon Sep 17 00:00:00 2001 From: itfirst Date: Fri, 22 May 2026 23:56:24 +0900 Subject: [PATCH 02/18] Update src/main/resources/server: port: 18211 spring: main: allow-bean-definition-overriding: true datasource: defaultdatasource: jdbc-url: jdbc:mysql:/10.2.3.97:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQuer --- src/main/resources/application-dev.yaml | 133 ------------------ .../Seoul&autoReconnect=true&allowMultiQuer | 32 +++++ 2 files changed, 32 insertions(+), 133 deletions(-) delete mode 100644 src/main/resources/application-dev.yaml create mode 100644 src/main/resources/server: port: 18211 spring: main: allow-bean-definition-overriding: true datasource: defaultdatasource: jdbc-url: jdbc:mysql:/10.2.3.97:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQuer diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml deleted file mode 100644 index 1deb63c..0000000 --- a/src/main/resources/application-dev.yaml +++ /dev/null @@ -1,133 +0,0 @@ -server: - port: 18210 - - -spring: - security: - oauth2: - resourceserver: - jwt: - issuer-uri: http://172.31.21.12:18320/realms/ADMIN - main: - allow-bean-definition-overriding: true - datasource: - defaultdatasource: - jdbc-url: jdbc:mysql://10.2.1.101:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQueries=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=false&verifyServerCertificate=false - driver-class-name: com.mysql.cj.jdbc.Driver - username: sakeone - password: dnlfxjtm13@$ - gconedatasource: - jdbc-url: jdbc:mysql://10.2.1.101:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQueries=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=false&verifyServerCertificate=false - driver-class-name: com.mysql.cj.jdbc.Driver - username: sakeone - password: dnlfxjtm13@$ - crmdatasource: - jdbc-url: jdbc:mysql://10.2.1.101:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQueries=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=false&verifyServerCertificate=false - driver-class-name: com.mysql.cj.jdbc.Driver - username: sakeone - password: dnlfxjtm13@$ - mqdatasource: - jdbc-url: jdbc:mysql://10.2.1.101:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQueries=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=false&verifyServerCertificate=false - driver-class-name: com.mysql.cj.jdbc.Driver - username: sakeone - password: dnlfxjtm13@$ - suredatasource: - jdbc-url: jdbc:mysql://10.2.1.101:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQueries=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=false&verifyServerCertificate=false - driver-class-name: com.mysql.cj.jdbc.Driver - username: sakeone - password: dnlfxjtm13@$ - batch: - job: - enabled: true - mybatis: - mapper-locations: classpath*:mybatis/xml/mapper/**/*.xml - config-location: classpath:/mybatis/xml/config/mapper-config.xml - -logging: - level: - org.springframework.web: debug - org.springframework.security: debug - org.springframework.security.oauth2: debug - com.wb.domainserver: debug - root: info - -#Resource-server-url -url: - resource: - server: - gconebo: http://127.0.0.1:18500 #로컬로 돌릴때 -# gconebo: http://127.0.0.1:18500 #개발서버 ip - reviewbo: http://127.0.0.1:18220 - -pagination: - page-unit: 10 - page-size: 10 - - -# 스윗트래커 url, api key -parcel: - trackApiUrl: https://info.sweettracker.co.kr - trackApiKey: R0sYxkD9vCxSXPKpStOY2w - -# 네이버 스마트스토어 api key -smartstore: - sopmal: - stores: - #참다한홍삼 - CH: - clientId: 48f8YgF04wTnge6taw9bsM - clientSecret: $2a$04$9Lfn5as5Vv/ZW5PAoKBBr. - -#스마트 스토어 api url -smartstoreurl: - tokenurl: https://api.commerce.naver.com/external/v1/oauth2/token - orderlisturl: https://api.commerce.naver.com/external/v1/pay-order/seller/product-orders/last-changed-statuses - orderdetailurl : https://api.commerce.naver.com/external/v1/pay-order/seller/product-orders/query - - -#슈어엠 법인별 정보 -surem: - sopmal: - #참다한홍삼 - CH: - code: GC - data: (주)지씨바이오 - erpcode: 01 - userid: gcbio02 - deptcode: KT-26E-ZS - yellowkey: cd51453ccf40ef714cadd5a7dd0506cd7340a986 - - -#GC EP 파일 저장 경로 -ep: - common: - fileupload: - uploaddirs: - path: /data/gcone/otrFile - naver: naver_third - google: googleEpXmlData - meta: metaEpXmlData - mobion: mobionEpXmlData - extensions: - xml: .xml - txt: .txt - cdnurl: http://img.groupit.co.kr - -secret: - key: 1df5be2f7e90ae36 - -mail: - host: 10.2.1.76 - port: 25 - -# SyncPos 요청경로 -pos: - syncpos: - url: https://smart.easypos.net - uri: /servlet/EasyPosChannelSVL?cmd=TlxSyncHanamCMD -#kakao REST-API test key(AF-T 키임) -kakao: - restApi-key: "5376f8866ab47cc78095e00c00d00c3f" - -#선물하기 URL -presenturl : dev.svc.gcone.co.kr \ No newline at end of file diff --git a/src/main/resources/server: port: 18211 spring: main: allow-bean-definition-overriding: true datasource: defaultdatasource: jdbc-url: jdbc:mysql:/10.2.3.97:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQuer b/src/main/resources/server: port: 18211 spring: main: allow-bean-definition-overriding: true datasource: defaultdatasource: jdbc-url: jdbc:mysql:/10.2.3.97:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQuer new file mode 100644 index 0000000..2af5716 --- /dev/null +++ b/src/main/resources/server: port: 18211 spring: main: allow-bean-definition-overriding: true datasource: defaultdatasource: jdbc-url: jdbc:mysql:/10.2.3.97:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQuer @@ -0,0 +1,32 @@ +server: + port: 18211 +spring: + main: + allow-bean-definition-overriding: true + datasource: + defaultdatasource: + jdbc-url: jdbc:mysql://10.2.3.97:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQueries=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=false&verifyServerCertificate=false + driver-class-name: com.mysql.cj.jdbc.Driver + username: sakeone + password: dnlfxjtm13@$ + batch: + job: + enabled: false + mybatis: + mapper-locations: classpath*:mybatis/xml/mapper/**/*.xml + config-location: classpath:/mybatis/xml/config/mapper-config.xml +logging: + level: + org.springframework.web: debug + org.springframework.security: debug + com.wb.domainserver: debug + root: info +url: + resource: + server: + gconebo: http://10.2.0.129:18500 +secret: + key: 1df5be2f7e90ae36 +mail: + host: 10.2.1.76 + port: 25 \ No newline at end of file From 7a3484cdcf94553dc4b97535a2e28c327dd6ad6d Mon Sep 17 00:00:00 2001 From: itfirst Date: Sat, 23 May 2026 00:06:28 +0900 Subject: [PATCH 03/18] =?UTF-8?q?fix:=20=EC=9E=98=EB=AA=BB=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=EB=90=9C=20=ED=8C=8C=EC=9D=BC=EB=AA=85=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EB=B0=8F=20application-dev.yaml=20=EC=9E=AC?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...l&autoReconnect=true&allowMultiQuer => application-dev.yaml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/main/resources/{server: port: 18211 spring: main: allow-bean-definition-overriding: true datasource: defaultdatasource: jdbc-url: jdbc:mysql:/10.2.3.97:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQuer => application-dev.yaml} (98%) diff --git a/src/main/resources/server: port: 18211 spring: main: allow-bean-definition-overriding: true datasource: defaultdatasource: jdbc-url: jdbc:mysql:/10.2.3.97:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQuer b/src/main/resources/application-dev.yaml similarity index 98% rename from src/main/resources/server: port: 18211 spring: main: allow-bean-definition-overriding: true datasource: defaultdatasource: jdbc-url: jdbc:mysql:/10.2.3.97:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQuer rename to src/main/resources/application-dev.yaml index 2af5716..74f42b5 100644 --- a/src/main/resources/server: port: 18211 spring: main: allow-bean-definition-overriding: true datasource: defaultdatasource: jdbc-url: jdbc:mysql:/10.2.3.97:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQuer +++ b/src/main/resources/application-dev.yaml @@ -29,4 +29,4 @@ secret: key: 1df5be2f7e90ae36 mail: host: 10.2.1.76 - port: 25 \ No newline at end of file + port: 25 From d7cc157171381b5a78a6edbb468f0d19ba799299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=9D=BC?= Date: Sat, 23 May 2026 03:33:28 +0900 Subject: [PATCH 04/18] =?UTF-8?q?feat:=20ACIKey=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EB=B0=9C=EA=B8=89=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=B0=B0?= =?UTF-8?q?=EC=B9=98=20=EC=B6=94=EA=B0=80=20(TASK=5FBATCH=5FACIKEY)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - acikey 패키지 신규 생성 - AciKeyTokenJobConfig.java: Job/Step 설정 - AciKeyTokenTasklet.java: API 호출 및 토큰 확인 로직 - application-dev.yaml: acikey 설정값 추가 (url/userid/apikey) --- .../acikey/AciKeyTokenJobConfig.java | 35 ++++++++ .../acikey/AciKeyTokenTasklet.java | 79 +++++++++++++++++++ src/main/resources/application-dev.yaml | 5 ++ 3 files changed, 119 insertions(+) create mode 100644 src/main/java/com/wb/domainserver/acikey/AciKeyTokenJobConfig.java create mode 100644 src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java diff --git a/src/main/java/com/wb/domainserver/acikey/AciKeyTokenJobConfig.java b/src/main/java/com/wb/domainserver/acikey/AciKeyTokenJobConfig.java new file mode 100644 index 0000000..e7e2da3 --- /dev/null +++ b/src/main/java/com/wb/domainserver/acikey/AciKeyTokenJobConfig.java @@ -0,0 +1,35 @@ +package com.wb.domainserver.acikey; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.PlatformTransactionManager; +import lombok.RequiredArgsConstructor; + +// ACIKey 토큰 발급 테스트 배치 - Job/Step 설정 +@Configuration +@RequiredArgsConstructor +public class AciKeyTokenJobConfig { + + private final JobRepository jobRepository; + private final PlatformTransactionManager transactionManager; + private final AciKeyTokenTasklet aciKeyTokenTasklet; + + @Bean + public Job aciKeyTokenJob() { + return new JobBuilder("aciKeyTokenJob", jobRepository) + .start(aciKeyTokenStep()) + .build(); + } + + @Bean + public Step aciKeyTokenStep() { + return new StepBuilder("aciKeyTokenStep", jobRepository) + .tasklet(aciKeyTokenTasklet, transactionManager) + .build(); + } +} diff --git a/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java b/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java new file mode 100644 index 0000000..7a773ed --- /dev/null +++ b/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java @@ -0,0 +1,79 @@ +package com.wb.domainserver.acikey; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.*; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +// ACIKey 토큰 발급 테스트 배치 - API 호출 및 토큰 확인 로직 +@Slf4j +@Component +public class AciKeyTokenTasklet implements Tasklet { + + @Value("${acikey.url}") + private String aciKeyUrl; + + @Value("${acikey.userid}") + private String userId; + + @Value("${acikey.apikey}") + private String apiKey; + + @Override + public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) { + + log.info("[AciKeyBatch] 배치 시작"); + log.info("[AciKeyBatch] API URL: {}", aciKeyUrl); + + try { + // Header 설정 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("USERID", userId); + headers.set("APIKEY", apiKey); + + HttpEntity requestEntity = new HttpEntity<>("{}", headers); + + // API 호출 + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity response = restTemplate.exchange( + aciKeyUrl, + HttpMethod.POST, + requestEntity, + Map.class + ); + + Map body = response.getBody(); + log.info("[AciKeyBatch] 응답 전체: {}", body); + + String status = (String) body.get("Status"); + String aciKey = (String) body.get("ACIKey"); + String errMsg = (String) body.get("ErrMsg"); + + if ("A10".equals(status)) { + log.info("[AciKeyBatch] ✅ 토큰 발급 성공!"); + log.info("[AciKeyBatch] ACIKey: {}", aciKey); + contribution.incrementWriteCount(1); + } else { + log.error("[AciKeyBatch] ❌ 토큰 발급 실패. Status: {}, ErrMsg: {}", status, errMsg); + throw new RuntimeException("ACIKey 토큰 발급 실패. Status: " + status + ", ErrMsg: " + errMsg); + } + + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + log.error("[AciKeyBatch] ❌ API 호출 중 오류 발생: {}", e.getMessage(), e); + throw new RuntimeException("AciKey API 호출 오류", e); + } + + log.info("[AciKeyBatch] 배치 종료"); + return RepeatStatus.FINISHED; + } +} diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index 74f42b5..8b5558b 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -30,3 +30,8 @@ secret: mail: host: 10.2.1.76 port: 25 + +acikey: + url: https://acieshop.com/api/kr/token/ + userid: UNIHAN + apikey: DC94F29AFD5399F54AAE7FAA46045B65 From 34acf68408cc82c13609e824f5d967f9f1d65064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=9D=BC?= Date: Sat, 23 May 2026 10:10:29 +0900 Subject: [PATCH 05/18] =?UTF-8?q?refactor:=20BatchServerConfig=20Keycloak/?= =?UTF-8?q?OAuth2=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0,=20=EB=8B=A8?= =?UTF-8?q?=EC=88=9C=20permitAll=20=EC=84=A4=EC=A0=95=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/config/BatchServerConfig.java | 87 ------------------- 1 file changed, 87 deletions(-) diff --git a/src/main/java/com/wb/domainserver/security/config/BatchServerConfig.java b/src/main/java/com/wb/domainserver/security/config/BatchServerConfig.java index 201ef3e..f7d77a7 100644 --- a/src/main/java/com/wb/domainserver/security/config/BatchServerConfig.java +++ b/src/main/java/com/wb/domainserver/security/config/BatchServerConfig.java @@ -1,56 +1,15 @@ package com.wb.domainserver.security.config; -import com.nimbusds.jwt.JWT; -import com.nimbusds.jwt.JWTParser; -import com.wb.domainserver.security.authentication.CustomAuthenticationEntryPoint; -import com.wb.domainserver.security.authentication.MemberJwtAuthenticationConverter; -import com.wb.domainserver.security.authorization.WnbtAuthorizationManager; -import jakarta.servlet.http.HttpServletRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.aop.Advisor; -import org.springframework.aop.support.JdkRegexpMethodPointcut; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Role; -import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor; -import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.oauth2.jwt.JwtDecoder; -import org.springframework.security.oauth2.jwt.JwtDecoders; -import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; -import org.springframework.util.StringUtils; - -import java.text.ParseException; - -import static org.springframework.beans.factory.config.BeanDefinition.ROLE_INFRASTRUCTURE; @EnableWebSecurity @Configuration -@EnableMethodSecurity public class BatchServerConfig { - private static final Logger logger = LoggerFactory.getLogger(BatchServerConfig.class); - - @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}") - String issuerUri; - - @Autowired - private CustomAuthenticationEntryPoint authenticationEntryPoint; - - @Bean - @Role(ROLE_INFRASTRUCTURE) - public Advisor authorizationManagerBeforeMethodInterception(WnbtAuthorizationManager authorizationManager) { - JdkRegexpMethodPointcut pattern = new JdkRegexpMethodPointcut(); - pattern.setPattern("com.wb.domainserver.*.controller.*"); - return new AuthorizationManagerBeforeMethodInterceptor(pattern, authorizationManager); - } @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { @@ -58,53 +17,7 @@ public class BatchServerConfig { .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests(authorize -> authorize .anyRequest().permitAll() - ) - .oauth2ResourceServer(oauth2 -> oauth2 - .jwt(jwt -> jwt - .decoder(jwtDecoder()) - .jwtAuthenticationConverter(new MemberJwtAuthenticationConverter()) - ) - .bearerTokenResolver(this::customBearerTokenResolver) - - ) - .exceptionHandling(exceptions -> exceptions - .authenticationEntryPoint(authenticationEntryPoint) ); - return http.build(); } - - private String customBearerTokenResolver(HttpServletRequest request) { - String authorization = request.getHeader("Authorization"); - if (StringUtils.hasText(authorization) && authorization.startsWith("Bearer ")) { - return authorization.substring(7); - } - return null; - } - - @Bean - public JwtDecoder jwtDecoder() { - return token -> { - String issuerUri = determineIssuerUri(); - logger.debug("Determined issuerUri: {}", issuerUri); - JWT jwt = null; - try { - jwt = JWTParser.parse(token); - logger.debug("Token issuer: {}", jwt.getJWTClaimsSet().getIssuer()); - } catch (ParseException e) { - throw new RuntimeException(e); - } - NimbusJwtDecoder jwtDecoder = JwtDecoders.fromOidcIssuerLocation(issuerUri); - return jwtDecoder.decode(token); - }; - } - - private String determineIssuerUri() { - return String.format(issuerUri); - } - - @Bean - public BCryptPasswordEncoder bCryptPasswordEncoder() { - return new BCryptPasswordEncoder(); - } } From 14f90c8d4bbfff342e31d9c543c5552e778d7439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=9D=BC?= Date: Sat, 23 May 2026 10:21:12 +0900 Subject: [PATCH 06/18] =?UTF-8?q?fix:=20application-dev.yaml=20gconedataso?= =?UTF-8?q?urce=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80=20(GconeSourceCo?= =?UTF-8?q?nfig=20JobRepository=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=ED=95=B4=EA=B2=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index 8b5558b..43279ed 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -9,6 +9,11 @@ spring: driver-class-name: com.mysql.cj.jdbc.Driver username: sakeone password: dnlfxjtm13@$ + gconedatasource: + jdbc-url: jdbc:mysql://10.2.3.97:3306/sake?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&autoReconnect=true&allowMultiQueries=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=false&verifyServerCertificate=false + driver-class-name: com.mysql.cj.jdbc.Driver + username: sakeone + password: dnlfxjtm13@$ batch: job: enabled: false @@ -34,4 +39,4 @@ mail: acikey: url: https://acieshop.com/api/kr/token/ userid: UNIHAN - apikey: DC94F29AFD5399F54AAE7FAA46045B65 + apikey: DC94F29AFD5399F54AAE7FAA46045B65 \ No newline at end of file From 1d9c29f7bcc4a9475b059276a7eee883b66e96c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=9D=BC?= Date: Sat, 23 May 2026 10:23:49 +0900 Subject: [PATCH 07/18] =?UTF-8?q?fix:=20application-dev.yaml=20reviewbo=20?= =?UTF-8?q?URL=20=EC=B6=94=EA=B0=80=20(RESRC=5FURL=20=ED=94=8C=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=ED=99=80=EB=8D=94=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index 43279ed..18aaa3d 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -30,6 +30,7 @@ url: resource: server: gconebo: http://10.2.0.129:18500 + reviewbo: http://127.0.0.1:18220 secret: key: 1df5be2f7e90ae36 mail: From 01471c650e296f58e060be5570715d33e28e9531 Mon Sep 17 00:00:00 2001 From: itfirst Date: Sat, 23 May 2026 10:37:29 +0900 Subject: [PATCH 08/18] Update src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java --- .../java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java b/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java index 7a773ed..a1372f8 100644 --- a/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java +++ b/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java @@ -57,7 +57,7 @@ public class AciKeyTokenTasklet implements Tasklet { String aciKey = (String) body.get("ACIKey"); String errMsg = (String) body.get("ErrMsg"); - if ("A10".equals(status)) { + if ("success".equals(status)) { log.info("[AciKeyBatch] ✅ 토큰 발급 성공!"); log.info("[AciKeyBatch] ACIKey: {}", aciKey); contribution.incrementWriteCount(1); @@ -76,4 +76,4 @@ public class AciKeyTokenTasklet implements Tasklet { log.info("[AciKeyBatch] 배치 종료"); return RepeatStatus.FINISHED; } -} +} From c4ac3c8cf1ef8ce9e70993e2be0123e9e48cd065 Mon Sep 17 00:00:00 2001 From: itfirst Date: Sat, 23 May 2026 11:01:35 +0900 Subject: [PATCH 09/18] Update src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java --- .../com/wb/domainserver/acikey/AciKeyTokenTasklet.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java b/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java index a1372f8..52b7fc6 100644 --- a/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java +++ b/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java @@ -10,6 +10,7 @@ import org.springframework.http.*; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; +import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Map; // ACIKey 토큰 발급 테스트 배치 - API 호출 및 토큰 확인 로직 @@ -42,15 +43,16 @@ public class AciKeyTokenTasklet implements Tasklet { HttpEntity requestEntity = new HttpEntity<>("{}", headers); // API 호출 - RestTemplate restTemplate = new RestTemplate(); - ResponseEntity response = restTemplate.exchange( + ResponseEntity response = restTemplate.exchange( aciKeyUrl, HttpMethod.POST, requestEntity, - Map.class + String.class ); - Map body = response.getBody(); + ObjectMapper objectMapper = new ObjectMapper(); + Map body = objectMapper.readValue(response.getBody(), Map.class); + log.info("[AciKeyBatch] 응답 전체: {}", body); String status = (String) body.get("Status"); From f46f0ad5974da4775f4d93ea47d655681bd8532e Mon Sep 17 00:00:00 2001 From: itfirst Date: Sat, 23 May 2026 11:08:00 +0900 Subject: [PATCH 10/18] Update src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java --- src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java b/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java index 52b7fc6..df24b66 100644 --- a/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java +++ b/src/main/java/com/wb/domainserver/acikey/AciKeyTokenTasklet.java @@ -43,6 +43,7 @@ public class AciKeyTokenTasklet implements Tasklet { HttpEntity requestEntity = new HttpEntity<>("{}", headers); // API 호출 + RestTemplate restTemplate = new RestTemplate(); ResponseEntity response = restTemplate.exchange( aciKeyUrl, HttpMethod.POST, From 0bf03de005966b64dad7a7506879b0f8d2faea9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=9D=BC?= Date: Sat, 23 May 2026 11:17:18 +0900 Subject: [PATCH 11/18] =?UTF-8?q?fix:=20Spring=20Batch=20MySQL=20=EC=8B=9C?= =?UTF-8?q?=ED=80=80=EC=8A=A4=20=EC=B1=84=EB=B2=88=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(BATCH=5FJOB=5FINSTANCE=20Duplicate=20entr?= =?UTF-8?q?y=200)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GconeSourceConfig.jobRepository: setDatabaseType(MYSQL) 추가 - application-dev.yaml: spring.batch.jdbc.initialize-schema=always 추가 (BATCH_JOB_SEQ 등 시퀀스 테이블 자동 생성) --- .../wb/domainserver/common/config/GconeSourceConfig.java | 7 +++---- src/main/resources/application-dev.yaml | 2 ++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/wb/domainserver/common/config/GconeSourceConfig.java b/src/main/java/com/wb/domainserver/common/config/GconeSourceConfig.java index 0b52ebd..1ac6914 100644 --- a/src/main/java/com/wb/domainserver/common/config/GconeSourceConfig.java +++ b/src/main/java/com/wb/domainserver/common/config/GconeSourceConfig.java @@ -62,13 +62,12 @@ public class GconeSourceConfig { } @Bean - public JobRepository jobRepository( @Qualifier("gconeTransactionManager") PlatformTransactionManager transactionManager, @Qualifier("gconeDataSource") DataSource gconeDataSource) throws Exception { + public JobRepository jobRepository(@Qualifier("gconeTransactionManager") PlatformTransactionManager transactionManager, @Qualifier("gconeDataSource") DataSource gconeDataSource) throws Exception { JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean(); factory.setDataSource(gconeDataSource); factory.setTransactionManager(transactionManager); + factory.setDatabaseType("MYSQL"); factory.afterPropertiesSet(); return factory.getObject(); } -} - - +} \ No newline at end of file diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index 18aaa3d..a1c12ba 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -15,6 +15,8 @@ spring: username: sakeone password: dnlfxjtm13@$ batch: + jdbc: + initialize-schema: always job: enabled: false mybatis: From 6cbdc36c710bcaa06612650b45cbd1ece667ebf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=9D=BC?= Date: Sat, 23 May 2026 11:24:12 +0900 Subject: [PATCH 12/18] =?UTF-8?q?fix:=20GconeSourceConfig=20=EB=B0=B0?= =?UTF-8?q?=EC=B9=98=20=EC=8A=A4=ED=82=A4=EB=A7=88=20=EC=B4=88=EA=B8=B0?= =?UTF-8?q?=ED=99=94=20=EC=B6=94=EA=B0=80=20(BATCH=5FJOB=5FSEQ=20=EC=8B=9C?= =?UTF-8?q?=ED=80=80=EC=8A=A4=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=20=EC=83=9D=EC=84=B1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - batchSchemaInitializer 빈 추가: schema-drop-mysql.sql + schema-mysql.sql 실행 - jobRepository에 @DependsOn(batchSchemaInitializer) 추가하여 초기화 순서 보장 - spring.batch.jdbc.initialize-schema 미적용 우회 (커스텀 JobRepository 빈 충돌) --- .../common/config/GconeSourceConfig.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/com/wb/domainserver/common/config/GconeSourceConfig.java b/src/main/java/com/wb/domainserver/common/config/GconeSourceConfig.java index 1ac6914..989c16c 100644 --- a/src/main/java/com/wb/domainserver/common/config/GconeSourceConfig.java +++ b/src/main/java/com/wb/domainserver/common/config/GconeSourceConfig.java @@ -10,9 +10,13 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Primary; +import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.jdbc.datasource.init.DataSourceInitializer; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; @@ -61,7 +65,21 @@ public class GconeSourceConfig { return new DataSourceTransactionManager(gconeDataSource); } + // Spring Batch 스키마 초기화 (BATCH_JOB_SEQ 등 시퀀스 테이블 생성) + @Bean(name = "batchSchemaInitializer") + public DataSourceInitializer batchSchemaInitializer(@Qualifier("gconeDataSource") DataSource gconeDataSource) { + ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); + populator.addScript(new ClassPathResource("org/springframework/batch/core/schema-drop-mysql.sql")); + populator.addScript(new ClassPathResource("org/springframework/batch/core/schema-mysql.sql")); + populator.setContinueOnError(true); + DataSourceInitializer initializer = new DataSourceInitializer(); + initializer.setDataSource(gconeDataSource); + initializer.setDatabasePopulator(populator); + return initializer; + } + @Bean + @DependsOn("batchSchemaInitializer") public JobRepository jobRepository(@Qualifier("gconeTransactionManager") PlatformTransactionManager transactionManager, @Qualifier("gconeDataSource") DataSource gconeDataSource) throws Exception { JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean(); factory.setDataSource(gconeDataSource); From c9f2843a10e5616b3ed69a859d4a94d9c196d5b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=9D=BC?= Date: Sun, 24 May 2026 21:17:56 +0900 Subject: [PATCH 13/18] =?UTF-8?q?[TASK=5FBATCH=5FACIDLIVY]=20ACI=20?= =?UTF-8?q?=EB=B0=B0=EC=86=A1=EC=9E=90=EB=A3=8C=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EB=B0=8F=20=EC=B6=9C=EA=B3=A0=EC=B2=98=EB=A6=AC=20=EB=B0=B0?= =?UTF-8?q?=EC=B9=98=20=EC=8B=A0=EA=B7=9C=20=EC=83=9D=EC=84=B1=20-=20AciDl?= =?UTF-8?q?ivyJobConfig/Tasklet/Mapper/VO=20=EC=83=9D=EC=84=B1,=20applicat?= =?UTF-8?q?ion-dev.yaml=20aci.dlivy.api-url=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shell/aciDlivyJob_run.sh | 34 ++ .../acidlivy/AciDlivyJobConfig.java | 35 ++ .../domainserver/acidlivy/AciDlivyMapper.java | 51 +++ .../acidlivy/AciDlivyOrderVO.java | 26 ++ .../acidlivy/AciDlivyTasklet.java | 263 +++++++++++++ .../wb/domainserver/acidlivy/AciDlivyVO.java | 14 + src/main/resources/application-dev.yaml | 5 +- .../xml/mapper/acidlivy/AciDlivyMapper.xml | 356 ++++++++++++++++++ 8 files changed, 783 insertions(+), 1 deletion(-) create mode 100755 shell/aciDlivyJob_run.sh create mode 100644 src/main/java/com/wb/domainserver/acidlivy/AciDlivyJobConfig.java create mode 100644 src/main/java/com/wb/domainserver/acidlivy/AciDlivyMapper.java create mode 100644 src/main/java/com/wb/domainserver/acidlivy/AciDlivyOrderVO.java create mode 100644 src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java create mode 100644 src/main/java/com/wb/domainserver/acidlivy/AciDlivyVO.java create mode 100644 src/main/resources/mybatis/xml/mapper/acidlivy/AciDlivyMapper.xml diff --git a/shell/aciDlivyJob_run.sh b/shell/aciDlivyJob_run.sh new file mode 100755 index 0000000..de6d7d1 --- /dev/null +++ b/shell/aciDlivyJob_run.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +JOB_NAME="aciDlivyJob" +HOST="10.2.1.76" +PORT="18211" + +LOG_DIR="/home/batch_shell/logs" +LOG_FILE="${LOG_DIR}/${JOB_NAME}_$(date +%Y%m%d).log" + +mkdir -p ${LOG_DIR} + +TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') +echo "[${TIMESTAMP}] ===== ${JOB_NAME} 실행 시작 =====" >> ${LOG_FILE} + +HTTP_CODE=$(curl -s -o /tmp/${JOB_NAME}_resp.tmp -w "%{http_code}" \ + -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" \ + -H "Content-Type: application/json") + +BODY=$(cat /tmp/${JOB_NAME}_resp.tmp 2>/dev/null) +rm -f /tmp/${JOB_NAME}_resp.tmp + +TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') +echo "[${TIMESTAMP}] HTTP Status: ${HTTP_CODE}" >> ${LOG_FILE} +echo "[${TIMESTAMP}] Response : ${BODY}" >> ${LOG_FILE} + +if [ "${HTTP_CODE}" = "200" ]; then + echo "[${TIMESTAMP}] ${JOB_NAME} 실행 성공" >> ${LOG_FILE} + echo "Batch job ${JOB_NAME} executed successfully." +else + echo "[${TIMESTAMP}] ${JOB_NAME} 실행 실패 (HTTP ${HTTP_CODE})" >> ${LOG_FILE} + echo "Failed to execute batch job ${JOB_NAME}. HTTP Status: ${HTTP_CODE}" +fi + +echo "[${TIMESTAMP}] ===== ${JOB_NAME} 실행 완료 =====" >> ${LOG_FILE} diff --git a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyJobConfig.java b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyJobConfig.java new file mode 100644 index 0000000..6366d7c --- /dev/null +++ b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyJobConfig.java @@ -0,0 +1,35 @@ +package com.wb.domainserver.acidlivy; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.PlatformTransactionManager; +import lombok.RequiredArgsConstructor; + +// ACI ???? ?? ? ???? ?? Job/Step ?? +@Configuration +@RequiredArgsConstructor +public class AciDlivyJobConfig { + + private final JobRepository jobRepository; + private final PlatformTransactionManager transactionManager; + private final AciDlivyTasklet aciDlivyTasklet; + + @Bean + public Job aciDlivyJob() { + return new JobBuilder("aciDlivyJob", jobRepository) + .start(aciDlivyStep()) + .build(); + } + + @Bean + public Step aciDlivyStep() { + return new StepBuilder("aciDlivyStep", jobRepository) + .tasklet(aciDlivyTasklet, transactionManager) + .build(); + } +} diff --git a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyMapper.java b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyMapper.java new file mode 100644 index 0000000..0f37b21 --- /dev/null +++ b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyMapper.java @@ -0,0 +1,51 @@ +package com.wb.domainserver.acidlivy; + +import com.wb.domainserver.util.dataaccess.DataMap; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Mapper +@Repository +public interface AciDlivyMapper { + + /** ?? ?? ???? ?? ?? (gc_order_shipping.ORDR_STTUS_CD = '35') */ + List selectAciDlivyTargetList(); + + /** ?? ?? ?????? ?? ?? (gc_order_item_option) */ + List selectAciDlivyTargetItemList(AciDlivyOrderVO vo); + + /** gc_goods_export ?? ?? */ + int selectGoodsExportCount(AciDlivyOrderVO vo); + + /** gc_goods_export INSERT */ + int insertGoodsExport(AciDlivyOrderVO vo); + + /** gc_goods_export UPDATE (?? ???? ??) */ + int updateGoodsExport(AciDlivyOrderVO vo); + + /** gc_goods_export_item ?? ?? */ + int selectGoodsExportItemCount(DataMap itemMap); + + /** gc_goods_export_item INSERT */ + int insertGoodsExportItem(DataMap itemMap); + + /** gc_goods_export_item UPDATE (?? ???? ??) */ + int updateGoodsExportItem(DataMap itemMap); + + /** gc_order_item_option ?? UPDATE */ + int updateOrderItemOptionStatus(DataMap itemMap); + + /** gc_order_shipping ?? UPDATE (?? item_option ?? ???? ?? ??) */ + int updateOrderShippingStatus(AciDlivyOrderVO vo); + + /** gc_order ?? UPDATE (?? shipping ?? ???? ?? ??) */ + int updateOrderStatus(AciDlivyOrderVO vo); + + /** GC_GOODS_EXPORT_LOG INSERT */ + int insertGoodsExportLog(DataMap logMap); + + /** GC_ORDER_LOG INSERT */ + int insertOrderLog(DataMap logMap); +} diff --git a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyOrderVO.java b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyOrderVO.java new file mode 100644 index 0000000..d40160e --- /dev/null +++ b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyOrderVO.java @@ -0,0 +1,26 @@ +package com.wb.domainserver.acidlivy; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +// DB ?? ?? ?? ???? ?? + ??? ?? +@Getter +@Setter +@ToString +public class AciDlivyOrderVO { + + // DB ?? ?? (gc_order_shipping) + private String ordrDlvyInnb; // ???????? (ACI OverseaSellerNo ???) + private String ordrInnb; // ???? (API orderNumber ????) + private String sopmalCd; // ????? + + // ACI API ?? ? ?? + private String blno; // ACI ????? (BLNO) + + // ???? ? ?? + private String hdrycpnCd; // ????? (???: code22) + private String dlivySttusCd; // ?????? (???: 55) + private String dlivyInnb; // ?????? (insertGoodsExport ? selectKey? ??) + private String dlivyCdNb; // ?????? (dlivyInnb ?? ? Java?? ??) +} diff --git a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java new file mode 100644 index 0000000..98b3fcc --- /dev/null +++ b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java @@ -0,0 +1,263 @@ +package com.wb.domainserver.acidlivy; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.wb.domainserver.util.dataaccess.DataMap; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.*; +import org.springframework.stereotype.Component; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.support.TransactionTemplate; +import org.springframework.web.client.RestTemplate; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Map; + +// ACI ???? ?? ? ???? ?? Tasklet +// ????: gc_order_shipping(ORDR_STTUS_CD=35) ?? ? ACI API ?? ? BLNO ?? ? ???? +@Slf4j +@Component +@RequiredArgsConstructor +public class AciDlivyTasklet implements Tasklet { + + private final AciDlivyMapper aciDlivyMapper; + private final PlatformTransactionManager transactionManager; + + @Value("${aci.dlivy.api-url}") + private String aciDlivyApiUrl; + + @Value("${acikey.userid}") + private String userId; + + @Value("${acikey.apikey}") + private String apiKey; + + private static final String HDRYCPN_CD = "code22"; // ACI ????? ?? + private static final String DLIVY_STTUS_CD = "55"; // ???? ?? + + @Override + public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) { + log.info("[AciDlivyBatch] ?? ??"); + + // ? ?? ?? ?? (ORDR_STTUS_CD = '35') + List targetList = aciDlivyMapper.selectAciDlivyTargetList(); + log.info("[AciDlivyBatch] ?? ?? ??: {}", targetList.size()); + + if (targetList.isEmpty()) { + log.info("[AciDlivyBatch] ??? ?? ??? ????."); + return RepeatStatus.FINISHED; + } + + int successCnt = 0; + int failCnt = 0; + int skipCnt = 0; + + // ???? ?? ???? (REQUIRES_NEW) ? ? ? ??? ?? ?? ?? ??? + TransactionTemplate txTemplate = new TransactionTemplate(transactionManager); + txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + for (AciDlivyOrderVO orderVO : targetList) { + try { + // ? ACI ???? API ?? ? BLNO ?? + String blno = callAciDlivyApi(orderVO); + + if (blno == null) { + log.info("[AciDlivyBatch] ?? - ORDR_DLVY_INNB={}, ORDR_INNB={} (BLNO ?? ?? ?? ??)", + orderVO.getOrdrDlvyInnb(), orderVO.getOrdrInnb()); + skipCnt++; + } else { + orderVO.setBlno(blno); + orderVO.setHdrycpnCd(HDRYCPN_CD); + orderVO.setDlivySttusCd(DLIVY_STTUS_CD); + + // ? ???? (?? ????) + txTemplate.execute(status -> { + processDelivery(orderVO); + return null; + }); + + successCnt++; + log.info("[AciDlivyBatch] ???? ?? - ORDR_DLVY_INNB={}, BLNO={}", + orderVO.getOrdrDlvyInnb(), blno); + } + + } catch (Exception e) { + log.error("[AciDlivyBatch] ???? ?? - ORDR_DLVY_INNB={}, ??={}", + orderVO.getOrdrDlvyInnb(), e.getMessage(), e); + failCnt++; + } + + // ? API ?? ?? ?? (?? 10? ? 1? ??) + try { + Thread.sleep(1000); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + break; + } + } + + log.info("[AciDlivyBatch] ?? ?? - ??: {}, ??: {}, ??: {}", successCnt, failCnt, skipCnt); + return RepeatStatus.FINISHED; + } + + /** + * ACI ???? API ?? + * Content-Type? text/html? ?? ??? JSON ? String ?? ? ObjectMapper ?? + * @return BLNO(?????), ??? null + */ + private String callAciDlivyApi(AciDlivyOrderVO orderVO) { + try { + HttpHeaders headers = new HttpHeaders(); + headers.set("UserID", userId); + headers.set("ACIKey", apiKey); + + String url = aciDlivyApiUrl + "?searchType=1&orderNumber=" + orderVO.getOrdrInnb(); + HttpEntity entity = new HttpEntity<>(headers); + + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class); + + log.debug("[AciDlivyBatch] API ?? ?? (ORDR_INNB={}): {}", orderVO.getOrdrInnb(), response.getBody()); + + ObjectMapper objectMapper = new ObjectMapper(); + Map body = objectMapper.readValue(response.getBody(), Map.class); + + String status = (String) body.get("Status"); + log.debug("[AciDlivyBatch] API Status={} (ORDR_INNB={})", status, orderVO.getOrdrInnb()); + + // ??/????? ?? ?? (?? Status?? ??? ?? ? ???? ?? ?? ??) + if (!"A10".equals(status)) { + log.info("[AciDlivyBatch] API ??? ?? - ORDR_INNB={}, Status={}", orderVO.getOrdrInnb(), status); + return null; + } + + // Data ?? (?? Map ?? List ?? ??) + Object dataObj = body.get("Data"); + if (dataObj == null) { + return null; + } + + List> dataList; + if (dataObj instanceof List) { + dataList = (List>) dataObj; + } else if (dataObj instanceof Map) { + dataList = List.of((Map) dataObj); + } else { + return null; + } + + // OverseaSellerNo == ORDR_DLVY_INNB ?? ? BLNO ?? + for (Map item : dataList) { + Object sellerNo = item.get("OverseaSellerNo"); + if (sellerNo != null && orderVO.getOrdrDlvyInnb().equals(String.valueOf(sellerNo).trim())) { + Object blno = item.get("BLNO"); + if (blno != null && !String.valueOf(blno).isBlank()) { + return String.valueOf(blno).trim(); + } + } + } + + log.info("[AciDlivyBatch] OverseaSellerNo ?? ?? - ORDR_DLVY_INNB={}", orderVO.getOrdrDlvyInnb()); + return null; + + } catch (Exception e) { + log.error("[AciDlivyBatch] API ?? ?? - ORDR_INNB={}, ??={}", orderVO.getOrdrInnb(), e.getMessage(), e); + return null; + } + } + + /** + * ???? (??: gc_goods_export ? gc_goods_export_item ? gc_order_item_option + * ? gc_order_shipping ? gc_order ? ???? ? ????) + * gc_order_shipping/gc_order ????? ?? ??? ?? ???? ?? ?? + */ + private void processDelivery(AciDlivyOrderVO orderVO) { + + // ? gc_goods_export ?? + int exportCnt = aciDlivyMapper.selectGoodsExportCount(orderVO); + if (exportCnt > 0) { + aciDlivyMapper.updateGoodsExport(orderVO); // selectKey? dlivyInnb ??? + } else { + aciDlivyMapper.insertGoodsExport(orderVO); // selectKey? dlivyInnb ??? + } + + // dlivyCdNb ?? (GC_GOODS_EXPORT ? DLIVY_CD_NB ??? ?? ??) + String dlivyCdNb = "D" + new SimpleDateFormat("yyMMddHH").format(new Date()) + orderVO.getDlivyInnb(); + orderVO.setDlivyCdNb(dlivyCdNb); + + // ? ?? ?? ?? ?? ?? (gc_order_item_option) + List itemList = aciDlivyMapper.selectAciDlivyTargetItemList(orderVO); + log.debug("[AciDlivyBatch] ?? ?? ?? ?={} (ORDR_DLVY_INNB={})", itemList.size(), orderVO.getOrdrDlvyInnb()); + + for (DataMap itemMap : itemList) { + Object qyObj = itemMap.get("qy"); + if (qyObj == null) continue; + int qy; + try { + qy = Integer.parseInt(String.valueOf(qyObj)); + } catch (NumberFormatException e) { + continue; + } + if (qy <= 0) continue; + + itemMap.put("sopmalCd", orderVO.getSopmalCd()); + itemMap.put("ordrDlvyInnb", orderVO.getOrdrDlvyInnb()); + itemMap.put("dlivyInnb", orderVO.getDlivyInnb()); + itemMap.put("ordrInnb", orderVO.getOrdrInnb()); + itemMap.put("hdrycpnCd", HDRYCPN_CD); + itemMap.put("invcnb", orderVO.getBlno()); + itemMap.put("dlivySttusCd", DLIVY_STTUS_CD); + + // ? gc_goods_export_item ?? + int exportItemCnt = aciDlivyMapper.selectGoodsExportItemCount(itemMap); + if (exportItemCnt > 0) { + aciDlivyMapper.updateGoodsExportItem(itemMap); + } else { + aciDlivyMapper.insertGoodsExportItem(itemMap); + } + + // ? gc_order_item_option ?? UPDATE + aciDlivyMapper.updateOrderItemOptionStatus(itemMap); + + // ? ?? ?? INSERT (???) + DataMap exportLogMap = new DataMap(); + exportLogMap.put("ordrInnb", orderVO.getOrdrInnb()); + exportLogMap.put("ordrDlvyInnb", orderVO.getOrdrDlvyInnb()); + exportLogMap.put("sopmalCd", orderVO.getSopmalCd()); + exportLogMap.put("dlivyInnb", orderVO.getDlivyInnb()); + exportLogMap.put("dlivyGoodsCdNb", itemMap.get("ordrGoodsOptnInnb")); + exportLogMap.put("reqstProcsSttusCd", DLIVY_STTUS_CD); + exportLogMap.put("mssageCn", "[ACI ??] ORDR_INNB:" + orderVO.getOrdrInnb() + " ????"); + exportLogMap.put("regusr", 0); + aciDlivyMapper.insertGoodsExportLog(exportLogMap); + } + + // ? gc_order_shipping ?? UPDATE (?? item_option ?? ???? ?? ??) + aciDlivyMapper.updateOrderShippingStatus(orderVO); + + // ? gc_order ?? UPDATE (?? shipping ?? ???? ?? ??) + aciDlivyMapper.updateOrderStatus(orderVO); + + // ? ?? ?? INSERT + DataMap orderLogMap = new DataMap(); + orderLogMap.put("ordrInnb", orderVO.getOrdrInnb()); + orderLogMap.put("sopmalCd", orderVO.getSopmalCd()); + orderLogMap.put("logSj", "????(" + dlivyCdNb + ")"); + orderLogMap.put("logDtlCn", "[ACI ??] ?? ???? ??"); + orderLogMap.put("dlivyCdNb", dlivyCdNb); + orderLogMap.put("logDvCd", "01"); + orderLogMap.put("dvCd", "BATCH"); + orderLogMap.put("opetrNm", "ACI ??"); + orderLogMap.put("qy", 0); + orderLogMap.put("amt", 0); + aciDlivyMapper.insertOrderLog(orderLogMap); + } +} diff --git a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyVO.java b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyVO.java new file mode 100644 index 0000000..6476e7d --- /dev/null +++ b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyVO.java @@ -0,0 +1,14 @@ +package com.wb.domainserver.acidlivy; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +// ACI API ???? ??? Data ?? (BLNO, OverseaSellerNo) +@Getter +@Setter +@ToString +public class AciDlivyVO { + private String blno; // ACI ????? + private String overseaSellerNo; // ????? ???? (= ORDR_DLVY_INNB) +} diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index a1c12ba..9780f90 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -42,4 +42,7 @@ mail: acikey: url: https://acieshop.com/api/kr/token/ userid: UNIHAN - apikey: DC94F29AFD5399F54AAE7FAA46045B65 \ No newline at end of file + apikey: DC94F29AFD5399F54AAE7FAA46045B65 +aci: + dlivy: + api-url: https://acieshop.com/api/kr/delivery/v1.5/detail/index.php diff --git a/src/main/resources/mybatis/xml/mapper/acidlivy/AciDlivyMapper.xml b/src/main/resources/mybatis/xml/mapper/acidlivy/AciDlivyMapper.xml new file mode 100644 index 0000000..8a5a638 --- /dev/null +++ b/src/main/resources/mybatis/xml/mapper/acidlivy/AciDlivyMapper.xml @@ -0,0 +1,356 @@ + + + + + + + + + + + + + + + + + + + + + + + SELECT IFNULL(MAX(DLIVY_INNB), 0) + 1 FROM GC_GOODS_EXPORT + + + + + + + + + + + + + + + + + + + + + + + + + + + SELECT IFNULL(MAX(DLIVY_GOODS_INNB), 0) + 1 FROM GC_GOODS_EXPORT_ITEM + + + + + + + + + + + + + + + + #{qy} THEN '50' + WHEN (ORDR_QY - STEP85) = #{qy} THEN '55' + ELSE ORDR_STTUS_CD + END, + STEP55 = #{qy}, + STEP45 = 0, + UPDT_DT = SYSDATE() + WHERE SOPMAL_CD = #{sopmalCd} + AND OPTN_TY = #{optnTy} + AND ORDR_GOODS_OPTN_INNB = #{ordrGoodsOptnInnb} + ]]> + + + + + + + OIOP.STEP85 + WHERE SH.SOPMAL_CD = #{sopmalCd} + AND SH.ORDR_INNB = #{ordrInnb} + AND SH.ORDR_DLVY_INNB = #{ordrDlvyInnb} + AND SH.USE_AT = 'Y' + GROUP BY SH.SOPMAL_CD, SH.ORDR_INNB, SH.ORDR_DLVY_INNB + ) STEP + SET + SH.ORDR_STTUS_CD = STEP.ORDR_STTUS_CD, + SH.UPDT_DT = SYSDATE() + WHERE SH.SOPMAL_CD = STEP.SOPMAL_CD + AND SH.ORDR_INNB = STEP.ORDR_INNB + AND SH.ORDR_DLVY_INNB = STEP.ORDR_DLVY_INNB + ]]> + + + + + + + '85' + WHERE O.SOPMAL_CD = #{sopmalCd} + AND O.ORDR_INNB = #{ordrInnb} + GROUP BY O.SOPMAL_CD, O.ORDR_INNB + ) STEP + SET + O.ORDR_STTUS_CD = STEP.ORDR_STTUS_CD, + O.UPDT_DT = SYSDATE() + WHERE O.SOPMAL_CD = STEP.SOPMAL_CD + AND O.ORDR_INNB = STEP.ORDR_INNB + AND O.USE_AT = 'Y' + ]]> + + + + + + + + SELECT IFNULL(MAX(DLIVY_LOG_INNB), 0) + 1 FROM GC_GOODS_EXPORT_LOG + + + + + + + + + + + + From 4c6dd27e9f5a65fcdba851ffc9f93da954bdeeb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=9D=BC?= Date: Mon, 25 May 2026 01:19:19 +0900 Subject: [PATCH 14/18] =?UTF-8?q?[TASK=5FBATCH=5FACIDLIVY]=20BOM=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/wb/domainserver/acidlivy/AciDlivyJobConfig.java | 2 +- src/main/java/com/wb/domainserver/acidlivy/AciDlivyMapper.java | 2 +- src/main/java/com/wb/domainserver/acidlivy/AciDlivyOrderVO.java | 2 +- src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java | 2 +- src/main/java/com/wb/domainserver/acidlivy/AciDlivyVO.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyJobConfig.java b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyJobConfig.java index 6366d7c..66d897a 100644 --- a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyJobConfig.java +++ b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyJobConfig.java @@ -1,4 +1,4 @@ -package com.wb.domainserver.acidlivy; +package com.wb.domainserver.acidlivy; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; diff --git a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyMapper.java b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyMapper.java index 0f37b21..f7fc9fc 100644 --- a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyMapper.java +++ b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyMapper.java @@ -1,4 +1,4 @@ -package com.wb.domainserver.acidlivy; +package com.wb.domainserver.acidlivy; import com.wb.domainserver.util.dataaccess.DataMap; import org.apache.ibatis.annotations.Mapper; diff --git a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyOrderVO.java b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyOrderVO.java index d40160e..787622e 100644 --- a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyOrderVO.java +++ b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyOrderVO.java @@ -1,4 +1,4 @@ -package com.wb.domainserver.acidlivy; +package com.wb.domainserver.acidlivy; import lombok.Getter; import lombok.Setter; diff --git a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java index 98b3fcc..3c62669 100644 --- a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java +++ b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java @@ -1,4 +1,4 @@ -package com.wb.domainserver.acidlivy; +package com.wb.domainserver.acidlivy; import com.fasterxml.jackson.databind.ObjectMapper; import com.wb.domainserver.util.dataaccess.DataMap; diff --git a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyVO.java b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyVO.java index 6476e7d..3c5e030 100644 --- a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyVO.java +++ b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyVO.java @@ -1,4 +1,4 @@ -package com.wb.domainserver.acidlivy; +package com.wb.domainserver.acidlivy; import lombok.Getter; import lombok.Setter; From 2ef23049474311c06fbf6460bac111cb61b870e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=9D=BC?= Date: Mon, 25 May 2026 01:47:35 +0900 Subject: [PATCH 15/18] =?UTF-8?q?[TASK=5FBATCH=5FACIDLIVY]=20GconeSourceCo?= =?UTF-8?q?nfig=20MapperScan/setMapperLocations=20acidlivy=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/config/GconeSourceConfig.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/wb/domainserver/common/config/GconeSourceConfig.java b/src/main/java/com/wb/domainserver/common/config/GconeSourceConfig.java index 989c16c..9ec79f9 100644 --- a/src/main/java/com/wb/domainserver/common/config/GconeSourceConfig.java +++ b/src/main/java/com/wb/domainserver/common/config/GconeSourceConfig.java @@ -13,6 +13,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Primary; import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.init.DataSourceInitializer; @@ -21,11 +22,17 @@ import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.sql.DataSource; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; @Configuration @EnableTransactionManagement @MapperScan( - basePackages = "com.wb.domainserver.mapper.gcone", + basePackages = { + "com.wb.domainserver.mapper.gcone", + "com.wb.domainserver.acidlivy" + }, sqlSessionFactoryRef = "gconeSqlSessionFactory" ) public class GconeSourceConfig { @@ -49,7 +56,13 @@ public class GconeSourceConfig { // SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); SqlSessionFactoryBean sessionFactory = new RefreshableSqlSessionFactoryBean(); sessionFactory.setDataSource(gconeDataSource); - sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mybatis/xml/mapper/gcone/**/*.xml")); + + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + List mapperLocations = new ArrayList<>(); + mapperLocations.addAll(Arrays.asList(resolver.getResources("classpath*:mybatis/xml/mapper/gcone/**/*.xml"))); + mapperLocations.addAll(Arrays.asList(resolver.getResources("classpath*:mybatis/xml/mapper/acidlivy/**/*.xml"))); + sessionFactory.setMapperLocations(mapperLocations.toArray(new Resource[0])); + sessionFactory.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/xml/config/mapper-config.xml")); return sessionFactory.getObject(); } @@ -65,7 +78,7 @@ public class GconeSourceConfig { return new DataSourceTransactionManager(gconeDataSource); } - // Spring Batch 스키마 초기화 (BATCH_JOB_SEQ 등 시퀀스 테이블 생성) + // Spring Batch schema init (BATCH_JOB_SEQ etc) @Bean(name = "batchSchemaInitializer") public DataSourceInitializer batchSchemaInitializer(@Qualifier("gconeDataSource") DataSource gconeDataSource) { ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); From f7eaac1ca8deac4024d4a36f0b09fbebce2a2fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=9D=BC?= Date: Mon, 25 May 2026 02:13:04 +0900 Subject: [PATCH 16/18] =?UTF-8?q?[TASK=5FBATCH=5FACIDLIVY]=20application-d?= =?UTF-8?q?ev.yaml=20BOM=20=EB=B0=8F=20^M=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index 9780f90..dc29a54 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -42,7 +42,7 @@ mail: acikey: url: https://acieshop.com/api/kr/token/ userid: UNIHAN - apikey: DC94F29AFD5399F54AAE7FAA46045B65 + apikey: DC94F29AFD5399F54AAE7FAA46045B65 aci: dlivy: - api-url: https://acieshop.com/api/kr/delivery/v1.5/detail/index.php + api-url: https://acieshop.com/api/kr/delivery/v1.5/detail/index.php From 4c500550d97a55e37772eb51554dc542c3257c66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=9D=BC?= Date: Mon, 25 May 2026 02:29:50 +0900 Subject: [PATCH 17/18] =?UTF-8?q?TASK=5FBATCH=5FACIDLIVY:=20AciDlivyTaskle?= =?UTF-8?q?t=20=ED=86=A0=ED=81=B0=20=EB=B0=9C=EA=B8=89=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 배치 시작 시 issueAciKeyToken() 호출하여 ACIKey 토큰 발급 - yaml 고정 apikey는 토큰 발급 시 APIKEY Header로만 사용 - 발급받은 토큰은 메모리에만 유지, ACIKey Header에 세팅하여 API 호출 - acikey.url 주입 추가 --- .../acidlivy/AciDlivyTasklet.java | 147 ++++++++++++------ 1 file changed, 98 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java index 3c62669..4eebc26 100644 --- a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java +++ b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java @@ -21,8 +21,8 @@ import java.util.Date; import java.util.List; import java.util.Map; -// ACI ???? ?? ? ???? ?? Tasklet -// ????: gc_order_shipping(ORDR_STTUS_CD=35) ?? ? ACI API ?? ? BLNO ?? ? ???? +// ACI 출고자료 조회 및 출고처리 배치 Tasklet +// 흐름: gc_order_shipping(ORDR_STTUS_CD=35) 조회 → 토큰 발급 → ACI API 호출 → BLNO 추출 → 출고처리 @Slf4j @Component @RequiredArgsConstructor @@ -31,6 +31,9 @@ public class AciDlivyTasklet implements Tasklet { private final AciDlivyMapper aciDlivyMapper; private final PlatformTransactionManager transactionManager; + @Value("${acikey.url}") + private String aciKeyUrl; + @Value("${aci.dlivy.api-url}") private String aciDlivyApiUrl; @@ -40,19 +43,22 @@ public class AciDlivyTasklet implements Tasklet { @Value("${acikey.apikey}") private String apiKey; - private static final String HDRYCPN_CD = "code22"; // ACI ????? ?? - private static final String DLIVY_STTUS_CD = "55"; // ???? ?? + private static final String HDRYCPN_CD = "code22"; // ACI 택배사 코드 + private static final String DLIVY_STTUS_CD = "55"; // 출고완료 코드 @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) { - log.info("[AciDlivyBatch] ?? ??"); + log.info("[AciDlivyBatch] 배치 시작"); - // ? ?? ?? ?? (ORDR_STTUS_CD = '35') + // 토큰 발급 (yaml 고정 apikey → ACIKey 토큰 발급, 메모리에만 유지) + String aciKeyToken = issueAciKeyToken(); + + // 대상 주문 목록 조회 (ORDR_STTUS_CD = '35') List targetList = aciDlivyMapper.selectAciDlivyTargetList(); - log.info("[AciDlivyBatch] ?? ?? ??: {}", targetList.size()); + log.info("[AciDlivyBatch] 대상 주문 건수: {}", targetList.size()); if (targetList.isEmpty()) { - log.info("[AciDlivyBatch] ??? ?? ??? ????."); + log.info("[AciDlivyBatch] 처리할 대상 주문이 없습니다."); return RepeatStatus.FINISHED; } @@ -60,17 +66,17 @@ public class AciDlivyTasklet implements Tasklet { int failCnt = 0; int skipCnt = 0; - // ???? ?? ???? (REQUIRES_NEW) ? ? ? ??? ?? ?? ?? ??? + // 건별로 독립 트랜잭션 (REQUIRES_NEW) 으로 처리 - 한 건 실패가 다른 건에 영향 없도록 TransactionTemplate txTemplate = new TransactionTemplate(transactionManager); txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); for (AciDlivyOrderVO orderVO : targetList) { try { - // ? ACI ???? API ?? ? BLNO ?? - String blno = callAciDlivyApi(orderVO); + // 건별 ACI 출고자료 API 호출 → BLNO 추출 + String blno = callAciDlivyApi(orderVO, aciKeyToken); if (blno == null) { - log.info("[AciDlivyBatch] ?? - ORDR_DLVY_INNB={}, ORDR_INNB={} (BLNO ?? ?? ?? ??)", + log.info("[AciDlivyBatch] 스킵 - ORDR_DLVY_INNB={}, ORDR_INNB={} (BLNO 없음 또는 조건 미충족)", orderVO.getOrdrDlvyInnb(), orderVO.getOrdrInnb()); skipCnt++; } else { @@ -78,24 +84,24 @@ public class AciDlivyTasklet implements Tasklet { orderVO.setHdrycpnCd(HDRYCPN_CD); orderVO.setDlivySttusCd(DLIVY_STTUS_CD); - // ? ???? (?? ????) + // 건별 처리 (독립 트랜잭션) txTemplate.execute(status -> { processDelivery(orderVO); return null; }); successCnt++; - log.info("[AciDlivyBatch] ???? ?? - ORDR_DLVY_INNB={}, BLNO={}", + log.info("[AciDlivyBatch] 출고처리 완료 - ORDR_DLVY_INNB={}, BLNO={}", orderVO.getOrdrDlvyInnb(), blno); } } catch (Exception e) { - log.error("[AciDlivyBatch] ???? ?? - ORDR_DLVY_INNB={}, ??={}", + log.error("[AciDlivyBatch] 출고처리 실패 - ORDR_DLVY_INNB={}, 오류={}", orderVO.getOrdrDlvyInnb(), e.getMessage(), e); failCnt++; } - // ? API ?? ?? ?? (?? 10? ? 1? ??) + // 건별 API 호출 간격 유지 (과부하 방지 - 1초 대기) try { Thread.sleep(1000); } catch (InterruptedException ie) { @@ -104,20 +110,63 @@ public class AciDlivyTasklet implements Tasklet { } } - log.info("[AciDlivyBatch] ?? ?? - ??: {}, ??: {}, ??: {}", successCnt, failCnt, skipCnt); + log.info("[AciDlivyBatch] 배치 완료 - 성공: {}, 실패: {}, 스킵: {}", successCnt, failCnt, skipCnt); return RepeatStatus.FINISHED; } /** - * ACI ???? API ?? - * Content-Type? text/html? ?? ??? JSON ? String ?? ? ObjectMapper ?? - * @return BLNO(?????), ??? null + * ACIKey 토큰 발급 + * yaml 고정 apikey를 APIKEY Header로 사용하여 POST 호출 → 발급받은 토큰은 메모리에만 유지 */ - private String callAciDlivyApi(AciDlivyOrderVO orderVO) { + private String issueAciKeyToken() { + try { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("USERID", userId); + headers.set("APIKEY", apiKey); + + HttpEntity requestEntity = new HttpEntity<>("{}", headers); + + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity response = restTemplate.exchange( + aciKeyUrl, + HttpMethod.POST, + requestEntity, + String.class + ); + + ObjectMapper objectMapper = new ObjectMapper(); + Map body = objectMapper.readValue(response.getBody(), Map.class); + + String status = (String) body.get("Status"); + String aciKey = (String) body.get("ACIKey"); + String errMsg = (String) body.get("ErrMsg"); + + if ("success".equals(status) && aciKey != null) { + log.info("[AciDlivyBatch] ACIKey 토큰 발급 성공"); + return aciKey; + } else { + throw new RuntimeException("ACIKey 토큰 발급 실패. Status: " + status + ", ErrMsg: " + errMsg); + } + + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException("ACIKey 토큰 발급 오류", e); + } + } + + /** + * ACI 출고자료 API 호출 + * Content-Type이 text/html로 오는 경우를 대비해 JSON을 String으로 받아 ObjectMapper 파싱 + * @param aciKeyToken 발급받은 ACIKey 토큰 + * @return BLNO(운송장번호), 없으면 null + */ + private String callAciDlivyApi(AciDlivyOrderVO orderVO, String aciKeyToken) { try { HttpHeaders headers = new HttpHeaders(); headers.set("UserID", userId); - headers.set("ACIKey", apiKey); + headers.set("ACIKey", aciKeyToken); String url = aciDlivyApiUrl + "?searchType=1&orderNumber=" + orderVO.getOrdrInnb(); HttpEntity entity = new HttpEntity<>(headers); @@ -125,7 +174,7 @@ public class AciDlivyTasklet implements Tasklet { RestTemplate restTemplate = new RestTemplate(); ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class); - log.debug("[AciDlivyBatch] API ?? ?? (ORDR_INNB={}): {}", orderVO.getOrdrInnb(), response.getBody()); + log.debug("[AciDlivyBatch] API 응답 원문 (ORDR_INNB={}): {}", orderVO.getOrdrInnb(), response.getBody()); ObjectMapper objectMapper = new ObjectMapper(); Map body = objectMapper.readValue(response.getBody(), Map.class); @@ -133,13 +182,13 @@ public class AciDlivyTasklet implements Tasklet { String status = (String) body.get("Status"); log.debug("[AciDlivyBatch] API Status={} (ORDR_INNB={})", status, orderVO.getOrdrInnb()); - // ??/????? ?? ?? (?? Status?? ??? ?? ? ???? ?? ?? ??) + // 출고/발송완료 상태 검증 (정확한 Status값은 실제 응답 확인 후 조정 필요) if (!"A10".equals(status)) { - log.info("[AciDlivyBatch] API ??? ?? - ORDR_INNB={}, Status={}", orderVO.getOrdrInnb(), status); + log.info("[AciDlivyBatch] API 출고 미완료 - ORDR_INNB={}, Status={}", orderVO.getOrdrInnb(), status); return null; } - // Data ?? (?? Map ?? List ?? ??) + // Data 파싱 (단일 Map 또는 List 모두 대응) Object dataObj = body.get("Data"); if (dataObj == null) { return null; @@ -154,7 +203,7 @@ public class AciDlivyTasklet implements Tasklet { return null; } - // OverseaSellerNo == ORDR_DLVY_INNB ?? ? BLNO ?? + // OverseaSellerNo == ORDR_DLVY_INNB 매칭 → BLNO 추출 for (Map item : dataList) { Object sellerNo = item.get("OverseaSellerNo"); if (sellerNo != null && orderVO.getOrdrDlvyInnb().equals(String.valueOf(sellerNo).trim())) { @@ -165,37 +214,37 @@ public class AciDlivyTasklet implements Tasklet { } } - log.info("[AciDlivyBatch] OverseaSellerNo ?? ?? - ORDR_DLVY_INNB={}", orderVO.getOrdrDlvyInnb()); + log.info("[AciDlivyBatch] OverseaSellerNo 매칭 없음 - ORDR_DLVY_INNB={}", orderVO.getOrdrDlvyInnb()); return null; } catch (Exception e) { - log.error("[AciDlivyBatch] API ?? ?? - ORDR_INNB={}, ??={}", orderVO.getOrdrInnb(), e.getMessage(), e); + log.error("[AciDlivyBatch] API 호출 오류 - ORDR_INNB={}, 오류={}", orderVO.getOrdrInnb(), e.getMessage(), e); return null; } } /** - * ???? (??: gc_goods_export ? gc_goods_export_item ? gc_order_item_option - * ? gc_order_shipping ? gc_order ? ???? ? ????) - * gc_order_shipping/gc_order ????? ?? ??? ?? ???? ?? ?? + * 출고처리 (순서: gc_goods_export → gc_goods_export_item → gc_order_item_option + * → gc_order_shipping → gc_order → 출고로그 → 주문로그) + * gc_order_shipping/gc_order 상태변경은 모든 아이템 처리 완료 후 일괄 수행 */ private void processDelivery(AciDlivyOrderVO orderVO) { - // ? gc_goods_export ?? + // 출고 gc_goods_export 처리 int exportCnt = aciDlivyMapper.selectGoodsExportCount(orderVO); if (exportCnt > 0) { - aciDlivyMapper.updateGoodsExport(orderVO); // selectKey? dlivyInnb ??? + aciDlivyMapper.updateGoodsExport(orderVO); } else { - aciDlivyMapper.insertGoodsExport(orderVO); // selectKey? dlivyInnb ??? + aciDlivyMapper.insertGoodsExport(orderVO); } - // dlivyCdNb ?? (GC_GOODS_EXPORT ? DLIVY_CD_NB ??? ?? ??) + // 출고코드 생성 (GC_GOODS_EXPORT의 DLIVY_CD_NB 규칙 따름) String dlivyCdNb = "D" + new SimpleDateFormat("yyMMddHH").format(new Date()) + orderVO.getDlivyInnb(); orderVO.setDlivyCdNb(dlivyCdNb); - // ? ?? ?? ?? ?? ?? (gc_order_item_option) + // 주문 상품 옵션 목록 조회 및 건별 처리 (gc_order_item_option) List itemList = aciDlivyMapper.selectAciDlivyTargetItemList(orderVO); - log.debug("[AciDlivyBatch] ?? ?? ?? ?={} (ORDR_DLVY_INNB={})", itemList.size(), orderVO.getOrdrDlvyInnb()); + log.debug("[AciDlivyBatch] 주문 상품 옵션 수={} (ORDR_DLVY_INNB={})", itemList.size(), orderVO.getOrdrDlvyInnb()); for (DataMap itemMap : itemList) { Object qyObj = itemMap.get("qy"); @@ -216,7 +265,7 @@ public class AciDlivyTasklet implements Tasklet { itemMap.put("invcnb", orderVO.getBlno()); itemMap.put("dlivySttusCd", DLIVY_STTUS_CD); - // ? gc_goods_export_item ?? + // gc_goods_export_item 처리 int exportItemCnt = aciDlivyMapper.selectGoodsExportItemCount(itemMap); if (exportItemCnt > 0) { aciDlivyMapper.updateGoodsExportItem(itemMap); @@ -224,10 +273,10 @@ public class AciDlivyTasklet implements Tasklet { aciDlivyMapper.insertGoodsExportItem(itemMap); } - // ? gc_order_item_option ?? UPDATE + // gc_order_item_option 상태 UPDATE aciDlivyMapper.updateOrderItemOptionStatus(itemMap); - // ? ?? ?? INSERT (???) + // 출고 로그 INSERT (건별) DataMap exportLogMap = new DataMap(); exportLogMap.put("ordrInnb", orderVO.getOrdrInnb()); exportLogMap.put("ordrDlvyInnb", orderVO.getOrdrDlvyInnb()); @@ -235,29 +284,29 @@ public class AciDlivyTasklet implements Tasklet { exportLogMap.put("dlivyInnb", orderVO.getDlivyInnb()); exportLogMap.put("dlivyGoodsCdNb", itemMap.get("ordrGoodsOptnInnb")); exportLogMap.put("reqstProcsSttusCd", DLIVY_STTUS_CD); - exportLogMap.put("mssageCn", "[ACI ??] ORDR_INNB:" + orderVO.getOrdrInnb() + " ????"); + exportLogMap.put("mssageCn", "[ACI 배치] ORDR_INNB:" + orderVO.getOrdrInnb() + " 출고처리"); exportLogMap.put("regusr", 0); aciDlivyMapper.insertGoodsExportLog(exportLogMap); } - // ? gc_order_shipping ?? UPDATE (?? item_option ?? ???? ?? ??) + // gc_order_shipping 상태 UPDATE (모든 item_option 처리 완료 후 일괄) aciDlivyMapper.updateOrderShippingStatus(orderVO); - // ? gc_order ?? UPDATE (?? shipping ?? ???? ?? ??) + // gc_order 상태 UPDATE (모든 shipping 처리 완료 후 일괄) aciDlivyMapper.updateOrderStatus(orderVO); - // ? ?? ?? INSERT + // 주문 로그 INSERT DataMap orderLogMap = new DataMap(); orderLogMap.put("ordrInnb", orderVO.getOrdrInnb()); orderLogMap.put("sopmalCd", orderVO.getSopmalCd()); - orderLogMap.put("logSj", "????(" + dlivyCdNb + ")"); - orderLogMap.put("logDtlCn", "[ACI ??] ?? ???? ??"); + orderLogMap.put("logSj", "출고처리(" + dlivyCdNb + ")"); + orderLogMap.put("logDtlCn", "[ACI 배치] 배치 출고처리 완료"); orderLogMap.put("dlivyCdNb", dlivyCdNb); orderLogMap.put("logDvCd", "01"); orderLogMap.put("dvCd", "BATCH"); - orderLogMap.put("opetrNm", "ACI ??"); + orderLogMap.put("opetrNm", "ACI 배치"); orderLogMap.put("qy", 0); orderLogMap.put("amt", 0); aciDlivyMapper.insertOrderLog(orderLogMap); } -} +} From 1322a2ffbbb8f2173673e99db686567eceb165bd Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 25 May 2026 03:25:30 +0900 Subject: [PATCH 18/18] =?UTF-8?q?feat:=20AciDlivyTasklet=20processDelivery?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20-=200=EA=B1=B4=20=EC=8A=A4=ED=82=B5,=20?= =?UTF-8?q?dlivyCdNb=20Java=20=ED=86=B5=EC=9D=BC,=20orderLogMap=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=EA=B0=92=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domainserver/acidlivy/AciDlivyMapper.java | 23 +++++---- .../acidlivy/AciDlivyTasklet.java | 28 ++++++++--- .../xml/mapper/acidlivy/AciDlivyMapper.xml | 50 ++++++++++++------- 3 files changed, 65 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyMapper.java b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyMapper.java index f7fc9fc..d486f25 100644 --- a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyMapper.java +++ b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyMapper.java @@ -10,37 +10,40 @@ import java.util.List; @Repository public interface AciDlivyMapper { - /** ?? ?? ???? ?? ?? (gc_order_shipping.ORDR_STTUS_CD = '35') */ + /** 출고 대상 주문 목록 조회 (gc_order_shipping.ORDR_STTUS_CD = '35') */ List selectAciDlivyTargetList(); - /** ?? ?? ?????? ?? ?? (gc_order_item_option) */ + /** 출고 대상 주문상품 옵션 조회 (gc_order_item_option) */ List selectAciDlivyTargetItemList(AciDlivyOrderVO vo); - /** gc_goods_export ?? ?? */ + /** gc_goods_export 존재 여부 */ int selectGoodsExportCount(AciDlivyOrderVO vo); /** gc_goods_export INSERT */ int insertGoodsExport(AciDlivyOrderVO vo); - /** gc_goods_export UPDATE (?? ???? ??) */ + /** gc_goods_export UPDATE (기존 레코드 있음) */ int updateGoodsExport(AciDlivyOrderVO vo); - /** gc_goods_export_item ?? ?? */ + /** gc_goods_export DLIVY_CD_NB UPDATE (INSERT 경로에서 dlivyCdNb 생성 후 호출) */ + int updateGoodsExportDlivyCdNb(AciDlivyOrderVO vo); + + /** gc_goods_export_item 존재 여부 */ int selectGoodsExportItemCount(DataMap itemMap); /** gc_goods_export_item INSERT */ int insertGoodsExportItem(DataMap itemMap); - /** gc_goods_export_item UPDATE (?? ???? ??) */ + /** gc_goods_export_item UPDATE (기존 레코드 있음) */ int updateGoodsExportItem(DataMap itemMap); - /** gc_order_item_option ?? UPDATE */ + /** gc_order_item_option 상태 UPDATE */ int updateOrderItemOptionStatus(DataMap itemMap); - /** gc_order_shipping ?? UPDATE (?? item_option ?? ???? ?? ??) */ + /** gc_order_shipping 상태 UPDATE (하위 item_option 상태 기반으로 동적 결정) */ int updateOrderShippingStatus(AciDlivyOrderVO vo); - /** gc_order ?? UPDATE (?? shipping ?? ???? ?? ??) */ + /** gc_order 상태 UPDATE (하위 shipping 상태 기반으로 동적 결정) */ int updateOrderStatus(AciDlivyOrderVO vo); /** GC_GOODS_EXPORT_LOG INSERT */ @@ -48,4 +51,4 @@ public interface AciDlivyMapper { /** GC_ORDER_LOG INSERT */ int insertOrderLog(DataMap logMap); -} +} diff --git a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java index 4eebc26..0cfbedd 100644 --- a/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java +++ b/src/main/java/com/wb/domainserver/acidlivy/AciDlivyTasklet.java @@ -230,7 +230,15 @@ public class AciDlivyTasklet implements Tasklet { */ private void processDelivery(AciDlivyOrderVO orderVO) { - // 출고 gc_goods_export 처리 + // ① 주문 상품 옵션 목록 먼저 조회 (0건이면 출고처리 전체 스킵) + List itemList = aciDlivyMapper.selectAciDlivyTargetItemList(orderVO); + if (itemList.isEmpty()) { + log.warn("[AciDlivyBatch] 주문 상품 옵션 없음 - 출고처리 스킵 (ORDR_DLVY_INNB={})", orderVO.getOrdrDlvyInnb()); + return; + } + log.debug("[AciDlivyBatch] 주문 상품 옵션 수={} (ORDR_DLVY_INNB={})", itemList.size(), orderVO.getOrdrDlvyInnb()); + + // ② gc_goods_export 처리 (selectKey로 dlivyInnb 채번) int exportCnt = aciDlivyMapper.selectGoodsExportCount(orderVO); if (exportCnt > 0) { aciDlivyMapper.updateGoodsExport(orderVO); @@ -238,14 +246,16 @@ public class AciDlivyTasklet implements Tasklet { aciDlivyMapper.insertGoodsExport(orderVO); } - // 출고코드 생성 (GC_GOODS_EXPORT의 DLIVY_CD_NB 규칙 따름) + // ③ dlivyCdNb 생성 (insertGoodsExport 실행 후, dlivyInnb 채번 완료 후) String dlivyCdNb = "D" + new SimpleDateFormat("yyMMddHH").format(new Date()) + orderVO.getDlivyInnb(); orderVO.setDlivyCdNb(dlivyCdNb); - // 주문 상품 옵션 목록 조회 및 건별 처리 (gc_order_item_option) - List itemList = aciDlivyMapper.selectAciDlivyTargetItemList(orderVO); - log.debug("[AciDlivyBatch] 주문 상품 옵션 수={} (ORDR_DLVY_INNB={})", itemList.size(), orderVO.getOrdrDlvyInnb()); + // ④ INSERT 경로: DLIVY_CD_NB 업데이트 (INSERT 시 #{dlivyCdNb}가 null이었으므로) + if (exportCnt == 0) { + aciDlivyMapper.updateGoodsExportDlivyCdNb(orderVO); + } + // ⑤ 주문 상품 옵션별 처리 (gc_goods_export_item, gc_order_item_option) for (DataMap itemMap : itemList) { Object qyObj = itemMap.get("qy"); if (qyObj == null) continue; @@ -289,19 +299,21 @@ public class AciDlivyTasklet implements Tasklet { aciDlivyMapper.insertGoodsExportLog(exportLogMap); } - // gc_order_shipping 상태 UPDATE (모든 item_option 처리 완료 후 일괄) + // ⑥ gc_order_shipping 상태 UPDATE (모든 item_option 처리 완료 후 일괄) aciDlivyMapper.updateOrderShippingStatus(orderVO); - // gc_order 상태 UPDATE (모든 shipping 처리 완료 후 일괄) + // ⑦ gc_order 상태 UPDATE (모든 shipping 처리 완료 후 일괄) aciDlivyMapper.updateOrderStatus(orderVO); - // 주문 로그 INSERT + // ⑧ 주문 로그 INSERT DataMap orderLogMap = new DataMap(); orderLogMap.put("ordrInnb", orderVO.getOrdrInnb()); orderLogMap.put("sopmalCd", orderVO.getSopmalCd()); orderLogMap.put("logSj", "출고처리(" + dlivyCdNb + ")"); orderLogMap.put("logDtlCn", "[ACI 배치] 배치 출고처리 완료"); + orderLogMap.put("aditInfoCn", null); orderLogMap.put("dlivyCdNb", dlivyCdNb); + orderLogMap.put("refundCdNb", null); orderLogMap.put("logDvCd", "01"); orderLogMap.put("dvCd", "BATCH"); orderLogMap.put("opetrNm", "ACI 배치"); diff --git a/src/main/resources/mybatis/xml/mapper/acidlivy/AciDlivyMapper.xml b/src/main/resources/mybatis/xml/mapper/acidlivy/AciDlivyMapper.xml index 8a5a638..58d342b 100644 --- a/src/main/resources/mybatis/xml/mapper/acidlivy/AciDlivyMapper.xml +++ b/src/main/resources/mybatis/xml/mapper/acidlivy/AciDlivyMapper.xml @@ -1,8 +1,8 @@ - + - + @@ -39,7 +39,7 @@ - + @@ -179,7 +193,7 @@ - + - - + + - - + + - - + + - +