Files
gridpilot.gg/core/payments/application/use-cases/GetSponsorBillingUseCase.test.ts
Marc Mintel 9f219c0181
Some checks failed
CI / lint-typecheck (push) Failing after 4m52s
CI / tests (push) Has been skipped
CI / contract-tests (push) Has been skipped
CI / e2e-tests (push) Has been skipped
CI / comment-pr (push) Has been skipped
CI / commit-types (push) Has been skipped
core tests
2026-01-25 11:38:16 +01:00

127 lines
4.0 KiB
TypeScript

import { SeasonSponsorship } from '@core/racing/domain/entities/season/SeasonSponsorship';
import type { SeasonSponsorshipRepository } from '@core/racing/domain/repositories/SeasonSponsorshipRepository';
import { Money } from '@core/racing/domain/value-objects/Money';
import { describe, expect, it, vi, type Mock } from 'vitest';
import type { Payment } from '../../domain/entities/Payment';
import { PayerType, PaymentStatus, PaymentType } from '../../domain/entities/Payment';
import type { PaymentRepository } from '../../domain/repositories/PaymentRepository';
import type { SponsorRepository } from '@core/racing/domain/repositories/SponsorRepository';
import { GetSponsorBillingUseCase, type GetSponsorBillingInput } from './GetSponsorBillingUseCase';
describe('GetSponsorBillingUseCase', () => {
let paymentRepository: { findByFilters: Mock };
let seasonSponsorshipRepository: { findBySponsorId: Mock };
let sponsorRepository: { findById: Mock };
let useCase: GetSponsorBillingUseCase;
beforeEach(() => {
paymentRepository = {
findByFilters: vi.fn(),
};
seasonSponsorshipRepository = {
findBySponsorId: vi.fn(),
};
sponsorRepository = {
findById: vi.fn(),
};
useCase = new GetSponsorBillingUseCase(
paymentRepository as unknown as PaymentRepository,
seasonSponsorshipRepository as unknown as SeasonSponsorshipRepository,
sponsorRepository as unknown as SponsorRepository,
);
});
it('derives invoices and stats from payments and sponsorships', async () => {
const sponsorId = 'sponsor-1';
// Mock sponsor exists
sponsorRepository.findById.mockResolvedValue({
id: sponsorId,
name: 'Test Sponsor',
});
const payments: Payment[] = [
{
id: 'pay-1',
type: PaymentType.SPONSORSHIP,
amount: 100,
platformFee: 10,
netAmount: 90,
payerId: sponsorId,
payerType: PayerType.SPONSOR,
leagueId: 'league-1',
seasonId: 'season-1',
status: PaymentStatus.COMPLETED,
createdAt: new Date('2024-01-01T00:00:00.000Z'),
completedAt: new Date('2024-01-01T00:00:00.000Z'),
},
{
id: 'pay-2',
type: PaymentType.SPONSORSHIP,
amount: 50,
platformFee: 5,
netAmount: 45,
payerId: sponsorId,
payerType: PayerType.SPONSOR,
leagueId: 'league-1',
seasonId: 'season-1',
status: PaymentStatus.PENDING,
createdAt: new Date('2024-02-01T00:00:00.000Z'),
},
];
paymentRepository.findByFilters.mockResolvedValue(payments);
const sponsorships = [
SeasonSponsorship.create({
id: 'ss-1',
seasonId: 'season-1',
leagueId: 'league-1',
sponsorId,
tier: 'main',
pricing: Money.create(100, 'USD'),
status: 'active',
}),
SeasonSponsorship.create({
id: 'ss-2',
seasonId: 'season-2',
leagueId: 'league-1',
sponsorId,
tier: 'secondary',
pricing: Money.create(50, 'USD'),
status: 'pending',
}),
];
seasonSponsorshipRepository.findBySponsorId.mockResolvedValue(sponsorships);
const input: GetSponsorBillingInput = { sponsorId };
const result = await useCase.execute(input);
expect(result.isOk()).toBe(true);
const value = result.unwrap();
expect(paymentRepository.findByFilters).toHaveBeenCalledWith({
payerId: sponsorId,
type: PaymentType.SPONSORSHIP,
});
expect(seasonSponsorshipRepository.findBySponsorId).toHaveBeenCalledWith(sponsorId);
expect(value.paymentMethods).toEqual([]);
expect(value.invoices).toHaveLength(2);
// totals: each invoice adds 19% VAT
// pay-1 total: 100 + 19 = 119 (paid)
// pay-2 total: 50 + 9.5 = 59.5 (pending)
expect(value.stats.totalSpent).toBeCloseTo(119, 5);
expect(value.stats.pendingAmount).toBeCloseTo(59.5, 5);
expect(value.stats.activeSponsorships).toBe(1);
expect(value.stats.nextPaymentDate).not.toBeNull();
expect(value.stats.nextPaymentAmount).not.toBeNull();
});
});