refactor
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Use Case: AcceptSponsorshipRequestUseCase
|
||||
*
|
||||
*
|
||||
* Allows an entity owner to accept a sponsorship request.
|
||||
* This creates an active sponsorship and notifies the sponsor.
|
||||
*/
|
||||
@@ -15,23 +15,16 @@ import type { IWalletRepository } from '@core/payments/domain/repositories/IWall
|
||||
import type { ILeagueWalletRepository } from '../../domain/repositories/ILeagueWalletRepository';
|
||||
import { SeasonSponsorship } from '../../domain/entities/SeasonSponsorship';
|
||||
import type { AsyncUseCase } from '@core/shared/application';
|
||||
|
||||
export interface AcceptSponsorshipRequestDTO {
|
||||
requestId: string;
|
||||
respondedBy: string; // driverId of the person accepting
|
||||
}
|
||||
|
||||
export interface AcceptSponsorshipRequestResultDTO {
|
||||
requestId: string;
|
||||
sponsorshipId: string;
|
||||
status: 'accepted';
|
||||
acceptedAt: Date;
|
||||
platformFee: number;
|
||||
netAmount: number;
|
||||
}
|
||||
import { Result } from '@core/shared/result/Result';
|
||||
import {
|
||||
RacingDomainValidationError,
|
||||
RacingDomainInvariantError,
|
||||
} from '../../domain/errors/RacingDomainError';
|
||||
import type { AcceptSponsorshipRequestDTO } from '../dto/AcceptSponsorshipRequestDTO';
|
||||
import type { AcceptSponsorshipRequestResultDTO } from '../dto/AcceptSponsorshipRequestResultDTO';
|
||||
|
||||
export class AcceptSponsorshipRequestUseCase
|
||||
implements AsyncUseCase<AcceptSponsorshipRequestDTO, AcceptSponsorshipRequestResultDTO> {
|
||||
implements AsyncUseCase<AcceptSponsorshipRequestDTO, Result<AcceptSponsorshipRequestResultDTO, RacingDomainValidationError | RacingDomainInvariantError>> {
|
||||
constructor(
|
||||
private readonly sponsorshipRequestRepo: ISponsorshipRequestRepository,
|
||||
private readonly seasonSponsorshipRepo: ISeasonSponsorshipRepository,
|
||||
@@ -43,118 +36,113 @@ export class AcceptSponsorshipRequestUseCase
|
||||
private readonly logger: Logger,
|
||||
) {}
|
||||
|
||||
async execute(dto: AcceptSponsorshipRequestDTO): Promise<AcceptSponsorshipRequestResultDTO> {
|
||||
async execute(dto: AcceptSponsorshipRequestDTO): Promise<Result<AcceptSponsorshipRequestResultDTO, RacingDomainValidationError | RacingDomainInvariantError>> {
|
||||
this.logger.debug(`Attempting to accept sponsorship request: ${dto.requestId}`, { requestId: dto.requestId, respondedBy: dto.respondedBy });
|
||||
try {
|
||||
// Find the request
|
||||
const request = await this.sponsorshipRequestRepo.findById(dto.requestId);
|
||||
if (!request) {
|
||||
this.logger.warn(`Sponsorship request not found: ${dto.requestId}`, { requestId: dto.requestId });
|
||||
throw new Error('Sponsorship request not found');
|
||||
}
|
||||
|
||||
if (!request.isPending()) {
|
||||
this.logger.warn(`Cannot accept a ${request.status} sponsorship request: ${dto.requestId}`, { requestId: dto.requestId, status: request.status });
|
||||
throw new Error(`Cannot accept a ${request.status} sponsorship request`);
|
||||
}
|
||||
|
||||
this.logger.info(`Sponsorship request ${dto.requestId} found and is pending. Proceeding with acceptance.`, { requestId: dto.requestId });
|
||||
|
||||
// Accept the request
|
||||
const acceptedRequest = request.accept(dto.respondedBy);
|
||||
await this.sponsorshipRequestRepo.update(acceptedRequest);
|
||||
this.logger.debug(`Sponsorship request ${dto.requestId} accepted and updated in repository.`, { requestId: dto.requestId });
|
||||
|
||||
// If this is a season sponsorship, create the SeasonSponsorship record
|
||||
let sponsorshipId = `spons_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
if (request.entityType === 'season') {
|
||||
this.logger.debug(`Sponsorship request ${dto.requestId} is for a season. Creating SeasonSponsorship record.`, { requestId: dto.requestId, entityType: request.entityType });
|
||||
const season = await this.seasonRepository.findById(request.entityId);
|
||||
if (!season) {
|
||||
this.logger.warn(`Season not found for sponsorship request ${dto.requestId} and entityId ${request.entityId}`, { requestId: dto.requestId, entityId: request.entityId });
|
||||
throw new Error('Season not found for sponsorship request');
|
||||
}
|
||||
|
||||
const sponsorship = SeasonSponsorship.create({
|
||||
id: sponsorshipId,
|
||||
seasonId: season.id,
|
||||
leagueId: season.leagueId,
|
||||
sponsorId: request.sponsorId,
|
||||
tier: request.tier,
|
||||
pricing: request.offeredAmount,
|
||||
status: 'active',
|
||||
});
|
||||
await this.seasonSponsorshipRepo.create(sponsorship);
|
||||
this.logger.info(`Season sponsorship ${sponsorshipId} created for request ${dto.requestId}.`, { sponsorshipId, requestId: dto.requestId });
|
||||
|
||||
// Notify the sponsor
|
||||
await this.notificationService.sendNotification({
|
||||
recipientId: request.sponsorId,
|
||||
type: 'sponsorship_request_accepted',
|
||||
title: 'Sponsorship Accepted',
|
||||
body: `Your sponsorship request for ${season.name} has been accepted.`,
|
||||
channel: 'in_app',
|
||||
urgency: 'toast',
|
||||
data: {
|
||||
requestId: request.id,
|
||||
sponsorshipId,
|
||||
},
|
||||
});
|
||||
|
||||
// Process payment
|
||||
const paymentResult = await this.paymentGateway.processPayment(
|
||||
request.offeredAmount,
|
||||
request.sponsorId,
|
||||
`Sponsorship payment for ${request.entityType} ${request.entityId}`,
|
||||
{ requestId: request.id }
|
||||
);
|
||||
if (!paymentResult.success) {
|
||||
this.logger.error(`Payment failed for sponsorship request ${request.id}: ${paymentResult.error}`, undefined, { requestId: request.id });
|
||||
throw new Error('Payment processing failed');
|
||||
}
|
||||
|
||||
// Update wallets
|
||||
const sponsorWallet = await this.walletRepository.findById(request.sponsorId);
|
||||
if (!sponsorWallet) {
|
||||
this.logger.error(`Sponsor wallet not found for ${request.sponsorId}`, undefined, { sponsorId: request.sponsorId });
|
||||
throw new Error('Sponsor wallet not found');
|
||||
}
|
||||
|
||||
const leagueWallet = await this.leagueWalletRepository.findById(season.leagueId);
|
||||
if (!leagueWallet) {
|
||||
this.logger.error(`League wallet not found for ${season.leagueId}`, undefined, { leagueId: season.leagueId });
|
||||
throw new Error('League wallet not found');
|
||||
}
|
||||
|
||||
const netAmount = acceptedRequest.getNetAmount();
|
||||
|
||||
// Deduct from sponsor wallet
|
||||
const updatedSponsorWallet = {
|
||||
...sponsorWallet,
|
||||
balance: sponsorWallet.balance - request.offeredAmount.amount,
|
||||
};
|
||||
await this.walletRepository.update(updatedSponsorWallet);
|
||||
|
||||
// Add to league wallet
|
||||
const updatedLeagueWallet = leagueWallet.addFunds(netAmount, paymentResult.transactionId!);
|
||||
await this.leagueWalletRepository.update(updatedLeagueWallet);
|
||||
}
|
||||
|
||||
this.logger.info(`Sponsorship request ${acceptedRequest.id} successfully accepted.`, { requestId: acceptedRequest.id, sponsorshipId });
|
||||
|
||||
return {
|
||||
requestId: acceptedRequest.id,
|
||||
sponsorshipId,
|
||||
status: 'accepted',
|
||||
acceptedAt: acceptedRequest.respondedAt!,
|
||||
platformFee: acceptedRequest.getPlatformFee().amount,
|
||||
netAmount: acceptedRequest.getNetAmount().amount,
|
||||
};
|
||||
} catch (error) {
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
this.logger.error(`Failed to accept sponsorship request ${dto.requestId}: ${err.message}`, err, { requestId: dto.requestId });
|
||||
throw err;
|
||||
// Find the request
|
||||
const request = await this.sponsorshipRequestRepo.findById(dto.requestId);
|
||||
if (!request) {
|
||||
this.logger.warn(`Sponsorship request not found: ${dto.requestId}`, { requestId: dto.requestId });
|
||||
return Result.err(new RacingDomainValidationError('Sponsorship request not found'));
|
||||
}
|
||||
|
||||
if (!request.isPending()) {
|
||||
this.logger.warn(`Cannot accept a ${request.status} sponsorship request: ${dto.requestId}`, { requestId: dto.requestId, status: request.status });
|
||||
return Result.err(new RacingDomainValidationError(`Cannot accept a ${request.status} sponsorship request`));
|
||||
}
|
||||
|
||||
this.logger.info(`Sponsorship request ${dto.requestId} found and is pending. Proceeding with acceptance.`, { requestId: dto.requestId });
|
||||
|
||||
// Accept the request
|
||||
const acceptedRequest = request.accept(dto.respondedBy);
|
||||
await this.sponsorshipRequestRepo.update(acceptedRequest);
|
||||
this.logger.debug(`Sponsorship request ${dto.requestId} accepted and updated in repository.`, { requestId: dto.requestId });
|
||||
|
||||
// If this is a season sponsorship, create the SeasonSponsorship record
|
||||
let sponsorshipId = `spons_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
if (request.entityType === 'season') {
|
||||
this.logger.debug(`Sponsorship request ${dto.requestId} is for a season. Creating SeasonSponsorship record.`, { requestId: dto.requestId, entityType: request.entityType });
|
||||
const season = await this.seasonRepository.findById(request.entityId);
|
||||
if (!season) {
|
||||
this.logger.warn(`Season not found for sponsorship request ${dto.requestId} and entityId ${request.entityId}`, { requestId: dto.requestId, entityId: request.entityId });
|
||||
return Result.err(new RacingDomainValidationError('Season not found for sponsorship request'));
|
||||
}
|
||||
|
||||
const sponsorship = SeasonSponsorship.create({
|
||||
id: sponsorshipId,
|
||||
seasonId: season.id,
|
||||
leagueId: season.leagueId,
|
||||
sponsorId: request.sponsorId,
|
||||
tier: request.tier,
|
||||
pricing: request.offeredAmount,
|
||||
status: 'active',
|
||||
});
|
||||
await this.seasonSponsorshipRepo.create(sponsorship);
|
||||
this.logger.info(`Season sponsorship ${sponsorshipId} created for request ${dto.requestId}.`, { sponsorshipId, requestId: dto.requestId });
|
||||
|
||||
// Notify the sponsor
|
||||
await this.notificationService.sendNotification({
|
||||
recipientId: request.sponsorId,
|
||||
type: 'sponsorship_request_accepted',
|
||||
title: 'Sponsorship Accepted',
|
||||
body: `Your sponsorship request for ${season.name} has been accepted.`,
|
||||
channel: 'in_app',
|
||||
urgency: 'toast',
|
||||
data: {
|
||||
requestId: request.id,
|
||||
sponsorshipId,
|
||||
},
|
||||
});
|
||||
|
||||
// Process payment
|
||||
const paymentResult = await this.paymentGateway.processPayment(
|
||||
request.offeredAmount,
|
||||
request.sponsorId,
|
||||
`Sponsorship payment for ${request.entityType} ${request.entityId}`,
|
||||
{ requestId: request.id }
|
||||
);
|
||||
if (!paymentResult.success) {
|
||||
this.logger.error(`Payment failed for sponsorship request ${request.id}: ${paymentResult.error}`, undefined, { requestId: request.id });
|
||||
return Result.err(new RacingDomainInvariantError('Payment processing failed'));
|
||||
}
|
||||
|
||||
// Update wallets
|
||||
const sponsorWallet = await this.walletRepository.findById(request.sponsorId);
|
||||
if (!sponsorWallet) {
|
||||
this.logger.error(`Sponsor wallet not found for ${request.sponsorId}`, undefined, { sponsorId: request.sponsorId });
|
||||
return Result.err(new RacingDomainInvariantError('Sponsor wallet not found'));
|
||||
}
|
||||
|
||||
const leagueWallet = await this.leagueWalletRepository.findById(season.leagueId);
|
||||
if (!leagueWallet) {
|
||||
this.logger.error(`League wallet not found for ${season.leagueId}`, undefined, { leagueId: season.leagueId });
|
||||
return Result.err(new RacingDomainInvariantError('League wallet not found'));
|
||||
}
|
||||
|
||||
const netAmount = acceptedRequest.getNetAmount();
|
||||
|
||||
// Deduct from sponsor wallet
|
||||
const updatedSponsorWallet = {
|
||||
...sponsorWallet,
|
||||
balance: sponsorWallet.balance - request.offeredAmount.amount,
|
||||
};
|
||||
await this.walletRepository.update(updatedSponsorWallet);
|
||||
|
||||
// Add to league wallet
|
||||
const updatedLeagueWallet = leagueWallet.addFunds(netAmount, paymentResult.transactionId!);
|
||||
await this.leagueWalletRepository.update(updatedLeagueWallet);
|
||||
}
|
||||
|
||||
this.logger.info(`Sponsorship request ${acceptedRequest.id} successfully accepted.`, { requestId: acceptedRequest.id, sponsorshipId });
|
||||
|
||||
return Result.ok({
|
||||
requestId: acceptedRequest.id,
|
||||
sponsorshipId,
|
||||
status: 'accepted',
|
||||
acceptedAt: acceptedRequest.respondedAt!,
|
||||
platformFee: acceptedRequest.getPlatformFee().amount,
|
||||
netAmount: acceptedRequest.getNetAmount().amount,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user