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
+17 -7
View File
@@ -124,13 +124,23 @@ jobs:
node -e "require('@rollup/rollup-linux-arm64-gnu')"
fi
- run: npm run db:generate
- run: npm run type-check
- run: npm run test:api
- run: npm run test:frontends
- run: npm run db:deploy
- run: npx prisma db push --schema packages/database/prisma/schema.prisma
- run: npm run test:api:integration
- name: Generate database client
run: npm run db:generate
- name: Type check
run: npm run type-check
- name: Unit tests
run: npm run test:unit
- name: Apply test database migrations
run: npm run db:deploy
- name: Synchronize test database schema
run: npx prisma db push --schema packages/database/prisma/schema.prisma
- name: Integration tests
run: npm run test:integration
build-image:
name: Build & Push Docker Image
BIN
View File
Binary file not shown.
@@ -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')
+1
View File
@@ -8,6 +8,7 @@
"start": "next start -H 0.0.0.0 -p 3000",
"type-check": "tsc --noEmit",
"test": "vitest run",
"test:integration": "vitest run --config vitest.integration.config.ts",
"test:watch": "vitest",
"lint": "eslint . --max-warnings=0",
"format": "prettier --write .",
+3
View File
@@ -61,8 +61,11 @@
"test:dashboard": "npm run test --workspace @rentaldrivego/dashboard",
"test:admin": "npm run test --workspace @rentaldrivego/admin",
"test:homepage": "npm run test --workspace @rentaldrivego/homepage",
"test:homepage:integration": "npm run test:integration --workspace @rentaldrivego/homepage",
"test:carplace": "npm run test --workspace @rentaldrivego/carplace",
"test:frontends": "npm run test:dashboard && npm run test:admin && npm run test:homepage && npm run test:carplace",
"test:unit": "npm run test:api && npm run test:frontends",
"test:integration": "npm run test:api:integration && npm run test:homepage:integration",
"security:static": "node scripts/security-static-check.mjs",
"security:scan": "npm run security:static && npm audit --production"
},