mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
140 lines
6.5 KiB
JavaScript
140 lines
6.5 KiB
JavaScript
/***********************************************************************************************************************************************************************
|
|
* File Name: plan_prices.controller.js (admin)
|
|
* Type of Program: Controller
|
|
* Description: Admin CRUD for localized price overrides per tier plan.
|
|
* Routes: GET/POST/PUT/DELETE /admin/tiers/:id/prices[/:currency]
|
|
* Author: Kenneth Obsequio (@lash0000)
|
|
* Date Created: Jun. 29, 2026
|
|
***********************************************************************************************************************************************************************/
|
|
'use strict';
|
|
|
|
const mdl_TierPlans = require('../../models/tiers/tier_plans.mdl');
|
|
const mdl_PlanPrices = require('../../models/tiers/plan_prices.mdl');
|
|
const R = require('../../utils/response.util');
|
|
const logActivity = require('../../utils/logActivity.util');
|
|
const { isSupported, SUPPORTED_CURRENCIES, validateLocalizedPrice } = require('../../utils/currency.util');
|
|
|
|
// ─── GET /admin/tiers/:id/prices ─────────────────────────────────────────────
|
|
|
|
exports.getPrices = async (req, res) => {
|
|
try {
|
|
const plan = await mdl_TierPlans.findByPk(req.params.id);
|
|
if (!plan) return R.error(res, 'Plan not found.', 404);
|
|
|
|
const prices = await mdl_PlanPrices.findAll({
|
|
where: { plan_id: plan.plan_id },
|
|
order: [['currency', 'ASC']],
|
|
});
|
|
|
|
return R.success(res, 'Localized prices retrieved.', prices);
|
|
} catch (err) {
|
|
console.error('[ADMIN][GET PLAN PRICES]', err);
|
|
return R.error(res, 'Could not retrieve localized prices.', 500);
|
|
}
|
|
};
|
|
|
|
// ─── POST /admin/tiers/:id/prices ────────────────────────────────────────────
|
|
|
|
exports.addPrice = async (req, res) => {
|
|
try {
|
|
const plan = await mdl_TierPlans.findByPk(req.params.id);
|
|
if (!plan) return R.error(res, 'Plan not found.', 404);
|
|
|
|
const { currency, price } = req.body;
|
|
if (!currency || price === undefined) return R.error(res, 'currency and price are required.', 400);
|
|
if (!isSupported(currency)) return R.error(res, `Unsupported currency: ${currency}.`, 400);
|
|
if (currency === plan.currency) return R.error(res, `${currency} is already the plan's base currency.`, 400);
|
|
if (Number(price) < 0) return R.error(res, 'Price must be 0 or greater.', 400);
|
|
|
|
const exists = await mdl_PlanPrices.findOne({ where: { plan_id: plan.plan_id, currency } });
|
|
if (exists) return R.error(res, `A localized price for ${currency} already exists. Use PUT to update it.`, 409);
|
|
|
|
// ── Rate validation ────────────────────────────────────────────────────────
|
|
const validation = await validateLocalizedPrice(plan.price, plan.currency, price, currency);
|
|
if (validation.zone === 'block') return R.error(res, validation.message, 422);
|
|
|
|
const entry = await mdl_PlanPrices.create({
|
|
plan_id: plan.plan_id,
|
|
currency: currency.toUpperCase(),
|
|
price: Number(price),
|
|
});
|
|
|
|
logActivity(req.user?.user_id, 'add_plan_price', {
|
|
entityType: 'plan_price',
|
|
details: { plan_id: plan.plan_id, currency, price },
|
|
});
|
|
|
|
if (validation.zone === 'warn')
|
|
return res.status(201).json({ success: true, warning: true, message: validation.message, data: entry });
|
|
|
|
return R.success(res, 'Localized price added.', entry, 201);
|
|
} catch (err) {
|
|
console.error('[ADMIN][ADD PLAN PRICE]', err);
|
|
return R.error(res, 'Could not add localized price.', 500);
|
|
}
|
|
};
|
|
|
|
// ─── PUT /admin/tiers/:id/prices/:currency ───────────────────────────────────
|
|
|
|
exports.updatePrice = async (req, res) => {
|
|
try {
|
|
const { id, currency } = req.params;
|
|
const { price } = req.body;
|
|
|
|
if (price === undefined) return R.error(res, 'price is required.', 400);
|
|
if (Number(price) < 0) return R.error(res, 'Price must be 0 or greater.', 400);
|
|
|
|
const entry = await mdl_PlanPrices.findOne({ where: { plan_id: id, currency: currency.toUpperCase() } });
|
|
if (!entry) return R.error(res, `No localized price found for ${currency} on this plan.`, 404);
|
|
|
|
// ── Rate validation ────────────────────────────────────────────────────────
|
|
const plan = await mdl_TierPlans.findByPk(id);
|
|
const validation = await validateLocalizedPrice(plan.price, plan.currency, price, currency);
|
|
if (validation.zone === 'block') return R.error(res, validation.message, 422);
|
|
|
|
await entry.update({ price: Number(price) });
|
|
|
|
logActivity(req.user?.user_id, 'update_plan_price', {
|
|
entityType: 'plan_price',
|
|
details: { plan_id: id, currency, price },
|
|
});
|
|
|
|
if (validation.zone === 'warn')
|
|
return res.status(200).json({ success: true, warning: true, message: validation.message, data: entry });
|
|
|
|
return R.success(res, 'Localized price updated.', entry);
|
|
} catch (err) {
|
|
console.error('[ADMIN][UPDATE PLAN PRICE]', err);
|
|
return R.error(res, 'Could not update localized price.', 500);
|
|
}
|
|
};
|
|
|
|
// ─── DELETE /admin/tiers/:id/prices/:currency ────────────────────────────────
|
|
|
|
exports.removePrice = async (req, res) => {
|
|
try {
|
|
const { id, currency } = req.params;
|
|
|
|
const entry = await mdl_PlanPrices.findOne({ where: { plan_id: id, currency: currency.toUpperCase() } });
|
|
if (!entry) return R.error(res, `No localized price found for ${currency} on this plan.`, 404);
|
|
|
|
await entry.destroy();
|
|
|
|
logActivity(req.user?.user_id, 'remove_plan_price', {
|
|
entityType: 'plan_price',
|
|
details: { plan_id: id, currency },
|
|
});
|
|
|
|
return R.success(res, 'Localized price removed.');
|
|
} catch (err) {
|
|
console.error('[ADMIN][REMOVE PLAN PRICE]', err);
|
|
return R.error(res, 'Could not remove localized price.', 500);
|
|
}
|
|
};
|
|
|
|
// ─── GET /admin/currencies ────────────────────────────────────────────────────
|
|
|
|
exports.getCurrencies = async (_req, res) => {
|
|
return R.success(res, 'Supported currencies retrieved.', SUPPORTED_CURRENCIES);
|
|
};
|