fix stripe error
Build & Push / Pipeline Tests (push) Successful in 1m51s
Test / Type Check (all packages) (push) Successful in 55s
Build & Push / Build & Push Docker Image (push) Successful in 5m44s
Test / API Unit Tests (push) Successful in 1m12s
Test / Homepage Unit Tests (push) Successful in 47s
Test / Carplace Unit Tests (push) Successful in 46s
Test / Admin Unit Tests (push) Successful in 43s
Test / Dashboard Unit Tests (push) Successful in 44s
Test / API Integration Tests (push) Successful in 1m8s

This commit is contained in:
root
2026-08-09 13:44:11 -04:00
parent cfc3f371de
commit 10ca76fc1e
6 changed files with 58 additions and 22 deletions
@@ -74,18 +74,9 @@ webhookRouter.post('/webhooks/stripe', async (req, res, next) => {
} catch (err) { next(err) }
})
// ─── PayPal capture (auth but no subscription check) ──────────
// ─── Authenticated billing recovery/self-service ───────────────
router.post('/capture-paypal', requireCompanyAuth, requireTenant, requireSubscriptionFull, requireRole('OWNER'), async (req, res, next) => {
try {
const { paypalOrderId } = parseBody(capturePaypalSchema, req)
ok(res, await service.capturePaypal(req.companyId, paypalOrderId))
} catch (err) { next(err) }
})
// ─── Authenticated ─────────────────────────────────────────────
router.use(requireCompanyAuth, requireTenant, requireSubscriptionRead)
router.use(requireCompanyAuth, requireTenant)
router.get('/me', async (req, res, next) => {
try { ok(res, await service.getSubscription(req.companyId)) } catch (err) { next(err) }
@@ -103,34 +94,45 @@ router.get('/entitlement', async (req, res, next) => {
try { ok(res, await service.getEntitlement(req.companyId)) } catch (err) { next(err) }
})
router.post('/trial', requireSubscriptionFull, requireRole('OWNER'), async (req, res, next) => {
router.post('/trial', requireRole('OWNER'), async (req, res, next) => {
try {
const body = parseBody(startTrialSchema, req)
ok(res, await service.startTrial(req.companyId, body.plan, body.billingPeriod, body.currency))
} catch (err) { next(err) }
})
router.post('/checkout', requireSubscriptionFull, requireRole('OWNER'), async (req, res, next) => {
router.post('/checkout', requireRole('OWNER'), async (req, res, next) => {
try {
const body = parseBody(checkoutSchema, req)
ok(res, await service.checkout(req.companyId, body))
} catch (err) { next(err) }
})
router.post('/reactivate', requireSubscriptionFull, requireRole('OWNER'), async (req, res, next) => {
router.post('/reactivate', requireRole('OWNER'), async (req, res, next) => {
try {
const body = parseBody(reactivateSchema, req)
ok(res, await service.reactivate(req.companyId, body))
} catch (err) { next(err) }
})
router.post('/change-plan', requireSubscriptionFull, requireRole('OWNER'), async (req, res, next) => {
router.post('/change-plan', requireRole('OWNER'), async (req, res, next) => {
try {
const body = parseBody(changePlanSchema, req)
ok(res, await service.changePlan(req.companyId, body))
} catch (err) { next(err) }
})
router.post('/capture-paypal', requireRole('OWNER'), async (req, res, next) => {
try {
const { paypalOrderId } = parseBody(capturePaypalSchema, req)
ok(res, await service.capturePaypal(req.companyId, paypalOrderId))
} catch (err) { next(err) }
})
// ─── Active subscription actions ───────────────────────────────
router.use(requireSubscriptionRead)
router.post('/cancel', requireSubscriptionFull, requireRole('OWNER'), async (req, res, next) => {
try {
const { mode, reason } = parseBody(cancelSchema, req)
@@ -128,6 +128,26 @@ describe('Subscriptions API', () => {
expect(res.body.data.some((item: any) => item.id === invoice.id)).toBe(true)
})
it('allows expired subscriptions to read billing recovery data', async () => {
const { company, employee } = await createCompanyWithEmployee({ role: 'OWNER' })
const subscription = await prisma.subscription.update({
where: { companyId: company.id },
data: { status: 'EXPIRED' },
})
const invoice = await createSubscriptionInvoice(company.id, subscription.id)
const token = signEmployeeToken(employee.id, company.id, 'OWNER')
const [subscriptionRes, invoicesRes] = await Promise.all([
request(app).get('/api/v1/subscriptions/me').set(authHeader(token)),
request(app).get('/api/v1/subscriptions/invoices').set(authHeader(token)),
])
expect(subscriptionRes.status).toBe(200)
expect(subscriptionRes.body.data.status).toBe('EXPIRED')
expect(invoicesRes.status).toBe(200)
expect(invoicesRes.body.data.some((item: any) => item.id === invoice.id)).toBe(true)
})
it('changes the subscription plan for OWNER', async () => {
const res = await request(app)
.post('/api/v1/subscriptions/change-plan')