Merge branch 'agent/payment-training-progress' into master

master
chenyuan 3 days ago
commit e1e6c31c23

@ -0,0 +1,26 @@
package com.yau.digitalrmb.issuance.application;
import io.swagger.v3.oas.annotations.media.Schema;
import java.math.BigDecimal;
@Schema(description = "货币发行实验重置结果")
public class IssuanceTrainingResetResult {
private final boolean reset;
private final int deletedRecordCount;
private final BigDecimal restoredReserveAmount;
private final BigDecimal restoredCurrencyAmount;
public IssuanceTrainingResetResult(int deletedRecordCount, BigDecimal restoredReserveAmount,
BigDecimal restoredCurrencyAmount) {
this.reset = true;
this.deletedRecordCount = deletedRecordCount;
this.restoredReserveAmount = restoredReserveAmount;
this.restoredCurrencyAmount = restoredCurrencyAmount;
}
public boolean isReset() { return reset; }
public int getDeletedRecordCount() { return deletedRecordCount; }
public BigDecimal getRestoredReserveAmount() { return restoredReserveAmount; }
public BigDecimal getRestoredCurrencyAmount() { return restoredCurrencyAmount; }
}

@ -0,0 +1,197 @@
package com.yau.digitalrmb.issuance.application.service;
import com.yau.digitalrmb.issuance.application.IssuanceTrainingResetResult;
import com.yau.digitalrmb.shared.api.ErrorCode;
import com.yau.digitalrmb.shared.exception.BusinessException;
import com.yau.digitalrmb.training.attempt.domain.ExperimentModule;
import com.yau.digitalrmb.training.attempt.domain.ExperimentSubject;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@Service
public class IssuanceTrainingResetService {
private static final String PROGRESS_MODULE_CODE = "PBOC_CURRENCY_ISSUANCE";
private final JdbcTemplate jdbc;
public IssuanceTrainingResetService(JdbcTemplate jdbc) {
this.jdbc = jdbc;
}
@Transactional
public IssuanceTrainingResetResult reset(ExperimentSubject subject) {
requireSubject(subject);
List<AttemptRecord> attempts = jdbc.query(
"SELECT id,business_id FROM training_experiment_attempt WHERE module_code=? "
+ "AND user_id=? AND school_id=? AND class_id=? AND organization_id=? FOR UPDATE",
(rs, rowNum) -> new AttemptRecord(rs.getString("id"), rs.getString("business_id")),
ExperimentModule.ISSUANCE.name(), subject.getUserId(), subject.getSchoolId(), subject.getClassId(),
subject.getOrganizationId());
Set<String> requestIds = new LinkedHashSet<String>();
for (AttemptRecord attempt : attempts) {
if (attempt.businessId != null && !attempt.businessId.trim().isEmpty()) {
requestIds.add(attempt.businessId.trim());
}
}
for (String requestId : requestIds) {
requireOwnedRequest(requestId, subject.getUserId());
requireUnusedByFollowingModules(requestId);
}
BigDecimal restoredReserve = BigDecimal.ZERO.setScale(2);
BigDecimal restoredCurrency = BigDecimal.ZERO.setScale(2);
int affected = 0;
for (String requestId : requestIds) {
for (ReserveRestoration value : reserveRestorations(requestId)) {
int updated = jdbc.update("UPDATE central_bank_institution_account "
+ "SET reserve_balance=reserve_balance+? WHERE bank_code=?",
value.amount, value.bankCode);
if (updated != 1) throw internal("恢复商业银行准备金余额失败:" + value.bankCode);
restoredReserve = restoredReserve.add(value.amount);
}
for (CurrencyRestoration value : currencyRestorations(requestId)) {
int vaultUpdated = jdbc.update("UPDATE central_bank_currency_vault "
+ "SET available_balance=available_balance+? WHERE currency=?",
value.amount, value.currency);
if (vaultUpdated != 1) throw internal("恢复央行发行库余额失败:" + value.currency);
int bankUpdated = jdbc.update("UPDATE issuance_bank_inventory "
+ "SET current_balance=current_balance-?,updated_at=CURRENT_TIMESTAMP "
+ "WHERE bank_code=? AND current_balance>=?",
value.amount, value.bankCode, value.amount);
if (bankUpdated != 1) throw internal("恢复商业银行数字货币库存失败:" + value.bankCode);
restoredCurrency = restoredCurrency.add(value.amount);
}
affected += deleteRequestData(requestId, subject.getUserId());
}
for (AttemptRecord attempt : attempts) {
affected += jdbc.update("DELETE FROM training_experiment_action WHERE attempt_id=?", attempt.id);
}
affected += jdbc.update("DELETE FROM training_experiment_attempt WHERE module_code=? "
+ "AND user_id=? AND school_id=? AND class_id=? AND organization_id=?",
ExperimentModule.ISSUANCE.name(), subject.getUserId(), subject.getSchoolId(), subject.getClassId(),
subject.getOrganizationId());
affected += jdbc.update("DELETE FROM training_task_step_progress WHERE user_id=? AND module_code=?",
subject.getUserId(), PROGRESS_MODULE_CODE);
return new IssuanceTrainingResetResult(affected, restoredReserve, restoredCurrency);
}
private void requireOwnedRequest(String requestId, String userId) {
Integer count = jdbc.queryForObject("SELECT COUNT(*) FROM issuance_request "
+ "WHERE id=? AND created_by_user_id=?", Integer.class, requestId, userId);
if (count == null || count != 1) {
throw new BusinessException(ErrorCode.UNAUTHORIZED, "发行申请不存在或不属于当前用户");
}
}
private void requireUnusedByFollowingModules(String requestId) {
Integer issued = jdbc.queryForObject("SELECT COUNT(*) FROM commercial_bank_currency "
+ "WHERE issuance_request_id=?", Integer.class, requestId);
Integer resettable = jdbc.queryForObject("SELECT COUNT(*) FROM commercial_bank_currency c "
+ "JOIN central_bank_currency_ownership o ON o.currency_id=c.currency_id "
+ "WHERE c.issuance_request_id=? AND c.status='可用' AND o.owner_type='BANK' "
+ "AND o.owner_id=c.bank_code AND o.status='AVAILABLE' AND o.lock_business_type IS NULL "
+ "AND o.lock_business_id IS NULL AND o.last_transaction_id IS NULL", Integer.class, requestId);
if (!safeEquals(issued, resettable)) {
throw validation("模块二发行的数字货币已被后续模块使用,不能从模块二重置");
}
Integer exchangeReferences = jdbc.queryForObject("SELECT COUNT(*) FROM exchange_coin_reservation r "
+ "JOIN commercial_bank_currency c ON c.currency_id=r.currency_id "
+ "WHERE c.issuance_request_id=?", Integer.class, requestId);
Integer paymentReferences = jdbc.queryForObject("SELECT COUNT(*) FROM payment_coin_reservation r "
+ "JOIN commercial_bank_currency c ON c.currency_id=r.currency_id "
+ "WHERE c.issuance_request_id=?", Integer.class, requestId);
if (positive(exchangeReferences) || positive(paymentReferences)) {
throw validation("模块二发行的数字货币已产生兑换或支付记录,不能从模块二重置");
}
}
private List<ReserveRestoration> reserveRestorations(String requestId) {
return jdbc.query("SELECT n.bank_code,e.deduction_amount FROM reserve_deduction_execution e "
+ "JOIN reserve_deduction_notification n ON n.request_id=e.request_id "
+ "WHERE e.request_id=? AND e.status='DEDUCTED' FOR UPDATE",
(rs, rowNum) -> new ReserveRestoration(rs.getString("bank_code"),
rs.getBigDecimal("deduction_amount")), requestId);
}
private List<CurrencyRestoration> currencyRestorations(String requestId) {
return jdbc.query("SELECT bank_code,currency,SUM(denomination) amount "
+ "FROM commercial_bank_currency WHERE issuance_request_id=? "
+ "GROUP BY bank_code,currency",
(rs, rowNum) -> new CurrencyRestoration(rs.getString("bank_code"), rs.getString("currency"),
rs.getBigDecimal("amount")), requestId);
}
private int deleteRequestData(String requestId, String userId) {
int count = 0;
count += jdbc.update("DELETE FROM central_bank_currency_ownership WHERE currency_id IN "
+ "(SELECT currency_id FROM commercial_bank_currency WHERE issuance_request_id=?)", requestId);
count += jdbc.update("DELETE FROM commercial_bank_currency WHERE issuance_request_id=?", requestId);
count += jdbc.update("DELETE FROM digital_currency_ownership_confirmation WHERE request_id=?", requestId);
count += jdbc.update("DELETE FROM draft_digital_currency WHERE batch_id IN "
+ "(SELECT batch_id FROM digital_currency_production_batch WHERE request_id=?)", requestId);
count += jdbc.update("DELETE FROM digital_currency_production_batch WHERE request_id=?", requestId);
count += jdbc.update("DELETE FROM issuance_source_currency_usage WHERE issuance_request_id=?", requestId);
count += jdbc.update("DELETE FROM reserve_deduction_execution WHERE request_id=?", requestId);
count += jdbc.update("DELETE FROM reserve_deduction_notification WHERE request_id=?", requestId);
count += jdbc.update("DELETE FROM central_bank_issuance_business_review WHERE request_id=?", requestId);
count += jdbc.update("DELETE FROM central_bank_issuance_verification WHERE request_id=?", requestId);
count += jdbc.update("DELETE FROM central_bank_issuance_receipt WHERE request_id=?", requestId);
count += jdbc.update("DELETE FROM issuance_request_denomination WHERE request_id=?", requestId);
count += jdbc.update("UPDATE issuance_request SET deleted=TRUE,updated_at=CURRENT_TIMESTAMP,"
+ "updated_by_user_id=?,updated_by=? WHERE id=? AND created_by_user_id=? AND deleted=FALSE",
userId, userId, requestId, userId);
return count;
}
private void requireSubject(ExperimentSubject subject) {
if (subject == null || subject.getUserId() == null || subject.getUserId().trim().isEmpty()
|| subject.getSchoolId() <= 0 || subject.getClassId() <= 0) {
throw new BusinessException(ErrorCode.UNAUTHORIZED, "缺少货币发行实验主体信息");
}
}
private boolean safeEquals(Integer left, Integer right) {
return left != null && right != null && left.intValue() == right.intValue();
}
private boolean positive(Integer value) { return value != null && value > 0; }
private BusinessException validation(String message) {
return new BusinessException(ErrorCode.VALIDATION_ERROR, message);
}
private BusinessException internal(String message) {
return new BusinessException(ErrorCode.INTERNAL_ERROR, message);
}
private static final class AttemptRecord {
private final String id;
private final String businessId;
private AttemptRecord(String id, String businessId) { this.id = id; this.businessId = businessId; }
}
private static final class ReserveRestoration {
private final String bankCode;
private final BigDecimal amount;
private ReserveRestoration(String bankCode, BigDecimal amount) {
this.bankCode = bankCode; this.amount = amount;
}
}
private static final class CurrencyRestoration {
private final String bankCode;
private final String currency;
private final BigDecimal amount;
private CurrencyRestoration(String bankCode, String currency, BigDecimal amount) {
this.bankCode = bankCode; this.currency = currency; this.amount = amount;
}
}
}

@ -0,0 +1,59 @@
package com.yau.digitalrmb.issuance.interfaces.rest;
import com.yau.digitalrmb.issuance.application.IssuanceTrainingResetResult;
import com.yau.digitalrmb.issuance.application.service.IssuanceTrainingResetService;
import com.yau.digitalrmb.security.application.CurrentUser;
import com.yau.digitalrmb.security.application.CurrentUserService;
import com.yau.digitalrmb.shared.api.ApiResponse;
import com.yau.digitalrmb.shared.api.ErrorCode;
import com.yau.digitalrmb.shared.exception.BusinessException;
import com.yau.digitalrmb.shared.web.TraceIdFilter;
import com.yau.digitalrmb.training.attempt.domain.ExperimentSubject;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.MDC;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/issuance/training")
@Tag(name = "数字货币发行实验管理")
public class IssuanceTrainingResetController {
private final IssuanceTrainingResetService resetService;
private final CurrentUserService currentUserService;
public IssuanceTrainingResetController(IssuanceTrainingResetService resetService,
CurrentUserService currentUserService) {
this.resetService = resetService;
this.currentUserService = currentUserService;
}
@PostMapping("/reset")
@Operation(summary = "重新开始货币发行实验",
description = "恢复当前实训主体在模块二产生的准备金和数字货币库存,删除发行流程业务及操作数据;模块一前置数据保持不变。")
public ApiResponse<IssuanceTrainingResetResult> reset() {
CurrentUser user = currentUserService.getCurrentUser();
IssuanceTrainingResetResult result = resetService.reset(new ExperimentSubject(
required(user.getUserId(), "用户 ID"), numeric(user.getSchoolId(), "学校 ID"),
numeric(user.getClassId(), "班级 ID"), ""));
return ApiResponse.success(result, MDC.get(TraceIdFilter.MDC_KEY));
}
private long numeric(String value, String name) {
try {
long result = Long.parseLong(required(value, name));
if (result <= 0) throw new NumberFormatException(name);
return result;
} catch (NumberFormatException exception) {
throw new BusinessException(ErrorCode.UNAUTHORIZED, "登录凭据中的" + name + "无效");
}
}
private String required(String value, String name) {
if (value == null || value.trim().isEmpty()) {
throw new BusinessException(ErrorCode.UNAUTHORIZED, "登录凭据缺少" + name);
}
return value.trim();
}
}

@ -0,0 +1,223 @@
package com.yau.digitalrmb.issuance.application.service;
import com.yau.digitalrmb.issuance.application.IssuanceTrainingResetResult;
import com.yau.digitalrmb.shared.exception.BusinessException;
import com.yau.digitalrmb.training.attempt.domain.ExperimentSubject;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@SpringBootTest
@ActiveProfiles("test")
@Transactional
class IssuanceTrainingResetServiceTest {
private static final String USER_ID = "00000000-0000-0000-0000-000000009901";
private static final String OTHER_USER_ID = "00000000-0000-0000-0000-000000009902";
private static final long SCHOOL_ID = 9901L;
private static final long CLASS_ID = 9902L;
private static final String REQUEST_ID = "00000000-0000-0000-0000-000000009911";
private static final String OTHER_REQUEST_ID = "00000000-0000-0000-0000-000000009912";
private static final String ATTEMPT_ID = "00000000-0000-0000-0000-000000009921";
private static final String OTHER_ATTEMPT_ID = "00000000-0000-0000-0000-000000009922";
private static final String BANK_CODE = "RSTBANK9901";
private static final String ORGANIZATION_ID = "ORG_RESET_9901";
private static final String CURRENCY = "RST9901";
private static final String TRANSACTION_ID = "RST_TX_9901";
private static final String BATCH_ID = "RST_BATCH_9901";
private static final String COIN_ID = "RST_COIN_9901";
private static final long SOURCE_BATCH_ID = 9901001L;
private static final long SOURCE_CURRENCY_ID = 9901002L;
@Autowired private JdbcTemplate jdbc;
@Autowired private IssuanceTrainingResetService service;
@Test
void restoresCompletedIssuanceAndDeletesOnlyCurrentSubjectsOperationData() {
seedCompletedIssuance("BANK", "AVAILABLE", null);
seedOtherUsersRequestAndAttempt();
IssuanceTrainingResetResult result = service.reset(subject());
assertThat(result.isReset()).isTrue();
assertThat(result.getRestoredReserveAmount()).isEqualByComparingTo("100.00");
assertThat(result.getRestoredCurrencyAmount()).isEqualByComparingTo("100.00");
assertThat(result.getDeletedRecordCount()).isPositive();
assertThat(decimal("SELECT reserve_balance FROM central_bank_institution_account WHERE bank_code=?", BANK_CODE))
.isEqualByComparingTo("1000.00");
assertThat(decimal("SELECT current_balance FROM issuance_bank_inventory WHERE bank_code=?", BANK_CODE))
.isEqualByComparingTo("0.00");
assertThat(decimal("SELECT available_balance FROM central_bank_currency_vault WHERE currency=?", CURRENCY))
.isEqualByComparingTo("1000.00");
assertThat(count("SELECT COUNT(*) FROM standard_currency WHERE id=?", SOURCE_CURRENCY_ID)).isEqualTo(1);
assertThat(count("SELECT COUNT(*) FROM issuance_source_currency_usage WHERE issuance_request_id=?", REQUEST_ID))
.isZero();
assertThat(count("SELECT COUNT(*) FROM commercial_bank_currency WHERE issuance_request_id=?", REQUEST_ID))
.isZero();
assertThat(count("SELECT COUNT(*) FROM reserve_deduction_execution WHERE request_id=?", REQUEST_ID))
.isZero();
assertThat(count("SELECT COUNT(*) FROM training_experiment_attempt WHERE id=?", ATTEMPT_ID)).isZero();
assertThat(count("SELECT COUNT(*) FROM training_experiment_action WHERE attempt_id=?", ATTEMPT_ID)).isZero();
assertThat(count("SELECT COUNT(*) FROM training_task_step_progress WHERE user_id=? "
+ "AND module_code='PBOC_CURRENCY_ISSUANCE'", USER_ID)).isZero();
assertThat(count("SELECT COUNT(*) FROM issuance_request WHERE id=? AND deleted=TRUE", REQUEST_ID))
.isEqualTo(1);
assertThat(count("SELECT COUNT(*) FROM issuance_request WHERE id=? AND deleted=FALSE", OTHER_REQUEST_ID))
.isEqualTo(1);
assertThat(count("SELECT COUNT(*) FROM training_experiment_attempt WHERE id=?", OTHER_ATTEMPT_ID))
.isEqualTo(1);
IssuanceTrainingResetResult repeated = service.reset(subject());
assertThat(repeated.getDeletedRecordCount()).isZero();
assertThat(repeated.getRestoredReserveAmount()).isEqualByComparingTo("0.00");
assertThat(repeated.getRestoredCurrencyAmount()).isEqualByComparingTo("0.00");
}
@Test
void rejectsResetWhenIssuedCurrencyWasUsedByFollowingModule() {
seedCompletedIssuance("WALLET", "AVAILABLE", "EXCHANGE_9901");
assertThatThrownBy(() -> service.reset(subject()))
.isInstanceOf(BusinessException.class)
.hasMessageContaining("后续模块");
assertThat(decimal("SELECT reserve_balance FROM central_bank_institution_account WHERE bank_code=?", BANK_CODE))
.isEqualByComparingTo("900.00");
assertThat(count("SELECT COUNT(*) FROM issuance_request WHERE id=? AND deleted=FALSE", REQUEST_ID))
.isEqualTo(1);
assertThat(count("SELECT COUNT(*) FROM commercial_bank_currency WHERE issuance_request_id=?", REQUEST_ID))
.isEqualTo(1);
assertThat(count("SELECT COUNT(*) FROM training_experiment_attempt WHERE id=?", ATTEMPT_ID)).isEqualTo(1);
}
private void seedCompletedIssuance(String ownerType, String ownerStatus, String lastTransactionId) {
jdbc.update("INSERT INTO central_bank_institution_account "
+ "(bank_code,organization_id,reserve_account_no,reserve_account_name,status,opened_on,reserve_balance) "
+ "VALUES (?,?,?,?,?,'2020-01-01',?)",
BANK_CODE, ORGANIZATION_ID, "RESERVE_RESET_9901", "重置测试准备金账户", "NORMAL", new BigDecimal("900.00"));
jdbc.update("INSERT INTO issuance_bank_inventory (bank_code,current_balance,warning_threshold,updated_at) "
+ "VALUES (?,?,?,CURRENT_TIMESTAMP)", BANK_CODE, new BigDecimal("100.00"), BigDecimal.ZERO);
jdbc.update("INSERT INTO central_bank_currency_vault (currency,available_balance) VALUES (?,?)",
CURRENCY, new BigDecimal("900.00"));
jdbc.update("INSERT INTO standard_currency_batch "
+ "(id,quota_control_bit_id,batch_number,total_amount,total_count,denomination_summary,status,"
+ "user_id,school_id,class_id,created_at,updated_at,created_by,updated_by,deleted) "
+ "VALUES (?,?,?,?,?,?,?, ?,?,?,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,?,?,FALSE)",
SOURCE_BATCH_ID, 9901000L, "RST_STD_BATCH", new BigDecimal("100.00"), 1, "100:1", "GENERATED",
USER_ID, SCHOOL_ID, CLASS_ID, "tester", "tester");
jdbc.update("INSERT INTO standard_currency "
+ "(id,batch_id,sequence_number,denomination,random_check_code,currency_id,institution_identifier,"
+ "bank_signature_segment,central_bank_signature_segment,complete_currency,status,created_at,"
+ "updated_at,created_by,updated_by,deleted) "
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,?,?,FALSE)",
SOURCE_CURRENCY_ID, SOURCE_BATCH_ID, 1, new BigDecimal("100.00"), "990101", COIN_ID,
ORGANIZATION_ID, "BANK_SIG", "CB_SIG", "SOURCE_COMPLETE", "待生效", "tester", "tester");
insertRequest(REQUEST_ID, "RST_REQ_9901", USER_ID);
jdbc.update("INSERT INTO issuance_request_denomination "
+ "(request_id,denomination,quantity,created_at,updated_at,created_by,updated_by,created_by_user_id,updated_by_user_id) "
+ "VALUES (?,?,1,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,'tester','tester',?,?)",
REQUEST_ID, new BigDecimal("100.00"), USER_ID, USER_ID);
jdbc.update("INSERT INTO central_bank_issuance_receipt "
+ "(request_id,request_no,payload_json,received_at,received_by_user_id,received_by) "
+ "VALUES (?,?,'{}',CURRENT_TIMESTAMP,?,'tester')", REQUEST_ID, "RST_REQ_9901", USER_ID);
jdbc.update("INSERT INTO central_bank_issuance_verification "
+ "(request_id,digest_matched,signature_verified,status,verified_at,verified_by_user_id,verified_by) "
+ "VALUES (?,TRUE,TRUE,'PASSED',CURRENT_TIMESTAMP,?,'tester')", REQUEST_ID, USER_ID);
jdbc.update("INSERT INTO central_bank_issuance_business_review "
+ "(request_id,account_valid,vault_sufficient,amount_consistent,status,reviewed_at,reviewed_by_user_id,reviewed_by) "
+ "VALUES (?,TRUE,TRUE,TRUE,'PASSED',CURRENT_TIMESTAMP,?,'tester')", REQUEST_ID, USER_ID);
jdbc.update("INSERT INTO reserve_deduction_notification "
+ "(request_id,transaction_id,bank_code,organization_id,reserve_account_no,reserve_account_name,currency,"
+ "deduction_amount,status,sent_at,sent_by_user_id,sent_by) "
+ "VALUES (?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP,?,'tester')",
REQUEST_ID, TRANSACTION_ID, BANK_CODE, ORGANIZATION_ID, "RESERVE_RESET_9901",
"重置测试准备金账户", CURRENCY, new BigDecimal("100.00"), "SUBMITTED", USER_ID);
jdbc.update("INSERT INTO reserve_deduction_execution "
+ "(transaction_id,request_id,before_balance,deduction_amount,after_balance,status,executed_at,executed_by_user_id,executed_by) "
+ "VALUES (?,?,?,?,?,'DEDUCTED',CURRENT_TIMESTAMP,?,'tester')",
TRANSACTION_ID, REQUEST_ID, new BigDecimal("1000.00"), new BigDecimal("100.00"),
new BigDecimal("900.00"), USER_ID);
jdbc.update("INSERT INTO digital_currency_production_batch "
+ "(batch_id,request_id,deduction_transaction_id,organization_id,currency,total_amount,status,created_at,"
+ "created_by_user_id,created_by,quota_control_bit_id,control_system_signature_id,complete_control_bit,control_system_signature) "
+ "VALUES (?,?,?,?,?,?,?,CURRENT_TIMESTAMP,?,'tester',?,?,?,?)",
BATCH_ID, REQUEST_ID, TRANSACTION_ID, ORGANIZATION_ID, CURRENCY, new BigDecimal("100.00"),
"OWNERSHIP_CONFIRMED", USER_ID, 9901000L, 9901003L, "CONTROL_BIT", "CONTROL_SIG");
jdbc.update("INSERT INTO draft_digital_currency "
+ "(coin_id,batch_id,sequence_no,denomination,organization_id,currency,status,created_at,created_by_user_id,created_by,"
+ "source_currency_id,source_currency_batch_id,source_complete_currency,complete_control_bit,control_system_signature,"
+ "ownership_original_text,ownership_signature,complete_currency,confirmed_at,confirmed_by_user_id,confirmed_by) "
+ "VALUES (?,?,?,?,?,?,?,CURRENT_TIMESTAMP,?,'tester',?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP,?,'tester')",
COIN_ID, BATCH_ID, 1, new BigDecimal("100.00"), ORGANIZATION_ID, CURRENCY, "AVAILABLE", USER_ID,
SOURCE_CURRENCY_ID, SOURCE_BATCH_ID, "SOURCE_COMPLETE", "CONTROL_BIT", "CONTROL_SIG", "OWNERSHIP_TEXT",
"OWNERSHIP_SIG", "COMPLETE_CURRENCY", USER_ID);
jdbc.update("INSERT INTO digital_currency_ownership_confirmation "
+ "(request_id,batch_id,status,confirmed_at,confirmed_by_user_id,confirmed_by,signing_key_id,central_bank_signature) "
+ "VALUES (?,?,'RECEIPT_SENT',CURRENT_TIMESTAMP,?,'tester','CENTRAL_FIRST_SM2_KEY','CB_FINAL_SIG')",
REQUEST_ID, BATCH_ID, USER_ID);
jdbc.update("INSERT INTO issuance_source_currency_usage "
+ "(id,source_currency_id,source_batch_id,issuance_request_id,status,reserved_at,issued_at,audit_user_id,audit_username,created_at,updated_at) "
+ "VALUES (?,?,?,?, 'ISSUED',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,?,'tester',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)",
9901004L, SOURCE_CURRENCY_ID, SOURCE_BATCH_ID, REQUEST_ID, USER_ID);
jdbc.update("INSERT INTO commercial_bank_currency "
+ "(currency_id,source_currency_id,source_batch_id,issuance_request_id,bank_code,organization_id,denomination,currency,"
+ "complete_currency,issuance_ownership_original_text,issuance_ownership_signature,status,received_at,received_by_user_id,received_by) "
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,'可用',CURRENT_TIMESTAMP,?,'tester')",
COIN_ID, SOURCE_CURRENCY_ID, SOURCE_BATCH_ID, REQUEST_ID, BANK_CODE, ORGANIZATION_ID,
new BigDecimal("100.00"), CURRENCY, "COMPLETE_CURRENCY", "OWNERSHIP_TEXT", "OWNERSHIP_SIG", USER_ID);
jdbc.update("INSERT INTO central_bank_currency_ownership "
+ "(currency_id,owner_type,owner_id,status,lock_business_type,lock_business_id,last_transaction_id,updated_at) "
+ "VALUES (?,?,?,?,NULL,NULL,?,CURRENT_TIMESTAMP)",
COIN_ID, ownerType, "BANK".equals(ownerType) ? BANK_CODE : "WALLET_9901", ownerStatus,
lastTransactionId);
insertAttempt(ATTEMPT_ID, USER_ID, REQUEST_ID);
jdbc.update("INSERT INTO training_experiment_action "
+ "(id,attempt_id,step_code,action_code,status,request_fingerprint,started_at,completed_at,updated_at,version) "
+ "VALUES ('00000000-0000-0000-0000-000000009931',?,'07','sign-bank-receipt','COMPLETED',"
+ "'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,0)",
ATTEMPT_ID);
jdbc.update("INSERT INTO training_task_step_progress (user_id,module_code,step_code,completed_at) "
+ "VALUES (?,'PBOC_CURRENCY_ISSUANCE','07',CURRENT_TIMESTAMP)", USER_ID);
}
private void seedOtherUsersRequestAndAttempt() {
insertRequest(OTHER_REQUEST_ID, "RST_REQ_9902", OTHER_USER_ID);
insertAttempt(OTHER_ATTEMPT_ID, OTHER_USER_ID, OTHER_REQUEST_ID);
}
private void insertRequest(String requestId, String requestNo, String userId) {
jdbc.update("INSERT INTO issuance_request "
+ "(id,request_no,bank_code,organization_id,total_amount,currency,status,central_receive_status,"
+ "created_at,updated_at,created_by,updated_by,created_by_user_id,updated_by_user_id,deleted) "
+ "VALUES (?,?,?,?,?,?,'SENT','RECEIVED',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,'tester','tester',?,?,FALSE)",
requestId, requestNo, BANK_CODE, ORGANIZATION_ID, new BigDecimal("100.00"), CURRENCY, userId, userId);
}
private void insertAttempt(String attemptId, String userId, String requestId) {
jdbc.update("INSERT INTO training_experiment_attempt "
+ "(id,module_code,user_id,school_id,class_id,organization_id,attempt_no,status,current_step_code,current_action_code,"
+ "business_id,version,created_at,updated_at,completed_at) "
+ "VALUES (?,'ISSUANCE',?,?,?,'',1,'COMPLETED','07','sign-bank-receipt',?,0,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)",
attemptId, userId, SCHOOL_ID, CLASS_ID, requestId);
}
private ExperimentSubject subject() {
return new ExperimentSubject(USER_ID, SCHOOL_ID, CLASS_ID, "");
}
private int count(String sql, Object... args) {
Integer value = jdbc.queryForObject(sql, Integer.class, args);
return value == null ? 0 : value;
}
private BigDecimal decimal(String sql, Object... args) {
return jdbc.queryForObject(sql, BigDecimal.class, args);
}
}

@ -88,6 +88,10 @@ class IssuanceTrainingAttemptControllerTest {
.andExpect(status().isOk()).andExpect(jsonPath("$.data.attemptId").value(attemptId.toString())); .andExpect(status().isOk()).andExpect(jsonPath("$.data.attemptId").value(attemptId.toString()));
mockMvc.perform(post("/api/v1/issuance/attempts/{id}/cancel", attemptId).with(jwtFor(USER_ID))) mockMvc.perform(post("/api/v1/issuance/attempts/{id}/cancel", attemptId).with(jwtFor(USER_ID)))
.andExpect(status().isOk()).andExpect(jsonPath("$.data.attemptStatus").value("CANCELLED")); .andExpect(status().isOk()).andExpect(jsonPath("$.data.attemptStatus").value("CANCELLED"));
mockMvc.perform(post("/api/v1/issuance/training/reset").with(jwtFor(USER_ID)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.reset").value(true))
.andExpect(jsonPath("$.data.deletedRecordCount").isNumber());
} }
private CurrentUser user(String userId) { private CurrentUser user(String userId) {

Loading…
Cancel
Save