Compare commits
No commits in common. 'master' and 'agent/payment-training-progress' have entirely different histories.
master
...
agent/paym
@ -0,0 +1,645 @@
|
||||
# Downstream Wallet Prerequisite Projection Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Make modules 4 and 5 pull completed module 3 wallet-opening results on first access and initialize shared wallet runtime state without module 3 writing downstream process data.
|
||||
|
||||
**Architecture:** A shared transactional `WalletPrerequisiteProjectionService` reads completed module 3 fact tables with full user/school/class isolation and inserts only missing shared wallet runtime rows. Exchange and payment repositories invoke it before their existing runtime-state queries; existing rows are validated and never overwritten, so real balances and limit counters remain authoritative.
|
||||
|
||||
**Tech Stack:** Java 8-compatible code, Spring Boot 2.7, `JdbcTemplate`, Spring transactions, JUnit 5, MockMvc, AssertJ, H2/MySQL-compatible SQL.
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-08-18-downstream-wallet-prerequisite-projection-design.md`
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Module 3 fact tables remain read-only to modules 4 and 5.
|
||||
- Every module 1 and module 3 lookup is scoped by `user_id`, `school_id`, and `class_id`.
|
||||
- Projection is pull-based, transactional, idempotent, and insert-only for existing shared runtime rows.
|
||||
- Entering a context endpoint must not create exchange orders, payment orders, or step logs.
|
||||
- A module 5 payer needs module 4 wallet-owned currency; a payee only needs a completed module 3 wallet.
|
||||
- Do not address unrelated full-suite error-code assertion failures.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Put wallet private-key encryption in the shared boundary
|
||||
|
||||
**Files:**
|
||||
- Create: `src/main/java/com/yau/digitalrmb/shared/wallet/WalletPrivateKeyCipher.java`
|
||||
- Delete: `src/main/java/com/yau/digitalrmb/exchange/infrastructure/crypto/WalletPrivateKeyCipher.java`
|
||||
- Modify: `src/main/java/com/yau/digitalrmb/exchange/infrastructure/persistence/JdbcExchangeResourceRepository.java`
|
||||
- Modify: `src/main/java/com/yau/digitalrmb/payment/infrastructure/persistence/JdbcPaymentResourceRepository.java`
|
||||
- Modify: `src/test/java/com/yau/digitalrmb/exchange/interfaces/rest/ExchangeControllerTest.java`
|
||||
- Modify: `src/test/java/com/yau/digitalrmb/payment/interfaces/rest/PaymentControllerTest.java`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `SecurityProperties.getJwt().getSecret()`.
|
||||
- Produces: `WalletPrivateKeyCipher.encrypt(String)` and `WalletPrivateKeyCipher.decrypt(String)` in `com.yau.digitalrmb.shared.wallet`.
|
||||
|
||||
- [ ] **Step 1: Move the component without changing its implementation**
|
||||
|
||||
Create the class under the shared package with the existing constructor and methods:
|
||||
|
||||
```java
|
||||
package com.yau.digitalrmb.shared.wallet;
|
||||
|
||||
import com.yau.digitalrmb.security.config.SecurityProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
|
||||
@Component
|
||||
public class WalletPrivateKeyCipher {
|
||||
private static final int IV_LENGTH = 12;
|
||||
private final SecretKeySpec key;
|
||||
|
||||
public WalletPrivateKeyCipher(SecurityProperties properties) {
|
||||
try {
|
||||
byte[] digest = MessageDigest.getInstance("SHA-256")
|
||||
.digest(properties.getJwt().getSecret().getBytes(StandardCharsets.UTF_8));
|
||||
this.key = new SecretKeySpec(digest, "AES");
|
||||
} catch (Exception exception) {
|
||||
throw new IllegalStateException("钱包私钥加密组件初始化失败", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public String encrypt(String privateKey) {
|
||||
try {
|
||||
byte[] iv = new byte[IV_LENGTH];
|
||||
new SecureRandom().nextBytes(iv);
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, iv));
|
||||
byte[] encrypted = cipher.doFinal(privateKey.getBytes(StandardCharsets.US_ASCII));
|
||||
byte[] output = new byte[iv.length + encrypted.length];
|
||||
System.arraycopy(iv, 0, output, 0, iv.length);
|
||||
System.arraycopy(encrypted, 0, output, iv.length, encrypted.length);
|
||||
return Base64.getEncoder().encodeToString(output);
|
||||
} catch (Exception exception) {
|
||||
throw new IllegalStateException("钱包私钥加密失败", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public String decrypt(String value) {
|
||||
try {
|
||||
byte[] input = Base64.getDecoder().decode(value);
|
||||
byte[] iv = new byte[IV_LENGTH];
|
||||
byte[] encrypted = new byte[input.length - IV_LENGTH];
|
||||
System.arraycopy(input, 0, iv, 0, iv.length);
|
||||
System.arraycopy(input, iv.length, encrypted, 0, encrypted.length);
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(128, iv));
|
||||
return new String(cipher.doFinal(encrypted), StandardCharsets.US_ASCII);
|
||||
} catch (Exception exception) {
|
||||
throw new IllegalStateException("钱包私钥解密失败", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Delete the old class and replace all four imports with:
|
||||
|
||||
```java
|
||||
import com.yau.digitalrmb.shared.wallet.WalletPrivateKeyCipher;
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Compile and run the existing exchange/payment tests**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -DskipTests compile
|
||||
mvn "-Dtest=ExchangeControllerTest,PaymentControllerTest" test
|
||||
```
|
||||
|
||||
Expected: compilation succeeds; 3 tests pass with 0 failures.
|
||||
|
||||
- [ ] **Step 3: Commit the boundary-only refactor**
|
||||
|
||||
```bash
|
||||
git add src/main/java/com/yau/digitalrmb/shared/wallet/WalletPrivateKeyCipher.java src/main/java/com/yau/digitalrmb/exchange/infrastructure/crypto/WalletPrivateKeyCipher.java src/main/java/com/yau/digitalrmb/exchange/infrastructure/persistence/JdbcExchangeResourceRepository.java src/main/java/com/yau/digitalrmb/payment/infrastructure/persistence/JdbcPaymentResourceRepository.java src/test/java/com/yau/digitalrmb/exchange/interfaces/rest/ExchangeControllerTest.java src/test/java/com/yau/digitalrmb/payment/interfaces/rest/PaymentControllerTest.java
|
||||
git commit -m "refactor: share wallet private key cipher"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Project completed module 3 facts into shared wallet runtime state
|
||||
|
||||
**Files:**
|
||||
- Create: `src/main/java/com/yau/digitalrmb/shared/wallet/WalletPrerequisiteReference.java`
|
||||
- Create: `src/main/java/com/yau/digitalrmb/shared/wallet/WalletPrerequisiteProjectionService.java`
|
||||
- Create: `src/test/java/com/yau/digitalrmb/shared/wallet/WalletPrerequisiteProjectionServiceTest.java`
|
||||
- Create: `src/test/java/com/yau/digitalrmb/testsupport/WalletOpeningTestData.java`
|
||||
- Modify: `src/test/resources/schema.sql`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `InstitutionKeySubject`, module 3 fact rows, module 1 institution identifier, `WalletPrivateKeyCipher`.
|
||||
- Produces:
|
||||
|
||||
```java
|
||||
public final class WalletPrerequisiteReference {
|
||||
public String getUserId();
|
||||
public long getSchoolId();
|
||||
public long getClassId();
|
||||
public String getWalletId();
|
||||
public String getBankCode();
|
||||
public String getOrganizationId();
|
||||
}
|
||||
|
||||
public class WalletPrerequisiteProjectionService {
|
||||
public WalletPrerequisiteReference ensureForSubject(InstitutionKeySubject subject);
|
||||
public WalletPrerequisiteReference ensureForWallet(String walletId);
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 1: Add module 3 source tables to the H2 test schema**
|
||||
|
||||
Append H2-compatible definitions matching the production columns used by the projector. Define all columns below, including audit/scope columns, so production SQL is exercised unchanged:
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS wallet_application (
|
||||
id BIGINT PRIMARY KEY, user_id VARCHAR(36) NOT NULL, school_id BIGINT NOT NULL, class_id BIGINT NOT NULL,
|
||||
account_bank VARCHAR(100), bank_card_number VARCHAR(30), account_balance DECIMAL(20,2), selected_bank VARCHAR(100),
|
||||
wallet_type VARCHAR(20), application_id VARCHAR(64), status VARCHAR(32) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, created_by VARCHAR(64) NOT NULL,
|
||||
updated_by VARCHAR(64) NOT NULL, deleted BOOLEAN NOT NULL DEFAULT FALSE
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS wallet_identifier_generation (
|
||||
id BIGINT PRIMARY KEY, user_id VARCHAR(36) NOT NULL, school_id BIGINT NOT NULL, class_id BIGINT NOT NULL,
|
||||
wallet_identifier VARCHAR(128), cert_private_key VARCHAR(512), cert_public_key VARCHAR(512),
|
||||
cert_serial_number VARCHAR(64), cert_issued_time VARCHAR(20), status VARCHAR(32) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, created_by VARCHAR(64) NOT NULL,
|
||||
updated_by VARCHAR(64) NOT NULL, deleted BOOLEAN NOT NULL DEFAULT FALSE
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS central_wallet_registration (
|
||||
id BIGINT PRIMARY KEY, user_id VARCHAR(36) NOT NULL, school_id BIGINT NOT NULL, class_id BIGINT NOT NULL,
|
||||
wallet_id VARCHAR(128), cb_root_signature VARCHAR(512), wallet_registered BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
sent BOOLEAN NOT NULL DEFAULT FALSE, status VARCHAR(32) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, created_by VARCHAR(64) NOT NULL,
|
||||
updated_by VARCHAR(64) NOT NULL, deleted BOOLEAN NOT NULL DEFAULT FALSE
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS smart_contract_generation (
|
||||
id BIGINT PRIMARY KEY, user_id VARCHAR(36) NOT NULL, school_id BIGINT NOT NULL, class_id BIGINT NOT NULL,
|
||||
wallet_id VARCHAR(128), wallet_type VARCHAR(30), single_payment_limit VARCHAR(30), daily_payment_limit VARCHAR(30),
|
||||
annual_payment_limit VARCHAR(30), balance_ceiling VARCHAR(30), validity VARCHAR(20), contract_plaintext VARCHAR(1000),
|
||||
contract_digest VARCHAR(128), contract_id VARCHAR(64), contract_effective_time VARCHAR(20), sent BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
status VARCHAR(32) NOT NULL, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL,
|
||||
created_by VARCHAR(64) NOT NULL, updated_by VARCHAR(64) NOT NULL, deleted BOOLEAN NOT NULL DEFAULT FALSE
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS central_wallet_activation (
|
||||
id BIGINT PRIMARY KEY, user_id VARCHAR(36) NOT NULL, school_id BIGINT NOT NULL, class_id BIGINT NOT NULL,
|
||||
wallet_id VARCHAR(128), wallet_activated BOOLEAN NOT NULL DEFAULT FALSE, wallet_register_status VARCHAR(32),
|
||||
cb_final_signature VARCHAR(512), final_time VARCHAR(20), final_sent BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
status VARCHAR(32) NOT NULL, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL,
|
||||
created_by VARCHAR(64) NOT NULL, updated_by VARCHAR(64) NOT NULL, deleted BOOLEAN NOT NULL DEFAULT FALSE
|
||||
);
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Write failing integration tests for incomplete, complete, idempotent, and isolated projection**
|
||||
|
||||
Create a shared test-data utility so all three integration test classes seed the same module 3 completion contract:
|
||||
|
||||
```java
|
||||
public final class WalletOpeningTestData {
|
||||
private WalletOpeningTestData() {}
|
||||
|
||||
public static void insertCompletedWallet(JdbcTemplate jdbc, long baseId, String userId,
|
||||
long schoolId, long classId, String walletId, String privateKey, String publicKey,
|
||||
String bankName, String cardNumber, BigDecimal bankBalance) {
|
||||
jdbc.update("INSERT INTO wallet_application (id,user_id,school_id,class_id,account_bank,bank_card_number," +
|
||||
"account_balance,selected_bank,wallet_type,application_id,status,created_at,updated_at,created_by,updated_by,deleted) " +
|
||||
"VALUES (?,?,?,?,?,?,?,?,? ,?,'SUBMITTED',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,'test','test',FALSE)",
|
||||
baseId, userId, schoolId, classId, bankName, cardNumber, bankBalance, bankName, "TYPE_II", "APP_" + baseId);
|
||||
jdbc.update("INSERT INTO wallet_identifier_generation (id,user_id,school_id,class_id,wallet_identifier," +
|
||||
"cert_private_key,cert_public_key,cert_serial_number,cert_issued_time,status,created_at,updated_at,created_by,updated_by,deleted) " +
|
||||
"VALUES (?,?,?,?,?,?,?,?,?,'CERT_ISSUED',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,'test','test',FALSE)",
|
||||
baseId + 1, userId, schoolId, classId, walletId, privateKey, publicKey, "CERT_" + baseId, "20260818090000");
|
||||
jdbc.update("INSERT INTO central_wallet_registration (id,user_id,school_id,class_id,wallet_id,cb_root_signature," +
|
||||
"wallet_registered,sent,status,created_at,updated_at,created_by,updated_by,deleted) " +
|
||||
"VALUES (?,?,?,?,?,'CB_ROOT_TEST',TRUE,TRUE,'SENT',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,'test','test',FALSE)",
|
||||
baseId + 2, userId, schoolId, classId, walletId);
|
||||
jdbc.update("INSERT INTO smart_contract_generation (id,user_id,school_id,class_id,wallet_id,wallet_type," +
|
||||
"single_payment_limit,daily_payment_limit,annual_payment_limit,balance_ceiling,validity,contract_plaintext," +
|
||||
"contract_digest,contract_id,contract_effective_time,sent,status,created_at,updated_at,created_by,updated_by,deleted) " +
|
||||
"VALUES (?,?,?,?,?,'TYPE_II','50000.00','100000.00','500000.00','500000.00','长期有效'," +
|
||||
"'CONTRACT_TEXT','0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',?," +
|
||||
"'20260818090000',TRUE,'SENT',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,'test','test',FALSE)",
|
||||
baseId + 3, userId, schoolId, classId, walletId, "CONTRACT_" + baseId);
|
||||
jdbc.update("INSERT INTO central_wallet_activation (id,user_id,school_id,class_id,wallet_id,wallet_activated," +
|
||||
"wallet_register_status,cb_final_signature,final_time,final_sent,status,created_at,updated_at,created_by,updated_by,deleted) " +
|
||||
"VALUES (?,?,?,?,?,TRUE,'AVAILABLE','CB_FINAL_TEST','20260818090000',TRUE,'FINAL_SENT'," +
|
||||
"CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,'test','test',FALSE)",
|
||||
baseId + 4, userId, schoolId, classId, walletId);
|
||||
}
|
||||
|
||||
public static void deleteWalletFacts(JdbcTemplate jdbc, String userId) {
|
||||
jdbc.update("DELETE FROM central_wallet_activation WHERE user_id=?", userId);
|
||||
jdbc.update("DELETE FROM smart_contract_generation WHERE user_id=?", userId);
|
||||
jdbc.update("DELETE FROM central_wallet_registration WHERE user_id=?", userId);
|
||||
jdbc.update("DELETE FROM wallet_identifier_generation WHERE user_id=?", userId);
|
||||
jdbc.update("DELETE FROM wallet_application WHERE user_id=?", userId);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Create `@SpringBootTest` tests using real `JdbcTemplate` and the real cipher. Seed unique IDs and clean them in `@AfterEach`.
|
||||
|
||||
```java
|
||||
@Test
|
||||
void incompleteModuleThreeCreatesNoSharedRuntimeRows() {
|
||||
jdbc.update("INSERT INTO central_wallet_activation (id,user_id,school_id,class_id,wallet_id,wallet_activated," +
|
||||
"final_sent,status,created_at,updated_at,created_by,updated_by,deleted) " +
|
||||
"VALUES (?,?,?,?,?,FALSE,FALSE,'PENDING',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,'test','test',FALSE)",
|
||||
ACTIVATION_ID, SUBJECT_USER, SCHOOL_ID, CLASS_ID, WALLET_ID);
|
||||
assertThatThrownBy(() -> service.ensureForSubject(subject()))
|
||||
.isInstanceOf(BusinessException.class)
|
||||
.hasMessageContaining("个人数字钱包开通");
|
||||
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM digital_wallet WHERE user_id=?", Integer.class, SUBJECT_USER)).isZero();
|
||||
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM simulated_bank_account WHERE user_id=?", Integer.class, SUBJECT_USER)).isZero();
|
||||
}
|
||||
|
||||
@Test
|
||||
void completedModuleThreeCreatesAllSharedRuntimeRows() {
|
||||
WalletOpeningTestData.insertCompletedWallet(jdbc, 980000L, SUBJECT_USER, SCHOOL_ID, CLASS_ID,
|
||||
WALLET_ID, keyPair.getPrivateKey(), keyPair.getPublicKey(), "测试银行", "6216610100001234567", new BigDecimal("50000.00"));
|
||||
seedInstitutionIdentifier(SUBJECT_USER, SCHOOL_ID, CLASS_ID, BANK_CODE, "ORG_EXPECTED", true);
|
||||
WalletPrerequisiteReference reference = service.ensureForSubject(subject());
|
||||
assertThat(reference.getWalletId()).isEqualTo(WALLET_ID);
|
||||
assertThat(reference.getOrganizationId()).isEqualTo("ORG_EXPECTED");
|
||||
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM digital_wallet WHERE wallet_id=?", Integer.class, WALLET_ID)).isEqualTo(1);
|
||||
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM wallet_certificate WHERE wallet_id=?", Integer.class, WALLET_ID)).isEqualTo(1);
|
||||
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM wallet_contract WHERE wallet_id=?", Integer.class, WALLET_ID)).isEqualTo(1);
|
||||
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM wallet_bank_binding WHERE wallet_id=?", Integer.class, WALLET_ID)).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void repeatedProjectionDoesNotOverwriteMutableRuntimeStateOrModuleThreeFacts() {
|
||||
WalletOpeningTestData.insertCompletedWallet(jdbc, 980000L, SUBJECT_USER, SCHOOL_ID, CLASS_ID,
|
||||
WALLET_ID, keyPair.getPrivateKey(), keyPair.getPublicKey(), "测试银行", "6216610100001234567", new BigDecimal("50000.00"));
|
||||
seedInstitutionIdentifier(SUBJECT_USER, SCHOOL_ID, CLASS_ID, BANK_CODE, "ORG_EXPECTED", true);
|
||||
service.ensureForSubject(subject());
|
||||
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);
|
||||
String activationUpdatedAt = jdbc.queryForObject("SELECT CAST(updated_at AS VARCHAR) FROM central_wallet_activation WHERE id=?", String.class, ACTIVATION_ID);
|
||||
service.ensureForSubject(subject());
|
||||
assertThat(jdbc.queryForObject("SELECT balance FROM digital_wallet WHERE wallet_id=?", BigDecimal.class, WALLET_ID)).isEqualByComparingTo("321.00");
|
||||
assertThat(jdbc.queryForObject("SELECT daily_used_amount FROM wallet_contract WHERE wallet_id=?", BigDecimal.class, WALLET_ID)).isEqualByComparingTo("45.00");
|
||||
assertThat(jdbc.queryForObject("SELECT CAST(updated_at AS VARCHAR) FROM central_wallet_activation WHERE id=?", String.class, ACTIVATION_ID)).isEqualTo(activationUpdatedAt);
|
||||
}
|
||||
|
||||
@Test
|
||||
void sameBankCodeFromAnotherScopeCannotSupplyOrganizationId() {
|
||||
WalletOpeningTestData.insertCompletedWallet(jdbc, 980000L, SUBJECT_USER, SCHOOL_ID, CLASS_ID,
|
||||
WALLET_ID, keyPair.getPrivateKey(), keyPair.getPublicKey(), "测试银行", "6216610100001234567", new BigDecimal("50000.00"));
|
||||
seedInstitutionIdentifier(SUBJECT_USER, SCHOOL_ID, CLASS_ID, BANK_CODE, "ORG_EXPECTED", true);
|
||||
seedInstitutionIdentifier("other-user", SCHOOL_ID + 1, CLASS_ID + 1, BANK_CODE, "ORG_WRONG", true);
|
||||
assertThat(service.ensureForWallet(WALLET_ID).getOrganizationId()).isEqualTo("ORG_EXPECTED");
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Run the new test and verify RED**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn "-Dtest=WalletPrerequisiteProjectionServiceTest" test
|
||||
```
|
||||
|
||||
Expected: test compilation fails because `WalletPrerequisiteProjectionService` and `WalletPrerequisiteReference` do not exist. This is the intended RED condition.
|
||||
|
||||
- [ ] **Step 4: Implement the immutable reference**
|
||||
|
||||
```java
|
||||
public final class WalletPrerequisiteReference {
|
||||
private final String userId;
|
||||
private final long schoolId;
|
||||
private final long classId;
|
||||
private final String walletId;
|
||||
private final String bankCode;
|
||||
private final String organizationId;
|
||||
|
||||
public WalletPrerequisiteReference(String userId, long schoolId, long classId,
|
||||
String walletId, String bankCode, String organizationId) {
|
||||
this.userId = userId;
|
||||
this.schoolId = schoolId;
|
||||
this.classId = classId;
|
||||
this.walletId = walletId;
|
||||
this.bankCode = bankCode;
|
||||
this.organizationId = organizationId;
|
||||
}
|
||||
|
||||
public String getUserId() { return userId; }
|
||||
public long getSchoolId() { return schoolId; }
|
||||
public long getClassId() { return classId; }
|
||||
public String getWalletId() { return walletId; }
|
||||
public String getBankCode() { return bankCode; }
|
||||
public String getOrganizationId() { return organizationId; }
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Implement transactional source validation and lookup**
|
||||
|
||||
Annotate both public methods with `@Transactional`. `ensureForSubject` must query each module 3 table using the same three scope columns, `deleted=FALSE`, expected completion state, descending `created_at`, and `LIMIT 1`. Link identifier, registration, and contract rows to the activation wallet ID. Query module 1 with all scope columns:
|
||||
|
||||
```sql
|
||||
SELECT bank_code,institution_identifier
|
||||
FROM institution_identifier_application
|
||||
WHERE user_id=? AND school_id=? AND class_id=?
|
||||
AND status IN ('ISSUED','FEEDBACKED') AND deleted=FALSE
|
||||
AND bank_code IS NOT NULL AND institution_identifier IS NOT NULL
|
||||
ORDER BY created_at DESC LIMIT 1
|
||||
```
|
||||
|
||||
`ensureForWallet` must locate exactly one completed activation by `wallet_id`, `wallet_activated=TRUE`, `final_sent=TRUE`, non-null final signature, and `deleted=FALSE`, then delegate with the located subject. Zero matches returns the same prerequisite validation error; more than one scope returns a data-conflict error.
|
||||
|
||||
- [ ] **Step 6: Implement insert-only runtime projection**
|
||||
|
||||
Use deterministic account ID `ACCOUNT_` plus `UUID.nameUUIDFromBytes((userId + "|" + bankCode).getBytes(UTF_8))`. Parse `yyyyMMddHHmmss` timestamps when possible, otherwise use `CURRENT_TIMESTAMP`. Insert in this order:
|
||||
|
||||
```sql
|
||||
INSERT INTO simulated_bank_account
|
||||
(account_id,user_id,bank_code,bank_name,card_number,card_last4,balance,frozen_amount,status,created_at,updated_at)
|
||||
VALUES (?,?,?,?,?,?,?,0,'ACTIVE',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)
|
||||
|
||||
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 (?,?,?,'ACTIVE',0,0,?,?,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)
|
||||
|
||||
INSERT INTO wallet_certificate
|
||||
(certificate_serial,wallet_id,public_key,encrypted_private_key,filing_status,central_bank_root_signature,status,issued_at)
|
||||
VALUES (?,?,?,?, 'REGISTERED',?,'VALID',?)
|
||||
|
||||
INSERT INTO wallet_contract
|
||||
(contract_id,wallet_id,wallet_type,single_payment_limit,daily_payment_limit,annual_payment_limit,balance_limit,
|
||||
valid_until,original_text,digest,status,daily_used_amount,daily_counter_date,annual_used_amount,annual_counter_year,created_at,updated_at)
|
||||
VALUES (?,?,?,?,?,?,?,NULL,?,?,'ACTIVE',0,NULL,0,NULL,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)
|
||||
|
||||
INSERT INTO wallet_bank_binding (wallet_id,bank_account_id,status,bound_at)
|
||||
VALUES (?,?,'BOUND',CURRENT_TIMESTAMP)
|
||||
```
|
||||
|
||||
Before each insert, query by its primary/unique business key. If a row exists, validate immutable ownership fields and skip the insert. Catch `DuplicateKeyException`, re-read, and run the same validation; never use an updating upsert. Encrypt the module 3 certificate private key with `WalletPrivateKeyCipher.encrypt` only when inserting a missing certificate.
|
||||
|
||||
- [ ] **Step 7: Run the new test and verify GREEN**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn "-Dtest=WalletPrerequisiteProjectionServiceTest" test
|
||||
```
|
||||
|
||||
Expected: 4 tests pass with 0 failures and 0 errors.
|
||||
|
||||
- [ ] **Step 8: Commit the shared projection**
|
||||
|
||||
```bash
|
||||
git add src/main/java/com/yau/digitalrmb/shared/wallet src/test/java/com/yau/digitalrmb/shared/wallet/WalletPrerequisiteProjectionServiceTest.java src/test/java/com/yau/digitalrmb/testsupport/WalletOpeningTestData.java src/test/resources/schema.sql
|
||||
git commit -m "feat: project completed wallet prerequisites on demand"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Make module 4 pull module 3 prerequisites
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/main/java/com/yau/digitalrmb/exchange/infrastructure/persistence/JdbcExchangeResourceRepository.java`
|
||||
- Modify: `src/test/java/com/yau/digitalrmb/exchange/interfaces/rest/ExchangeControllerTest.java`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `WalletPrerequisiteProjectionService.ensureForSubject(InstitutionKeySubject)`.
|
||||
- Produces: unchanged `ExchangeResourceRepository.loadContext(ExchangeActor)` API.
|
||||
|
||||
- [ ] **Step 1: Rewrite exchange test setup to seed module 3 facts, not shared runtime rows**
|
||||
|
||||
Keep module 1 identifiers, keys, module 2 bank currency, and ownership setup. Replace direct inserts into the five shared wallet tables with:
|
||||
|
||||
```java
|
||||
WalletOpeningTestData.insertCompletedWallet(jdbc, 990100L, USER_ID, 1999L, 2999L,
|
||||
"WALLET_EXCHANGE_TEST", walletKey.getPrivateKey(), walletKey.getPublicKey(),
|
||||
"中国银行北京分行", "6216610100001234567", new BigDecimal("50000.00"));
|
||||
```
|
||||
|
||||
Add assertions to the successful context test:
|
||||
|
||||
```java
|
||||
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM currency_exchange_order", Integer.class)).isZero();
|
||||
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM exchange_step_log", Integer.class)).isZero();
|
||||
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM digital_wallet WHERE user_id=?", Integer.class, USER_ID)).isEqualTo(1);
|
||||
```
|
||||
|
||||
Change `doesNotCreateDemoWalletWhenWalletOpeningOutputIsMissing` so it deletes module 3 fact rows as well as shared rows and retains the assertion that no wallet is created.
|
||||
|
||||
- [ ] **Step 2: Run exchange tests and verify RED**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn "-Dtest=ExchangeControllerTest" test
|
||||
```
|
||||
|
||||
Expected: the successful context test returns 400 because the repository still reads shared rows without invoking the projector.
|
||||
|
||||
- [ ] **Step 3: Inject and invoke the projector**
|
||||
|
||||
Add `WalletPrerequisiteProjectionService` to the repository constructor and start `loadContext` with:
|
||||
|
||||
```java
|
||||
InstitutionKeySubject subject = new InstitutionKeySubject(actor.getUserId(), actor.getSchoolId(), actor.getClassId());
|
||||
walletPrerequisiteProjectionService.ensureForSubject(subject);
|
||||
Institution institution = loadIssuedInstitution(actor);
|
||||
```
|
||||
|
||||
Do not invoke the projector from module 3 services or controllers.
|
||||
|
||||
- [ ] **Step 4: Run exchange tests and verify GREEN**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn "-Dtest=ExchangeControllerTest" test
|
||||
```
|
||||
|
||||
Expected: both exchange tests pass. The full five-step exchange still updates shared balances and ownership, while the missing-prerequisite test creates no shared rows.
|
||||
|
||||
- [ ] **Step 5: Commit module 4 integration**
|
||||
|
||||
```bash
|
||||
git add src/main/java/com/yau/digitalrmb/exchange/infrastructure/persistence/JdbcExchangeResourceRepository.java src/test/java/com/yau/digitalrmb/exchange/interfaces/rest/ExchangeControllerTest.java
|
||||
git commit -m "feat: load module three wallet data for exchange"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Make module 5 pull both parties and enforce scoped identifiers
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/main/java/com/yau/digitalrmb/payment/domain/repository/PaymentResourceRepository.java`
|
||||
- Modify: `src/main/java/com/yau/digitalrmb/payment/application/service/PaymentApplicationService.java`
|
||||
- Modify: `src/main/java/com/yau/digitalrmb/payment/infrastructure/persistence/JdbcPaymentResourceRepository.java`
|
||||
- Modify: `src/test/java/com/yau/digitalrmb/payment/interfaces/rest/PaymentControllerTest.java`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `ensureForSubject` for payer and `ensureForWallet` for payee.
|
||||
- Changes repository API to:
|
||||
|
||||
```java
|
||||
PaymentContext loadContext(PaymentActor actor, String payeeWalletId);
|
||||
```
|
||||
|
||||
- [ ] **Step 1: Add failing payment association tests**
|
||||
|
||||
Seed completed module 3 facts for both users. For the payer, retain an already-existing shared wallet with balance `200.00` and module 4 `WALLET/AVAILABLE` coins; this represents completed module 4. Do not seed payee shared rows. Assert context access projects only the payee and creates no payment order:
|
||||
|
||||
```java
|
||||
@Test
|
||||
void loadsPayeeFromCompletedModuleThreeWithoutCreatingPaymentOrder() throws Exception {
|
||||
jdbc.update("DELETE FROM wallet_bank_binding WHERE wallet_id=?", PAYEE_WALLET);
|
||||
jdbc.update("DELETE FROM wallet_certificate WHERE wallet_id=?", PAYEE_WALLET);
|
||||
jdbc.update("DELETE FROM simulated_bank_account WHERE user_id=?", PAYEE_USER);
|
||||
jdbc.update("DELETE FROM digital_wallet WHERE wallet_id=?", PAYEE_WALLET);
|
||||
|
||||
mockMvc.perform(get("/api/v1/payments/context")
|
||||
.param("payeeWalletId", PAYEE_WALLET).with(payer()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data.payee.walletId").value(PAYEE_WALLET));
|
||||
|
||||
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM digital_wallet WHERE wallet_id=?", Integer.class, PAYEE_WALLET)).isEqualTo(1);
|
||||
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM payment_order", Integer.class)).isZero();
|
||||
}
|
||||
```
|
||||
|
||||
Add a second test with the same bank code in another school/class and assert payer/payee `organizationId` values come from their own scoped module 1 records. Add a third test where the payer has completed module 3 but has no `WALLET/AVAILABLE` coins; create and sign the request, then assert `/payer-bank-process` returns 400 and no ownership transfer is created.
|
||||
|
||||
- [ ] **Step 2: Run payment tests and verify RED**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn "-Dtest=PaymentControllerTest" test
|
||||
```
|
||||
|
||||
Expected: payee context returns 400 because no shared payee row exists, or the scope assertion returns the other user's organization identifier.
|
||||
|
||||
- [ ] **Step 3: Pass the complete actor through the payment repository boundary**
|
||||
|
||||
Change both service call sites:
|
||||
|
||||
```java
|
||||
return resourceRepository.loadContext(actor, payeeWalletId);
|
||||
PaymentContext context = resourceRepository.loadContext(actor, command.getPayeeWalletId());
|
||||
```
|
||||
|
||||
Update the interface and implementation signature to use `PaymentActor`.
|
||||
|
||||
- [ ] **Step 4: Pull payer and payee prerequisites before participant queries**
|
||||
|
||||
Implement:
|
||||
|
||||
```java
|
||||
WalletPrerequisiteReference payerRef = projector.ensureForSubject(
|
||||
new InstitutionKeySubject(actor.getUserId(), actor.getSchoolId(), actor.getClassId()));
|
||||
WalletPrerequisiteReference payeeRef = projector.ensureForWallet(payeeWalletId);
|
||||
PaymentParticipant payer = loadParticipant(payerRef);
|
||||
PaymentParticipant payee = loadParticipant(payeeRef);
|
||||
```
|
||||
|
||||
Replace the dynamic `where` SQL and unscoped `organizationId(bankCode)` method with a fixed wallet query:
|
||||
|
||||
```java
|
||||
private PaymentParticipant loadParticipant(WalletPrerequisiteReference reference) {
|
||||
List<PaymentParticipant> values = jdbc.query(
|
||||
"SELECT w.user_id,w.wallet_id,w.wallet_type,cert.certificate_serial,cert.public_key," +
|
||||
"a.bank_code,a.bank_name,w.balance,COALESCE(w.frozen_amount,0) frozen_amount " +
|
||||
"FROM digital_wallet w JOIN wallet_certificate cert ON cert.wallet_id=w.wallet_id " +
|
||||
"AND cert.status='VALID' AND cert.filing_status='REGISTERED' " +
|
||||
"JOIN wallet_bank_binding binding ON binding.wallet_id=w.wallet_id AND binding.status='BOUND' " +
|
||||
"JOIN simulated_bank_account a ON a.account_id=binding.bank_account_id AND a.status='ACTIVE' " +
|
||||
"WHERE w.wallet_id=? AND w.user_id=? AND w.status='ACTIVE' " +
|
||||
"AND w.central_bank_confirmation_signature IS NOT NULL",
|
||||
(rs, row) -> new PaymentParticipant(rs.getString("user_id"), rs.getString("wallet_id"),
|
||||
rs.getString("wallet_type"), rs.getString("certificate_serial"), rs.getString("public_key"),
|
||||
rs.getString("bank_code"), rs.getString("bank_name"), reference.getOrganizationId(),
|
||||
rs.getBigDecimal("balance"), rs.getBigDecimal("frozen_amount")),
|
||||
reference.getWalletId(), reference.getUserId());
|
||||
if (values.isEmpty()) throw validation("付款方或收款方钱包运行态不存在或状态异常");
|
||||
return values.get(0);
|
||||
}
|
||||
```
|
||||
|
||||
Delete the query that selects `institution_identifier_application` by `bank_code` only. The scoped organization ID must come from the projection reference.
|
||||
|
||||
- [ ] **Step 5: Run payment tests and verify GREEN**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn "-Dtest=PaymentControllerTest" test
|
||||
```
|
||||
|
||||
Expected: all payment tests pass; payee-only module 3 data is readable, scoped organization IDs are correct, and a payer without module 4 coins cannot proceed through payer-bank processing.
|
||||
|
||||
- [ ] **Step 6: Commit module 5 integration**
|
||||
|
||||
```bash
|
||||
git add src/main/java/com/yau/digitalrmb/payment/domain/repository/PaymentResourceRepository.java src/main/java/com/yau/digitalrmb/payment/application/service/PaymentApplicationService.java src/main/java/com/yau/digitalrmb/payment/infrastructure/persistence/JdbcPaymentResourceRepository.java src/test/java/com/yau/digitalrmb/payment/interfaces/rest/PaymentControllerTest.java
|
||||
git commit -m "feat: load scoped wallet prerequisites for payment"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Verify the complete module chain and document actual failures
|
||||
|
||||
**Files:**
|
||||
- Modify only if verification exposes a regression caused by Tasks 1-4.
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: completed implementation from Tasks 1-4.
|
||||
- Produces: reproducible compile/test evidence and a clean tracked worktree.
|
||||
|
||||
- [ ] **Step 1: Check formatting, conflicts, and production compilation**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
rg -n "^(<<<<<<<|=======|>>>>>>>)" src
|
||||
mvn -DskipTests compile
|
||||
```
|
||||
|
||||
Expected: `git diff --check` and compile exit 0; `rg` finds no conflict markers.
|
||||
|
||||
- [ ] **Step 2: Run the focused module-chain tests**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn "-Dtest=WalletPrerequisiteProjectionServiceTest,DigitalCurrencyGenerationStockIntegrationTest,ExchangeControllerTest,PaymentControllerTest" test
|
||||
```
|
||||
|
||||
Expected: all focused tests pass with 0 failures and 0 errors.
|
||||
|
||||
- [ ] **Step 3: Run the full suite without hiding existing failures**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn test
|
||||
```
|
||||
|
||||
Expected: report the exact total, failure count, and test names. Fix only failures introduced by Tasks 1-4; retain and explicitly report unrelated existing failures such as string-versus-numeric API error-code assertions.
|
||||
|
||||
- [ ] **Step 4: Verify repository state and module 3 write isolation**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
rg -n "UPDATE (wallet_application|bank_received_wallet_application|wallet_verification_record|wallet_identifier_generation|wallet_registration_request|central_wallet_registration|smart_contract_generation|central_wallet_activation)" src/main/java/com/yau/digitalrmb/exchange src/main/java/com/yau/digitalrmb/payment src/main/java/com/yau/digitalrmb/shared/wallet
|
||||
git status --short --branch
|
||||
git log --oneline -6
|
||||
```
|
||||
|
||||
Expected: no downstream update statements target module 3 fact tables. Only user-owned pre-existing untracked documents may remain outside the committed implementation.
|
||||
@ -1,34 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "企业法人提交申请输出结果")
|
||||
public class CorporateApplicationResult {
|
||||
@Schema(description = "申请编号", example = "CORP_APP_20260801_001")
|
||||
private final String applicationId;
|
||||
@Schema(description = "企业名称", example = "创新科技公司")
|
||||
private final String corpName;
|
||||
@Schema(description = "统一社会信用代码", example = "91440101MA5XXXXXX")
|
||||
private final String creditCode;
|
||||
@Schema(description = "法人代表", example = "张三")
|
||||
private final String legalPerson;
|
||||
@Schema(description = "注册资本", example = "10000000.00")
|
||||
private final String capital;
|
||||
@Schema(description = "申请时间", example = "20260801100000")
|
||||
private final String applyTime;
|
||||
@Schema(description = "申请状态", example = "已提交")
|
||||
private final String status;
|
||||
|
||||
public CorporateApplicationResult(String applicationId, String corpName, String creditCode,
|
||||
String legalPerson, String capital, String applyTime, String status) {
|
||||
this.applicationId = applicationId;
|
||||
this.corpName = corpName;
|
||||
this.creditCode = creditCode;
|
||||
this.legalPerson = legalPerson;
|
||||
this.capital = capital;
|
||||
this.applyTime = applyTime;
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "拼接原文结果")
|
||||
public class CorporateConcatenateResult {
|
||||
@Schema(description = "拼接后的原文", example = "CORP_OPEN|创新科技公司|91440101MA5XXXXXX|张三|10000000.00|软件开发、技术服务|20260801100000")
|
||||
private final String concatenatedMessage;
|
||||
|
||||
public CorporateConcatenateResult(String concatenatedMessage) {
|
||||
this.concatenatedMessage = concatenatedMessage;
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "SM3摘要运算结果")
|
||||
public class CorporateDigestResult {
|
||||
@Schema(description = "哈希算法", example = "SM3")
|
||||
private final String algorithm;
|
||||
@Schema(description = "摘要值(十六进制)", example = "3A4B5C6D7E8F9A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6E7F8A9B0C1D2E3F4")
|
||||
private final String digestValue;
|
||||
|
||||
public CorporateDigestResult(String algorithm, String digestValue) {
|
||||
this.algorithm = algorithm;
|
||||
this.digestValue = digestValue;
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "提取摘要原文结果")
|
||||
public class CorporateExtractResult {
|
||||
@Schema(description = "提取的摘要原文", example = "91440101MA5XXXXXX|20260801101000")
|
||||
private final String extractMessage;
|
||||
|
||||
public CorporateExtractResult(String extractMessage) {
|
||||
this.extractMessage = extractMessage;
|
||||
}
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "银行端审核结果")
|
||||
public class CorporateVerifyResult {
|
||||
@Schema(description = "审核编号", example = "VERIFY_20260801_001")
|
||||
private final String verifyId;
|
||||
@Schema(description = "申请编号", example = "CORP_APP_20260801_001")
|
||||
private final String applicationId;
|
||||
@Schema(description = "审核状态", example = "APPROVED")
|
||||
private final String status;
|
||||
@Schema(description = "审核人", example = "李经理")
|
||||
private final String reviewer;
|
||||
@Schema(description = "审核时间", example = "20260801101000")
|
||||
private final String verifyTime;
|
||||
|
||||
public CorporateVerifyResult(String verifyId, String applicationId, String status,
|
||||
String reviewer, String verifyTime) {
|
||||
this.verifyId = verifyId;
|
||||
this.applicationId = applicationId;
|
||||
this.status = status;
|
||||
this.reviewer = reviewer;
|
||||
this.verifyTime = verifyTime;
|
||||
}
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "生成对公钱包输出结果")
|
||||
public class CorporateWalletResult {
|
||||
@Schema(description = "钱包ID", example = "CORP_3A4B5C6D7E8F9A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6E7F8A9B0C1D2E3F4")
|
||||
private final String walletId;
|
||||
@Schema(description = "企业名称", example = "创新科技公司")
|
||||
private final String corpName;
|
||||
@Schema(description = "统一社会信用代码", example = "91440101MA5XXXXXX")
|
||||
private final String creditCode;
|
||||
@Schema(description = "钱包类型", example = "对公钱包")
|
||||
private final String walletType;
|
||||
@Schema(description = "钱包状态", example = "ACTIVATED")
|
||||
private final String status;
|
||||
@Schema(description = "激活时间", example = "20260801101000")
|
||||
private final String activateTime;
|
||||
@Schema(description = "开立渠道:临柜开立 / 远程开立(复用时标注原渠道)")
|
||||
private final String channel;
|
||||
|
||||
public CorporateWalletResult(String walletId, String corpName, String creditCode,
|
||||
String walletType, String status, String activateTime) {
|
||||
this(walletId, corpName, creditCode, walletType, status, activateTime, "临柜开立");
|
||||
}
|
||||
|
||||
public CorporateWalletResult(String walletId, String corpName, String creditCode,
|
||||
String walletType, String status, String activateTime, String channel) {
|
||||
this.walletId = walletId;
|
||||
this.corpName = corpName;
|
||||
this.creditCode = creditCode;
|
||||
this.walletType = walletType;
|
||||
this.status = status;
|
||||
this.activateTime = activateTime;
|
||||
this.channel = channel;
|
||||
}
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "远程开立-步骤一输出结果")
|
||||
public class RemoteApplicationResult {
|
||||
@Schema(description = "申请编号", example = "REMOTE_APP_20260801_001")
|
||||
private final String applicationId;
|
||||
@Schema(description = "企业名称", example = "阳光公益基金")
|
||||
private final String corpName;
|
||||
@Schema(description = "统一社会信用代码", example = "91440101MA6XXXXXX")
|
||||
private final String creditCode;
|
||||
@Schema(description = "法人代表", example = "李四")
|
||||
private final String legalPerson;
|
||||
@Schema(description = "手机号码", example = "13900139000")
|
||||
private final String phone;
|
||||
@Schema(description = "申请时间", example = "20260801110000")
|
||||
private final String applyTime;
|
||||
@Schema(description = "人脸识别结果")
|
||||
private final FaceRecognitionData faceRecognition;
|
||||
@Schema(description = "申请状态", example = "人脸识别已通过,等待电子签约")
|
||||
private final String status;
|
||||
|
||||
public RemoteApplicationResult(String applicationId, String corpName, String creditCode,
|
||||
String legalPerson, String phone, String applyTime,
|
||||
String faceStatus, String liveDetection, String similarityScore,
|
||||
String verifyTime, String status) {
|
||||
this.applicationId = applicationId;
|
||||
this.corpName = corpName;
|
||||
this.creditCode = creditCode;
|
||||
this.legalPerson = legalPerson;
|
||||
this.phone = phone;
|
||||
this.applyTime = applyTime;
|
||||
this.faceRecognition = new FaceRecognitionData(faceStatus, liveDetection, similarityScore, verifyTime);
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Schema(description = "人脸识别详情")
|
||||
public static class FaceRecognitionData {
|
||||
@Schema(description = "人脸识别状态", example = "PASSED")
|
||||
private final String status;
|
||||
@Schema(description = "活体检测状态", example = "PASSED")
|
||||
private final String liveDetection;
|
||||
@Schema(description = "相似度", example = "98.7%")
|
||||
private final String similarityScore;
|
||||
@Schema(description = "验证时间", example = "20260801110230")
|
||||
private final String verifyTime;
|
||||
|
||||
public FaceRecognitionData(String status, String liveDetection, String similarityScore, String verifyTime) {
|
||||
this.status = status;
|
||||
this.liveDetection = liveDetection;
|
||||
this.similarityScore = similarityScore;
|
||||
this.verifyTime = verifyTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "远程开立-拼接原文结果")
|
||||
public class RemoteConcatenateResult {
|
||||
@Schema(description = "拼接后的原文", example = "REMOTE_OPEN|阳光公益基金|91440101MA6XXXXXX|李四|13900139000|20260801110000")
|
||||
private final String concatenatedMessage;
|
||||
|
||||
public RemoteConcatenateResult(String concatenatedMessage) {
|
||||
this.concatenatedMessage = concatenatedMessage;
|
||||
}
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "远程开立-步骤二电子签约输出结果")
|
||||
public class RemoteContractResult {
|
||||
@Schema(description = "合约编号", example = "E_SIGN_20260801_001")
|
||||
private final String contractId;
|
||||
@Schema(description = "申请编号", example = "REMOTE_APP_20260801_001")
|
||||
private final String applicationId;
|
||||
@Schema(description = "签约人", example = "李四")
|
||||
private final String signer;
|
||||
@Schema(description = "人脸识别确认", example = "PASSED")
|
||||
private final String faceRecognitionConfirm;
|
||||
@Schema(description = "SM2签名值")
|
||||
private final String signature;
|
||||
@Schema(description = "签约时间", example = "20260801110500")
|
||||
private final String signTime;
|
||||
@Schema(description = "签约状态", example = "SIGNED")
|
||||
private final String status;
|
||||
|
||||
public RemoteContractResult(String contractId, String applicationId, String signer,
|
||||
String faceRecognitionConfirm, String signature,
|
||||
String signTime, String status) {
|
||||
this.contractId = contractId;
|
||||
this.applicationId = applicationId;
|
||||
this.signer = signer;
|
||||
this.faceRecognitionConfirm = faceRecognitionConfirm;
|
||||
this.signature = signature;
|
||||
this.signTime = signTime;
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "远程开立-SM3摘要运算结果")
|
||||
public class RemoteDigestResult {
|
||||
@Schema(description = "哈希算法", example = "SM3")
|
||||
private final String algorithm;
|
||||
@Schema(description = "摘要值(十六进制)")
|
||||
private final String digestValue;
|
||||
|
||||
public RemoteDigestResult(String algorithm, String digestValue) {
|
||||
this.algorithm = algorithm;
|
||||
this.digestValue = digestValue;
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "远程开立-提取摘要原文结果")
|
||||
public class RemoteExtractResult {
|
||||
@Schema(description = "提取的摘要原文")
|
||||
private final String extractMessage;
|
||||
|
||||
public RemoteExtractResult(String extractMessage) {
|
||||
this.extractMessage = extractMessage;
|
||||
}
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "远程开立-SM2签名结果")
|
||||
public class RemoteSignatureResult {
|
||||
@Schema(description = "签名私钥(十六进制)")
|
||||
private final String privateKey;
|
||||
@Schema(description = "签名算法", example = "SM2")
|
||||
private final String algorithm;
|
||||
@Schema(description = "签名值(十六进制)")
|
||||
private final String signature;
|
||||
|
||||
public RemoteSignatureResult(String privateKey, String algorithm, String signature) {
|
||||
this.privateKey = privateKey;
|
||||
this.algorithm = algorithm;
|
||||
this.signature = signature;
|
||||
}
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "远程开立-步骤三公钱包输出结果")
|
||||
public class RemoteWalletResult {
|
||||
@Schema(description = "钱包ID", example = "CORP_7D8E9F0A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6E7F8A9B0C1D2E3F4A5B6")
|
||||
private final String walletId;
|
||||
@Schema(description = "企业名称", example = "阳光公益基金")
|
||||
private final String corpName;
|
||||
@Schema(description = "统一社会信用代码", example = "91440101MA6XXXXXX")
|
||||
private final String creditCode;
|
||||
@Schema(description = "钱包类型", example = "对公钱包")
|
||||
private final String walletType;
|
||||
@Schema(description = "钱包状态", example = "ACTIVATED")
|
||||
private final String status;
|
||||
@Schema(description = "激活时间", example = "20260801110500")
|
||||
private final String activateTime;
|
||||
@Schema(description = "人脸识别记录", example = "已验证")
|
||||
private final String faceRecognitionLog;
|
||||
@Schema(description = "开立渠道:远程开立 / 临柜开立(复用时标注原渠道)")
|
||||
private final String channel;
|
||||
|
||||
public RemoteWalletResult(String walletId, String corpName, String creditCode,
|
||||
String walletType, String status, String activateTime,
|
||||
String faceRecognitionLog) {
|
||||
this(walletId, corpName, creditCode, walletType, status, activateTime, faceRecognitionLog, "远程开立");
|
||||
}
|
||||
|
||||
public RemoteWalletResult(String walletId, String corpName, String creditCode,
|
||||
String walletType, String status, String activateTime,
|
||||
String faceRecognitionLog, String channel) {
|
||||
this.walletId = walletId;
|
||||
this.corpName = corpName;
|
||||
this.creditCode = creditCode;
|
||||
this.walletType = walletType;
|
||||
this.status = status;
|
||||
this.activateTime = activateTime;
|
||||
this.faceRecognitionLog = faceRecognitionLog;
|
||||
this.channel = channel;
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "拼接工资发放申请原文结果")
|
||||
public class SalaryConcatenateResult {
|
||||
@Schema(description = "拼接原文(管道分隔)")
|
||||
private final String concatenatedMessage;
|
||||
|
||||
public SalaryConcatenateResult(String concatenatedMessage) {
|
||||
this.concatenatedMessage = concatenatedMessage;
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "交易确认SM3摘要结果")
|
||||
public class SalaryConfirmDigestResult {
|
||||
@Schema(description = "摘要值(十六进制大写)")
|
||||
private final String digestValue;
|
||||
|
||||
public SalaryConfirmDigestResult(String digestValue) {
|
||||
this.digestValue = digestValue;
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "交易确认输出JSON结果")
|
||||
public class SalaryConfirmOutputResult {
|
||||
@Schema(description = "输出JSON报文")
|
||||
private final String outputJson;
|
||||
|
||||
public SalaryConfirmOutputResult(String outputJson) {
|
||||
this.outputJson = outputJson;
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "输出JSON结果")
|
||||
public class SalaryOutputResult {
|
||||
@Schema(description = "输出JSON报文")
|
||||
private final String outputJson;
|
||||
|
||||
public SalaryOutputResult(String outputJson) {
|
||||
this.outputJson = outputJson;
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "审核输出JSON结果")
|
||||
public class SalaryReviewOutputResult {
|
||||
@Schema(description = "输出JSON报文")
|
||||
private final String outputJson;
|
||||
|
||||
public SalaryReviewOutputResult(String outputJson) {
|
||||
this.outputJson = outputJson;
|
||||
}
|
||||
}
|
||||
@ -1,94 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.yau.digitalrmb.institutionidentity.infrastructure.StuModuleScoreDetailsEntity;
|
||||
import com.yau.digitalrmb.institutionidentity.infrastructure.StuModuleScoreDetailsMapper;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 企业发放数字人民币工资模块的成绩统计服务。
|
||||
* 错误次数同步到平台统一成绩明细表。
|
||||
*/
|
||||
@Service
|
||||
public class SalaryScoreService {
|
||||
public static final String MODULE_NAME = "企业发放数字人民币工资";
|
||||
private static final int MODULE_SERIAL_NUMBER = 6;
|
||||
private static final double TOTAL_SCORE = 100.0;
|
||||
|
||||
@Resource
|
||||
private StuModuleScoreDetailsMapper scoreDetailsMapper;
|
||||
|
||||
@Value("${salary.score.wrong-deduct:0.50}")
|
||||
private BigDecimal wrongDeduct = new BigDecimal("0.50");
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public int recordError(String userId) {
|
||||
if (userId == null || userId.trim().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
StuModuleScoreDetailsEntity detail = getOrCreate(userId);
|
||||
int accumulatedErrorCount = errorCount(detail.getCompletionStatus()) + 1;
|
||||
detail.setCompletionStatus(String.valueOf(accumulatedErrorCount));
|
||||
detail.setScoreProject(score(accumulatedErrorCount, progress(detail.getSchedule())));
|
||||
scoreDetailsMapper.updateById(detail);
|
||||
return accumulatedErrorCount;
|
||||
}
|
||||
|
||||
private StuModuleScoreDetailsEntity getOrCreate(String userId) {
|
||||
StuModuleScoreDetailsEntity existing = scoreDetailsMapper.selectOne(
|
||||
new LambdaQueryWrapper<StuModuleScoreDetailsEntity>()
|
||||
.eq(StuModuleScoreDetailsEntity::getUserId, userId)
|
||||
.eq(StuModuleScoreDetailsEntity::getMoudule, MODULE_NAME)
|
||||
.eq(StuModuleScoreDetailsEntity::getSerialNumber, MODULE_SERIAL_NUMBER)
|
||||
.last("LIMIT 1"));
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
StuModuleScoreDetailsEntity created = new StuModuleScoreDetailsEntity();
|
||||
created.setId(UUID.randomUUID().toString());
|
||||
created.setMoudule(MODULE_NAME);
|
||||
created.setLearningProjects("实验实训");
|
||||
created.setAssessmentItems("工资发放流程错误次数");
|
||||
created.setScoringCriteria(wrongDeduct.stripTrailingZeros().toPlainString());
|
||||
created.setCompletionStatus("0");
|
||||
created.setScoreProject(0.0);
|
||||
created.setUserId(userId);
|
||||
created.setTotalScore(TOTAL_SCORE);
|
||||
created.setSerialNumber(MODULE_SERIAL_NUMBER);
|
||||
created.setSchedule(0.0);
|
||||
scoreDetailsMapper.insert(created);
|
||||
return created;
|
||||
}
|
||||
|
||||
private double score(int errorCount, double schedule) {
|
||||
BigDecimal base = BigDecimal.valueOf(TOTAL_SCORE)
|
||||
.subtract(wrongDeduct.multiply(BigDecimal.valueOf(Math.max(0, errorCount))))
|
||||
.max(BigDecimal.ZERO);
|
||||
return base.multiply(BigDecimal.valueOf(schedule))
|
||||
.divide(BigDecimal.valueOf(TOTAL_SCORE), 2, RoundingMode.HALF_UP)
|
||||
.doubleValue();
|
||||
}
|
||||
|
||||
private double progress(Double schedule) {
|
||||
return schedule == null ? 0.0 : schedule;
|
||||
}
|
||||
|
||||
private int errorCount(String completionStatus) {
|
||||
if (completionStatus == null || completionStatus.trim().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return Math.max(0, Integer.parseInt(completionStatus));
|
||||
} catch (NumberFormatException exception) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.application;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Schema(description = "发送结果")
|
||||
public class SalarySendResult {
|
||||
@Schema(description = "状态:待审核")
|
||||
private final String status;
|
||||
@Schema(description = "发送时间")
|
||||
private final String submitTime;
|
||||
|
||||
public SalarySendResult(String status, String submitTime) {
|
||||
this.status = status;
|
||||
this.submitTime = submitTime;
|
||||
}
|
||||
}
|
||||
@ -1,145 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.domain;
|
||||
|
||||
public class CorporateWalletApplication {
|
||||
public enum Status {
|
||||
DRAFT, SUBMITTED, APPROVED, ACTIVATED
|
||||
}
|
||||
|
||||
private Long id;
|
||||
private String userId;
|
||||
private long schoolId;
|
||||
private long classId;
|
||||
|
||||
// 企业申请信息
|
||||
private String corpName;
|
||||
private String creditCode;
|
||||
private String legalPerson;
|
||||
private String capital;
|
||||
private String businessScope;
|
||||
private String applyTime;
|
||||
|
||||
// 拼接报文
|
||||
private String concatenatedMessage;
|
||||
|
||||
// 申请输出
|
||||
private String applicationId;
|
||||
private String applicationMessage;
|
||||
private Status status;
|
||||
|
||||
// 审核信息
|
||||
private String verifyId;
|
||||
private String reviewer;
|
||||
private String verifyTime;
|
||||
|
||||
// 提取摘要原文
|
||||
private String extractMessage;
|
||||
|
||||
// SM3摘要
|
||||
private String digestAlgorithm;
|
||||
private String digestValue;
|
||||
|
||||
// 对公钱包
|
||||
private String walletId;
|
||||
private String walletType;
|
||||
private String activateTime;
|
||||
|
||||
public static CorporateWalletApplication create(String userId, long schoolId, long classId) {
|
||||
CorporateWalletApplication app = new CorporateWalletApplication();
|
||||
app.userId = userId;
|
||||
app.schoolId = schoolId;
|
||||
app.classId = classId;
|
||||
app.status = Status.DRAFT;
|
||||
app.walletType = "对公钱包";
|
||||
return app;
|
||||
}
|
||||
|
||||
public void fillForm(String corpName, String creditCode, String legalPerson,
|
||||
String capital, String businessScope, String applyTime) {
|
||||
this.corpName = corpName;
|
||||
this.creditCode = creditCode;
|
||||
this.legalPerson = legalPerson;
|
||||
this.capital = capital;
|
||||
this.businessScope = businessScope;
|
||||
this.applyTime = applyTime;
|
||||
}
|
||||
|
||||
public void concatenate(String concatenatedMessage) {
|
||||
this.concatenatedMessage = concatenatedMessage;
|
||||
}
|
||||
|
||||
public void outputApplication(String applicationId, String applicationMessage) {
|
||||
this.applicationId = applicationId;
|
||||
this.applicationMessage = applicationMessage;
|
||||
this.status = Status.SUBMITTED;
|
||||
}
|
||||
|
||||
public void approve(String verifyId, String reviewer, String verifyTime) {
|
||||
this.verifyId = verifyId;
|
||||
this.reviewer = reviewer;
|
||||
this.verifyTime = verifyTime;
|
||||
this.status = Status.APPROVED;
|
||||
}
|
||||
|
||||
public void extract(String extractMessage) {
|
||||
this.extractMessage = extractMessage;
|
||||
}
|
||||
|
||||
public void computeDigest(String algorithm, String digestValue) {
|
||||
this.digestAlgorithm = algorithm;
|
||||
this.digestValue = digestValue;
|
||||
}
|
||||
|
||||
public void activateWallet(String walletId, String activateTime) {
|
||||
this.walletId = walletId;
|
||||
this.activateTime = activateTime;
|
||||
this.status = Status.ACTIVATED;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
public String getUserId() { return userId; }
|
||||
public void setUserId(String userId) { this.userId = userId; }
|
||||
public long getSchoolId() { return schoolId; }
|
||||
public void setSchoolId(long schoolId) { this.schoolId = schoolId; }
|
||||
public long getClassId() { return classId; }
|
||||
public void setClassId(long classId) { this.classId = classId; }
|
||||
public String getCorpName() { return corpName; }
|
||||
public void setCorpName(String corpName) { this.corpName = corpName; }
|
||||
public String getCreditCode() { return creditCode; }
|
||||
public void setCreditCode(String creditCode) { this.creditCode = creditCode; }
|
||||
public String getLegalPerson() { return legalPerson; }
|
||||
public void setLegalPerson(String legalPerson) { this.legalPerson = legalPerson; }
|
||||
public String getCapital() { return capital; }
|
||||
public void setCapital(String capital) { this.capital = capital; }
|
||||
public String getBusinessScope() { return businessScope; }
|
||||
public void setBusinessScope(String businessScope) { this.businessScope = businessScope; }
|
||||
public String getApplyTime() { return applyTime; }
|
||||
public void setApplyTime(String applyTime) { this.applyTime = applyTime; }
|
||||
public String getConcatenatedMessage() { return concatenatedMessage; }
|
||||
public void setConcatenatedMessage(String concatenatedMessage) { this.concatenatedMessage = concatenatedMessage; }
|
||||
public String getApplicationId() { return applicationId; }
|
||||
public void setApplicationId(String applicationId) { this.applicationId = applicationId; }
|
||||
public String getApplicationMessage() { return applicationMessage; }
|
||||
public void setApplicationMessage(String applicationMessage) { this.applicationMessage = applicationMessage; }
|
||||
public Status getStatus() { return status; }
|
||||
public void setStatus(Status status) { this.status = status; }
|
||||
public String getVerifyId() { return verifyId; }
|
||||
public void setVerifyId(String verifyId) { this.verifyId = verifyId; }
|
||||
public String getReviewer() { return reviewer; }
|
||||
public void setReviewer(String reviewer) { this.reviewer = reviewer; }
|
||||
public String getVerifyTime() { return verifyTime; }
|
||||
public void setVerifyTime(String verifyTime) { this.verifyTime = verifyTime; }
|
||||
public String getExtractMessage() { return extractMessage; }
|
||||
public void setExtractMessage(String extractMessage) { this.extractMessage = extractMessage; }
|
||||
public String getDigestAlgorithm() { return digestAlgorithm; }
|
||||
public void setDigestAlgorithm(String digestAlgorithm) { this.digestAlgorithm = digestAlgorithm; }
|
||||
public String getDigestValue() { return digestValue; }
|
||||
public void setDigestValue(String digestValue) { this.digestValue = digestValue; }
|
||||
public String getWalletId() { return walletId; }
|
||||
public void setWalletId(String walletId) { this.walletId = walletId; }
|
||||
public String getWalletType() { return walletType; }
|
||||
public void setWalletType(String walletType) { this.walletType = walletType; }
|
||||
public String getActivateTime() { return activateTime; }
|
||||
public void setActivateTime(String activateTime) { this.activateTime = activateTime; }
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.domain;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface CorporateWalletApplicationRepository {
|
||||
CorporateWalletApplication save(CorporateWalletApplication application);
|
||||
Optional<CorporateWalletApplication> findLatest(String userId, long schoolId, long classId);
|
||||
Optional<CorporateWalletApplication> findByApplicationId(String applicationId);
|
||||
Optional<CorporateWalletApplication> findActivatedByCreditCode(String creditCode, String userId, long schoolId, long classId);
|
||||
void update(CorporateWalletApplication application);
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.domain;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface RemoteWalletApplicationRepository {
|
||||
RemoteWalletApplication save(RemoteWalletApplication application);
|
||||
Optional<RemoteWalletApplication> findLatest(String userId, long schoolId, long classId);
|
||||
Optional<RemoteWalletApplication> findActivatedByCreditCode(String creditCode, String userId, long schoolId, long classId);
|
||||
void update(RemoteWalletApplication application);
|
||||
}
|
||||
@ -1,220 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.domain;
|
||||
|
||||
public class SalaryBatch {
|
||||
public enum Status {
|
||||
DRAFT, BLOCKCHAIN_FETCHED, CONCATENATED, DIGESTED, SIGNED, OUTPUT, SENT,
|
||||
REVIEW_EXTRACTED, REVIEW_CHECKED, REVIEW_DIGESTED, REVIEW_SIGNED, REVIEWED,
|
||||
CONFIRM_EXTRACTED, CONFIRM_DIGESTED, CONFIRM_SIGNED, CONFIRM_COMPLETED
|
||||
}
|
||||
|
||||
private Long id;
|
||||
private String userId;
|
||||
private long schoolId;
|
||||
private long classId;
|
||||
|
||||
// 调取区块信息
|
||||
private String batchId;
|
||||
private String corpWalletId;
|
||||
private String operatorName;
|
||||
private String operatorTimestamp;
|
||||
|
||||
// 拼接原文
|
||||
private String concatenatedMessage;
|
||||
|
||||
// SM3摘要
|
||||
private String digestAlgorithm;
|
||||
private String digestValue;
|
||||
|
||||
// SM2签名
|
||||
private String signature;
|
||||
|
||||
// 输出JSON
|
||||
private String outputJson;
|
||||
|
||||
// 状态
|
||||
private Status status;
|
||||
private String submitTime;
|
||||
|
||||
// 复核员审核相关
|
||||
private String reviewerName;
|
||||
private String reviewTimestamp;
|
||||
private String reviewConcatenatedMessage;
|
||||
private String reviewDigestAlgorithm;
|
||||
private String reviewDigestValue;
|
||||
private String reviewSignature;
|
||||
private String reviewOutputJson;
|
||||
private Integer singleLimitStatus;
|
||||
private Integer batchLimitStatus;
|
||||
private Integer dailyLimitStatus;
|
||||
private String reviewResult;
|
||||
|
||||
// 交易确认相关
|
||||
private String confirmMessage;
|
||||
private String confirmTimestamp;
|
||||
private String confirmDigestAlgorithm;
|
||||
private String confirmDigestValue;
|
||||
private String cbSignature;
|
||||
private String confirmOutputJson;
|
||||
|
||||
public static SalaryBatch create(String userId, long schoolId, long classId) {
|
||||
SalaryBatch batch = new SalaryBatch();
|
||||
batch.userId = userId;
|
||||
batch.schoolId = schoolId;
|
||||
batch.classId = classId;
|
||||
batch.status = Status.DRAFT;
|
||||
return batch;
|
||||
}
|
||||
|
||||
public void fetchBlockchain(String batchId, String corpWalletId, String operatorName, String timestamp) {
|
||||
this.batchId = batchId;
|
||||
this.corpWalletId = corpWalletId;
|
||||
this.operatorName = operatorName;
|
||||
this.operatorTimestamp = timestamp;
|
||||
this.status = Status.BLOCKCHAIN_FETCHED;
|
||||
}
|
||||
|
||||
public void concatenate(String message) {
|
||||
this.concatenatedMessage = message;
|
||||
this.status = Status.CONCATENATED;
|
||||
}
|
||||
|
||||
public void computeDigest(String algorithm, String digest) {
|
||||
this.digestAlgorithm = algorithm;
|
||||
this.digestValue = digest;
|
||||
this.status = Status.DIGESTED;
|
||||
}
|
||||
|
||||
public void sign(String signature) {
|
||||
this.signature = signature;
|
||||
this.status = Status.SIGNED;
|
||||
}
|
||||
|
||||
public void output(String outputJson) {
|
||||
this.outputJson = outputJson;
|
||||
this.status = Status.OUTPUT;
|
||||
}
|
||||
|
||||
public void send(String submitTime) {
|
||||
this.submitTime = submitTime;
|
||||
this.status = Status.SENT;
|
||||
}
|
||||
|
||||
public void extractReviewText(String reviewerName, String reviewTimestamp, String reviewMessage) {
|
||||
this.reviewerName = reviewerName;
|
||||
this.reviewTimestamp = reviewTimestamp;
|
||||
this.reviewConcatenatedMessage = reviewMessage;
|
||||
this.status = Status.REVIEW_EXTRACTED;
|
||||
}
|
||||
|
||||
public void checkPermission(Integer singleLimitStatus, Integer batchLimitStatus, Integer dailyLimitStatus, String reviewResult) {
|
||||
this.singleLimitStatus = singleLimitStatus;
|
||||
this.batchLimitStatus = batchLimitStatus;
|
||||
this.dailyLimitStatus = dailyLimitStatus;
|
||||
this.reviewResult = reviewResult;
|
||||
this.status = Status.REVIEW_CHECKED;
|
||||
}
|
||||
|
||||
public void computeReviewDigest(String algorithm, String digest) {
|
||||
this.reviewDigestAlgorithm = algorithm;
|
||||
this.reviewDigestValue = digest;
|
||||
this.status = Status.REVIEW_DIGESTED;
|
||||
}
|
||||
|
||||
public void signReview(String signature) {
|
||||
this.reviewSignature = signature;
|
||||
this.status = Status.REVIEW_SIGNED;
|
||||
}
|
||||
|
||||
public void outputReview(String outputJson) {
|
||||
this.reviewOutputJson = outputJson;
|
||||
this.status = Status.REVIEWED;
|
||||
}
|
||||
|
||||
public void extractConfirmText(String confirmTimestamp, String confirmMessage) {
|
||||
this.confirmTimestamp = confirmTimestamp;
|
||||
this.confirmMessage = confirmMessage;
|
||||
this.status = Status.CONFIRM_EXTRACTED;
|
||||
}
|
||||
|
||||
public void computeConfirmDigest(String algorithm, String digest) {
|
||||
this.confirmDigestAlgorithm = algorithm;
|
||||
this.confirmDigestValue = digest;
|
||||
this.status = Status.CONFIRM_DIGESTED;
|
||||
}
|
||||
|
||||
public void signConfirm(String cbSignature) {
|
||||
this.cbSignature = cbSignature;
|
||||
this.status = Status.CONFIRM_SIGNED;
|
||||
}
|
||||
|
||||
public void outputConfirm(String outputJson) {
|
||||
this.confirmOutputJson = outputJson;
|
||||
this.status = Status.CONFIRM_COMPLETED;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
public String getUserId() { return userId; }
|
||||
public void setUserId(String userId) { this.userId = userId; }
|
||||
public long getSchoolId() { return schoolId; }
|
||||
public void setSchoolId(long schoolId) { this.schoolId = schoolId; }
|
||||
public long getClassId() { return classId; }
|
||||
public void setClassId(long classId) { this.classId = classId; }
|
||||
public String getBatchId() { return batchId; }
|
||||
public void setBatchId(String batchId) { this.batchId = batchId; }
|
||||
public String getCorpWalletId() { return corpWalletId; }
|
||||
public void setCorpWalletId(String corpWalletId) { this.corpWalletId = corpWalletId; }
|
||||
public String getOperatorName() { return operatorName; }
|
||||
public void setOperatorName(String operatorName) { this.operatorName = operatorName; }
|
||||
public String getOperatorTimestamp() { return operatorTimestamp; }
|
||||
public void setOperatorTimestamp(String operatorTimestamp) { this.operatorTimestamp = operatorTimestamp; }
|
||||
public String getConcatenatedMessage() { return concatenatedMessage; }
|
||||
public void setConcatenatedMessage(String concatenatedMessage) { this.concatenatedMessage = concatenatedMessage; }
|
||||
public String getDigestAlgorithm() { return digestAlgorithm; }
|
||||
public void setDigestAlgorithm(String digestAlgorithm) { this.digestAlgorithm = digestAlgorithm; }
|
||||
public String getDigestValue() { return digestValue; }
|
||||
public void setDigestValue(String digestValue) { this.digestValue = digestValue; }
|
||||
public String getSignature() { return signature; }
|
||||
public void setSignature(String signature) { this.signature = signature; }
|
||||
public String getOutputJson() { return outputJson; }
|
||||
public void setOutputJson(String outputJson) { this.outputJson = outputJson; }
|
||||
public Status getStatus() { return status; }
|
||||
public void setStatus(Status status) { this.status = status; }
|
||||
public String getSubmitTime() { return submitTime; }
|
||||
public void setSubmitTime(String submitTime) { this.submitTime = submitTime; }
|
||||
public String getReviewerName() { return reviewerName; }
|
||||
public void setReviewerName(String reviewerName) { this.reviewerName = reviewerName; }
|
||||
public String getReviewTimestamp() { return reviewTimestamp; }
|
||||
public void setReviewTimestamp(String reviewTimestamp) { this.reviewTimestamp = reviewTimestamp; }
|
||||
public String getReviewConcatenatedMessage() { return reviewConcatenatedMessage; }
|
||||
public void setReviewConcatenatedMessage(String reviewConcatenatedMessage) { this.reviewConcatenatedMessage = reviewConcatenatedMessage; }
|
||||
public String getReviewDigestAlgorithm() { return reviewDigestAlgorithm; }
|
||||
public void setReviewDigestAlgorithm(String reviewDigestAlgorithm) { this.reviewDigestAlgorithm = reviewDigestAlgorithm; }
|
||||
public String getReviewDigestValue() { return reviewDigestValue; }
|
||||
public void setReviewDigestValue(String reviewDigestValue) { this.reviewDigestValue = reviewDigestValue; }
|
||||
public String getReviewSignature() { return reviewSignature; }
|
||||
public void setReviewSignature(String reviewSignature) { this.reviewSignature = reviewSignature; }
|
||||
public String getReviewOutputJson() { return reviewOutputJson; }
|
||||
public void setReviewOutputJson(String reviewOutputJson) { this.reviewOutputJson = reviewOutputJson; }
|
||||
public Integer getSingleLimitStatus() { return singleLimitStatus; }
|
||||
public void setSingleLimitStatus(Integer singleLimitStatus) { this.singleLimitStatus = singleLimitStatus; }
|
||||
public Integer getBatchLimitStatus() { return batchLimitStatus; }
|
||||
public void setBatchLimitStatus(Integer batchLimitStatus) { this.batchLimitStatus = batchLimitStatus; }
|
||||
public Integer getDailyLimitStatus() { return dailyLimitStatus; }
|
||||
public void setDailyLimitStatus(Integer dailyLimitStatus) { this.dailyLimitStatus = dailyLimitStatus; }
|
||||
public String getReviewResult() { return reviewResult; }
|
||||
public void setReviewResult(String reviewResult) { this.reviewResult = reviewResult; }
|
||||
public String getConfirmMessage() { return confirmMessage; }
|
||||
public void setConfirmMessage(String confirmMessage) { this.confirmMessage = confirmMessage; }
|
||||
public String getConfirmTimestamp() { return confirmTimestamp; }
|
||||
public void setConfirmTimestamp(String confirmTimestamp) { this.confirmTimestamp = confirmTimestamp; }
|
||||
public String getConfirmDigestAlgorithm() { return confirmDigestAlgorithm; }
|
||||
public void setConfirmDigestAlgorithm(String confirmDigestAlgorithm) { this.confirmDigestAlgorithm = confirmDigestAlgorithm; }
|
||||
public String getConfirmDigestValue() { return confirmDigestValue; }
|
||||
public void setConfirmDigestValue(String confirmDigestValue) { this.confirmDigestValue = confirmDigestValue; }
|
||||
public String getCbSignature() { return cbSignature; }
|
||||
public void setCbSignature(String cbSignature) { this.cbSignature = cbSignature; }
|
||||
public String getConfirmOutputJson() { return confirmOutputJson; }
|
||||
public void setConfirmOutputJson(String confirmOutputJson) { this.confirmOutputJson = confirmOutputJson; }
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.domain;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface SalaryBatchRepository {
|
||||
SalaryBatch save(SalaryBatch batch);
|
||||
Optional<SalaryBatch> findLatest(String userId, long schoolId, long classId);
|
||||
void update(SalaryBatch batch);
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.yau.digitalrmb.shared.infrastructure.persistence.AuditableEntity;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("corporate_wallet_application")
|
||||
public class CorporateWalletApplicationEntity extends AuditableEntity {
|
||||
@TableField("user_id")
|
||||
private String userId;
|
||||
@TableField("school_id")
|
||||
private Long schoolId;
|
||||
@TableField("class_id")
|
||||
private Long classId;
|
||||
|
||||
@TableField("corp_name")
|
||||
private String corpName;
|
||||
@TableField("credit_code")
|
||||
private String creditCode;
|
||||
@TableField("legal_person")
|
||||
private String legalPerson;
|
||||
private String capital;
|
||||
@TableField("business_scope")
|
||||
private String businessScope;
|
||||
@TableField("apply_time")
|
||||
private String applyTime;
|
||||
|
||||
@TableField("concatenated_message")
|
||||
private String concatenatedMessage;
|
||||
|
||||
@TableField("application_id")
|
||||
private String applicationId;
|
||||
@TableField("application_message")
|
||||
private String applicationMessage;
|
||||
private String status;
|
||||
|
||||
@TableField("verify_id")
|
||||
private String verifyId;
|
||||
private String reviewer;
|
||||
@TableField("verify_time")
|
||||
private String verifyTime;
|
||||
|
||||
@TableField("extract_message")
|
||||
private String extractMessage;
|
||||
|
||||
@TableField("digest_algorithm")
|
||||
private String digestAlgorithm;
|
||||
@TableField("digest_value")
|
||||
private String digestValue;
|
||||
|
||||
@TableField("wallet_id")
|
||||
private String walletId;
|
||||
@TableField("wallet_type")
|
||||
private String walletType;
|
||||
@TableField("activate_time")
|
||||
private String activateTime;
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface CorporateWalletApplicationMapper extends BaseMapper<CorporateWalletApplicationEntity> {
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.yau.digitalrmb.shared.infrastructure.persistence.AuditableEntity;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("corporate_wallet_key_info")
|
||||
public class CorporateWalletKeyInfoEntity extends AuditableEntity {
|
||||
@TableField("user_id")
|
||||
private String userId;
|
||||
@TableField("school_id")
|
||||
private Long schoolId;
|
||||
@TableField("class_id")
|
||||
private Long classId;
|
||||
@TableField("key_type")
|
||||
private String keyType;
|
||||
@TableField("holder")
|
||||
private String holder;
|
||||
@TableField("key_algorithm")
|
||||
private String keyAlgorithm;
|
||||
@TableField("key_value")
|
||||
private String keyValue;
|
||||
@TableField("is_private_key")
|
||||
private Boolean isPrivateKey;
|
||||
@TableField("source")
|
||||
private String source;
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface CorporateWalletKeyInfoMapper extends BaseMapper<CorporateWalletKeyInfoEntity> {
|
||||
}
|
||||
@ -1,123 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.yau.digitalrmb.corporatewallet.domain.CorporateWalletApplication;
|
||||
import com.yau.digitalrmb.corporatewallet.domain.CorporateWalletApplicationRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public class MybatisCorporateWalletApplicationRepository implements CorporateWalletApplicationRepository {
|
||||
@Resource
|
||||
private CorporateWalletApplicationMapper mapper;
|
||||
|
||||
@Override
|
||||
public CorporateWalletApplication save(CorporateWalletApplication application) {
|
||||
CorporateWalletApplicationEntity entity = toEntity(application);
|
||||
mapper.insert(entity);
|
||||
application.setId(entity.getId());
|
||||
return application;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CorporateWalletApplication> findLatest(String userId, long schoolId, long classId) {
|
||||
CorporateWalletApplicationEntity entity = mapper.selectOne(
|
||||
new LambdaQueryWrapper<CorporateWalletApplicationEntity>()
|
||||
.eq(CorporateWalletApplicationEntity::getUserId, userId)
|
||||
.eq(CorporateWalletApplicationEntity::getSchoolId, schoolId)
|
||||
.eq(CorporateWalletApplicationEntity::getClassId, classId)
|
||||
.eq(CorporateWalletApplicationEntity::getDeleted, false)
|
||||
.orderByDesc(CorporateWalletApplicationEntity::getCreatedAt)
|
||||
.last("LIMIT 1"));
|
||||
return entity == null ? Optional.empty() : Optional.of(toDomain(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CorporateWalletApplication> findByApplicationId(String applicationId) {
|
||||
CorporateWalletApplicationEntity entity = mapper.selectOne(
|
||||
new LambdaQueryWrapper<CorporateWalletApplicationEntity>()
|
||||
.eq(CorporateWalletApplicationEntity::getApplicationId, applicationId)
|
||||
.eq(CorporateWalletApplicationEntity::getDeleted, false)
|
||||
.last("LIMIT 1"));
|
||||
return entity == null ? Optional.empty() : Optional.of(toDomain(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CorporateWalletApplication> findActivatedByCreditCode(String creditCode, String userId, long schoolId, long classId) {
|
||||
CorporateWalletApplicationEntity entity = mapper.selectOne(
|
||||
new LambdaQueryWrapper<CorporateWalletApplicationEntity>()
|
||||
.eq(CorporateWalletApplicationEntity::getCreditCode, creditCode)
|
||||
.eq(CorporateWalletApplicationEntity::getUserId, userId)
|
||||
.eq(CorporateWalletApplicationEntity::getSchoolId, schoolId)
|
||||
.eq(CorporateWalletApplicationEntity::getClassId, classId)
|
||||
.eq(CorporateWalletApplicationEntity::getDeleted, false)
|
||||
.isNotNull(CorporateWalletApplicationEntity::getWalletId)
|
||||
.ne(CorporateWalletApplicationEntity::getWalletId, "")
|
||||
.orderByDesc(CorporateWalletApplicationEntity::getCreatedAt)
|
||||
.last("LIMIT 1"));
|
||||
return entity == null ? Optional.empty() : Optional.of(toDomain(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(CorporateWalletApplication application) {
|
||||
mapper.updateById(toEntity(application));
|
||||
}
|
||||
|
||||
private CorporateWalletApplicationEntity toEntity(CorporateWalletApplication app) {
|
||||
CorporateWalletApplicationEntity entity = new CorporateWalletApplicationEntity();
|
||||
entity.setId(app.getId());
|
||||
entity.setUserId(app.getUserId());
|
||||
entity.setSchoolId(app.getSchoolId());
|
||||
entity.setClassId(app.getClassId());
|
||||
entity.setCorpName(app.getCorpName());
|
||||
entity.setCreditCode(app.getCreditCode());
|
||||
entity.setLegalPerson(app.getLegalPerson());
|
||||
entity.setCapital(app.getCapital());
|
||||
entity.setBusinessScope(app.getBusinessScope());
|
||||
entity.setApplyTime(app.getApplyTime());
|
||||
entity.setConcatenatedMessage(app.getConcatenatedMessage());
|
||||
entity.setApplicationId(app.getApplicationId());
|
||||
entity.setApplicationMessage(app.getApplicationMessage());
|
||||
entity.setStatus(app.getStatus() == null ? null : app.getStatus().name());
|
||||
entity.setVerifyId(app.getVerifyId());
|
||||
entity.setReviewer(app.getReviewer());
|
||||
entity.setVerifyTime(app.getVerifyTime());
|
||||
entity.setExtractMessage(app.getExtractMessage());
|
||||
entity.setDigestAlgorithm(app.getDigestAlgorithm());
|
||||
entity.setDigestValue(app.getDigestValue());
|
||||
entity.setWalletId(app.getWalletId());
|
||||
entity.setWalletType(app.getWalletType());
|
||||
entity.setActivateTime(app.getActivateTime());
|
||||
return entity;
|
||||
}
|
||||
|
||||
private CorporateWalletApplication toDomain(CorporateWalletApplicationEntity entity) {
|
||||
CorporateWalletApplication app = new CorporateWalletApplication();
|
||||
app.setId(entity.getId());
|
||||
app.setUserId(entity.getUserId());
|
||||
app.setSchoolId(entity.getSchoolId());
|
||||
app.setClassId(entity.getClassId());
|
||||
app.setCorpName(entity.getCorpName());
|
||||
app.setCreditCode(entity.getCreditCode());
|
||||
app.setLegalPerson(entity.getLegalPerson());
|
||||
app.setCapital(entity.getCapital());
|
||||
app.setBusinessScope(entity.getBusinessScope());
|
||||
app.setApplyTime(entity.getApplyTime());
|
||||
app.setConcatenatedMessage(entity.getConcatenatedMessage());
|
||||
app.setApplicationId(entity.getApplicationId());
|
||||
app.setApplicationMessage(entity.getApplicationMessage());
|
||||
app.setStatus(entity.getStatus() == null ? null : CorporateWalletApplication.Status.valueOf(entity.getStatus()));
|
||||
app.setVerifyId(entity.getVerifyId());
|
||||
app.setReviewer(entity.getReviewer());
|
||||
app.setVerifyTime(entity.getVerifyTime());
|
||||
app.setExtractMessage(entity.getExtractMessage());
|
||||
app.setDigestAlgorithm(entity.getDigestAlgorithm());
|
||||
app.setDigestValue(entity.getDigestValue());
|
||||
app.setWalletId(entity.getWalletId());
|
||||
app.setWalletType(entity.getWalletType());
|
||||
app.setActivateTime(entity.getActivateTime());
|
||||
return app;
|
||||
}
|
||||
}
|
||||
@ -1,121 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.yau.digitalrmb.corporatewallet.domain.RemoteWalletApplication;
|
||||
import com.yau.digitalrmb.corporatewallet.domain.RemoteWalletApplicationRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public class MybatisRemoteWalletApplicationRepository implements RemoteWalletApplicationRepository {
|
||||
@Resource
|
||||
private RemoteWalletApplicationMapper mapper;
|
||||
|
||||
@Override
|
||||
public RemoteWalletApplication save(RemoteWalletApplication application) {
|
||||
RemoteWalletApplicationEntity entity = toEntity(application);
|
||||
mapper.insert(entity);
|
||||
application.setId(entity.getId());
|
||||
return application;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<RemoteWalletApplication> findLatest(String userId, long schoolId, long classId) {
|
||||
RemoteWalletApplicationEntity entity = mapper.selectOne(
|
||||
new LambdaQueryWrapper<RemoteWalletApplicationEntity>()
|
||||
.eq(RemoteWalletApplicationEntity::getUserId, userId)
|
||||
.eq(RemoteWalletApplicationEntity::getSchoolId, schoolId)
|
||||
.eq(RemoteWalletApplicationEntity::getClassId, classId)
|
||||
.eq(RemoteWalletApplicationEntity::getDeleted, false)
|
||||
.orderByDesc(RemoteWalletApplicationEntity::getCreatedAt)
|
||||
.last("LIMIT 1"));
|
||||
return entity == null ? Optional.empty() : Optional.of(toDomain(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<RemoteWalletApplication> findActivatedByCreditCode(String creditCode, String userId, long schoolId, long classId) {
|
||||
RemoteWalletApplicationEntity entity = mapper.selectOne(
|
||||
new LambdaQueryWrapper<RemoteWalletApplicationEntity>()
|
||||
.eq(RemoteWalletApplicationEntity::getCreditCode, creditCode)
|
||||
.eq(RemoteWalletApplicationEntity::getUserId, userId)
|
||||
.eq(RemoteWalletApplicationEntity::getSchoolId, schoolId)
|
||||
.eq(RemoteWalletApplicationEntity::getClassId, classId)
|
||||
.eq(RemoteWalletApplicationEntity::getDeleted, false)
|
||||
.isNotNull(RemoteWalletApplicationEntity::getWalletId)
|
||||
.ne(RemoteWalletApplicationEntity::getWalletId, "")
|
||||
.orderByDesc(RemoteWalletApplicationEntity::getCreatedAt)
|
||||
.last("LIMIT 1"));
|
||||
return entity == null ? Optional.empty() : Optional.of(toDomain(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(RemoteWalletApplication application) {
|
||||
mapper.updateById(toEntity(application));
|
||||
}
|
||||
|
||||
private RemoteWalletApplicationEntity toEntity(RemoteWalletApplication app) {
|
||||
RemoteWalletApplicationEntity entity = new RemoteWalletApplicationEntity();
|
||||
entity.setId(app.getId());
|
||||
entity.setUserId(app.getUserId());
|
||||
entity.setSchoolId(app.getSchoolId());
|
||||
entity.setClassId(app.getClassId());
|
||||
entity.setCorpName(app.getCorpName());
|
||||
entity.setCreditCode(app.getCreditCode());
|
||||
entity.setLegalPerson(app.getLegalPerson());
|
||||
entity.setPhone(app.getPhone());
|
||||
entity.setApplyTime(app.getApplyTime());
|
||||
entity.setConcatenatedMessage(app.getConcatenatedMessage());
|
||||
entity.setApplicationId(app.getApplicationId());
|
||||
entity.setFaceRecognitionStatus(app.getFaceRecognitionStatus());
|
||||
entity.setFaceVerifyTime(app.getFaceVerifyTime());
|
||||
entity.setStatus(app.getStatus() == null ? null : app.getStatus().name());
|
||||
entity.setSigningExtractMessage(app.getSigningExtractMessage());
|
||||
entity.setSigningDigestAlgorithm(app.getSigningDigestAlgorithm());
|
||||
entity.setSigningDigestValue(app.getSigningDigestValue());
|
||||
entity.setSignPrivateKey(app.getSignPrivateKey());
|
||||
entity.setSignature(app.getSignature());
|
||||
entity.setContractId(app.getContractId());
|
||||
entity.setSignTime(app.getSignTime());
|
||||
entity.setWalletExtractMessage(app.getWalletExtractMessage());
|
||||
entity.setWalletDigestAlgorithm(app.getWalletDigestAlgorithm());
|
||||
entity.setWalletDigestValue(app.getWalletDigestValue());
|
||||
entity.setWalletId(app.getWalletId());
|
||||
entity.setWalletType(app.getWalletType());
|
||||
entity.setActivateTime(app.getActivateTime());
|
||||
return entity;
|
||||
}
|
||||
|
||||
private RemoteWalletApplication toDomain(RemoteWalletApplicationEntity entity) {
|
||||
RemoteWalletApplication app = new RemoteWalletApplication();
|
||||
app.setId(entity.getId());
|
||||
app.setUserId(entity.getUserId());
|
||||
app.setSchoolId(entity.getSchoolId());
|
||||
app.setClassId(entity.getClassId());
|
||||
app.setCorpName(entity.getCorpName());
|
||||
app.setCreditCode(entity.getCreditCode());
|
||||
app.setLegalPerson(entity.getLegalPerson());
|
||||
app.setPhone(entity.getPhone());
|
||||
app.setApplyTime(entity.getApplyTime());
|
||||
app.setConcatenatedMessage(entity.getConcatenatedMessage());
|
||||
app.setApplicationId(entity.getApplicationId());
|
||||
app.setFaceRecognitionStatus(entity.getFaceRecognitionStatus());
|
||||
app.setFaceVerifyTime(entity.getFaceVerifyTime());
|
||||
app.setStatus(entity.getStatus() == null ? null : RemoteWalletApplication.Status.valueOf(entity.getStatus()));
|
||||
app.setSigningExtractMessage(entity.getSigningExtractMessage());
|
||||
app.setSigningDigestAlgorithm(entity.getSigningDigestAlgorithm());
|
||||
app.setSigningDigestValue(entity.getSigningDigestValue());
|
||||
app.setSignPrivateKey(entity.getSignPrivateKey());
|
||||
app.setSignature(entity.getSignature());
|
||||
app.setContractId(entity.getContractId());
|
||||
app.setSignTime(entity.getSignTime());
|
||||
app.setWalletExtractMessage(entity.getWalletExtractMessage());
|
||||
app.setWalletDigestAlgorithm(entity.getWalletDigestAlgorithm());
|
||||
app.setWalletDigestValue(entity.getWalletDigestValue());
|
||||
app.setWalletId(entity.getWalletId());
|
||||
app.setWalletType(entity.getWalletType());
|
||||
app.setActivateTime(entity.getActivateTime());
|
||||
return app;
|
||||
}
|
||||
}
|
||||
@ -1,115 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.yau.digitalrmb.corporatewallet.domain.SalaryBatch;
|
||||
import com.yau.digitalrmb.corporatewallet.domain.SalaryBatchRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public class MybatisSalaryBatchRepository implements SalaryBatchRepository {
|
||||
@Resource
|
||||
private SalaryBatchMapper mapper;
|
||||
|
||||
@Override
|
||||
public SalaryBatch save(SalaryBatch batch) {
|
||||
SalaryBatchEntity entity = toEntity(batch);
|
||||
mapper.insert(entity);
|
||||
batch.setId(entity.getId());
|
||||
return batch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SalaryBatch> findLatest(String userId, long schoolId, long classId) {
|
||||
SalaryBatchEntity entity = mapper.selectOne(
|
||||
new LambdaQueryWrapper<SalaryBatchEntity>()
|
||||
.eq(SalaryBatchEntity::getUserId, userId)
|
||||
.eq(SalaryBatchEntity::getSchoolId, schoolId)
|
||||
.eq(SalaryBatchEntity::getClassId, classId)
|
||||
.eq(SalaryBatchEntity::getDeleted, false)
|
||||
.orderByDesc(SalaryBatchEntity::getCreatedAt)
|
||||
.last("LIMIT 1"));
|
||||
return entity == null ? Optional.empty() : Optional.of(toDomain(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(SalaryBatch batch) {
|
||||
mapper.updateById(toEntity(batch));
|
||||
}
|
||||
|
||||
private SalaryBatchEntity toEntity(SalaryBatch batch) {
|
||||
SalaryBatchEntity entity = new SalaryBatchEntity();
|
||||
entity.setId(batch.getId());
|
||||
entity.setUserId(batch.getUserId());
|
||||
entity.setSchoolId(batch.getSchoolId());
|
||||
entity.setClassId(batch.getClassId());
|
||||
entity.setBatchId(batch.getBatchId());
|
||||
entity.setCorpWalletId(batch.getCorpWalletId());
|
||||
entity.setOperatorName(batch.getOperatorName());
|
||||
entity.setOperatorTimestamp(batch.getOperatorTimestamp());
|
||||
entity.setConcatenatedMessage(batch.getConcatenatedMessage());
|
||||
entity.setDigestAlgorithm(batch.getDigestAlgorithm());
|
||||
entity.setDigestValue(batch.getDigestValue());
|
||||
entity.setSignature(batch.getSignature());
|
||||
entity.setOutputJson(batch.getOutputJson());
|
||||
entity.setStatus(batch.getStatus() == null ? null : batch.getStatus().name());
|
||||
entity.setSubmitTime(batch.getSubmitTime());
|
||||
entity.setReviewerName(batch.getReviewerName());
|
||||
entity.setReviewTimestamp(batch.getReviewTimestamp());
|
||||
entity.setReviewConcatenatedMessage(batch.getReviewConcatenatedMessage());
|
||||
entity.setReviewDigestAlgorithm(batch.getReviewDigestAlgorithm());
|
||||
entity.setReviewDigestValue(batch.getReviewDigestValue());
|
||||
entity.setReviewSignature(batch.getReviewSignature());
|
||||
entity.setReviewOutputJson(batch.getReviewOutputJson());
|
||||
entity.setSingleLimitStatus(batch.getSingleLimitStatus());
|
||||
entity.setBatchLimitStatus(batch.getBatchLimitStatus());
|
||||
entity.setDailyLimitStatus(batch.getDailyLimitStatus());
|
||||
entity.setReviewResult(batch.getReviewResult());
|
||||
entity.setConfirmMessage(batch.getConfirmMessage());
|
||||
entity.setConfirmTimestamp(batch.getConfirmTimestamp());
|
||||
entity.setConfirmDigestAlgorithm(batch.getConfirmDigestAlgorithm());
|
||||
entity.setConfirmDigestValue(batch.getConfirmDigestValue());
|
||||
entity.setCbSignature(batch.getCbSignature());
|
||||
entity.setConfirmOutputJson(batch.getConfirmOutputJson());
|
||||
return entity;
|
||||
}
|
||||
|
||||
private SalaryBatch toDomain(SalaryBatchEntity entity) {
|
||||
SalaryBatch batch = new SalaryBatch();
|
||||
batch.setId(entity.getId());
|
||||
batch.setUserId(entity.getUserId());
|
||||
batch.setSchoolId(entity.getSchoolId());
|
||||
batch.setClassId(entity.getClassId());
|
||||
batch.setBatchId(entity.getBatchId());
|
||||
batch.setCorpWalletId(entity.getCorpWalletId());
|
||||
batch.setOperatorName(entity.getOperatorName());
|
||||
batch.setOperatorTimestamp(entity.getOperatorTimestamp());
|
||||
batch.setConcatenatedMessage(entity.getConcatenatedMessage());
|
||||
batch.setDigestAlgorithm(entity.getDigestAlgorithm());
|
||||
batch.setDigestValue(entity.getDigestValue());
|
||||
batch.setSignature(entity.getSignature());
|
||||
batch.setOutputJson(entity.getOutputJson());
|
||||
batch.setStatus(entity.getStatus() == null ? null : SalaryBatch.Status.valueOf(entity.getStatus()));
|
||||
batch.setSubmitTime(entity.getSubmitTime());
|
||||
batch.setReviewerName(entity.getReviewerName());
|
||||
batch.setReviewTimestamp(entity.getReviewTimestamp());
|
||||
batch.setReviewConcatenatedMessage(entity.getReviewConcatenatedMessage());
|
||||
batch.setReviewDigestAlgorithm(entity.getReviewDigestAlgorithm());
|
||||
batch.setReviewDigestValue(entity.getReviewDigestValue());
|
||||
batch.setReviewSignature(entity.getReviewSignature());
|
||||
batch.setReviewOutputJson(entity.getReviewOutputJson());
|
||||
batch.setSingleLimitStatus(entity.getSingleLimitStatus());
|
||||
batch.setBatchLimitStatus(entity.getBatchLimitStatus());
|
||||
batch.setDailyLimitStatus(entity.getDailyLimitStatus());
|
||||
batch.setReviewResult(entity.getReviewResult());
|
||||
batch.setConfirmMessage(entity.getConfirmMessage());
|
||||
batch.setConfirmTimestamp(entity.getConfirmTimestamp());
|
||||
batch.setConfirmDigestAlgorithm(entity.getConfirmDigestAlgorithm());
|
||||
batch.setConfirmDigestValue(entity.getConfirmDigestValue());
|
||||
batch.setCbSignature(entity.getCbSignature());
|
||||
batch.setConfirmOutputJson(entity.getConfirmOutputJson());
|
||||
return batch;
|
||||
}
|
||||
}
|
||||
@ -1,68 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.yau.digitalrmb.shared.infrastructure.persistence.AuditableEntity;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("remote_wallet_application")
|
||||
public class RemoteWalletApplicationEntity extends AuditableEntity {
|
||||
@TableField("user_id")
|
||||
private String userId;
|
||||
@TableField("school_id")
|
||||
private Long schoolId;
|
||||
@TableField("class_id")
|
||||
private Long classId;
|
||||
|
||||
@TableField("corp_name")
|
||||
private String corpName;
|
||||
@TableField("credit_code")
|
||||
private String creditCode;
|
||||
@TableField("legal_person")
|
||||
private String legalPerson;
|
||||
private String phone;
|
||||
@TableField("apply_time")
|
||||
private String applyTime;
|
||||
|
||||
@TableField("concatenated_message")
|
||||
private String concatenatedMessage;
|
||||
@TableField("application_id")
|
||||
private String applicationId;
|
||||
|
||||
@TableField("face_recognition_status")
|
||||
private Integer faceRecognitionStatus;
|
||||
@TableField("face_verify_time")
|
||||
private String faceVerifyTime;
|
||||
|
||||
private String status;
|
||||
|
||||
@TableField("signing_extract_message")
|
||||
private String signingExtractMessage;
|
||||
@TableField("signing_digest_algorithm")
|
||||
private String signingDigestAlgorithm;
|
||||
@TableField("signing_digest_value")
|
||||
private String signingDigestValue;
|
||||
@TableField("sign_private_key")
|
||||
private String signPrivateKey;
|
||||
private String signature;
|
||||
@TableField("contract_id")
|
||||
private String contractId;
|
||||
@TableField("sign_time")
|
||||
private String signTime;
|
||||
|
||||
@TableField("wallet_extract_message")
|
||||
private String walletExtractMessage;
|
||||
@TableField("wallet_digest_algorithm")
|
||||
private String walletDigestAlgorithm;
|
||||
@TableField("wallet_digest_value")
|
||||
private String walletDigestValue;
|
||||
@TableField("wallet_id")
|
||||
private String walletId;
|
||||
@TableField("wallet_type")
|
||||
private String walletType;
|
||||
@TableField("activate_time")
|
||||
private String activateTime;
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface RemoteWalletApplicationMapper extends BaseMapper<RemoteWalletApplicationEntity> {
|
||||
}
|
||||
@ -1,79 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.yau.digitalrmb.shared.infrastructure.persistence.AuditableEntity;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("salary_batch")
|
||||
public class SalaryBatchEntity extends AuditableEntity {
|
||||
@TableField("user_id")
|
||||
private String userId;
|
||||
@TableField("school_id")
|
||||
private Long schoolId;
|
||||
@TableField("class_id")
|
||||
private Long classId;
|
||||
@TableField("batch_id")
|
||||
private String batchId;
|
||||
@TableField("corp_wallet_id")
|
||||
private String corpWalletId;
|
||||
@TableField("operator_name")
|
||||
private String operatorName;
|
||||
@TableField("operator_timestamp")
|
||||
private String operatorTimestamp;
|
||||
@TableField("concatenated_message")
|
||||
private String concatenatedMessage;
|
||||
@TableField("digest_algorithm")
|
||||
private String digestAlgorithm;
|
||||
@TableField("digest_value")
|
||||
private String digestValue;
|
||||
@TableField("signature")
|
||||
private String signature;
|
||||
@TableField("output_json")
|
||||
private String outputJson;
|
||||
@TableField("status")
|
||||
private String status;
|
||||
@TableField("submit_time")
|
||||
private String submitTime;
|
||||
|
||||
// 复核员审核相关
|
||||
@TableField("reviewer_name")
|
||||
private String reviewerName;
|
||||
@TableField("review_timestamp")
|
||||
private String reviewTimestamp;
|
||||
@TableField("review_concatenated_message")
|
||||
private String reviewConcatenatedMessage;
|
||||
@TableField("review_digest_algorithm")
|
||||
private String reviewDigestAlgorithm;
|
||||
@TableField("review_digest_value")
|
||||
private String reviewDigestValue;
|
||||
@TableField("review_signature")
|
||||
private String reviewSignature;
|
||||
@TableField("review_output_json")
|
||||
private String reviewOutputJson;
|
||||
@TableField("single_limit_status")
|
||||
private Integer singleLimitStatus;
|
||||
@TableField("batch_limit_status")
|
||||
private Integer batchLimitStatus;
|
||||
@TableField("daily_limit_status")
|
||||
private Integer dailyLimitStatus;
|
||||
@TableField("review_result")
|
||||
private String reviewResult;
|
||||
|
||||
// 交易确认相关
|
||||
@TableField("confirm_message")
|
||||
private String confirmMessage;
|
||||
@TableField("confirm_timestamp")
|
||||
private String confirmTimestamp;
|
||||
@TableField("confirm_digest_algorithm")
|
||||
private String confirmDigestAlgorithm;
|
||||
@TableField("confirm_digest_value")
|
||||
private String confirmDigestValue;
|
||||
@TableField("cb_signature")
|
||||
private String cbSignature;
|
||||
@TableField("confirm_output_json")
|
||||
private String confirmOutputJson;
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SalaryBatchMapper extends BaseMapper<SalaryBatchEntity> {
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.interfaces.rest.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Data
|
||||
@Schema(description = "交易确认央行签名请求")
|
||||
public class SalaryConfirmSignRequest {
|
||||
@NotBlank(message = "央行第一私钥不能为空")
|
||||
@Schema(description = "央行第一私钥(十六进制)", required = true)
|
||||
private String privateKey;
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.interfaces.rest.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Data
|
||||
@Schema(description = "复核员SM2签名请求")
|
||||
public class SalaryReviewSignRequest {
|
||||
@NotBlank(message = "数币复核员私钥不能为空")
|
||||
@Schema(description = "数币复核员私钥(十六进制)", required = true)
|
||||
private String privateKey;
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
package com.yau.digitalrmb.corporatewallet.interfaces.rest.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Data
|
||||
@Schema(description = "SM2签名请求")
|
||||
public class SalarySignRequest {
|
||||
@NotBlank(message = "数币操作员私钥不能为空")
|
||||
@Schema(description = "数币操作员私钥(十六进制)", required = true)
|
||||
private String privateKey;
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.yau.digitalrmb.institutionidentity.interfaces.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class CurrencyRuleRequest {
|
||||
@NotBlank(message = "币串前缀不能为空")
|
||||
private String prefix;
|
||||
|
||||
@NotBlank(message = "币串ID规则不能为空")
|
||||
private String idRule;
|
||||
|
||||
@NotBlank(message = "币串初始状态不能为空")
|
||||
private String currencyStatus;
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package com.yau.digitalrmb.institutionidentity.interfaces.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Positive;
|
||||
|
||||
@ApiModel(description = "货币生成的步骤三货币生成请求验证分步操作参数")
|
||||
@Schema(description = "货币生成的步骤三货币生成请求验证分步操作参数")
|
||||
public class CurrencyVerificationStepRequest {
|
||||
@ApiModelProperty(value = "货币生成的步骤三验证记录编号", required = true, example = "1900000000000000003")
|
||||
@Schema(description = "货币生成的步骤三验证记录编号", required = true, example = "1900000000000000003")
|
||||
@NotNull(message = "步骤三验证编号不能为空")
|
||||
@Positive(message = "步骤三验证编号必须大于0")
|
||||
private Long verificationId;
|
||||
@ApiModelProperty(value = "验签步骤使用的商业银行第二SM2公钥完整值")
|
||||
@Schema(description = "验签步骤使用的商业银行第二SM2公钥完整值")
|
||||
private String publicKey;
|
||||
@ApiModelProperty(value = "确认步骤使用的中央银行第一SM2私钥完整值")
|
||||
@Schema(description = "确认步骤使用的中央银行第一SM2私钥完整值")
|
||||
private String privateKey;
|
||||
|
||||
public Long getVerificationId() { return verificationId; }
|
||||
public void setVerificationId(Long verificationId) { this.verificationId = verificationId; }
|
||||
public String getPublicKey() { return publicKey; }
|
||||
public void setPublicKey(String publicKey) { this.publicKey = publicKey; }
|
||||
public String getPrivateKey() { return privateKey; }
|
||||
public void setPrivateKey(String privateKey) { this.privateKey = privateKey; }
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
package com.yau.digitalrmb.institutionidentity.interfaces.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Schema(description = "第二公钥SM2验签参数")
|
||||
public class VerifySignatureRequest {
|
||||
@NotBlank(message = "商业银行第二公钥不能为空")
|
||||
@Schema(description = "货币生成的步骤一生成并备案的商业银行第二SM2公钥", required = true)
|
||||
private String publicKey;
|
||||
|
||||
public String getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public void setPublicKey(String publicKey) {
|
||||
this.publicKey = publicKey;
|
||||
}
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
package com.yau.digitalrmb.issuance.application.query;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class DigitalCurrencyProductionDigestView {
|
||||
private final DigitalCurrencyProductionBatchView batch;
|
||||
private final List<CoinDigestView> digests;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public static class CoinDigestView {
|
||||
private final String coinId;
|
||||
private final BigDecimal denomination;
|
||||
private final String digest;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue