feat(billing): implement billing module with Stripe and Mercado Pago integration
- Add Stripe and Mercado Pago providers for handling subscriptions. - Create billing repository and access services for managing billing records. - Implement webhook handlers for processing events from Stripe and Mercado Pago. - Add routes for checkout, canceling subscriptions, and retrieving billing status. - Introduce billing status management with appropriate state transitions. - Create tests for billing functionalities including webhook idempotency and provider resolution. - Document the billing module architecture, environment variables, and API endpoints.
This commit is contained in:
66
apps/backend/test/billing/duplicate-subscription.test.ts
Normal file
66
apps/backend/test/billing/duplicate-subscription.test.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { describe, expect, it, mock } from 'bun:test';
|
||||
import { prismaMock } from '../support/prisma.mock';
|
||||
|
||||
describe('duplicate-subscription', () => {
|
||||
it('returns true when status is ACTIVE', async () => {
|
||||
prismaMock.complexBilling.findUnique.mockResolvedValue({
|
||||
status: 'ACTIVE',
|
||||
} as never);
|
||||
|
||||
const { hasActiveSubscription } = await import(
|
||||
'@/modules/billing/services/billing-repository.service'
|
||||
);
|
||||
|
||||
const result = await hasActiveSubscription('complex-active');
|
||||
expect(result.ok).toBe(true);
|
||||
if (result.ok) {
|
||||
expect(result.value).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it('returns true when status is TRIAL', async () => {
|
||||
prismaMock.complexBilling.findUnique.mockResolvedValue({
|
||||
status: 'TRIAL',
|
||||
} as never);
|
||||
|
||||
const { hasActiveSubscription } = await import(
|
||||
'@/modules/billing/services/billing-repository.service'
|
||||
);
|
||||
|
||||
const result = await hasActiveSubscription('complex-trial');
|
||||
expect(result.ok).toBe(true);
|
||||
if (result.ok) {
|
||||
expect(result.value).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it('returns false when status is CANCELED', async () => {
|
||||
prismaMock.complexBilling.findUnique.mockResolvedValue({
|
||||
status: 'CANCELED',
|
||||
} as never);
|
||||
|
||||
const { hasActiveSubscription } = await import(
|
||||
'@/modules/billing/services/billing-repository.service'
|
||||
);
|
||||
|
||||
const result = await hasActiveSubscription('complex-canceled');
|
||||
expect(result.ok).toBe(true);
|
||||
if (result.ok) {
|
||||
expect(result.value).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it('returns false when no billing record exists', async () => {
|
||||
prismaMock.complexBilling.findUnique.mockResolvedValue(null as never);
|
||||
|
||||
const { hasActiveSubscription } = await import(
|
||||
'@/modules/billing/services/billing-repository.service'
|
||||
);
|
||||
|
||||
const result = await hasActiveSubscription('complex-no-billing');
|
||||
expect(result.ok).toBe(true);
|
||||
if (result.ok) {
|
||||
expect(result.value).toBe(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user