mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
@@ -0,0 +1,139 @@
|
||||
/***********************************************************************************************************************************************************************
|
||||
* 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);
|
||||
};
|
||||
Reference in New Issue
Block a user