feat(order): support balance payment, dynamic marketing coupon recommendation, and quick activity picker

这个提交包含在:
xcbyy
2026-10-10 15:37:41 +08:00
父节点 872af22c20
当前提交 7ac81035b4
共有 7 个文件被更改,包括 559 次插入 和 18 次删除

查看文件

@@ -120,7 +120,9 @@ export async function initDatabase(): Promise<void> {
"ALTER TABLE orders ADD COLUMN expert_avatar TEXT AFTER companion_name",
"ALTER TABLE orders ADD COLUMN service_title VARCHAR(255) DEFAULT '同城陪伴服务' AFTER track",
"ALTER TABLE orders ADD COLUMN verify_code VARCHAR(8) AFTER location",
"ALTER TABLE orders ADD COLUMN remark VARCHAR(255) AFTER verify_code"
"ALTER TABLE orders ADD COLUMN remark VARCHAR(255) AFTER verify_code",
"ALTER TABLE orders ADD COLUMN pay_type VARCHAR(32) DEFAULT 'WECHAT' AFTER status",
"ALTER TABLE orders ADD COLUMN coupon_discount DECIMAL(10,2) DEFAULT 0.00 AFTER amount"
];
for (const colSql of extraOrderCols) {
try {

查看文件

@@ -617,6 +617,8 @@ export class MysqlRepository {
hourly_rate as hourlyRate,
duration_hours as durationHours,
amount,
COALESCE(coupon_discount, 0.00) as couponDiscount,
COALESCE(pay_type, 'WECHAT') as payType,
location,
verify_code as verifyCode,
remark,
@@ -639,6 +641,8 @@ export class MysqlRepository {
hourlyRate?: number;
durationHours?: number;
amount?: number;
couponDiscount?: number;
payType?: string;
location?: string;
expenseBurden?: string;
remark?: string;
@@ -656,6 +660,8 @@ export class MysqlRepository {
const hourlyRate = Number(data.hourlyRate) || 35;
const durationHours = Number(data.durationHours) || 2;
const amount = Number(data.amount) || hourlyRate * durationHours;
const couponDiscount = Number(data.couponDiscount || 0);
const payType = data.payType === 'BALANCE' ? 'BALANCE' : 'WECHAT';
const location = data.location || '朝阳大悦城';
const expenseBurden = data.expenseBurden || 'AA制各自付';
const verifyCode = String(Math.floor(1000 + Math.random() * 9000));
@@ -665,27 +671,52 @@ export class MysqlRepository {
const conn = await pool.getConnection();
try {
await conn.beginTransaction();
// 如果是余额支付,先锁行校验扣减用户钱包余额
if (payType === 'BALANCE') {
const [uRows]: any = await conn.query('SELECT balance FROM users WHERE id = ? FOR UPDATE', [buyerId]);
if (!uRows || uRows.length === 0) {
throw new Error('支付账户不存在');
}
const userBalance = Number(uRows[0].balance || 0);
if (userBalance < amount) {
throw new Error(`钱包余额不足 (当前可用 ¥${userBalance.toFixed(2)},需支付 ¥${amount.toFixed(2)})`);
}
const newBalance = userBalance - amount;
await conn.query('UPDATE users SET balance = ? WHERE id = ?', [newBalance, buyerId]);
// 记一笔钱包扣款流水
const walletFinId = `fin_bal_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
const walletRecNo = `WB${Date.now()}${Math.floor(Math.random() * 100)}`;
await conn.query(`
INSERT INTO finance_records (id, record_no, type, amount, direction, counterparty, related_id)
VALUES (?, ?, '钱包余额支付订单', ?, 'OUT', ?, ?)
`, [walletFinId, walletRecNo, amount.toFixed(2), `用户 ${buyerId} (${companionName})`, id]);
}
await conn.query(`
INSERT INTO orders (
id, buyer_id, expert_id, order_no, client_name,
companion_name, expert_avatar, track, service_title,
expense_burden, hourly_rate, duration_hours, amount,
coupon_discount, pay_type,
location, verify_code, remark, status, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())
`, [
id, buyerId, expertId, orderNo, clientName,
companionName, expertAvatar, track, serviceTitle,
expenseBurden, hourlyRate, durationHours, amount,
couponDiscount, payType,
location, verifyCode, remark, status
]);
// 记一笔进账流水
// 记一笔平台订单进账流水
const finId = `fin_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
const recordNo = `TX${Date.now()}${Math.floor(Math.random() * 100)}`;
await conn.query(`
INSERT INTO finance_records (id, record_no, type, amount, direction, counterparty, related_id)
VALUES (?, ?, '服务预约订单付款', ?, 'IN', ?, ?)
`, [finId, recordNo, amount.toFixed(2), clientName, id]);
VALUES (?, ?, ?, ?, 'IN', ?, ?)
`, [finId, recordNo, payType === 'BALANCE' ? '服务预约订单付款 (钱包余额)' : '服务预约订单付款 (微信支付)', amount.toFixed(2), clientName, id]);
await conn.commit();
@@ -703,6 +734,8 @@ export class MysqlRepository {
hourlyRate,
durationHours,
amount,
couponDiscount,
payType,
location,
verifyCode,
remark,