153 lines
5.0 KiB
TypeScript
153 lines
5.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 { Result } from '@core/shared/application/Result';
|
|
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
|
|
export type GetSeasonSponsorshipsInput = {
|
|
seasonId: string;
|
|
};
|
|
|
|
export type SeasonSponsorshipMetrics = {
|
|
drivers: number;
|
|
races: number;
|
|
completedRaces: number;
|
|
impressions: number;
|
|
};
|
|
|
|
export type SeasonSponsorshipFinancials = {
|
|
amount: number;
|
|
currency: string;
|
|
};
|
|
|
|
export type SeasonSponsorshipDetail = {
|
|
id: string;
|
|
leagueId: string;
|
|
leagueName: string;
|
|
seasonId: string;
|
|
seasonName: string;
|
|
seasonStartDate?: Date;
|
|
seasonEndDate?: Date;
|
|
tier: string;
|
|
status: string;
|
|
pricing: SeasonSponsorshipFinancials;
|
|
platformFee: SeasonSponsorshipFinancials;
|
|
netAmount: SeasonSponsorshipFinancials;
|
|
metrics: SeasonSponsorshipMetrics;
|
|
createdAt: Date;
|
|
activatedAt?: Date;
|
|
};
|
|
|
|
export type GetSeasonSponsorshipsResult = {
|
|
seasonId: string;
|
|
sponsorships: SeasonSponsorshipDetail[];
|
|
};
|
|
|
|
export type GetSeasonSponsorshipsErrorCode =
|
|
| 'SEASON_NOT_FOUND'
|
|
| 'LEAGUE_NOT_FOUND'
|
|
| 'REPOSITORY_ERROR';
|
|
|
|
export class GetSeasonSponsorshipsUseCase {
|
|
constructor(private readonly seasonSponsorshipRepository: ISeasonSponsorshipRepository,
|
|
private readonly seasonRepository: ISeasonRepository,
|
|
private readonly leagueRepository: ILeagueRepository,
|
|
private readonly leagueMembershipRepository: ILeagueMembershipRepository,
|
|
private readonly raceRepository: IRaceRepository) {}
|
|
|
|
async execute(
|
|
input: GetSeasonSponsorshipsInput,
|
|
): Promise<Result<GetSeasonSponsorshipsResult, ApplicationErrorCode<GetSeasonSponsorshipsErrorCode, { message: string }>>> {
|
|
try {
|
|
const { seasonId } = input;
|
|
|
|
const season = await this.seasonRepository.findById(seasonId);
|
|
if (!season) {
|
|
return Result.err({
|
|
code: 'SEASON_NOT_FOUND',
|
|
details: {
|
|
message: 'Season not found',
|
|
},
|
|
});
|
|
}
|
|
|
|
const league = await this.leagueRepository.findById(season.leagueId);
|
|
if (!league) {
|
|
return Result.err({
|
|
code: 'LEAGUE_NOT_FOUND',
|
|
details: {
|
|
message: 'League not found for season',
|
|
},
|
|
});
|
|
}
|
|
|
|
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.isCompleted()).length;
|
|
const impressions = completedRaces * driverCount * 100;
|
|
|
|
const sponsorshipDetails: SeasonSponsorshipDetail[] = sponsorships.map((sponsorship) => {
|
|
const platformFee = sponsorship.getPlatformFee();
|
|
const netAmount = sponsorship.getNetAmount();
|
|
|
|
const detail: SeasonSponsorshipDetail = {
|
|
id: sponsorship.id,
|
|
leagueId: league.id.toString(),
|
|
leagueName: league.name.toString(),
|
|
seasonId: season.id,
|
|
seasonName: season.name,
|
|
tier: sponsorship.tier.toString(),
|
|
status: sponsorship.status.toString(),
|
|
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,
|
|
...(season.startDate ? { seasonStartDate: season.startDate } : {}),
|
|
...(season.endDate ? { seasonEndDate: season.endDate } : {}),
|
|
...(sponsorship.activatedAt ? { activatedAt: sponsorship.activatedAt } : {}),
|
|
};
|
|
|
|
return detail;
|
|
});
|
|
|
|
const result: GetSeasonSponsorshipsResult = {
|
|
seasonId,
|
|
sponsorships: sponsorshipDetails,
|
|
};
|
|
|
|
return Result.ok(result);
|
|
} catch (err) {
|
|
const error = err as { message?: string } | undefined;
|
|
|
|
return Result.err({
|
|
code: 'REPOSITORY_ERROR',
|
|
details: {
|
|
message: error?.message ?? 'Failed to fetch season sponsorships',
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|