feat:发行货币的功能开发

master
jiazheng.zhao 3 weeks ago
parent f2314bd821
commit 85cb148180

@ -115,6 +115,11 @@ public class ControlSystemSignatureService {
return new ControlSystemSignatureResult(requireLatest(subject));
}
@Transactional(readOnly = true)
public ControlSystemSignatureResult detail(InstitutionKeySubject subject) {
return new ControlSystemSignatureResult(requireLatest(subject));
}
@Transactional(readOnly = true)
public CommercialBankControlSystemSignatureResult commercialBankMessage(InstitutionKeySubject subject) {
return new CommercialBankControlSystemSignatureResult(latest(subject));

@ -43,12 +43,6 @@ public class CurrencyGenerationRequestService {
long identifierApplicationId = identifier.getApplicationId();
CurrencyGenerationRequest request = repository.findLatestBySubject(subject.getUserId(), subject.getSchoolId(),
subject.getClassId()).orElse(null);
if (request != null && request.getStatus() != CurrencyGenerationRequest.Status.CONCATENATED
&& request.getStatus() != CurrencyGenerationRequest.Status.DIGESTED) {
throw new BusinessException(ErrorCode.VALIDATION_ERROR,
"当前最新货币生成请求已进入" + request.getStatus().name()
+ ",不能重复创建;如需重新开始请先调用重新实现接口");
}
CurrencyGenerationRequest input = invokeDomainWithResult(() -> CurrencyGenerationRequest.prepare(
identifierApplicationId, institutionIdentifier,
identifier.getFullInstitutionIdentifier(), amount, deliveryNodeCode, requestTimestamp));

@ -64,13 +64,7 @@ public class InstitutionIdentifierStepService {
subject.getSchoolId(), subject.getClassId()).orElse(null);
if (application == null) {
prepare(normalizedOriginalText, subject, operator);
application = requireCurrent(subject, InstitutionIdentifierApplication.Status.PREPARED,
"当前没有待计算摘要的本轮机构标识数据");
} else if (application.getStatus() != InstitutionIdentifierApplication.Status.PREPARED
&& application.getStatus() != InstitutionIdentifierApplication.Status.DIGESTED) {
throw new BusinessException(ErrorCode.VALIDATION_ERROR,
"当前最新一轮已进入" + application.getStatus().name()
+ ",不能重复创建申请;如需重新开始请先调用重新实现接口");
application = requireCurrent(subject, "当前没有待计算摘要的本轮机构标识数据");
}
InstitutionIdentifierApplication.Status expectedStatus = application.getStatus();
String digest = cryptography.sm3(normalizedOriginalText);
@ -87,10 +81,11 @@ public class InstitutionIdentifierStepService {
@Transactional
public InstitutionSignatureResult sign(String privateKey, InstitutionKeySubject subject, String operator) {
InstitutionIdentifierApplication application = requireCurrent(subject,
InstitutionIdentifierApplication.Status.DIGESTED, "当前没有待签名的本轮机构标识数据");
"当前没有待签名的本轮机构标识数据");
if (application.getDigest() == null) {
throw new BusinessException(ErrorCode.VALIDATION_ERROR, "请先完成SM3摘要计算");
}
long applicationId = application.getId();
requireStatus(application, InstitutionIdentifierApplication.Status.DIGESTED,
"当前步骤不是商业银行签名,不能操作", operator);
InstitutionIdentifierApplication.Status expectedStatus = application.getStatus();
String signature = keyService.signCommercialBank(subject, privateKey, application.getDigest());
if (signature == null) {
@ -106,9 +101,11 @@ public class InstitutionIdentifierStepService {
@Transactional
public InstitutionApplicationPackageResult packageApplication(InstitutionKeySubject subject, String operator) {
InstitutionIdentifierApplication application = requireCurrent(subject,
InstitutionIdentifierApplication.Status.SIGNED, "当前没有待组装的本轮机构标识数据");
"当前没有待组装的本轮机构标识数据");
if (application.getBankSignature() == null) {
throw new BusinessException(ErrorCode.VALIDATION_ERROR, "请先完成商业银行签名");
}
long applicationId = application.getId();
requireStatus(application, InstitutionIdentifierApplication.Status.SIGNED, "当前步骤不是申请组装,不能操作", operator);
InstitutionIdentifierApplication.Status expectedStatus = application.getStatus();
invokeDomain(application::packageApplication);
repository.update(application, expectedStatus, "PACKAGE",
@ -121,7 +118,10 @@ public class InstitutionIdentifierStepService {
@Transactional
public InstitutionApplicationPackageResult sendApplication(InstitutionKeySubject subject, String operator) {
InstitutionIdentifierApplication application = requireCurrent(subject,
InstitutionIdentifierApplication.Status.PACKAGED, "当前没有待发送的已打包机构标识申请");
"当前没有待发送的已打包机构标识申请");
if (application.getBankSignature() == null) {
throw new BusinessException(ErrorCode.VALIDATION_ERROR, "请先完成申请报文组装");
}
InstitutionIdentifierApplication.Status expectedStatus = application.getStatus();
invokeDomain(application::submit);
repository.update(application, expectedStatus, "SEND",
@ -131,17 +131,9 @@ public class InstitutionIdentifierStepService {
application.getBankSignature());
}
private InstitutionIdentifierApplication requireCurrent(InstitutionKeySubject subject,
InstitutionIdentifierApplication.Status status,
String message) {
InstitutionIdentifierApplication application = repository.findLatestBySubject(subject.getUserId(),
subject.getSchoolId(), subject.getClassId()).orElseThrow(() ->
new BusinessException(ErrorCode.RESOURCE_NOT_FOUND, message));
if (application.getStatus() != status) {
throw new BusinessException(ErrorCode.VALIDATION_ERROR,
message + ",当前最新一轮状态:" + application.getStatus().name());
}
return application;
private InstitutionIdentifierApplication requireCurrent(InstitutionKeySubject subject, String message) {
return repository.findLatestBySubject(subject.getUserId(), subject.getSchoolId(), subject.getClassId())
.orElseThrow(() -> new BusinessException(ErrorCode.RESOURCE_NOT_FOUND, message));
}
private void requireStatus(InstitutionIdentifierApplication application,

@ -149,10 +149,14 @@ public class QuotaControlBitService {
public QuotaControlBitResult sign(String privateKey, String completeControlBit, String algorithm,
InstitutionKeySubject subject, String operator) {
QuotaControlBitEntity value = requireLatest(subject);
requireResult(value.getCompleteControlBit(), "请先拼接完整额度控制位");
requireResult(value.getStaticSegment(), "请先生成静态段");
requireResult(value.getDynamicSegment(), "请先生成动态段");
requireResult(value.getCentralBankSignatureSegment(), "请先读取央行签名段");
String expectedControlBit = value.getStaticSegment() + "|" + value.getDynamicSegment() + "|"
+ value.getCentralBankSignatureSegment();
String submittedControlBit = completeControlBit == null ? null : completeControlBit.trim();
if (!value.getCompleteControlBit().equals(submittedControlBit)) {
throw keyError(subject, "完整额度控制位与步骤八拼接结果不一致");
if (!expectedControlBit.equals(submittedControlBit)) {
throw keyError(subject, "完整额度控制位与静态段、动态段及央行签名段拼接结果不一致");
}
if (!"SM2".equalsIgnoreCase(algorithm == null ? "" : algorithm.trim())) {
throw keyError(subject, "签名算法必须选择SM2");
@ -163,6 +167,7 @@ public class QuotaControlBitService {
}
update(value, value.getStatus(), "SIGNED", operator,
new LambdaUpdateWrapper<QuotaControlBitEntity>()
.set(QuotaControlBitEntity::getCompleteControlBit, submittedControlBit)
.set(QuotaControlBitEntity::getSigningKeyId, InstitutionKeyService.BANK_SECOND_KEY)
.set(QuotaControlBitEntity::getHashAlgorithm, "SM2")
.set(QuotaControlBitEntity::getBankSignature, signature)

@ -0,0 +1,23 @@
package com.yau.digitalrmb.institutionidentity.application;
import com.yau.digitalrmb.institutionidentity.infrastructure.StandardCurrencyEntity;
import lombok.Getter;
import java.math.BigDecimal;
@Getter
public class StandardCurrencyListItemResult {
private final Integer sequenceNumber;
private final BigDecimal denomination;
private final String currencyId;
private final String completeCurrency;
private final Integer status;
public StandardCurrencyListItemResult(StandardCurrencyEntity value) {
this.sequenceNumber = value.getSequenceNumber();
this.denomination = value.getDenomination();
this.currencyId = value.getCurrencyId();
this.completeCurrency = value.getCompleteCurrency();
this.status = "可用".equals(value.getStatus()) || "已生效".equals(value.getStatus()) ? 2 : 1;
}
}

@ -43,11 +43,8 @@ public class StandardCurrencyService {
@Resource private InstitutionTrainingScoreService scoreService;
@Transactional
public StandardCurrencyBatchResult decompose(BigDecimal amount, InstitutionKeySubject subject, String operator) {
public StandardCurrencyBatchResult decompose(InstitutionKeySubject subject, String operator) {
QuotaControlBitEntity source = requireStepEight(subject);
if (amount == null || source.getAmount().compareTo(amount) != 0) {
throw inputError(subject, "用户输入的货币总额与步骤八额度控制位金额不一致");
}
StandardCurrencyBatchEntity current = latest(subject);
List<DenominationBreakdownResult> breakdown = decomposeAmount(source.getAmount());
if (current != null) {
@ -210,6 +207,16 @@ public class StandardCurrencyService {
return result(requireLatest(subject));
}
@Transactional(readOnly = true)
public List<StandardCurrencyListItemResult> currencyList(InstitutionKeySubject subject) {
StandardCurrencyBatchEntity batch = requireLatest(subject);
return currencyMapper.selectList(new LambdaQueryWrapper<StandardCurrencyEntity>()
.eq(StandardCurrencyEntity::getBatchId, batch.getId())
.eq(StandardCurrencyEntity::getDeleted, false)
.orderByAsc(StandardCurrencyEntity::getSequenceNumber))
.stream().map(StandardCurrencyListItemResult::new).collect(Collectors.toList());
}
private List<DenominationBreakdownResult> decomposeAmount(BigDecimal amount) {
long remaining = amount.movePointRight(2).longValueExact();
List<DenominationBreakdownResult> result = new ArrayList<>();

@ -132,8 +132,10 @@ public class TransactionInformationIdentifierService {
@Transactional
public TransactionIdentifierAssemblyResult assemble(InstitutionKeySubject subject, String operator) {
TransactionInformationIdentifier value = requireStatus(subject,
TransactionInformationIdentifier.Status.DIGESTED, "请先使用SM3生成摘要");
TransactionInformationIdentifier value = requireLatest(subject);
if (value.getDigest() == null) {
throw new BusinessException(ErrorCode.VALIDATION_ERROR, "请先使用SM3生成摘要");
}
TransactionInformationIdentifier.Status expected = value.getStatus();
invoke(value::assemble);
repository.update(value, expected, "ASSEMBLE", "将固定前缀TXN_与SM3摘要组装为交易信息标识", operator);
@ -196,8 +198,10 @@ public class TransactionInformationIdentifierService {
@Transactional
public QuotaRequestMessageResult packageQuotaRequest(InstitutionKeySubject subject,
String operator) {
TransactionInformationIdentifier value = requireStatus(subject,
TransactionInformationIdentifier.Status.QUOTA_SIGNED, "请先完成步骤五额度请求签名");
TransactionInformationIdentifier value = requireLatest(subject);
if (value.getQuotaSignature() == null) {
throw new BusinessException(ErrorCode.VALIDATION_ERROR, "请先完成步骤五额度请求签名");
}
TransactionInformationIdentifier.Status expected = value.getStatus();
String message = buildQuotaRequestMessage(value);
invoke(() -> value.packageQuotaRequest(message));
@ -207,8 +211,10 @@ public class TransactionInformationIdentifierService {
@Transactional
public QuotaRequestMessageResult sendQuotaRequest(InstitutionKeySubject subject, String operator) {
TransactionInformationIdentifier value = requireStatus(subject,
TransactionInformationIdentifier.Status.QUOTA_PACKAGED, "请先打包步骤五额度请求报文");
TransactionInformationIdentifier value = requireLatest(subject);
if (value.getQuotaRequestMessage() == null) {
throw new BusinessException(ErrorCode.VALIDATION_ERROR, "请先打包步骤五额度请求报文");
}
TransactionInformationIdentifier.Status expected = value.getStatus();
invoke(value::sendQuotaRequest);
invoke(value::receiveQuotaRequest);
@ -302,8 +308,10 @@ public class TransactionInformationIdentifierService {
@Transactional(readOnly = true)
public QuotaVerificationResult quotaVerificationDetail(InstitutionKeySubject subject) {
TransactionInformationIdentifier value = requireStatus(subject,
TransactionInformationIdentifier.Status.QUOTA_VERIFIED, "步骤六尚未完成额度请求验签");
TransactionInformationIdentifier value = requireLatest(subject);
if (!Boolean.TRUE.equals(value.getQuotaDigestMatches())) {
throw new BusinessException(ErrorCode.VALIDATION_ERROR, "步骤六尚未完成额度请求验签");
}
return new QuotaVerificationResult(value);
}

@ -91,9 +91,6 @@ public class CurrencyGenerationRequest {
public void replaceDigestInput(long identifierApplicationId, String institutionIdentifier,
String fullInstitutionIdentifier, BigDecimal amount,
String deliveryNodeCode, String requestTimestamp, String digest) {
if (status != Status.CONCATENATED && status != Status.DIGESTED) {
throw new IllegalStateException("当前货币生成请求已进入后续步骤,不能修改摘要输入");
}
CurrencyGenerationRequest replacement = prepare(identifierApplicationId, institutionIdentifier,
fullInstitutionIdentifier, amount, deliveryNodeCode, requestTimestamp);
if (digest == null || !digest.matches("[0-9A-F]{64}")) {
@ -107,6 +104,9 @@ public class CurrencyGenerationRequest {
this.requestTimestamp = replacement.requestTimestamp;
this.requestOriginalText = replacement.requestOriginalText;
this.requestDigest = digest;
this.bankSignature = null;
this.signingKeyId = null;
this.requestMessage = null;
this.status = Status.DIGESTED;
}
@ -120,17 +120,22 @@ public class CurrencyGenerationRequest {
}
public void recordSignature(String keyId, String signature) {
requireStatus(Status.DIGESTED, "当前步骤不是商业银行签名,不能操作");
if (requestDigest == null) {
throw new IllegalStateException("请先完成SM3摘要计算");
}
if (keyId == null || signature == null || !signature.matches("[0-9A-F]+")) {
throw new IllegalArgumentException("SM2签名信息不正确");
}
signingKeyId = keyId;
bankSignature = signature;
requestMessage = null;
status = Status.SIGNED;
}
public void packageMessage(String message) {
requireStatus(Status.SIGNED, "当前步骤不是请求报文组装,不能操作");
if (bankSignature == null) {
throw new IllegalStateException("请先完成商业银行签名");
}
if (message == null || message.trim().isEmpty()) {
throw new IllegalArgumentException("请求报文不能为空");
}
@ -139,12 +144,16 @@ public class CurrencyGenerationRequest {
}
public void send() {
requireStatus(Status.PACKAGED, "当前步骤不是请求发送,不能操作");
if (requestMessage == null) {
throw new IllegalStateException("请先完成请求报文组装");
}
status = Status.SENT;
}
public void receive() {
requireStatus(Status.SENT, "央行只能接收已发送的请求");
if (requestMessage == null) {
throw new IllegalStateException("央行只能接收已发送的请求");
}
status = Status.RECEIVED;
}

@ -133,7 +133,9 @@ public class CurrencyGenerationVerification {
}
public void verifyQuota(BigDecimal total, BigDecimal used, BigDecimal remaining) {
requireStatus(Status.DIGEST_MATCHED, "请先匹配摘要一和摘要二");
if (!Boolean.TRUE.equals(digestMatches)) {
throw new IllegalStateException("请先匹配摘要一和摘要二");
}
totalQuota = total;
usedQuota = used;
remainingQuota = remaining;
@ -144,7 +146,9 @@ public class CurrencyGenerationVerification {
}
public void confirm(String keyId, String signature, String time) {
requireStatus(Status.QUOTA_VERIFIED, "请先完成额度检查");
if (!Boolean.TRUE.equals(quotaSufficient)) {
throw new IllegalStateException("请先完成额度检查");
}
if (keyId == null || signature == null || time == null) {
throw new IllegalArgumentException("央行签名确权数据不完整");
}
@ -155,7 +159,9 @@ public class CurrencyGenerationVerification {
}
public void packageResponse(String message) {
requireStatus(Status.CONFIRMED, "请先完成央行签名确权");
if (centralBankSignature == null || confirmationTime == null) {
throw new IllegalStateException("请先完成央行签名确权");
}
if (message == null || message.trim().isEmpty()) {
throw new IllegalArgumentException("确认报文不能为空");
}
@ -164,7 +170,9 @@ public class CurrencyGenerationVerification {
}
public void returnResponse() {
requireStatus(Status.PACKAGED, "请先打包确认报文");
if (confirmationMessage == null) {
throw new IllegalStateException("请先打包确认报文");
}
status = Status.RESPONSE_RETURNED;
}

@ -67,9 +67,6 @@ public class InstitutionIdentifierApplication {
}
public void replaceDigestInput(String bankCode, String timestamp, String originalText, String digest) {
if (status != Status.PREPARED && status != Status.DIGESTED) {
throw new IllegalStateException("当前申请已进入后续步骤,不能修改摘要原文");
}
validateBase(bankCode, timestamp);
this.bankCode = bankCode;
this.timestamp = timestamp;
@ -78,6 +75,13 @@ public class InstitutionIdentifierApplication {
throw new IllegalArgumentException("SM3摘要格式不正确");
}
this.digest = digest;
this.bankSignature = null;
this.verificationKeyId = null;
this.signatureValid = null;
this.digestMatches = null;
this.signingKeyId = null;
this.institutionIdentifier = null;
this.centralBankSignature = null;
this.status = Status.DIGESTED;
}
@ -91,26 +95,40 @@ public class InstitutionIdentifierApplication {
}
public void recordBankSignature(String bankSignature) {
requireStatus(Status.DIGESTED, "当前步骤不是商业银行签名,不能操作");
if (digest == null) {
throw new IllegalStateException("请先完成SM3摘要计算");
}
if (bankSignature == null || !bankSignature.matches("[0-9A-F]+")) {
throw new IllegalArgumentException("银行SM2签名格式不正确");
}
this.bankSignature = bankSignature;
this.verificationKeyId = null;
this.signatureValid = null;
this.digestMatches = null;
this.signingKeyId = null;
this.institutionIdentifier = null;
this.centralBankSignature = null;
this.status = Status.SIGNED;
}
public void packageApplication() {
requireStatus(Status.SIGNED, "当前步骤不是申请组装,不能操作");
if (bankSignature == null) {
throw new IllegalStateException("请先完成商业银行签名");
}
this.status = Status.PACKAGED;
}
public void submit() {
requireStatus(Status.PACKAGED, "当前步骤不是发送申请,不能操作");
if (bankSignature == null) {
throw new IllegalStateException("请先完成申请报文组装");
}
this.status = Status.SUBMITTED;
}
public void recordVerification(String verificationKeyId, boolean signatureValid, boolean digestMatches) {
requireStatus(Status.SUBMITTED, "申请尚未发送至央行,不能进行解密验证");
if (bankSignature == null) {
throw new IllegalStateException("申请尚未发送至央行,不能进行解密验证");
}
this.verificationKeyId = verificationKeyId;
this.signatureValid = signatureValid;
this.digestMatches = digestMatches;
@ -118,7 +136,9 @@ public class InstitutionIdentifierApplication {
}
public void issue(String signingKeyId, String institutionIdentifier, String centralBankSignature) {
requireStatus(Status.VERIFIED, "申请尚未验证通过,不能进行央行签名确权");
if (!Boolean.TRUE.equals(signatureValid) || !Boolean.TRUE.equals(digestMatches)) {
throw new IllegalStateException("申请尚未验证通过,不能进行央行签名确权");
}
if (signingKeyId == null || institutionIdentifier == null || centralBankSignature == null) {
throw new IllegalArgumentException("签发信息不能为空");
}

@ -9,8 +9,8 @@ public class QuotaControlSignRequest {
@NotBlank(message = "商业银行第二私钥不能为空")
private String privateKey;
@NotBlank(message = "完整额度控制位不能为空")
@Schema(description = "前端拼接得到的完整额度控制位,格式为静态段|动态段|央行控制系统签名段",
example = "STATIC_7AD7D47A81F0230562F912AC5CFA6F44D5A851C978191F4DAB8241CF1BFD7971|DYN_YMUL9SQ0_20260807141518|CB_CTRL_30450220ABCDEF")
// @Schema(description = "前端拼接得到的完整额度控制位,格式为静态段|动态段|央行控制系统签名段",
// example = "STATIC_7AD7D47A81F0230562F912AC5CFA6F44D5A851C978191F4DAB8241CF1BFD7971|DYN_YMUL9SQ0_20260807141518|CB_CTRL_30450220ABCDEF")
private String completeControlBit;
@NotBlank(message = "签名算法不能为空")
@Schema(description = "必须为SM2", example = "SM2")

@ -75,7 +75,7 @@ public class QuotaControlBitController {
@PostMapping("/steps/sign")
@Operation(summary = "商业银行第二私钥签名确认",
description = "前端提交完整额度控制位、商业银行第二SM2私钥和SM2算法。后端校验完整额度控制位与步骤八拼接结果一致后进行签名错误内容、私钥或算法会累计实训错误次数。")
description = "前端提交由静态段、动态段和央行签名段拼接的完整额度控制位以及商业银行第二SM2私钥和SM2算法无需提前调用后端拼接接口。后端校验三段拼接结果一致后落库并签名错误内容、私钥或算法会累计实训错误次数。")
public ApiResponse<SignatureResult> sign(@Valid @RequestBody QuotaControlSignRequest request) {
JwtUser user = AuthContextHolder.get();
QuotaControlBitResult result = service.sign(request.getPrivateKey(), request.getCompleteControlBit(),

@ -2,8 +2,8 @@ package com.yau.digitalrmb.institutionidentity.interfaces.rest;
import com.yau.digitalrmb.institutionidentity.application.InstitutionKeySubject;
import com.yau.digitalrmb.institutionidentity.application.StandardCurrencyBatchResult;
import com.yau.digitalrmb.institutionidentity.application.StandardCurrencyListItemResult;
import com.yau.digitalrmb.institutionidentity.application.StandardCurrencyService;
import com.yau.digitalrmb.institutionidentity.interfaces.dto.CurrencyDecompositionRequest;
import com.yau.digitalrmb.institutionidentity.interfaces.dto.CurrencyRuleRequest;
import com.yau.digitalrmb.shared.api.ApiResponse;
import com.yau.digitalrmb.shared.web.TraceIdFilter;
@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
@Validated
@RestController
@ -30,12 +31,12 @@ public class StandardCurrencyController {
@Resource private StandardCurrencyService service;
@PostMapping("/steps/decompose")
@Operation(summary = "执行面额拆解", description = "按100、50、20、10、5、1、0.5、0.2、0.1、0.05、0.01从大到小拆解。")
public ApiResponse<StandardCurrencyBatchResult> decompose(
@Valid @RequestBody CurrencyDecompositionRequest request) {
@Operation(summary = "执行面额拆解",
description = "无需请求体。后端按当前JWT主体查询步骤八已确认额度控制位金额并按100、50、20、10、5、1、0.5、0.2、0.1、0.05、0.01从大到小拆解。")
public ApiResponse<StandardCurrencyBatchResult> decompose() {
JwtUser user = AuthContextHolder.get();
return ApiResponse.success(service.decompose(request.getAmount(), InstitutionKeySubject.from(user),
user.getUsername()), traceId());
return ApiResponse.success(service.decompose(
InstitutionKeySubject.from(user), user.getUsername()), traceId());
}
@PostMapping("/steps/confirm-rule")
@ -53,6 +54,12 @@ public class StandardCurrencyController {
return ApiResponse.success(service.generate(InstitutionKeySubject.from(user), user.getUsername()), traceId());
}
@GetMapping("/currencies")
@Operation(summary = "查询标准面额币串列表", description = "返回当前用户生成的全部币串status=1表示待生效status=2表示已生效。")
public ApiResponse<List<StandardCurrencyListItemResult>> currencies() {
return ApiResponse.success(service.currencyList(InstitutionKeySubject.from(AuthContextHolder.get())), traceId());
}
@GetMapping
@Operation(summary = "查询步骤九当前结果")
public ApiResponse<StandardCurrencyBatchResult> detail() {

@ -584,12 +584,10 @@ class TransactionInformationIdentifierControllerTest {
.andExpect(jsonPath("$.data.length()").value(1))
.andExpect(jsonPath("$.data.status").doesNotExist())
.andExpect(jsonPath("$.data.completeControlBit").doesNotExist());
mvc.perform(post(QUOTA_CONTROL_BASE_PATH + "/steps/assemble").header("Authorization", authorization))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.completeControlBit").value(org.hamcrest.Matchers.allOf(
org.hamcrest.Matchers.containsString("|DYN_"),
org.hamcrest.Matchers.containsString("|CB_CTRL_"))));
String completeControlBit = quotaControlBitMapper.selectList(null).get(0).getCompleteControlBit();
QuotaControlBitEntity beforeSign = quotaControlBitMapper.selectList(null).get(0);
assertThat(beforeSign.getCompleteControlBit()).isNull();
String completeControlBit = beforeSign.getStaticSegment() + "|" + beforeSign.getDynamicSegment() + "|"
+ beforeSign.getCentralBankSignatureSegment();
mvc.perform(post(QUOTA_CONTROL_BASE_PATH + "/steps/sign")
.header("Authorization", authorization).contentType("application/json")
@ -603,7 +601,7 @@ class TransactionInformationIdentifierControllerTest {
+ completeControlBit + "_TAMPERED\",\"hashAlgorithm\":\"SM2\"}"))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.allOf(
org.hamcrest.Matchers.containsString("完整额度控制位与步骤八拼接结果不一致"),
org.hamcrest.Matchers.containsString("完整额度控制位与静态段、动态段及央行签名段拼接结果不一致"),
org.hamcrest.Matchers.containsString("第5次错误"))));
mvc.perform(post(QUOTA_CONTROL_BASE_PATH + "/steps/sign")
.header("Authorization", authorization).contentType("application/json")
@ -618,6 +616,8 @@ class TransactionInformationIdentifierControllerTest {
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.signature").value(org.hamcrest.Matchers.matchesPattern("[0-9A-F]+")))
.andExpect(jsonPath("$.data.length()").value(1));
assertThat(quotaControlBitMapper.selectList(null).get(0).getCompleteControlBit())
.isEqualTo(completeControlBit);
mvc.perform(post(QUOTA_CONTROL_BASE_PATH + "/steps/package").header("Authorization", authorization))
.andExpect(status().isOk()).andExpect(jsonPath("$.data.status").value("PACKAGED"))
.andExpect(jsonPath("$.data.requestMessage").value(org.hamcrest.Matchers.containsString("\"quotaId\"")));
@ -684,13 +684,7 @@ class TransactionInformationIdentifierControllerTest {
flowsUserInputThroughCompleteStepEightAndAccumulatesErrors();
mvc.perform(post(STANDARD_CURRENCY_BASE_PATH + "/steps/decompose")
.header("Authorization", authorization).contentType("application/json")
.content("{\"amount\":1590.85}"))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString("第7次错误")));
mvc.perform(post(STANDARD_CURRENCY_BASE_PATH + "/steps/decompose")
.header("Authorization", authorization).contentType("application/json")
.content("{\"amount\":1589.85}"))
.header("Authorization", authorization))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.status").value("DECOMPOSED"))
.andExpect(jsonPath("$.data.totalCount").value(27))
@ -703,7 +697,7 @@ class TransactionInformationIdentifierControllerTest {
.content("{\"prefix\":\"RMB\",\"idRule\":\"批次号+枚序号+随机校验码\"," +
"\"currencyStatus\":\"待生效\"}"))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString("第8次错误")));
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString("第7次错误")));
mvc.perform(post(STANDARD_CURRENCY_BASE_PATH + "/steps/confirm-rule")
.header("Authorization", authorization).contentType("application/json")
.content("{\"prefix\":\"DC\",\"idRule\":\"批次号+枚序号+随机校验码\"," +
@ -722,6 +716,19 @@ class TransactionInformationIdentifierControllerTest {
org.hamcrest.Matchers.containsString("_ORG_3A4B5C6D7E8F_100.00_")))
.andExpect(jsonPath("$.data.currencies[26].denomination").value(0.05))
.andExpect(jsonPath("$.data.currencies[26].status").value("待生效"));
mvc.perform(get(STANDARD_CURRENCY_BASE_PATH + "/currencies")
.header("Authorization", authorization))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.length()").value(27))
.andExpect(jsonPath("$.data[0].sequenceNumber").value(1))
.andExpect(jsonPath("$.data[0].denomination").value(100.0))
.andExpect(jsonPath("$.data[0].currencyId").value(
org.hamcrest.Matchers.matchesPattern("DC_[0-9]{8}_[0-9]{3}_001_[0-9A-Z]{6}")))
.andExpect(jsonPath("$.data[0].completeCurrency").value(
org.hamcrest.Matchers.containsString("_ORG_3A4B5C6D7E8F_100.00_")))
.andExpect(jsonPath("$.data[0].status").value(1))
.andExpect(jsonPath("$.data[0].randomCheckCode").doesNotExist())
.andExpect(jsonPath("$.data[0].institutionIdentifier").doesNotExist());
List<StandardCurrencyEntity> currencies = standardCurrencyMapper.selectList(null);
assertThat(standardCurrencyBatchMapper.selectList(null)).hasSize(1);
@ -729,6 +736,17 @@ class TransactionInformationIdentifierControllerTest {
assertThat(currencies.stream().map(StandardCurrencyEntity::getDenomination)
.reduce(BigDecimal.ZERO, BigDecimal::add)).isEqualByComparingTo("1589.85");
assertThat(currencies.stream().map(StandardCurrencyEntity::getCurrencyId).distinct().count()).isEqualTo(27);
StandardCurrencyEntity activated = currencies.get(0);
activated.setStatus("可用");
standardCurrencyMapper.updateById(activated);
mvc.perform(get(STANDARD_CURRENCY_BASE_PATH + "/currencies")
.header("Authorization", authorization))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.length()").value(27))
.andExpect(jsonPath("$.data[0].status").value(2))
.andExpect(jsonPath("$.data[1].status").value(1));
activated.setStatus("待生效");
standardCurrencyMapper.updateById(activated);
List<Long> currencyIds = currencies.stream().map(StandardCurrencyEntity::getId)
.collect(java.util.stream.Collectors.toList());
long batchId = standardCurrencyBatchMapper.selectList(null).get(0).getId();
@ -746,8 +764,7 @@ class TransactionInformationIdentifierControllerTest {
@Test
void rejectsStepNineUntilStepEightIsReceived() throws Exception {
mvc.perform(post(STANDARD_CURRENCY_BASE_PATH + "/steps/decompose")
.header("Authorization", authorization).contentType("application/json")
.content("{\"amount\":1589.85}"))
.header("Authorization", authorization))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString(
"步骤八尚未完成央行接收")));

Loading…
Cancel
Save