init
This commit is contained in:
110
api/service/biz_usage_service.js
Normal file
110
api/service/biz_usage_service.js
Normal file
@@ -0,0 +1,110 @@
|
||||
const baseModel = require("../../middleware/baseModel");
|
||||
const { op } = baseModel;
|
||||
|
||||
function currentStatMonth(d = new Date()) {
|
||||
const y = d.getFullYear();
|
||||
const m = String(d.getMonth() + 1).padStart(2, "0");
|
||||
return `${y}-${m}`;
|
||||
}
|
||||
|
||||
function num(v) {
|
||||
if (v === null || v === undefined || v === "") return 0;
|
||||
const n = Number(v);
|
||||
return Number.isNaN(n) ? 0 : n;
|
||||
}
|
||||
|
||||
/** 0 表示无限制(不校验) */
|
||||
function quotaExceeded(used, limit) {
|
||||
const li = num(limit);
|
||||
if (li <= 0) return false;
|
||||
return num(used) >= li;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取或创建当月用量行
|
||||
*/
|
||||
async function getOrCreateUsage(userId, planId, statMonth) {
|
||||
const [row] = await baseModel.biz_usage_monthly.findOrCreate({
|
||||
where: { user_id: userId, stat_month: statMonth },
|
||||
defaults: {
|
||||
user_id: userId,
|
||||
plan_id: planId,
|
||||
stat_month: statMonth,
|
||||
msg_count: 0,
|
||||
mass_count: 0,
|
||||
friend_count: 0,
|
||||
sns_count: 0,
|
||||
active_user_count: 0,
|
||||
},
|
||||
});
|
||||
if (num(row.plan_id) !== num(planId)) {
|
||||
await row.update({ plan_id: planId });
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
async function applyDelta(userId, planId, statMonth, delta) {
|
||||
const row = await getOrCreateUsage(userId, planId, statMonth);
|
||||
const next = {
|
||||
msg_count: num(row.msg_count) + num(delta.msg),
|
||||
mass_count: num(row.mass_count) + num(delta.mass),
|
||||
friend_count: num(row.friend_count) + num(delta.friend),
|
||||
sns_count: num(row.sns_count) + num(delta.sns),
|
||||
active_user_count: num(row.active_user_count) + num(delta.active_user),
|
||||
};
|
||||
await row.update(next);
|
||||
return row.reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验「增量」后是否超限(与套餐额度对比)
|
||||
* feature: msg | mass | friend | sns | active_user
|
||||
*/
|
||||
function checkQuotaAfterDelta(plan, usageRow, delta) {
|
||||
const checks = [
|
||||
["msg", "msg_count", "msg_quota"],
|
||||
["mass", "mass_count", "mass_quota"],
|
||||
["friend", "friend_count", "friend_quota"],
|
||||
["sns", "sns_count", "sns_quota"],
|
||||
["active_user", "active_user_count", "active_user_limit"],
|
||||
];
|
||||
for (const [key, uCol, pCol] of checks) {
|
||||
const add = num(delta[key]);
|
||||
if (add <= 0) continue;
|
||||
const used = num(usageRow[uCol]) + add;
|
||||
if (quotaExceeded(used, plan[pCol])) {
|
||||
return { ok: false, error_code: "QUOTA_EXCEEDED", message: `额度不足: ${key}` };
|
||||
}
|
||||
}
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* 为当前月所有有效订阅补用量行(月结/初始化)
|
||||
*/
|
||||
async function ensureUsageRowsForCurrentMonth() {
|
||||
const statMonth = currentStatMonth();
|
||||
const now = new Date();
|
||||
const subs = await baseModel.biz_subscription.findAll({
|
||||
where: {
|
||||
status: "active",
|
||||
start_time: { [op.lte]: now },
|
||||
end_time: { [op.gte]: now },
|
||||
},
|
||||
});
|
||||
let n = 0;
|
||||
for (const s of subs) {
|
||||
await getOrCreateUsage(s.user_id, s.plan_id, statMonth);
|
||||
n += 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
currentStatMonth,
|
||||
getOrCreateUsage,
|
||||
applyDelta,
|
||||
checkQuotaAfterDelta,
|
||||
ensureUsageRowsForCurrentMonth,
|
||||
num,
|
||||
};
|
||||
Reference in New Issue
Block a user