feat: complete Spring Boot 카드 매입·정산 system (acquire-core migration target, mvn verify green, 24 tests)
This commit is contained in:
commit
0f6e3acfe6
92 changed files with 4320 additions and 0 deletions
38
modules/gateway/pom.xml
Normal file
38
modules/gateway/pom.xml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.klaro.acquiring</groupId>
|
||||
<artifactId>card-acquiring-boot</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>gateway</artifactId>
|
||||
<name>gateway</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.klaro.acquiring</groupId>
|
||||
<artifactId>common-framework</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.klaro.acquiring</groupId>
|
||||
<artifactId>domain</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.klaro.acquiring</groupId>
|
||||
<artifactId>persistence</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.klaro.acquiring</groupId>
|
||||
<artifactId>acquiring</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
package com.klaro.acquiring.gateway;
|
||||
|
||||
import com.klaro.acquiring.acquiring.AcquiringService;
|
||||
import com.klaro.acquiring.acquiring.dto.PurchaseCommand;
|
||||
import com.klaro.acquiring.common.codec.FieldSpec;
|
||||
import com.klaro.acquiring.common.codec.MessageCodec;
|
||||
import com.klaro.acquiring.common.codec.MessageSpec;
|
||||
import com.klaro.acquiring.common.error.ErrorCode;
|
||||
import com.klaro.acquiring.common.error.AcquiringException;
|
||||
import com.klaro.acquiring.domain.entity.Purchase;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 전문 게이트웨이(mg). 고정길이 전문을 수신·디코드하여 매입 서비스로 위임하고,
|
||||
* 처리 결과를 응답 전문으로 인코드한다. 레거시 mg_ol_* 의 전문 송수신 대체.
|
||||
*/
|
||||
@Service
|
||||
public class GatewayService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(GatewayService.class);
|
||||
|
||||
/** 매입 요청 전문. */
|
||||
public static final MessageSpec REQUEST_SPEC = MessageSpec.of("MG_REQ",
|
||||
FieldSpec.an("TXNCODE", 4),
|
||||
FieldSpec.an("APPRNO", 12),
|
||||
FieldSpec.num("AMOUNT", 15));
|
||||
|
||||
/** 매입 응답 전문. */
|
||||
public static final MessageSpec RESPONSE_SPEC = MessageSpec.of("MG_RES",
|
||||
FieldSpec.an("RESPCODE", 4),
|
||||
FieldSpec.an("APPRNO", 12),
|
||||
FieldSpec.num("NETAMOUNT", 15),
|
||||
FieldSpec.an("MESSAGE", 40));
|
||||
|
||||
/** 매입 접수 거래코드. */
|
||||
public static final String TXN_ACQUIRE = "0210";
|
||||
|
||||
private final MessageCodec requestCodec = new MessageCodec(REQUEST_SPEC);
|
||||
private final MessageCodec responseCodec = new MessageCodec(RESPONSE_SPEC);
|
||||
private final AcquiringService acquiringService;
|
||||
|
||||
public GatewayService(AcquiringService acquiringService) {
|
||||
this.acquiringService = acquiringService;
|
||||
}
|
||||
|
||||
/** 요청 전문 처리 → 응답 전문. */
|
||||
public String handle(String requestMessage) {
|
||||
Map<String, String> req;
|
||||
try {
|
||||
req = requestCodec.decode(requestMessage);
|
||||
} catch (RuntimeException e) {
|
||||
log.warn("[mg] 전문 디코드 실패: {}", e.getMessage());
|
||||
return respond(ErrorCode.INVALID_REQUEST, "", BigDecimal.ZERO, "전문 형식 오류");
|
||||
}
|
||||
|
||||
String txn = req.get("TXNCODE");
|
||||
String apprNo = req.get("APPRNO");
|
||||
if (!TXN_ACQUIRE.equals(txn)) {
|
||||
return respond(ErrorCode.INVALID_REQUEST, apprNo, BigDecimal.ZERO,
|
||||
"미지원 거래코드: " + txn);
|
||||
}
|
||||
|
||||
try {
|
||||
BigDecimal amount = new BigDecimal(req.get("AMOUNT"));
|
||||
Purchase p = acquiringService.acceptPurchase(new PurchaseCommand(apprNo, amount));
|
||||
log.info("[mg] 매입 승인 apprNo={} net={}", apprNo, p.getNetAmount());
|
||||
return respond(ErrorCode.OK, apprNo, p.getNetAmount(), "정상 처리");
|
||||
} catch (AcquiringException e) {
|
||||
log.warn("[mg] 매입 거절 apprNo={} code={} msg={}",
|
||||
apprNo, e.getErrorCode().code(), e.getMessage());
|
||||
return respond(e.getErrorCode(), apprNo, BigDecimal.ZERO, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String respond(ErrorCode code, String apprNo, BigDecimal netAmount, String message) {
|
||||
Map<String, String> res = new LinkedHashMap<>();
|
||||
res.put("RESPCODE", code.code());
|
||||
res.put("APPRNO", apprNo == null ? "" : apprNo);
|
||||
res.put("NETAMOUNT", netAmount.max(BigDecimal.ZERO).toBigInteger().toString());
|
||||
res.put("MESSAGE", message == null ? "" : message);
|
||||
return responseCodec.encode(res);
|
||||
}
|
||||
|
||||
public MessageCodec responseCodec() {
|
||||
return responseCodec;
|
||||
}
|
||||
}
|
||||
Reference in a new issue