rentease-backend-new/controllers/billingController.js

913 lines
25 KiB
JavaScript
Raw Normal View History

2026-04-20 06:43:09 +00:00
const { SubscriptionPlan, PricingConfig, Order, Payment, Tenant, User, Apartment, Room, PaymentSetting } = require('../models');
const { Op } = require('sequelize');
const billingService = require('../services/billingService');
2026-04-22 06:48:32 +00:00
const response = require('../utils/response');
2026-04-20 06:43:09 +00:00
// 获取所有套餐列表
const getAllPlans = async (req, res) => {
try {
const plans = await SubscriptionPlan.findAll({
where: { isDeleted: 0 },
order: [['sort', 'ASC']]
});
2026-04-22 06:48:32 +00:00
response.success(res, '获取套餐列表成功', plans);
2026-04-20 06:43:09 +00:00
} catch (error) {
2026-04-22 06:48:32 +00:00
response.serverError(res, '获取套餐列表失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 创建套餐
const createPlan = async (req, res) => {
try {
const { name, description, maxApartments, maxRooms, maxUsers, monthlyPrice } = req.body;
// 验证必填字段
if (!name) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '套餐名称不能为空');
2026-04-20 06:43:09 +00:00
}
// 检查是否是第一个套餐
const existingPlans = await SubscriptionPlan.count({ where: { isDeleted: 0 } });
const isDefault = existingPlans === 0;
// 创建套餐
const plan = await SubscriptionPlan.create({
name,
description,
maxApartments: maxApartments || 10,
maxRooms: maxRooms || 50,
maxUsers: maxUsers || 5,
monthlyPrice: monthlyPrice || 0,
isDefault
});
2026-04-22 06:48:32 +00:00
response.created(res, '套餐创建成功', plan);
2026-04-20 06:43:09 +00:00
} catch (error) {
2026-04-22 06:48:32 +00:00
response.serverError(res, '创建套餐失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 更新套餐
const updatePlan = async (req, res) => {
try {
const { id } = req.params;
const { name, description, maxApartments, maxRooms, maxUsers, monthlyPrice, status, sort } = req.body;
// 查找套餐
const plan = await SubscriptionPlan.findOne({
where: { id, isDeleted: 0 }
});
if (!plan) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '套餐不存在');
2026-04-20 06:43:09 +00:00
}
// 更新套餐信息
await plan.update({
name: name !== undefined ? name : plan.name,
description: description !== undefined ? description : plan.description,
maxApartments: maxApartments !== undefined ? maxApartments : plan.maxApartments,
maxRooms: maxRooms !== undefined ? maxRooms : plan.maxRooms,
maxUsers: maxUsers !== undefined ? maxUsers : plan.maxUsers,
monthlyPrice: monthlyPrice !== undefined ? monthlyPrice : plan.monthlyPrice,
status: status !== undefined ? status : plan.status,
sort: sort !== undefined ? sort : plan.sort
});
2026-04-22 06:48:32 +00:00
response.success(res, '套餐更新成功', plan);
2026-04-20 06:43:09 +00:00
} catch (error) {
2026-04-22 06:48:32 +00:00
response.serverError(res, '更新套餐失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 删除套餐(软删除)
const deletePlan = async (req, res) => {
try {
const { id } = req.params;
// 查找套餐
const plan = await SubscriptionPlan.findOne({
where: { id, isDeleted: 0 }
});
if (!plan) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '套餐不存在');
2026-04-20 06:43:09 +00:00
}
// 不能删除默认套餐
if (plan.isDefault) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '不能删除默认套餐');
2026-04-20 06:43:09 +00:00
}
// 软删除
await plan.update({ isDeleted: 1 });
2026-04-22 06:48:32 +00:00
response.success(res, '套餐删除成功');
2026-04-20 06:43:09 +00:00
} catch (error) {
2026-04-22 06:48:32 +00:00
response.serverError(res, '删除套餐失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 设置默认套餐
const setDefaultPlan = async (req, res) => {
try {
const { id } = req.params;
// 查找套餐
const plan = await SubscriptionPlan.findOne({
where: { id, isDeleted: 0 }
});
if (!plan) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '套餐不存在');
2026-04-20 06:43:09 +00:00
}
// 将其他套餐 isDefault 设为 false
await SubscriptionPlan.update(
{ isDefault: false },
{ where: { isDeleted: 0 } }
);
// 将指定套餐 isDefault 设为 true
await plan.update({ isDefault: true });
2026-04-22 06:48:32 +00:00
response.success(res, '设置默认套餐成功', plan);
2026-04-20 06:43:09 +00:00
} catch (error) {
2026-04-22 06:48:32 +00:00
response.serverError(res, '设置默认套餐失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 获取当前价格配置
const getPricingConfig = async (req, res) => {
try {
// 查询 isActive=true 且最新的记录
const config = await PricingConfig.findOne({
where: { isActive: true, isDeleted: 0 },
order: [['createTime', 'DESC']]
});
// 如果没有则返回默认配置
if (!config) {
2026-04-22 06:48:32 +00:00
return response.success(res, '获取价格配置成功', {
overageApartmentPrice: 10.00,
overageRoomPrice: 2.00,
overageUserPrice: 5.00,
currency: 'CNY'
2026-04-20 06:43:09 +00:00
});
}
2026-04-22 06:48:32 +00:00
response.success(res, '获取价格配置成功', config);
2026-04-20 06:43:09 +00:00
} catch (error) {
2026-04-22 06:48:32 +00:00
response.serverError(res, '获取价格配置失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 更新价格配置
const updatePricingConfig = async (req, res) => {
try {
const { overageApartmentPrice, overageRoomPrice, overageUserPrice } = req.body;
// 将旧配置 isActive 设为 false
await PricingConfig.update(
{ isActive: false },
{ where: { isActive: true } }
);
// 创建新配置记录
const config = await PricingConfig.create({
overageApartmentPrice: overageApartmentPrice || 10.00,
overageRoomPrice: overageRoomPrice || 2.00,
overageUserPrice: overageUserPrice || 5.00,
isActive: true
});
2026-04-22 06:48:32 +00:00
response.success(res, '价格配置更新成功', config);
2026-04-20 06:43:09 +00:00
} catch (error) {
2026-04-22 06:48:32 +00:00
response.serverError(res, '更新价格配置失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 初始化默认套餐数据
const initDefaultPlans = async (req, res) => {
try {
// 检查是否已有套餐
const existingCount = await SubscriptionPlan.count({ where: { isDeleted: 0 } });
if (existingCount > 0) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '套餐数据已存在,无需初始化');
2026-04-20 06:43:09 +00:00
}
// 默认套餐数据
const defaultPlans = [
{
name: '免费版',
description: '适合个人用户试用',
maxApartments: 2,
maxRooms: 10,
maxUsers: 2,
monthlyPrice: 0,
isDefault: true,
sort: 1
},
{
name: '基础版',
description: '适合小型公寓管理',
maxApartments: 5,
maxRooms: 50,
maxUsers: 5,
monthlyPrice: 99,
isDefault: false,
sort: 2
},
{
name: '专业版',
description: '适合中型公寓管理',
maxApartments: 20,
maxRooms: 200,
maxUsers: 20,
monthlyPrice: 299,
isDefault: false,
sort: 3
},
{
name: '旗舰版',
description: '适合大型公寓管理',
maxApartments: 100,
maxRooms: 1000,
maxUsers: 100,
monthlyPrice: 999,
isDefault: false,
sort: 4
}
];
// 批量创建套餐
const plans = await SubscriptionPlan.bulkCreate(defaultPlans);
2026-04-22 06:48:32 +00:00
response.success(res, '默认套餐初始化成功', plans);
2026-04-20 06:43:09 +00:00
} catch (error) {
2026-04-22 06:48:32 +00:00
response.serverError(res, '初始化默认套餐失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 初始化默认价格配置
const initDefaultPricing = async (req, res) => {
try {
// 检查是否已有活跃配置
const existingConfig = await PricingConfig.findOne({
where: { isActive: true, isDeleted: 0 }
});
if (existingConfig) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '价格配置已存在,无需初始化');
2026-04-20 06:43:09 +00:00
}
// 创建默认价格配置
const config = await PricingConfig.create({
overageApartmentPrice: 10.00,
overageRoomPrice: 2.00,
overageUserPrice: 5.00,
isActive: true
});
2026-04-22 06:48:32 +00:00
response.success(res, '默认价格配置初始化成功', config);
2026-04-20 06:43:09 +00:00
} catch (error) {
2026-04-22 06:48:32 +00:00
response.serverError(res, '初始化默认价格配置失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 获取订单列表
const getOrders = async (req, res) => {
try {
const { page = 1, pageSize = 10, tenantId, status } = req.query;
const offset = (page - 1) * pageSize;
const isSystemAdmin = req.user.userType === 'super_admin';
const currentTenantId = req.tenantId;
const where = { isDeleted: 0 };
// 权限检查:普通租户只能查看自己的订单
if (!isSystemAdmin) {
where.tenantId = currentTenantId;
} else if (tenantId) {
// 系统管理员可以查看指定租户的订单
where.tenantId = tenantId;
}
if (status) {
where.status = status;
}
const { count, rows } = await Order.findAndCountAll({
where,
limit: parseInt(pageSize),
offset: parseInt(offset),
order: [['createTime', 'DESC']],
include: [
{
model: Tenant,
as: 'tenant',
attributes: ['id', 'code', 'contactName']
},
{
model: SubscriptionPlan,
as: 'subscriptionPlan',
attributes: ['id', 'name', 'monthlyPrice']
}
]
});
2026-04-22 06:48:32 +00:00
response.success(res, '获取订单列表成功', {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
2026-04-20 06:43:09 +00:00
});
} catch (error) {
console.error('获取订单列表失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '获取订单列表失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 计算续费价格(含超额费用)
const calculatePrice = async (req, res) => {
try {
const { planId, months } = req.body;
const tenantId = req.tenantId;
// 验证必填字段
if (!planId || !months) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '套餐ID和购买月数不能为空');
2026-04-20 06:43:09 +00:00
}
if (months < 1 || months > 36) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '购买月数必须在1-36之间');
2026-04-20 06:43:09 +00:00
}
// 获取套餐信息
const plan = await SubscriptionPlan.findOne({
where: { id: planId, isDeleted: 0 }
});
if (!plan) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '套餐不存在');
2026-04-20 06:43:09 +00:00
}
// 计算订单金额(含超额费用)
const amountInfo = await billingService.calculateRenewalAmount(tenantId, planId, months);
2026-04-22 06:48:32 +00:00
response.success(res, '计算成功', amountInfo);
2026-04-20 06:43:09 +00:00
} catch (error) {
console.error('计算价格失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '计算价格失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 创建续费订单
const createOrder = async (req, res) => {
try {
const { planId, months } = req.body;
const tenantId = req.tenantId;
// 验证必填字段
if (!planId || !months) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '套餐ID和购买月数不能为空');
2026-04-20 06:43:09 +00:00
}
if (months < 1 || months > 36) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '购买月数必须在1-36之间');
2026-04-20 06:43:09 +00:00
}
// 获取套餐信息
const plan = await SubscriptionPlan.findOne({
where: { id: planId, isDeleted: 0 }
});
if (!plan) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '套餐不存在');
2026-04-20 06:43:09 +00:00
}
// 计算订单金额
const amountInfo = await billingService.calculateRenewalAmount(tenantId, planId, months);
// 生成订单编号
const orderNo = `ORD${Date.now()}${Math.floor(Math.random() * 1000)}`;
// 计算过期时间30分钟后过期
const expireTime = new Date();
expireTime.setMinutes(expireTime.getMinutes() + 30);
// 创建订单
const order = await Order.create({
orderNo,
tenantId,
planId,
planName: plan.name,
months,
amount: amountInfo.totalAmount,
discountAmount: 0,
actualAmount: amountInfo.totalAmount,
status: 'pending',
expireTime,
createBy: req.user.id,
updateBy: req.user.id
});
// 重新查询订单以确保数据完整,包含关联数据
const createdOrder = await Order.findByPk(order.id, {
include: [
{
model: Tenant,
as: 'tenant',
attributes: ['id', 'code', 'contactName']
},
{
model: SubscriptionPlan,
as: 'subscriptionPlan',
attributes: ['id', 'name', 'monthlyPrice']
}
]
});
2026-04-22 06:48:32 +00:00
response.created(res, '订单创建成功', {
order: createdOrder.toJSON(),
details: amountInfo.details
2026-04-20 06:43:09 +00:00
});
} catch (error) {
console.error('创建订单失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '创建订单失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 获取订单详情
const getOrderDetail = async (req, res) => {
try {
const { id } = req.params;
const isSystemAdmin = req.user.userType === 'super_admin';
const currentTenantId = req.tenantId;
const order = await Order.findOne({
where: { id, isDeleted: 0 },
include: [
{
model: Tenant,
as: 'tenant',
attributes: ['id', 'code', 'contactName']
},
{
model: SubscriptionPlan,
as: 'subscriptionPlan',
attributes: ['id', 'name', 'description', 'monthlyPrice', 'maxApartments', 'maxRooms', 'maxUsers']
},
{
model: Payment,
as: 'payments',
attributes: ['id', 'amount', 'paymentMethod', 'status', 'transactionId', 'paidAt', 'createTime']
}
]
});
if (!order) {
2026-04-22 06:48:32 +00:00
return response.notFound(res, '订单不存在');
2026-04-20 06:43:09 +00:00
}
// 权限检查:普通租户只能查看自己的订单
if (!isSystemAdmin && order.tenantId !== currentTenantId) {
2026-04-22 06:48:32 +00:00
return response.forbidden(res, '无权查看此订单');
2026-04-20 06:43:09 +00:00
}
2026-04-22 06:48:32 +00:00
response.success(res, '获取订单详情成功', order);
2026-04-20 06:43:09 +00:00
} catch (error) {
console.error('获取订单详情失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '获取订单详情失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 取消订单
const cancelOrder = async (req, res) => {
try {
const { id } = req.params;
const isSystemAdmin = req.user.userType === 'super_admin';
const currentTenantId = req.tenantId;
const order = await Order.findOne({
where: { id, isDeleted: 0 }
});
if (!order) {
2026-04-22 06:48:32 +00:00
return response.notFound(res, '订单不存在');
2026-04-20 06:43:09 +00:00
}
// 权限检查:普通租户只能取消自己的订单
if (!isSystemAdmin && order.tenantId !== currentTenantId) {
2026-04-22 06:48:32 +00:00
return response.forbidden(res, '无权取消此订单');
2026-04-20 06:43:09 +00:00
}
// 只能取消待支付的订单
if (order.status !== 'pending') {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '只能取消待支付的订单');
2026-04-20 06:43:09 +00:00
}
await order.update({ status: 'cancelled' });
2026-04-22 06:48:32 +00:00
response.success(res, '订单取消成功');
2026-04-20 06:43:09 +00:00
} catch (error) {
console.error('取消订单失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '取消订单失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 支付订单(管理员确认收款)
const payOrder = async (req, res) => {
try {
const { id: orderId } = req.params;
const { paymentMethod = 'other', amount, transactionId: customTransactionId, remark } = req.body || {};
const isSystemAdmin = req.user.userType === 'super_admin';
if (!orderId) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '订单ID不能为空');
2026-04-20 06:43:09 +00:00
}
// 只有管理员可以确认支付
if (!isSystemAdmin) {
2026-04-22 06:48:32 +00:00
return response.forbidden(res, '无权操作,请联系管理员');
2026-04-20 06:43:09 +00:00
}
// 查询订单
const order = await Order.findOne({
where: { id: orderId, isDeleted: 0 }
});
if (!order) {
2026-04-22 06:48:32 +00:00
return response.notFound(res, '订单不存在');
2026-04-20 06:43:09 +00:00
}
// 验证订单状态
if (order.status !== 'pending') {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '订单状态异常,无法支付');
2026-04-20 06:43:09 +00:00
}
// 验证金额
const paymentAmount = parseFloat(amount) || order.actualAmount;
if (paymentAmount <= 0) {
2026-04-22 06:48:32 +00:00
return response.badRequest(res, '支付金额必须大于0');
2026-04-20 06:43:09 +00:00
}
// 生成或使用自定义交易流水号
const transactionId = customTransactionId || `PAY${Date.now()}${Math.floor(Math.random() * 1000)}`;
// 创建支付记录
const payment = await Payment.create({
orderId,
tenantId: order.tenantId,
amount: paymentAmount,
paymentMethod: ['alipay', 'wechat', 'bank', 'other'].includes(paymentMethod) ? paymentMethod : 'other',
status: 'success',
transactionId,
paidAt: new Date(),
remark: remark || '管理员确认收款'
});
// 更新订单状态
const paidTime = new Date();
await order.update({
status: 'paid',
paidTime: paidTime
});
// 处理支付成功后的租户状态更新
// 使用订单的months字段和planId更新资源配置
const paymentResult = await billingService.processPaymentSuccess(order.tenantId, order.months, order.planId);
2026-04-22 06:48:32 +00:00
response.success(res, '支付成功', {
payment,
order: {
...order.toJSON(),
status: 'paid',
paidTime: paidTime
},
tenant: paymentResult
2026-04-20 06:43:09 +00:00
});
} catch (error) {
console.error('支付订单失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '支付订单失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 获取支付记录
const getPayments = async (req, res) => {
try {
const { page = 1, pageSize = 10, tenantId } = req.query;
const offset = (page - 1) * pageSize;
const isSystemAdmin = req.user.userType === 'super_admin';
const currentTenantId = req.tenantId;
const where = { isDeleted: 0 };
// 权限检查:普通租户只能查看自己的支付记录
if (!isSystemAdmin) {
where.tenantId = currentTenantId;
} else if (tenantId) {
// 系统管理员可以查看指定租户的支付记录
where.tenantId = tenantId;
}
const { count, rows } = await Payment.findAndCountAll({
where,
limit: parseInt(pageSize),
offset: parseInt(offset),
order: [['createTime', 'DESC']],
include: [
{
model: Tenant,
as: 'tenant',
attributes: ['id', 'code', 'contactName']
},
{
model: Order,
as: 'order',
attributes: ['id', 'orderNo', 'planId', 'planName', 'months', 'amount', 'discountAmount', 'actualAmount']
}
]
});
2026-04-22 06:48:32 +00:00
response.success(res, '获取支付记录成功', {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
2026-04-20 06:43:09 +00:00
});
} catch (error) {
console.error('获取支付记录失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '获取支付记录失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 获取当前租户计费信息
const getBillingInfo = async (req, res) => {
try {
const tenantId = req.tenantId;
const tenant = await Tenant.findOne({
where: { id: tenantId, isDeleted: 0 },
include: [
{
model: SubscriptionPlan,
as: 'subscriptionPlan',
attributes: ['id', 'name', 'description', 'monthlyPrice', 'maxApartments', 'maxRooms', 'maxUsers']
}
]
});
if (!tenant) {
2026-04-22 06:48:32 +00:00
return response.notFound(res, '租户不存在');
2026-04-20 06:43:09 +00:00
}
// 获取当前使用量
const [apartmentCount, roomCount, userCount] = await Promise.all([
Apartment.count({ where: { tenantId, isDeleted: 0 } }),
Room.count({ where: { tenantId, isDeleted: 0 } }),
User.count({ where: { tenantId, isDeleted: 0 } })
]);
2026-04-22 06:48:32 +00:00
response.success(res, '获取计费信息成功', {
tenant: {
id: tenant.id,
name: tenant.name,
code: tenant.code,
billingStatus: tenant.billingStatus,
trialStartDate: tenant.trialStartDate,
trialEndDate: tenant.trialEndDate,
paidStartDate: tenant.paidStartDate,
paidEndDate: tenant.paidEndDate,
currentPeriodStart: tenant.currentPeriodStart,
currentPeriodEnd: tenant.currentPeriodEnd
2026-04-20 06:43:09 +00:00
},
2026-04-22 06:48:32 +00:00
plan: tenant.subscriptionPlan,
usage: {
apartments: apartmentCount,
rooms: roomCount,
users: userCount
}
2026-04-20 06:43:09 +00:00
});
} catch (error) {
console.error('获取计费信息失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '获取计费信息失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 获取资源使用情况
const getUsageStats = async (req, res) => {
try {
const tenantId = req.tenantId;
const usageStats = await billingService.calculateOverage(tenantId);
2026-04-22 06:48:32 +00:00
response.success(res, '获取资源使用情况成功', usageStats);
2026-04-20 06:43:09 +00:00
} catch (error) {
console.error('获取资源使用情况失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '获取资源使用情况失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 获取计费统计(仅系统管理员)
const getBillingStats = async (req, res) => {
try {
const isSystemAdmin = req.user.userType === 'super_admin';
if (!isSystemAdmin) {
2026-04-22 06:48:32 +00:00
return response.forbidden(res, '无权访问此接口');
2026-04-20 06:43:09 +00:00
}
// 各计费状态租户数量
const billingStatusStats = await Tenant.findAll({
where: { isDeleted: 0 },
attributes: ['billingStatus', [require('sequelize').fn('COUNT', require('sequelize').col('id')), 'count']],
group: ['billingStatus']
});
// 总收入
const totalRevenue = await Payment.sum('amount', {
where: { status: 'success', isDeleted: 0 }
});
// 本月收入
const now = new Date();
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
const monthRevenue = await Payment.sum('amount', {
where: {
status: 'success',
isDeleted: 0,
paidAt: {
[Op.gte]: monthStart
}
}
});
// 即将到期租户数7天内
const reminderDate = new Date();
reminderDate.setDate(reminderDate.getDate() + 7);
const upcomingExpiredCount = await Tenant.count({
where: {
isDeleted: 0,
[Op.or]: [
{
billingStatus: 'trial_active',
trialEndDate: {
[Op.lte]: reminderDate,
[Op.gte]: now
}
},
{
billingStatus: 'paid_active',
paidEndDate: {
[Op.lte]: reminderDate,
[Op.gte]: now
}
}
]
}
});
// 已过期租户数
const expiredCount = await Tenant.count({
where: {
isDeleted: 0,
billingStatus: {
[Op.in]: ['trial_expired', 'paid_expired']
}
}
});
// 待处理订单数
const pendingOrdersCount = await Order.count({
where: {
status: 'pending',
isDeleted: 0
}
});
2026-04-22 06:48:32 +00:00
response.success(res, '获取计费统计成功', {
billingStatusStats: billingStatusStats.reduce((acc, item) => {
acc[item.billingStatus] = parseInt(item.get('count'));
return acc;
}, {}),
totalRevenue: totalRevenue || 0,
monthRevenue: monthRevenue || 0,
upcomingExpiredCount,
expiredCount,
pendingOrdersCount
2026-04-20 06:43:09 +00:00
});
} catch (error) {
console.error('获取计费统计失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '获取计费统计失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 获取支付设置
const getPaymentSettings = async (req, res) => {
try {
// 查询第一条记录(系统中只有一条支付设置记录)
let settings = await PaymentSetting.findOne({
where: { isDeleted: 0 }
});
// 如果没有记录,返回空对象
if (!settings) {
2026-04-22 06:48:32 +00:00
return response.success(res, '获取支付设置成功', {});
2026-04-20 06:43:09 +00:00
}
2026-04-22 06:48:32 +00:00
response.success(res, '获取支付设置成功', settings);
2026-04-20 06:43:09 +00:00
} catch (error) {
console.error('获取支付设置失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '获取支付设置失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 更新支付设置
const updatePaymentSettings = async (req, res) => {
try {
const isSystemAdmin = req.user.userType === 'super_admin';
// 只有超级管理员可以修改支付设置
if (!isSystemAdmin) {
2026-04-22 06:48:32 +00:00
return response.forbidden(res, '无权操作,请联系管理员');
2026-04-20 06:43:09 +00:00
}
const {
alipayAccount,
alipayName,
wechatId,
wechatText,
bankName,
bankAccount,
bankHolder,
servicePhone,
serviceTime
} = req.body;
// 查询是否存在记录
let settings = await PaymentSetting.findOne({
where: { isDeleted: 0 }
});
if (settings) {
// 更新现有记录
await settings.update({
alipayAccount: alipayAccount !== undefined ? alipayAccount : settings.alipayAccount,
alipayName: alipayName !== undefined ? alipayName : settings.alipayName,
wechatId: wechatId !== undefined ? wechatId : settings.wechatId,
wechatText: wechatText !== undefined ? wechatText : settings.wechatText,
bankName: bankName !== undefined ? bankName : settings.bankName,
bankAccount: bankAccount !== undefined ? bankAccount : settings.bankAccount,
bankHolder: bankHolder !== undefined ? bankHolder : settings.bankHolder,
servicePhone: servicePhone !== undefined ? servicePhone : settings.servicePhone,
serviceTime: serviceTime !== undefined ? serviceTime : settings.serviceTime
});
} else {
// 创建新记录
settings = await PaymentSetting.create({
alipayAccount,
alipayName,
wechatId,
wechatText,
bankName,
bankAccount,
bankHolder,
servicePhone,
serviceTime
});
}
2026-04-22 06:48:32 +00:00
response.success(res, '支付设置更新成功', settings);
2026-04-20 06:43:09 +00:00
} catch (error) {
console.error('更新支付设置失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '更新支付设置失败', error);
2026-04-20 06:43:09 +00:00
}
};
module.exports = {
getAllPlans,
createPlan,
updatePlan,
deletePlan,
setDefaultPlan,
getPricingConfig,
updatePricingConfig,
initDefaultPlans,
initDefaultPricing,
getOrders,
createOrder,
calculatePrice,
getOrderDetail,
cancelOrder,
payOrder,
getPayments,
getBillingInfo,
getUsageStats,
getBillingStats,
getPaymentSettings,
updatePaymentSettings
};