Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ls1vMdg2GYqbnKZmPaX1ot
38 lines
2.4 KiB
JavaScript
38 lines
2.4 KiB
JavaScript
// Coupon codes (v1). The logic is in services/deals.ts, shared with /api/v2 (1.51.9).
|
|
const deals = require('../services/deals');
|
|
const { safeErrorMessage } = require('../utils/errorUtils');
|
|
const { listWhere } = require('../utils/campusScope');
|
|
const { getClientIp } = require('../utils/requestUtils');
|
|
const { scopeFor } = require('../utils/campusScope');
|
|
|
|
const ctxOf = async (req) => ({ scope: await scopeFor(req), ip: getClientIp(req) });
|
|
const fail = (res, error) => res.status(error.statusCode || 400).json({ message: safeErrorMessage(error), ...(error.code && !/^P\d/.test(error.code) ? { code: error.code } : {}) });
|
|
|
|
const actorOf = (req) => (req.user ? { id: req.user.id, role: req.user.role, email: req.user.email } : null);
|
|
const dateOrNull = (v) => { if (!v) return null; const d = new Date(v); return isNaN(d.getTime()) ? null : d; };
|
|
|
|
// @route GET /api/coupons — with use counts
|
|
const listCoupons = async (req, res) => { try { res.json(await deals.listCoupons(await ctxOf(req))); } catch (e) { fail(res, e); } };
|
|
// @route GET /api/coupons/:id — with its redemptions
|
|
const getCoupon = async (req, res) => { try { res.json(await deals.getCoupon(req.params.id, await ctxOf(req))); } catch (e) { fail(res, e); } };
|
|
// @route POST /api/coupons
|
|
const createCoupon = async (req, res) => { try { res.status(201).json(await deals.createCoupon(req.body || {}, req.user, await ctxOf(req))); } catch (e) { fail(res, e); } };
|
|
// @route PUT /api/coupons/:id
|
|
const updateCoupon = async (req, res) => { try { res.json(await deals.updateCoupon(req.params.id, req.body || {}, req.user, await ctxOf(req))); } catch (e) { fail(res, e); } };
|
|
// @route POST /api/coupons/validate — a code against a basket ({ valid: false } answers 400, as before)
|
|
const validateCode = async (req, res) => {
|
|
try {
|
|
const result = await deals.checkCode(req.body || {}, actorOf(req));
|
|
res.status(result.valid ? 200 : 400).json(result);
|
|
} catch (e) { fail(res, e); }
|
|
};
|
|
// @route GET /api/coupons/redemptions?eventIds=a,b&from=&to= — the Discounts report
|
|
const listRedemptions = async (req, res) => {
|
|
try {
|
|
const eventIds = String(req.query.eventIds || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
res.json(await deals.listRedemptions({ eventIds, from: dateOrNull(req.query.from), to: dateOrNull(req.query.to) }, await listWhere(req, 'event')));
|
|
} catch (e) { fail(res, e); }
|
|
};
|
|
|
|
module.exports = { listCoupons, getCoupon, createCoupon, updateCoupon, validateCode, listRedemptions };
|