127 lines
4.0 KiB
TypeScript
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();
|
|
});
|
|
}); |