feat(redeem): streamline phone redemption confirmation
CI / verify (pull_request) Has been cancelled

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-21 11:41:06 +08:00
parent 36bec94639
commit eb96b36d0b
6 changed files with 181 additions and 211 deletions
@@ -311,6 +311,62 @@ export class RedeemService {
return session;
}
async preparePhoneRedeemDirect(
storeAccountId: bigint,
storeId: bigint,
phone: string,
amount: number,
) {
const account = await this.loadOpenStoreAccount(storeAccountId, storeId);
const normalizedPhone = this.normalizeMobilePhone(phone);
const user = await this.resolveUserByPhone(normalizedPhone);
const { allocations, totalBalance } = await this.computeDirectAllocations(user.id, amount);
const sessionId = randomBytes(16).toString('hex');
await this.authService.sendSms(normalizedPhone, SmsScene.REDEEM_PHONE_CONFIRM, {
clientApp: ClientApp.SHOP_H5,
});
await this.redis.setJson(
this.phoneSessionKey(sessionId),
{
userId: user.id.toString(),
phone: normalizedPhone,
storeAccountId: storeAccountId.toString(),
storeId: account.storeId.toString(),
amount,
allocations,
confirmPrepared: true,
} satisfies PhoneRedeemSession,
REDEEM_PHONE_SESSION_TTL_SECONDS,
);
this.analyticsService.trackStoreOneSafe(storeAccountId, ClientApp.SHOP_H5, {
storeId: account.storeId,
eventName: 'store_redeem_phone_prepare',
extraJson: {
sessionId,
amount,
phone: this.maskPhoneForStore(normalizedPhone),
flow: 'direct',
},
});
return serializeBigInt({
sessionId,
amount,
totalBalance,
maskedPhone: this.maskPhoneForStore(normalizedPhone),
expireInSeconds: REDEEM_PHONE_SESSION_TTL_SECONDS,
user: {
id: user.id,
userNo: user.userNo,
nickname: user.nickname,
phone: this.maskPhoneForStore(normalizedPhone),
},
});
}
async preparePhoneRedeem(storeAccountId: bigint, storeId: bigint, sessionId: string, amount: number) {
const account = await this.loadOpenStoreAccount(storeAccountId, storeId);
const session = await this.loadPhoneSession(sessionId, storeAccountId);