wip
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Use Case: ApplyForSponsorshipUseCase
|
||||
*
|
||||
* Allows a sponsor to apply for a sponsorship slot on any entity
|
||||
* (driver, team, race, or season/league).
|
||||
*/
|
||||
|
||||
import { SponsorshipRequest, type SponsorableEntityType } from '../../domain/entities/SponsorshipRequest';
|
||||
import type { SponsorshipTier } from '../../domain/entities/SeasonSponsorship';
|
||||
import type { ISponsorshipRequestRepository } from '../../domain/repositories/ISponsorshipRequestRepository';
|
||||
import type { ISponsorshipPricingRepository } from '../../domain/repositories/ISponsorshipPricingRepository';
|
||||
import type { ISponsorRepository } from '../../domain/repositories/ISponsorRepository';
|
||||
import { Money, type Currency } from '../../domain/value-objects/Money';
|
||||
|
||||
export interface ApplyForSponsorshipDTO {
|
||||
sponsorId: string;
|
||||
entityType: SponsorableEntityType;
|
||||
entityId: string;
|
||||
tier: SponsorshipTier;
|
||||
offeredAmount: number; // in cents
|
||||
currency?: Currency;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface ApplyForSponsorshipResultDTO {
|
||||
requestId: string;
|
||||
status: 'pending';
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export class ApplyForSponsorshipUseCase {
|
||||
constructor(
|
||||
private readonly sponsorshipRequestRepo: ISponsorshipRequestRepository,
|
||||
private readonly sponsorshipPricingRepo: ISponsorshipPricingRepository,
|
||||
private readonly sponsorRepo: ISponsorRepository,
|
||||
) {}
|
||||
|
||||
async execute(dto: ApplyForSponsorshipDTO): Promise<ApplyForSponsorshipResultDTO> {
|
||||
// Validate sponsor exists
|
||||
const sponsor = await this.sponsorRepo.findById(dto.sponsorId);
|
||||
if (!sponsor) {
|
||||
throw new Error('Sponsor not found');
|
||||
}
|
||||
|
||||
// Check if entity accepts sponsorship applications
|
||||
const pricing = await this.sponsorshipPricingRepo.findByEntity(dto.entityType, dto.entityId);
|
||||
if (!pricing) {
|
||||
throw new Error('This entity has not set up sponsorship pricing');
|
||||
}
|
||||
|
||||
if (!pricing.acceptingApplications) {
|
||||
throw new Error('This entity is not currently accepting sponsorship applications');
|
||||
}
|
||||
|
||||
// Check if the requested tier slot is available
|
||||
const slotAvailable = pricing.isSlotAvailable(dto.tier);
|
||||
if (!slotAvailable) {
|
||||
throw new Error(`No ${dto.tier} sponsorship slots are available`);
|
||||
}
|
||||
|
||||
// Check if sponsor already has a pending request for this entity
|
||||
const hasPending = await this.sponsorshipRequestRepo.hasPendingRequest(
|
||||
dto.sponsorId,
|
||||
dto.entityType,
|
||||
dto.entityId
|
||||
);
|
||||
if (hasPending) {
|
||||
throw new Error('You already have a pending sponsorship request for this entity');
|
||||
}
|
||||
|
||||
// Validate offered amount meets minimum price
|
||||
const minPrice = pricing.getPrice(dto.tier);
|
||||
if (minPrice && dto.offeredAmount < minPrice.amount) {
|
||||
throw new Error(`Offered amount must be at least ${minPrice.format()}`);
|
||||
}
|
||||
|
||||
// Create the sponsorship request
|
||||
const requestId = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
const offeredAmount = Money.create(dto.offeredAmount, dto.currency ?? 'USD');
|
||||
|
||||
const request = SponsorshipRequest.create({
|
||||
id: requestId,
|
||||
sponsorId: dto.sponsorId,
|
||||
entityType: dto.entityType,
|
||||
entityId: dto.entityId,
|
||||
tier: dto.tier,
|
||||
offeredAmount,
|
||||
message: dto.message,
|
||||
});
|
||||
|
||||
await this.sponsorshipRequestRepo.create(request);
|
||||
|
||||
return {
|
||||
requestId: request.id,
|
||||
status: 'pending',
|
||||
createdAt: request.createdAt,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user