feat(assoc): v4.0.1 合伙人关联码、分佣账单与 H5 用户管理

订单佣金只认关联用户;合伙人备注写入独立表;H5 增加用户管理与首页统计。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-30 14:35:39 +08:00
parent 3b669f7e38
commit 9c8d5f2cad
125 changed files with 6355 additions and 1436 deletions
@@ -436,10 +436,7 @@ export class TradeService {
const { externalNo } = payResult;
const now = new Date();
const paySnapshot = await this.partnerCityService.resolveForOrder(
order.cityId,
order.receiverDistrict,
);
const paySnapshot = await this.partnerCityService.snapshotForUser(order.userId);
// 现场提货:支付即完成(PRD SC-02 / REQ-U-008
const toStatus =
order.deliveryType === 'ON_SITE_PICKUP' ? 'COMPLETED' : 'PENDING_SHIP';
@@ -452,8 +449,8 @@ export class TradeService {
payStatus: 'PAID',
paidAt: now,
payExternalNo: externalNo,
partnerAccountIdAtPay: paySnapshot?.partnerAccountId ?? null,
orderCommissionRateAtPay: paySnapshot?.orderCommissionRate ?? null,
partnerAccountIdAtPay: paySnapshot.partnerAccountId,
orderCommissionRateAtPay: paySnapshot.orderCommissionRate,
},
});
await tx.logThirdParty.create({
@@ -618,10 +615,14 @@ export class TradeService {
}
const now = new Date();
const paySnapshot = await this.partnerCityService.resolveForOrder(
order.cityId,
order.receiverDistrict,
);
const paySnapshot =
order.orderType === 'PROXY'
? {
partnerAccountId: order.partnerAccountIdAtPay,
orderCommissionRate:
order.orderCommissionRateAtPay != null ? Number(order.orderCommissionRateAtPay) : null,
}
: await this.partnerCityService.snapshotForUser(order.userId);
// 现场提货:支付即完成(PRD SC-02 / REQ-U-008
const toStatus =
order.deliveryType === 'ON_SITE_PICKUP' ? 'COMPLETED' : 'PENDING_SHIP';
@@ -636,8 +637,8 @@ export class TradeService {
payStatus: 'PAID',
paidAt: now,
payExternalNo: params.transactionId,
partnerAccountIdAtPay: paySnapshot?.partnerAccountId ?? null,
orderCommissionRateAtPay: paySnapshot?.orderCommissionRate ?? null,
partnerAccountIdAtPay: paySnapshot.partnerAccountId,
orderCommissionRateAtPay: paySnapshot.orderCommissionRate,
},
});
await tx.logThirdParty.create({
@@ -1655,6 +1656,14 @@ export class TradeService {
cityName: s.cityName,
district: s.district,
})),
partners: [
{
id: primary.id.toString(),
companyName: primary.companyName,
name: primary.name,
phone: primary.phone,
},
],
});
}
@@ -1789,6 +1798,7 @@ export class TradeService {
quantity: number;
promoCodeId?: string;
skuId?: string;
assocPartnerAccountId?: string;
},
req: Request,
) {
@@ -1840,7 +1850,6 @@ export class TradeService {
let receiverCity = body.city?.trim() || '';
let receiverDistrict = body.district?.trim() || '';
let receiverAddress = '';
let commissionDistrict = receiverDistrict;
if (body.deliveryMode === 'ON_SITE_PICKUP') {
receiverName = body.receiverName?.trim() || `用户${normalizedPhone.slice(-4)}`;
@@ -1848,7 +1857,6 @@ export class TradeService {
receiverCity = '现场';
receiverDistrict = '取货';
receiverAddress = '现场提货';
commissionDistrict = '';
} else {
if (!receiverProvince || !receiverCity || !receiverDistrict) {
throw new BadRequestException('请选择省市区');
@@ -1859,7 +1867,15 @@ export class TradeService {
receiverAddress = `${receiverProvince}${receiverCity}${receiverDistrict}${body.addressDetail.trim()}`;
}
const paySnapshot = await this.partnerCityService.resolveForOrder(city.id, commissionDistrict);
if (body.assocPartnerAccountId) {
const chosen = await this.partnerCityService.resolvePrimaryAccount(BigInt(body.assocPartnerAccountId));
if (chosen.id !== primary.id) {
throw new BadRequestException('只能关联本合伙人');
}
}
const paySnapshot = body.assocPartnerAccountId
? await this.partnerCityService.applyProxyAssoc(user.id, BigInt(body.assocPartnerAccountId))
: { partnerAccountId: null as bigint | null, orderCommissionRate: null as number | null };
const orderNo = generateOrderNo();
const payExpireAt = new Date(Date.now() + 30 * 60 * 1000);
@@ -1916,8 +1932,8 @@ export class TradeService {
ipCity: location.ipCity,
ipDistrict: location.ipDistrict,
payExpireAt,
partnerAccountIdAtPay: paySnapshot?.partnerAccountId ?? primary.id,
orderCommissionRateAtPay: paySnapshot?.orderCommissionRate ?? null,
partnerAccountIdAtPay: paySnapshot.partnerAccountId,
orderCommissionRateAtPay: paySnapshot.orderCommissionRate,
proxyPartnerAccountId: primary.id,
proxyPartnerName: primary.name,
proxyPartnerPhone: partnerPhone,
@@ -2136,9 +2152,14 @@ export class TradeService {
/** HQ 代下单:商品/推广码选项(运营侧可看白名单测试酒) */
async getHqProxyOrderOptions() {
const [products, promoCodes] = await Promise.all([
const [products, promoCodes, partners] = await Promise.all([
this.catalogService.listProducts(undefined, undefined, { bypassWhitelist: true }),
this.promoCodeService.listActiveOptions(),
this.prisma.partnerAccount.findMany({
where: { isPrimary: 1, status: 'ACTIVE' },
select: { id: true, companyName: true, name: true, phone: true },
orderBy: { createdAt: 'desc' },
}),
]);
const details = await Promise.all(
products.map((p) =>
@@ -2165,6 +2186,12 @@ export class TradeService {
})),
promoCodes,
stores: [],
partners: partners.map((p) => ({
id: p.id.toString(),
companyName: p.companyName,
name: p.name,
phone: p.phone,
})),
});
}
@@ -2183,6 +2210,7 @@ export class TradeService {
quantity: number;
promoCodeId?: string;
skuId?: string;
assocPartnerAccountId?: string;
},
req: Request,
) {
@@ -2237,7 +2265,6 @@ export class TradeService {
let receiverCity = body.city?.trim() || '';
let receiverDistrict = body.district?.trim() || '';
let receiverAddress = '';
let commissionDistrict = receiverDistrict;
if (body.deliveryMode === 'ON_SITE_PICKUP') {
receiverName = body.receiverName?.trim() || `用户${normalizedPhone.slice(-4)}`;
@@ -2245,7 +2272,6 @@ export class TradeService {
receiverCity = '现场';
receiverDistrict = '取货';
receiverAddress = '现场提货';
commissionDistrict = '';
} else {
if (!receiverProvince || !receiverCity || !receiverDistrict) {
throw new BadRequestException('请选择省市区');
@@ -2256,7 +2282,9 @@ export class TradeService {
receiverAddress = `${receiverProvince}${receiverCity}${receiverDistrict}${body.addressDetail.trim()}`;
}
const paySnapshot = await this.partnerCityService.resolveForOrder(city.id, commissionDistrict);
const paySnapshot = body.assocPartnerAccountId
? await this.partnerCityService.applyProxyAssoc(user.id, BigInt(body.assocPartnerAccountId))
: { partnerAccountId: null as bigint | null, orderCommissionRate: null as number | null };
const orderNo = generateOrderNo();
const payExpireAt = new Date(Date.now() + 30 * 60 * 1000);
@@ -2313,8 +2341,8 @@ export class TradeService {
ipCity: location.ipCity,
ipDistrict: location.ipDistrict,
payExpireAt,
partnerAccountIdAtPay: paySnapshot?.partnerAccountId ?? null,
orderCommissionRateAtPay: paySnapshot?.orderCommissionRate ?? null,
partnerAccountIdAtPay: paySnapshot.partnerAccountId,
orderCommissionRateAtPay: paySnapshot.orderCommissionRate,
proxyPartnerAccountId: null,
proxyPartnerName: proxyDisplayName,
proxyPartnerPhone: operatorPhone,
@@ -2612,11 +2640,7 @@ export class TradeService {
if (order.payStatus === 'PAID') return;
const now = new Date();
const paySnapshot = await this.partnerCityService.resolveForOrder(
order.cityId,
order.receiverDistrict,
);
// 现场提货:支付即完成(代下单同 C 端 PRD)
// 现场提货:支付即完成(代下单同 C 端 PRD);佣金快照沿用创建时代下单选择,不回落区县
const toStatus =
order.deliveryType === 'ON_SITE_PICKUP' ? 'COMPLETED' : 'PENDING_SHIP';
@@ -2628,9 +2652,8 @@ export class TradeService {
payStatus: 'PAID',
paidAt: now,
payExternalNo: externalNo,
partnerAccountIdAtPay: paySnapshot?.partnerAccountId ?? order.partnerAccountIdAtPay,
orderCommissionRateAtPay:
paySnapshot?.orderCommissionRate ?? order.orderCommissionRateAtPay,
partnerAccountIdAtPay: order.partnerAccountIdAtPay,
orderCommissionRateAtPay: order.orderCommissionRateAtPay,
},
});
await tx.logThirdParty.create({