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
42
modules/master/pom.xml
Normal file
42
modules/master/pom.xml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?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>master</artifactId>
|
||||
<name>master</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>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.klaro.acquiring.master;
|
||||
|
||||
import com.klaro.acquiring.common.dto.ApiResponse;
|
||||
import com.klaro.acquiring.master.dto.MerchantRequest;
|
||||
import com.klaro.acquiring.master.dto.MerchantResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** 가맹점 마스터 REST. */
|
||||
@RestController
|
||||
@RequestMapping("/api/master/merchants")
|
||||
public class MasterController {
|
||||
|
||||
private final MasterService masterService;
|
||||
|
||||
public MasterController(MasterService masterService) {
|
||||
this.masterService = masterService;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ApiResponse<MerchantResponse> register(@Valid @RequestBody MerchantRequest req) {
|
||||
return ApiResponse.ok(MerchantResponse.from(masterService.register(req)));
|
||||
}
|
||||
|
||||
@PutMapping("/{merchId}")
|
||||
public ApiResponse<MerchantResponse> update(@PathVariable String merchId,
|
||||
@Valid @RequestBody MerchantRequest req) {
|
||||
return ApiResponse.ok(MerchantResponse.from(masterService.update(merchId, req)));
|
||||
}
|
||||
|
||||
@GetMapping("/{merchId}")
|
||||
public ApiResponse<MerchantResponse> get(@PathVariable String merchId) {
|
||||
return ApiResponse.ok(MerchantResponse.from(masterService.get(merchId)));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ApiResponse<List<MerchantResponse>> list() {
|
||||
return ApiResponse.ok(masterService.list().stream().map(MerchantResponse::from).toList());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package com.klaro.acquiring.master;
|
||||
|
||||
import com.klaro.acquiring.common.error.ErrorCode;
|
||||
import com.klaro.acquiring.common.error.AcquiringException;
|
||||
import com.klaro.acquiring.common.error.NotFoundException;
|
||||
import com.klaro.acquiring.domain.entity.Merchant;
|
||||
import com.klaro.acquiring.master.dto.MerchantRequest;
|
||||
import com.klaro.acquiring.persistence.repository.MerchantRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 가맹점/수수료율/한도 마스터(mm) CRUD 서비스.
|
||||
*/
|
||||
@Service
|
||||
public class MasterService {
|
||||
|
||||
private final MerchantRepository merchantRepository;
|
||||
|
||||
public MasterService(MerchantRepository merchantRepository) {
|
||||
this.merchantRepository = merchantRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Merchant register(MerchantRequest req) {
|
||||
if (merchantRepository.existsById(req.merchId())) {
|
||||
throw new AcquiringException(ErrorCode.DUPLICATE, "이미 존재하는 가맹점: " + req.merchId());
|
||||
}
|
||||
Merchant m = new Merchant(req.merchId(), req.merchName(), req.mdrRate(), req.vanFee(),
|
||||
req.settlementCycle(), req.bankCode(), req.accountNo());
|
||||
m.setBizNo(req.bizNo());
|
||||
return merchantRepository.save(m);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Merchant update(String merchId, MerchantRequest req) {
|
||||
Merchant m = get(merchId);
|
||||
m.setMerchName(req.merchName());
|
||||
m.setBizNo(req.bizNo());
|
||||
m.setMdrRate(req.mdrRate());
|
||||
m.setVanFee(req.vanFee());
|
||||
m.setSettlementCycle(req.settlementCycle());
|
||||
m.setBankCode(req.bankCode());
|
||||
m.setAccountNo(req.accountNo());
|
||||
return merchantRepository.save(m);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Merchant get(String merchId) {
|
||||
return merchantRepository.findById(merchId)
|
||||
.orElseThrow(() -> new NotFoundException("가맹점 없음: " + merchId));
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<Merchant> list() {
|
||||
return merchantRepository.findAll();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.klaro.acquiring.master.dto;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/** 가맹점 등록/수정 요청. */
|
||||
public record MerchantRequest(
|
||||
@NotBlank String merchId,
|
||||
@NotBlank String merchName,
|
||||
String bizNo,
|
||||
@NotNull @DecimalMin("0.0") BigDecimal mdrRate,
|
||||
@NotNull @DecimalMin("0.0") BigDecimal vanFee,
|
||||
@Min(0) int settlementCycle,
|
||||
String bankCode,
|
||||
String accountNo) {
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.klaro.acquiring.master.dto;
|
||||
|
||||
import com.klaro.acquiring.domain.entity.Merchant;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/** 가맹점 응답. */
|
||||
public record MerchantResponse(String merchId, String merchName, String bizNo, String status,
|
||||
BigDecimal mdrRate, BigDecimal vanFee, int settlementCycle,
|
||||
String bankCode, String accountNo) {
|
||||
|
||||
public static MerchantResponse from(Merchant m) {
|
||||
return new MerchantResponse(m.getMerchId(), m.getMerchName(), m.getBizNo(),
|
||||
m.getStatus().name(), m.getMdrRate(), m.getVanFee(), m.getSettlementCycle(),
|
||||
m.getBankCode(), m.getAccountNo());
|
||||
}
|
||||
}
|
||||
Reference in a new issue