← back to Professional Directory

agents/api-agent/routes/subscriptions.js

97 lines

/**
 * /subscriptions — Stripe Checkout for paid tier upgrades.
 *
 *   POST /subscriptions/checkout       — { plan } → returns { url } for hosted Checkout
 *   GET  /subscriptions/mine            — current user's subscriptions
 *
 * Two products:
 *   - doctor_pro_monthly  → STRIPE_PRICE_DOCTOR_PRO env var
 *   - patient_plus_monthly → STRIPE_PRICE_PATIENT_PLUS env var
 *
 * Webhook handling lives in data_market.js (extended) — that file already
 * verifies signatures. Sub events upsert into the subscriptions table and
 * flip users.tier accordingly.
 */
const express = require('express');
const Stripe = require('stripe');
const { query } = require('../../shared/db');

const router = express.Router();

const STRIPE_KEY = process.env.STRIPE_SECRET_KEY || '';
const stripe = STRIPE_KEY ? new Stripe(STRIPE_KEY) : null;

const PLAN_PRICES = {
  doctor_pro_monthly:    process.env.STRIPE_PRICE_DOCTOR_PRO || '',
  patient_plus_monthly:  process.env.STRIPE_PRICE_PATIENT_PLUS || '',
};

router.use((req, res, next) => {
  if (!req.user) return res.status(401).json({ error: 'auth required' });
  if (!stripe) return res.status(503).json({ error: 'Stripe not configured (set STRIPE_SECRET_KEY + STRIPE_PRICE_DOCTOR_PRO + STRIPE_PRICE_PATIENT_PLUS)' });
  next();
});

router.post('/checkout', async (req, res, next) => {
  try {
    const plan = String(req.body?.plan || '');
    const priceId = PLAN_PRICES[plan];
    if (!priceId) return res.status(400).json({ error: 'unknown plan; allowed: ' + Object.keys(PLAN_PRICES).join(', ') });

    // Doctor pro plan only available to verified-doctor accounts.
    if (plan === 'doctor_pro_monthly' && req.user.role !== 'doctor' && req.user.role !== 'admin') {
      return res.status(403).json({ error: 'doctor_pro_monthly requires a verified doctor account; submit a claim at /doctor-claims first' });
    }

    // Reuse existing Stripe customer or create one.
    let customerId = req.user.stripe_customer_id;
    if (!customerId) {
      const c = await stripe.customers.create({
        email: req.user.email,
        metadata: { pd_user_id: String(req.user.id), pd_role: req.user.role },
      });
      customerId = c.id;
      await query('UPDATE users SET stripe_customer_id = $1 WHERE id = $2', [customerId, req.user.id]);
    }

    const session = await stripe.checkout.sessions.create({
      mode: 'subscription',
      customer: customerId,
      line_items: [{ price: priceId, quantity: 1 }],
      success_url: `${req.protocol}://${req.get('host')}/?subscribed=${plan}`,
      cancel_url:  `${req.protocol}://${req.get('host')}/?cancelled=1`,
      allow_promotion_codes: true,
      metadata: { pd_user_id: String(req.user.id), plan },
    });

    res.json({ url: session.url, plan });
  } catch (e) { next(e); }
});

router.get('/mine', async (req, res, next) => {
  try {
    const r = await query(`
      SELECT id, stripe_subscription_id, plan, status, current_period_end,
             cancel_at_period_end, started_at, ended_at
        FROM subscriptions
       WHERE user_id = $1
       ORDER BY id DESC
    `, [req.user.id]);
    res.json({ count: r.rowCount, rows: r.rows, current_tier: req.user.tier });
  } catch (e) { next(e); }
});

// Stripe Billing Portal redirect (manage card, cancel, etc).
router.get('/portal', async (req, res, next) => {
  try {
    if (!req.user.stripe_customer_id) return res.status(400).json({ error: 'no Stripe customer on file' });
    const portal = await stripe.billingPortal.sessions.create({
      customer: req.user.stripe_customer_id,
      return_url: `${req.protocol}://${req.get('host')}/`,
    });
    res.json({ url: portal.url });
  } catch (e) { next(e); }
});

module.exports = router;