|
|
|
@ -3,11 +3,16 @@ package com.yau.digitalrmb.shared.wallet;
|
|
|
|
import com.yau.digitalrmb.institutionidentity.application.InstitutionKeySubject;
|
|
|
|
import com.yau.digitalrmb.institutionidentity.application.InstitutionKeySubject;
|
|
|
|
import com.yau.digitalrmb.institutionidentity.domain.InstitutionIdentityCryptography;
|
|
|
|
import com.yau.digitalrmb.institutionidentity.domain.InstitutionIdentityCryptography;
|
|
|
|
import com.yau.digitalrmb.institutionidentity.domain.InstitutionSm2KeyPair;
|
|
|
|
import com.yau.digitalrmb.institutionidentity.domain.InstitutionSm2KeyPair;
|
|
|
|
|
|
|
|
import com.yau.digitalrmb.exchange.domain.model.ExchangeActor;
|
|
|
|
|
|
|
|
import com.yau.digitalrmb.exchange.domain.model.ExchangeContext;
|
|
|
|
|
|
|
|
import com.yau.digitalrmb.exchange.domain.repository.ExchangeResourceRepository;
|
|
|
|
import com.yau.digitalrmb.shared.exception.BusinessException;
|
|
|
|
import com.yau.digitalrmb.shared.exception.BusinessException;
|
|
|
|
import com.yau.digitalrmb.testsupport.WalletOpeningTestData;
|
|
|
|
import com.yau.digitalrmb.testsupport.WalletOpeningTestData;
|
|
|
|
import org.junit.jupiter.api.AfterEach;
|
|
|
|
import org.junit.jupiter.api.AfterEach;
|
|
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
|
|
|
|
import org.junit.jupiter.params.ParameterizedTest;
|
|
|
|
|
|
|
|
import org.junit.jupiter.params.provider.ValueSource;
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
import org.springframework.boot.test.context.SpringBootTest;
|
|
|
|
import org.springframework.boot.test.context.SpringBootTest;
|
|
|
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
|
@ -33,6 +38,7 @@ class WalletPrerequisiteProjectionServiceTest {
|
|
|
|
@Autowired private JdbcTemplate jdbc;
|
|
|
|
@Autowired private JdbcTemplate jdbc;
|
|
|
|
@Autowired private InstitutionIdentityCryptography cryptography;
|
|
|
|
@Autowired private InstitutionIdentityCryptography cryptography;
|
|
|
|
@Autowired private WalletPrerequisiteProjectionService service;
|
|
|
|
@Autowired private WalletPrerequisiteProjectionService service;
|
|
|
|
|
|
|
|
@Autowired private ExchangeResourceRepository exchangeResources;
|
|
|
|
|
|
|
|
|
|
|
|
private InstitutionSm2KeyPair keyPair;
|
|
|
|
private InstitutionSm2KeyPair keyPair;
|
|
|
|
|
|
|
|
|
|
|
|
@ -109,6 +115,7 @@ class WalletPrerequisiteProjectionServiceTest {
|
|
|
|
service.ensureForSubject(subject());
|
|
|
|
service.ensureForSubject(subject());
|
|
|
|
jdbc.update("UPDATE digital_wallet SET balance=321.00,frozen_amount=20.00 WHERE wallet_id=?", WALLET_ID);
|
|
|
|
jdbc.update("UPDATE digital_wallet SET balance=321.00,frozen_amount=20.00 WHERE wallet_id=?", WALLET_ID);
|
|
|
|
jdbc.update("UPDATE wallet_contract SET daily_used_amount=45.00 WHERE wallet_id=?", WALLET_ID);
|
|
|
|
jdbc.update("UPDATE wallet_contract SET daily_used_amount=45.00 WHERE wallet_id=?", WALLET_ID);
|
|
|
|
|
|
|
|
jdbc.update("UPDATE simulated_bank_account SET balance=123.00,frozen_amount=10.00 WHERE user_id=?", SUBJECT_USER);
|
|
|
|
Timestamp activationUpdatedAt = jdbc.queryForObject(
|
|
|
|
Timestamp activationUpdatedAt = jdbc.queryForObject(
|
|
|
|
"SELECT updated_at FROM central_wallet_activation WHERE id=?", Timestamp.class, ACTIVATION_ID);
|
|
|
|
"SELECT updated_at FROM central_wallet_activation WHERE id=?", Timestamp.class, ACTIVATION_ID);
|
|
|
|
|
|
|
|
|
|
|
|
@ -122,6 +129,125 @@ class WalletPrerequisiteProjectionServiceTest {
|
|
|
|
BigDecimal.class, WALLET_ID)).isEqualByComparingTo("45.00");
|
|
|
|
BigDecimal.class, WALLET_ID)).isEqualByComparingTo("45.00");
|
|
|
|
assertThat(jdbc.queryForObject("SELECT updated_at FROM central_wallet_activation WHERE id=?",
|
|
|
|
assertThat(jdbc.queryForObject("SELECT updated_at FROM central_wallet_activation WHERE id=?",
|
|
|
|
Timestamp.class, ACTIVATION_ID)).isEqualTo(activationUpdatedAt);
|
|
|
|
Timestamp.class, ACTIVATION_ID)).isEqualTo(activationUpdatedAt);
|
|
|
|
|
|
|
|
assertThat(jdbc.queryForObject("SELECT balance FROM simulated_bank_account WHERE user_id=?",
|
|
|
|
|
|
|
|
BigDecimal.class, SUBJECT_USER)).isEqualByComparingTo("123.00");
|
|
|
|
|
|
|
|
assertThat(jdbc.queryForObject("SELECT frozen_amount FROM simulated_bank_account WHERE user_id=?",
|
|
|
|
|
|
|
|
BigDecimal.class, SUBJECT_USER)).isEqualByComparingTo("10.00");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
|
|
|
void unusedLegacyShellIsRestoredInPlaceFromCompletedModuleThreeAndOnlyOnce() {
|
|
|
|
|
|
|
|
seedCompleted();
|
|
|
|
|
|
|
|
String accountId = seedBoundShell();
|
|
|
|
|
|
|
|
jdbc.update("UPDATE wallet_application SET input_bank_card_number='6216610100007654321' WHERE user_id=?",
|
|
|
|
|
|
|
|
SUBJECT_USER);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
service.ensureForSubject(subject());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertThat(jdbc.queryForObject("SELECT card_number FROM simulated_bank_account WHERE account_id=?",
|
|
|
|
|
|
|
|
String.class, accountId)).isEqualTo("6216610100007654321");
|
|
|
|
|
|
|
|
assertThat(jdbc.queryForObject("SELECT card_last4 FROM simulated_bank_account WHERE account_id=?",
|
|
|
|
|
|
|
|
String.class, accountId)).isEqualTo("4321");
|
|
|
|
|
|
|
|
assertThat(jdbc.queryForObject("SELECT bank_name FROM simulated_bank_account WHERE account_id=?",
|
|
|
|
|
|
|
|
String.class, accountId)).isEqualTo("测试银行");
|
|
|
|
|
|
|
|
assertThat(jdbc.queryForObject("SELECT balance FROM simulated_bank_account WHERE account_id=?",
|
|
|
|
|
|
|
|
BigDecimal.class, accountId)).isEqualByComparingTo("50000.00");
|
|
|
|
|
|
|
|
assertThat(jdbc.queryForObject("SELECT bank_account_id FROM wallet_bank_binding WHERE wallet_id=?",
|
|
|
|
|
|
|
|
String.class, WALLET_ID)).isEqualTo(accountId);
|
|
|
|
|
|
|
|
ExchangeContext context = exchangeResources.loadContext(new ExchangeActor(SUBJECT_USER, "test", SCHOOL_ID, CLASS_ID));
|
|
|
|
|
|
|
|
assertThat(context.getBankAccountId()).isEqualTo(accountId);
|
|
|
|
|
|
|
|
assertThat(context.getBankCardNumber()).isEqualTo("6216610100007654321");
|
|
|
|
|
|
|
|
assertThat(context.getBankCardLast4()).isEqualTo("4321");
|
|
|
|
|
|
|
|
assertThat(context.getBankName()).isEqualTo("测试银行");
|
|
|
|
|
|
|
|
assertThat(context.getBankAccountBalance()).isEqualByComparingTo("50000.00");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
jdbc.update("UPDATE simulated_bank_account SET balance=49000.00 WHERE account_id=?", accountId);
|
|
|
|
|
|
|
|
service.ensureForSubject(subject());
|
|
|
|
|
|
|
|
assertThat(jdbc.queryForObject("SELECT balance FROM simulated_bank_account WHERE account_id=?",
|
|
|
|
|
|
|
|
BigDecimal.class, accountId)).isEqualByComparingTo("49000.00");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ParameterizedTest
|
|
|
|
|
|
|
|
@ValueSource(strings = {"balance=1", "frozen_amount=1", "bank_name='已有开户行'", "status='DISABLED'"})
|
|
|
|
|
|
|
|
void nonShellAccountWithDifferentCardIsNeverOverwritten(String state) {
|
|
|
|
|
|
|
|
seedCompleted();
|
|
|
|
|
|
|
|
String accountId = seedBoundShell();
|
|
|
|
|
|
|
|
jdbc.update("UPDATE simulated_bank_account SET " + state + " WHERE account_id=?", accountId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertThatThrownBy(() -> service.ensureForSubject(subject()))
|
|
|
|
|
|
|
|
.isInstanceOf(BusinessException.class).hasMessageContaining("共享银行账户与模块三银行卡结果不一致");
|
|
|
|
|
|
|
|
assertThat(jdbc.queryForObject("SELECT card_number FROM simulated_bank_account WHERE account_id=?",
|
|
|
|
|
|
|
|
String.class, accountId)).isEqualTo("6222020000000000000");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
|
|
|
void evenCancelledExchangeHistoryPreventsShellRestoration() {
|
|
|
|
|
|
|
|
seedCompleted();
|
|
|
|
|
|
|
|
String accountId = seedBoundShell();
|
|
|
|
|
|
|
|
jdbc.update("INSERT INTO currency_exchange_order (id,request_no,user_id,wallet_id,bank_account_id,bank_code," +
|
|
|
|
|
|
|
|
"organization_id,amount,currency,request_timestamp,message_text,signing_original_text,digest," +
|
|
|
|
|
|
|
|
"status,created_at,updated_at,created_by,updated_by) VALUES " +
|
|
|
|
|
|
|
|
"('00000000-0000-0000-0000-000000000880','PROJECTION_HISTORY',?,?,?,?," +
|
|
|
|
|
|
|
|
"'ORG_EXPECTED',1,'CNY','20260904090000','TEST','TEST','TEST','CANCELLED'," +
|
|
|
|
|
|
|
|
"CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,'test','test')",
|
|
|
|
|
|
|
|
SUBJECT_USER, WALLET_ID, accountId, BANK_CODE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertThatThrownBy(() -> service.ensureForSubject(subject()))
|
|
|
|
|
|
|
|
.isInstanceOf(BusinessException.class).hasMessageContaining("共享银行账户与模块三银行卡结果不一致");
|
|
|
|
|
|
|
|
assertThat(jdbc.queryForObject("SELECT balance FROM simulated_bank_account WHERE account_id=?",
|
|
|
|
|
|
|
|
BigDecimal.class, accountId)).isEqualByComparingTo("0");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
|
|
|
void laterWalletConflictRollsBackShellRestoration() {
|
|
|
|
|
|
|
|
seedCompleted();
|
|
|
|
|
|
|
|
String accountId = seedBoundShell();
|
|
|
|
|
|
|
|
jdbc.update("UPDATE digital_wallet SET central_bank_confirmation_signature='OTHER' WHERE wallet_id=?", WALLET_ID);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertThatThrownBy(() -> service.ensureForSubject(subject()))
|
|
|
|
|
|
|
|
.isInstanceOf(BusinessException.class).hasMessageContaining("共享钱包与模块三最终结果不一致");
|
|
|
|
|
|
|
|
assertThat(jdbc.queryForObject("SELECT card_number FROM simulated_bank_account WHERE account_id=?",
|
|
|
|
|
|
|
|
String.class, accountId)).isEqualTo("6222020000000000000");
|
|
|
|
|
|
|
|
assertThat(jdbc.queryForObject("SELECT balance FROM simulated_bank_account WHERE account_id=?",
|
|
|
|
|
|
|
|
BigDecimal.class, accountId)).isEqualByComparingTo("0");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
|
|
|
void incompleteModuleThreeCannotRestoreExistingShell() {
|
|
|
|
|
|
|
|
seedCompleted();
|
|
|
|
|
|
|
|
String accountId = seedBoundShell();
|
|
|
|
|
|
|
|
jdbc.update("UPDATE central_wallet_activation SET final_sent=FALSE WHERE id=?", ACTIVATION_ID);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertThatThrownBy(() -> service.ensureForSubject(subject()))
|
|
|
|
|
|
|
|
.isInstanceOf(BusinessException.class).hasMessageContaining("个人数字钱包开通");
|
|
|
|
|
|
|
|
assertThat(jdbc.queryForObject("SELECT bank_name FROM simulated_bank_account WHERE account_id=?",
|
|
|
|
|
|
|
|
String.class, accountId)).isEmpty();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
|
|
|
void accountBoundToAnotherWalletCannotBeRestored() {
|
|
|
|
|
|
|
|
seedCompleted();
|
|
|
|
|
|
|
|
String accountId = seedBoundShell();
|
|
|
|
|
|
|
|
jdbc.update("INSERT INTO digital_wallet (wallet_id,user_id,wallet_type,status,balance,frozen_amount," +
|
|
|
|
|
|
|
|
"central_bank_confirmation_signature,opened_at,created_at,updated_at) VALUES " +
|
|
|
|
|
|
|
|
"('WALLET_PROJECTION_OTHER',?,'TYPE_II','ACTIVE',0,0,'OTHER'," +
|
|
|
|
|
|
|
|
"CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)", OTHER_USER);
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
jdbc.update("INSERT INTO wallet_bank_binding (wallet_id,bank_account_id,status,bound_at) " +
|
|
|
|
|
|
|
|
"VALUES ('WALLET_PROJECTION_OTHER',?,'BOUND',CURRENT_TIMESTAMP)", accountId);
|
|
|
|
|
|
|
|
assertThatThrownBy(() -> service.ensureForSubject(subject()))
|
|
|
|
|
|
|
|
.isInstanceOf(BusinessException.class).hasMessageContaining("共享银行账户与模块三银行卡结果不一致");
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
|
|
jdbc.update("DELETE FROM wallet_bank_binding WHERE wallet_id='WALLET_PROJECTION_OTHER'");
|
|
|
|
|
|
|
|
jdbc.update("DELETE FROM digital_wallet WHERE wallet_id='WALLET_PROJECTION_OTHER'");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private String seedBoundShell() {
|
|
|
|
|
|
|
|
service.ensureForSubject(subject());
|
|
|
|
|
|
|
|
jdbc.update("UPDATE simulated_bank_account SET bank_name='',card_number='6222020000000000000'," +
|
|
|
|
|
|
|
|
"card_last4='0000',balance=0,frozen_amount=0 WHERE user_id=?", SUBJECT_USER);
|
|
|
|
|
|
|
|
return jdbc.queryForObject("SELECT account_id FROM simulated_bank_account WHERE user_id=?", String.class, SUBJECT_USER);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
@ -159,6 +285,8 @@ class WalletPrerequisiteProjectionServiceTest {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void clean() {
|
|
|
|
private void clean() {
|
|
|
|
|
|
|
|
jdbc.update("DELETE FROM exchange_debit_record WHERE exchange_id IN (SELECT id FROM currency_exchange_order WHERE user_id=?)", SUBJECT_USER);
|
|
|
|
|
|
|
|
jdbc.update("DELETE FROM currency_exchange_order WHERE user_id=?", SUBJECT_USER);
|
|
|
|
jdbc.update("DELETE FROM wallet_bank_binding WHERE wallet_id=?", WALLET_ID);
|
|
|
|
jdbc.update("DELETE FROM wallet_bank_binding WHERE wallet_id=?", WALLET_ID);
|
|
|
|
jdbc.update("DELETE FROM wallet_contract WHERE wallet_id=?", WALLET_ID);
|
|
|
|
jdbc.update("DELETE FROM wallet_contract WHERE wallet_id=?", WALLET_ID);
|
|
|
|
jdbc.update("DELETE FROM wallet_certificate WHERE wallet_id=?", WALLET_ID);
|
|
|
|
jdbc.update("DELETE FROM wallet_certificate WHERE wallet_id=?", WALLET_ID);
|
|
|
|
|