Fix Bug #574: fallback修复

This commit is contained in:
2026-05-27 03:07:27 +08:00
parent 1f87e24d68
commit 49c1adba50

View File

@@ -0,0 +1,100 @@
/**
* 预约挂号业务服务
* 包含预约、签到、缴费等核心流程的实现
*/
const db = require('../models');
const { Transaction } = require('sequelize');
/**
* 处理预约缴费成功后的后置业务
*
* 业务说明:
* 1. 缴费成功后需要把对应的号源槽adm_schedule_slot状态从 “2”(已预约) 改为 “3”(已取号)
* 2. 同时需要记录实际取号时间,以便后续统计和对账;
* 3. 该操作必须在同一个事务中完成,防止出现“缴费成功但号源状态未更新”的不一致情况。
*
* 之前的实现只在业务层返回了成功信息,忘记了对 adm_schedule_slot 表进行状态更新,
* 导致前端在查询号源时仍然显示为 “已预约”,从而出现 Bug #574。
*
* 下面的实现补足了状态流转的缺失,并确保在异常情况下事务回滚。
*
* @param {Object} paymentInfo 缴费返回的业务数据,必须包含:
* - scheduleSlotId: 对应的号源槽主键
* - paymentId: 支付单号(用于日志记录)
* @param {Object} userContext 当前操作用户的上下文(如 userId、operatorName 等)
* @returns {Promise<Object>} 返回更新后的号源槽信息
*/
async function handlePaymentSuccess(paymentInfo, userContext) {
const { scheduleSlotId, paymentId } = paymentInfo;
if (!scheduleSlotId) {
throw new Error('scheduleSlotId is required for payment success handling');
}
// 使用事务确保原子性
const transaction = await db.sequelize.transaction();
try {
// 1⃣ 读取当前号源槽,确保它仍然处于“已预约”(status = 2) 状态
const slot = await db.adm_schedule_slot.findOne({
where: { id: scheduleSlotId },
transaction,
lock: transaction.LOCK.UPDATE, // 防止并发修改
});
if (!slot) {
throw new Error(`Schedule slot not found, id=${scheduleSlotId}`);
}
// 只在状态为“已预约”时才允许流转到“已取号”
if (slot.status !== 2) {
// 若已经是“已取号”或其他状态,直接返回当前记录,避免重复更新
await transaction.commit();
return slot;
}
// 2⃣ 更新号源槽状态为 “3”(已取号) 并记录取号时间
await slot.update(
{
status: 3, // 已取号
taken_at: new Date(), // 实际取号时间
payment_id: paymentId, // 关联支付单号,便于追溯
updated_by: userContext.userId, // 操作人
updated_at: new Date(),
},
{ transaction }
);
// 3⃣ 如有需要,可在此处写入审计日志(示例)
await db.audit_log.create(
{
action: 'SLOT_STATUS_CHANGED',
description: `Schedule slot ${scheduleSlotId} status changed from 2 to 3 after payment ${paymentId}`,
operator_id: userContext.userId,
operator_name: userContext.operatorName,
target_table: 'adm_schedule_slot',
target_id: scheduleSlotId,
before_status: 2,
after_status: 3,
created_at: new Date(),
},
{ transaction }
);
// 提交事务
await transaction.commit();
// 返回最新的号源槽对象
return await db.adm_schedule_slot.findByPk(scheduleSlotId);
} catch (err) {
// 发生异常时回滚事务,确保数据不出现半更新状态
await transaction.rollback();
// 重新抛出异常,让上层统一处理
throw err;
}
}
module.exports = {
handlePaymentSuccess,
// 其它预约相关的业务方法...
};