104 lines
4.0 KiB
TypeScript
104 lines
4.0 KiB
TypeScript
import type { ISeasonSponsorshipRepository } from '../../domain/repositories/ISeasonSponsorshipRepository';
|
|
import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
|
|
import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
|
|
import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
|
|
import type { IRaceRepository } from '../../domain/repositories/IRaceRepository';
|
|
import type { AsyncUseCase } from '@core/shared/application';
|
|
import { Result } from '@core/shared/application/Result';
|
|
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
|
|
import type { SponsorshipDetailOutput } from '../ports/output/SponsorSponsorshipsOutputPort';
|
|
|
|
export interface GetSeasonSponsorshipsParams {
|
|
seasonId: string;
|
|
}
|
|
|
|
export interface GetSeasonSponsorshipsOutputPort {
|
|
seasonId: string;
|
|
sponsorships: SponsorshipDetailOutput[];
|
|
}
|
|
|
|
export class GetSeasonSponsorshipsUseCase
|
|
implements AsyncUseCase<GetSeasonSponsorshipsParams, GetSeasonSponsorshipsOutputPort | null, 'REPOSITORY_ERROR'>
|
|
{
|
|
constructor(
|
|
private readonly seasonSponsorshipRepository: ISeasonSponsorshipRepository,
|
|
private readonly seasonRepository: ISeasonRepository,
|
|
private readonly leagueRepository: ILeagueRepository,
|
|
private readonly leagueMembershipRepository: ILeagueMembershipRepository,
|
|
private readonly raceRepository: IRaceRepository,
|
|
) {}
|
|
|
|
async execute(
|
|
params: GetSeasonSponsorshipsParams,
|
|
): Promise<Result<GetSeasonSponsorshipsOutputPort | null, ApplicationErrorCode<'REPOSITORY_ERROR'>>> {
|
|
try {
|
|
const { seasonId } = params;
|
|
|
|
const season = await this.seasonRepository.findById(seasonId);
|
|
if (!season) {
|
|
return Result.ok(null);
|
|
}
|
|
|
|
const league = await this.leagueRepository.findById(season.leagueId);
|
|
if (!league) {
|
|
return Result.ok(null);
|
|
}
|
|
|
|
const sponsorships = await this.seasonSponsorshipRepository.findBySeasonId(seasonId);
|
|
|
|
// Pre-compute metrics shared across all sponsorships in this season
|
|
const memberships = await this.leagueMembershipRepository.getLeagueMembers(season.leagueId);
|
|
const driverCount = memberships.length;
|
|
|
|
const races = await this.raceRepository.findByLeagueId(season.leagueId);
|
|
const raceCount = races.length;
|
|
const completedRaces = races.filter(r => r.status === 'completed').length;
|
|
const impressions = completedRaces * driverCount * 100;
|
|
|
|
const sponsorshipDetails: SponsorshipDetailOutput[] = sponsorships.map(sponsorship => {
|
|
const platformFee = sponsorship.getPlatformFee();
|
|
const netAmount = sponsorship.getNetAmount();
|
|
|
|
return {
|
|
id: sponsorship.id,
|
|
leagueId: league.id,
|
|
leagueName: league.name,
|
|
seasonId: season.id,
|
|
seasonName: season.name,
|
|
...(season.startDate !== undefined ? { seasonStartDate: season.startDate } : {}),
|
|
...(season.endDate !== undefined ? { seasonEndDate: season.endDate } : {}),
|
|
tier: sponsorship.tier,
|
|
status: sponsorship.status,
|
|
pricing: {
|
|
amount: sponsorship.pricing.amount,
|
|
currency: sponsorship.pricing.currency,
|
|
},
|
|
platformFee: {
|
|
amount: platformFee.amount,
|
|
currency: platformFee.currency,
|
|
},
|
|
netAmount: {
|
|
amount: netAmount.amount,
|
|
currency: netAmount.currency,
|
|
},
|
|
metrics: {
|
|
drivers: driverCount,
|
|
races: raceCount,
|
|
completedRaces,
|
|
impressions,
|
|
},
|
|
createdAt: sponsorship.createdAt,
|
|
...(sponsorship.activatedAt !== undefined ? { activatedAt: sponsorship.activatedAt } : {}),
|
|
};
|
|
});
|
|
|
|
return Result.ok({
|
|
seasonId,
|
|
sponsorships: sponsorshipDetails,
|
|
});
|
|
} catch {
|
|
return Result.err({ code: 'REPOSITORY_ERROR', message: 'Failed to fetch season sponsorships' });
|
|
}
|
|
}
|
|
}
|