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
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:
@@ -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
|
||||
|
||||
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')
|
||||
|
||||
@@ -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 .",
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user