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:
Jose Selesan
2026-06-29 15:55:20 -03:00
parent f490eecd11
commit e06bc12097
45 changed files with 2553 additions and 30 deletions

View 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);
}
});
});