@@ -9,6 +9,7 @@ import {
|
||||
generateRedeemNo,
|
||||
generateRedeemPendingNo,
|
||||
REDEEM_WEAKNET_FAIL_THRESHOLD,
|
||||
resolveSettlementRate,
|
||||
validateRedeemAmount,
|
||||
allocateBenefitCoupons,
|
||||
} from '@dukang/domain';
|
||||
@@ -176,8 +177,15 @@ export class RedeemService {
|
||||
normalizedAllocations: Array<{ couponId: string; amount: number }>,
|
||||
analyticsExtra?: { channel: 'token' | 'phone'; sessionId?: string; tokenSuffix?: string },
|
||||
) {
|
||||
const settlementRate = Number(account.store.settlementRate);
|
||||
const settleAmount = calcRedeemSettleAmount(amount, settlementRate);
|
||||
const amountNum = Number(amount);
|
||||
if (!Number.isFinite(amountNum) || amountNum <= 0) {
|
||||
throw new BadRequestException('核销金额必须大于 0');
|
||||
}
|
||||
const settlementRate = resolveSettlementRate(account.store.settlementRate);
|
||||
const settleAmount = calcRedeemSettleAmount(amountNum, settlementRate);
|
||||
if (!Number.isFinite(settleAmount) || settleAmount < 0) {
|
||||
throw new BadRequestException('结算金额计算异常');
|
||||
}
|
||||
const redeemChannel = analyticsExtra?.channel === 'phone' ? 'PHONE' : 'SCAN';
|
||||
|
||||
const [userRow, storeRow] = await Promise.all([
|
||||
@@ -200,7 +208,7 @@ export class RedeemService {
|
||||
userId,
|
||||
couponId: BigInt(normalizedAllocations[0].couponId),
|
||||
storeId: account.storeId,
|
||||
amount,
|
||||
amount: amountNum,
|
||||
settleAmount,
|
||||
channel: redeemChannel,
|
||||
isTest,
|
||||
@@ -214,16 +222,14 @@ export class RedeemService {
|
||||
},
|
||||
});
|
||||
|
||||
if (!isTest) {
|
||||
await this.settlementService.createStorePayout(
|
||||
redeemRecord.id,
|
||||
account.storeId,
|
||||
amount,
|
||||
settleAmount,
|
||||
settlementRate,
|
||||
tx,
|
||||
);
|
||||
}
|
||||
await this.settlementService.createStorePayout(
|
||||
redeemRecord.id,
|
||||
account.storeId,
|
||||
amountNum,
|
||||
settleAmount,
|
||||
settlementRate,
|
||||
tx,
|
||||
);
|
||||
|
||||
return redeemRecord;
|
||||
});
|
||||
@@ -240,7 +246,7 @@ export class RedeemService {
|
||||
const redeemExtra = {
|
||||
redeemRecordId: record.id.toString(),
|
||||
storeId: account.storeId.toString(),
|
||||
amount,
|
||||
amount: amountNum,
|
||||
channel: analyticsExtra?.channel ?? 'token',
|
||||
...(analyticsExtra?.sessionId ? { sessionId: analyticsExtra.sessionId } : {}),
|
||||
...(analyticsExtra?.tokenSuffix ? { tokenSuffix: analyticsExtra.tokenSuffix } : {}),
|
||||
@@ -252,7 +258,7 @@ export class RedeemService {
|
||||
refId: record.id,
|
||||
extraJson: {
|
||||
redeemNo: record.redeemNo,
|
||||
amount,
|
||||
amount: amountNum,
|
||||
userId: userId.toString(),
|
||||
channel: analyticsExtra?.channel ?? 'token',
|
||||
},
|
||||
@@ -270,7 +276,11 @@ export class RedeemService {
|
||||
extraJson: redeemExtra,
|
||||
});
|
||||
|
||||
return record;
|
||||
return {
|
||||
...record,
|
||||
amount: amountNum,
|
||||
settleAmount,
|
||||
};
|
||||
}
|
||||
|
||||
async sendPhoneLookupSms(storeAccountId: bigint, storeId: bigint, phone: string) {
|
||||
@@ -484,6 +494,12 @@ export class RedeemService {
|
||||
}
|
||||
|
||||
async createToken(userId: bigint, body: { couponId?: string; amount: number; storeId?: string }) {
|
||||
const amount = Number(body.amount);
|
||||
if (!Number.isFinite(amount) || amount <= 0) {
|
||||
throw new BadRequestException('核销金额必须大于 0');
|
||||
}
|
||||
body = { ...body, amount };
|
||||
|
||||
let allocations: Array<{ couponId: string; amount: number }>;
|
||||
|
||||
if (body.couponId) {
|
||||
@@ -993,6 +1009,9 @@ export class RedeemService {
|
||||
await this.validateAllocations(normalizedAllocations);
|
||||
|
||||
const amount = Number(pending.amount);
|
||||
if (!Number.isFinite(amount) || amount <= 0) {
|
||||
throw new BadRequestException('待处理单核销金额无效');
|
||||
}
|
||||
const record = await this.executeRedeem(
|
||||
account,
|
||||
pending.userId,
|
||||
@@ -1101,7 +1120,26 @@ export class RedeemService {
|
||||
}),
|
||||
this.prisma.redeemRecord.count({ where: { storeId } }),
|
||||
]);
|
||||
return { list: serializeBigInt(list), total, page, pageSize };
|
||||
return {
|
||||
list: serializeBigInt(
|
||||
list.map((r) => ({
|
||||
...r,
|
||||
amount: Number(r.amount),
|
||||
settleAmount: Number(r.settleAmount),
|
||||
payout: r.payout
|
||||
? {
|
||||
...r.payout,
|
||||
redeemAmount: Number(r.payout.redeemAmount),
|
||||
payoutAmount: Number(r.payout.payoutAmount),
|
||||
settlementRate: Number(r.payout.settlementRate),
|
||||
}
|
||||
: r.payout,
|
||||
})),
|
||||
),
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
};
|
||||
}
|
||||
|
||||
async getShopRedeemStats(
|
||||
@@ -1174,7 +1212,11 @@ export class RedeemService {
|
||||
todayAmount,
|
||||
todayScanCount,
|
||||
todayPhoneCount,
|
||||
recentRecords: recent,
|
||||
recentRecords: recent.map((r) => ({
|
||||
...r,
|
||||
amount: Number(r.amount),
|
||||
settleAmount: Number(r.settleAmount),
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user