feat(store): v4.0.18 门店多收款账户与子账号继承二维码

C 端门店列表拼接省市区县地址;门店多银行账户与默认打款账户;子账号独立 sa_ 关联码及统计维度;同步 v4.0.18 开发文档。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-07 15:56:16 +08:00
parent a9c466930d
commit 4bdb09068c
26 changed files with 1193 additions and 102 deletions
@@ -47,7 +47,7 @@ import { AnalyticsService } from '../analytics/analytics.service';
import { PartnerCityService } from '../city-scope/partner-city.service';
import { FulfillmentProviderService } from '../fulfillment/fulfillment-provider.service';
import {
loadStorePrimaryBank,
loadStoreDefaultBank,
loadStorePrimaryBanksMap,
loadWineryBankConfig,
formatWecomBankAccount,
@@ -540,16 +540,14 @@ export class SettlementService implements OnModuleInit {
async getShopWithdrawSummary(storeAccountId: bigint, storeId: bigint) {
await this.assertShopStoreAccess(storeAccountId, storeId);
const [account, available, pending, todayApplied] = await Promise.all([
const [account, bank, available, pending, todayApplied] = await Promise.all([
this.prisma.storeAccount.findUniqueOrThrow({
where: { id: storeAccountId },
select: {
isPrimary: true,
bankAccountName: true,
bankAccountNo: true,
bankBranch: true,
},
}),
loadStoreDefaultBank(this.prisma, storeId),
this.listAvailableUnbilledPayouts(storeId),
this.prisma.storeWithdrawRequest.findFirst({
where: { storeId, status: 'PENDING_REVIEW' },
@@ -562,10 +560,7 @@ export class SettlementService implements OnModuleInit {
available.map((p) => ({ payoutAmount: Number(p.payoutAmount) })),
);
const dailyLimit = getStoreWithdrawDailyLimit();
const hasBankAccount = !!(
account.bankAccountName?.trim() &&
account.bankAccountNo?.trim()
);
const hasBankAccount = !!(bank?.bankAccountName?.trim() && bank?.bankAccountNo?.trim());
return {
availableAmount,
@@ -575,11 +570,13 @@ export class SettlementService implements OnModuleInit {
remainingDailyLimit: Math.max(0, round2(dailyLimit - todayApplied)),
isPrimary: account.isPrimary === 1,
hasBankAccount,
bankAccount: {
bankAccountName: account.bankAccountName,
bankAccountNo: account.bankAccountNo,
bankBranch: account.bankBranch,
},
bankAccount: bank
? {
bankAccountName: bank.bankAccountName,
bankAccountNo: bank.bankAccountNo,
bankBranch: bank.bankBranch,
}
: null,
};
}
@@ -590,7 +587,7 @@ export class SettlementService implements OnModuleInit {
) {
await this.assertShopStoreAccess(storeAccountId, storeId);
const [store, account, available, pending, todayApplied] = await Promise.all([
const [store, account, bank, available, pending, todayApplied] = await Promise.all([
this.prisma.store.findUniqueOrThrow({
where: { id: storeId },
select: { id: true, name: true, phone: true, cityName: true },
@@ -599,10 +596,9 @@ export class SettlementService implements OnModuleInit {
where: { id: storeAccountId },
select: {
isPrimary: true,
bankAccountName: true,
bankAccountNo: true,
},
}),
loadStoreDefaultBank(this.prisma, storeId),
this.listAvailableUnbilledPayouts(storeId),
this.prisma.storeWithdrawRequest.findFirst({
where: { storeId, status: 'PENDING_REVIEW' },
@@ -619,10 +615,7 @@ export class SettlementService implements OnModuleInit {
available.map((p) => ({ payoutAmount: Number(p.payoutAmount) })),
);
const dailyLimit = getStoreWithdrawDailyLimit();
const hasBankAccount = !!(
account.bankAccountName?.trim() &&
account.bankAccountNo?.trim()
);
const hasBankAccount = !!(bank?.bankAccountName?.trim() && bank?.bankAccountNo?.trim());
const requestAmount =
dto?.amount != null && Number.isFinite(Number(dto.amount))
? round2(Number(dto.amount))
@@ -827,8 +820,10 @@ export class SettlementService implements OnModuleInit {
},
});
if (!row) throw new NotFoundException('提现申请不存在');
const bankAccount = await loadStoreDefaultBank(this.prisma, row.storeId);
return serializeBigInt({
...row,
bankAccount,
paymentProofUrls: parsePaymentProofUrls(row.paymentProofUrls),
overdue:
row.status === 'PENDING_REVIEW' ? isWithdrawOverdue(row.appliedAt) : false,
@@ -900,7 +895,7 @@ export class SettlementService implements OnModuleInit {
},
},
}),
loadStorePrimaryBank(this.prisma, row.storeId),
loadStoreDefaultBank(this.prisma, row.storeId),
]);
const meta = storeWecomMeta(store, String(row.storeId));
const bankParts = wecomBankParts(bank);
@@ -1543,7 +1538,7 @@ export class SettlementService implements OnModuleInit {
},
});
if (!bill) throw new NotFoundException('门店对账单不存在');
const storeAccount = await loadStorePrimaryBank(this.prisma, bill.storeId);
const storeAccount = await loadStoreDefaultBank(this.prisma, bill.storeId);
return serializeBigInt({
...bill,
...mapStoreBillDates(bill.billDate),