mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
@@ -10,10 +10,11 @@
|
||||
***********************************************************************************************************************************************************************/
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
const mdl_TierPlans = require('../../models/tiers/tier_plans.mdl');
|
||||
const mdl_UserTiers = require('../../models/tiers/user_tiers.mdl');
|
||||
const mdl_Payments = require('../../models/tiers/payments.mdl');
|
||||
const mdl_Users = require('../../models/users/users.mdl');
|
||||
const mdl_TierCategories = require('../../models/tiers/tier_categories.mdl');
|
||||
const mdl_TierPlans = require('../../models/tiers/tier_plans.mdl');
|
||||
const mdl_UserTiers = require('../../models/tiers/user_tiers.mdl');
|
||||
const mdl_Payments = require('../../models/tiers/payments.mdl');
|
||||
const mdl_Users = require('../../models/users/users.mdl');
|
||||
const mdl_PlanCourses = require('../../models/tiers/plan_courses.mdl');
|
||||
const { Course } = require('../../models/courses/courses.mdl');
|
||||
|
||||
@@ -84,14 +85,24 @@ exports.getPlan = async (req, res) => {
|
||||
|
||||
exports.createPlan = async (req, res) => {
|
||||
try {
|
||||
const { tier, label, duration_days, price, currency } = req.body;
|
||||
if (!tier || !label || !duration_days || !price)
|
||||
return R.error(res, 'tier, label, duration_days, and price are required.', 400);
|
||||
const { tier_category_id, label, duration_days, price, currency } = req.body;
|
||||
if (!tier_category_id || !label || !duration_days || !price)
|
||||
return R.error(res, 'tier_category_id, label, duration_days, and price are required.', 400);
|
||||
|
||||
const plan = await mdl_TierPlans.create({ tier, label, duration_days, price, currency });
|
||||
const category = await mdl_TierCategories.findByPk(tier_category_id);
|
||||
if (!category || !category.is_active)
|
||||
return R.error(res, 'Tier category not found or inactive.', 404);
|
||||
|
||||
if (category.is_default)
|
||||
return R.error(res, 'Plans cannot be created under the default (Free) tier. Free access is automatic.', 400);
|
||||
|
||||
const plan = await mdl_TierPlans.create({
|
||||
tier_category_id: category.tier_category_id,
|
||||
tier: category.slug,
|
||||
label, duration_days, price, currency,
|
||||
});
|
||||
const plain = plan.get({ plain: true });
|
||||
logActivity(req.user?.user_id, 'create_tier_plan', { entityType: 'tier_plan', details: { label: plain.label, tier: plain.tier } });
|
||||
// Serialize plan_id as string — CockroachDB BigInts exceed JS Number.MAX_SAFE_INTEGER
|
||||
return R.success(res, 'Plan created.', { ...plain, plan_id: String(plain.plan_id) }, 201);
|
||||
} catch (err) {
|
||||
console.error('[ADMIN][CREATE PLAN]', err);
|
||||
@@ -104,9 +115,21 @@ exports.updatePlan = async (req, res) => {
|
||||
const plan = await mdl_TierPlans.findByPk(req.params.id);
|
||||
if (!plan) return R.error(res, 'Plan not found.', 404);
|
||||
|
||||
const allowed = ['label', 'duration_days', 'price', 'currency', 'is_active'];
|
||||
const allowed = ['label', 'duration_days', 'price', 'currency', 'is_active', 'tier_category_id'];
|
||||
const updates = {};
|
||||
allowed.forEach((k) => { if (req.body[k] !== undefined) updates[k] = req.body[k]; });
|
||||
for (const k of allowed) {
|
||||
if (req.body[k] !== undefined) updates[k] = req.body[k];
|
||||
}
|
||||
|
||||
// If tier_category_id is being changed, sync the tier slug
|
||||
if (updates.tier_category_id) {
|
||||
const category = await mdl_TierCategories.findByPk(updates.tier_category_id);
|
||||
if (!category || !category.is_active)
|
||||
return R.error(res, 'Tier category not found or inactive.', 404);
|
||||
if (category.is_default)
|
||||
return R.error(res, 'Plans cannot be moved to the Free tier category.', 400);
|
||||
updates.tier = category.slug;
|
||||
}
|
||||
|
||||
await plan.update(updates);
|
||||
logActivity(req.user?.user_id, 'update_tier_plan', { entityType: 'tier_plan', details: { label: plan.label } });
|
||||
@@ -234,16 +257,16 @@ exports.getUserTiers = async (req, res) => {
|
||||
|
||||
exports.grantTier = async (req, res) => {
|
||||
try {
|
||||
const { user_id, tier, plan_id, notes } = req.body;
|
||||
if (!user_id || !tier || !plan_id)
|
||||
return R.error(res, 'user_id, tier, and plan_id are required.', 400);
|
||||
const { user_id, plan_id, notes } = req.body;
|
||||
if (!user_id || !plan_id)
|
||||
return R.error(res, 'user_id and plan_id are required.', 400);
|
||||
|
||||
const user = await mdl_Users.findByPk(user_id);
|
||||
if (!user) return R.error(res, 'User not found.', 404);
|
||||
|
||||
const plan = await mdl_TierPlans.findByPk(plan_id);
|
||||
if (!plan || !plan.is_active) return R.error(res, 'Plan not found or inactive.', 404);
|
||||
if (plan.tier !== tier) return R.error(res, 'Plan tier mismatch.', 400);
|
||||
const tier = plan.tier;
|
||||
|
||||
await mdl_UserTiers.update(
|
||||
{ status: 'expired' },
|
||||
@@ -254,7 +277,7 @@ exports.grantTier = async (req, res) => {
|
||||
const expiresAt = new Date(startsAt.getTime() + plan.duration_days * 86400000);
|
||||
|
||||
const newTier = await mdl_UserTiers.create({
|
||||
user_id, tier, status: 'active',
|
||||
user_id, tier, plan_id, status: 'active',
|
||||
starts_at: startsAt,
|
||||
expires_at: expiresAt,
|
||||
granted_by: req.user.user_id,
|
||||
|
||||
Reference in New Issue
Block a user