fix issues in core

This commit is contained in:
2025-12-23 11:25:08 +01:00
parent 1efd971032
commit 2854ae3c5c
113 changed files with 1142 additions and 458 deletions

View File

@@ -39,12 +39,13 @@ export class JoinRequest implements IEntity<string> {
const id = props.id && props.id.trim().length > 0 ? props.id : `${props.leagueId}:${props.driverId}`;
const requestedAt = props.requestedAt ?? new Date();
const message = props.message;
return new JoinRequest({
id,
leagueId: props.leagueId,
driverId: props.driverId,
requestedAt,
message: props.message,
...(message !== undefined && { message }),
});
}

View File

@@ -11,6 +11,7 @@ import { MembershipRole, MembershipRoleValue } from './MembershipRole';
import { MembershipStatus, MembershipStatusValue } from './MembershipStatus';
import { JoinedAt } from '../value-objects/JoinedAt';
import { DriverId } from './DriverId';
import { JoinRequest } from './JoinRequest';
export interface LeagueMembershipProps {
id?: string;
@@ -82,4 +83,6 @@ export class LeagueMembership implements IEntity<string> {
throw new RacingDomainValidationError('Membership role is required');
}
}
}
}
export { MembershipRole, MembershipStatus, JoinRequest };

View File

@@ -94,23 +94,26 @@ export class Protest implements IEntity<string> {
const defenseRequestedAt = props.defenseRequestedAt ? DefenseRequestedAt.create(props.defenseRequestedAt) : undefined;
const defenseRequestedBy = props.defenseRequestedBy ? StewardId.create(props.defenseRequestedBy) : undefined;
return new Protest({
const protestProps: ProtestProps = {
id,
raceId,
protestingDriverId,
accusedDriverId,
incident,
comment,
proofVideoUrl,
status,
reviewedBy,
decisionNotes,
filedAt,
reviewedAt,
defense,
defenseRequestedAt,
defenseRequestedBy,
});
};
if (comment !== undefined) protestProps.comment = comment;
if (proofVideoUrl !== undefined) protestProps.proofVideoUrl = proofVideoUrl;
if (reviewedBy !== undefined) protestProps.reviewedBy = reviewedBy;
if (decisionNotes !== undefined) protestProps.decisionNotes = decisionNotes;
if (reviewedAt !== undefined) protestProps.reviewedAt = reviewedAt;
if (defense !== undefined) protestProps.defense = defense;
if (defenseRequestedAt !== undefined) protestProps.defenseRequestedAt = defenseRequestedAt;
if (defenseRequestedBy !== undefined) protestProps.defenseRequestedBy = defenseRequestedBy;
return new Protest(protestProps);
}
get id(): string { return this.props.id.toString(); }

View File

@@ -9,7 +9,7 @@ import { RacingDomainValidationError, RacingDomainInvariantError } from '../erro
import type { IEntity } from '@core/shared/domain';
import type { Money } from '../value-objects/Money';
import type { SponsorshipTier } from './SeasonSponsorship';
import type { SponsorshipTier } from './season/SeasonSponsorship';
export type SponsorableEntityType = 'driver' | 'team' | 'race' | 'season';
export type SponsorshipRequestStatus = 'pending' | 'accepted' | 'rejected' | 'withdrawn';

View File

@@ -0,0 +1 @@
export * from './Result';

View File

@@ -0,0 +1,3 @@
export * from './Season';
export * from './SeasonId';
export * from './SeasonSponsorship';

View File

@@ -30,8 +30,8 @@ export class Sponsor implements IEntity<SponsorId> {
this.id = props.id;
this.name = props.name;
this.contactEmail = props.contactEmail;
this.logoUrl = props.logoUrl;
this.websiteUrl = props.websiteUrl;
this.logoUrl = props.logoUrl ?? undefined;
this.websiteUrl = props.websiteUrl ?? undefined;
this.createdAt = props.createdAt;
}

View File

@@ -5,7 +5,9 @@
* Defines async methods using domain entities as types.
*/
import type { Car, CarClass, CarLicense } from '../entities/Car';
import type { Car } from '../entities/Car';
import type { CarClass } from '../entities/CarClass';
import type { CarLicense } from '../entities/CarLicense';
export interface ICarRepository {
/**

View File

@@ -1,4 +1,4 @@
import type { Season } from '../entities/Season';
import type { Season } from '../entities/season/Season';
export interface ISeasonRepository {
findById(id: string): Promise<Season | null>;

View File

@@ -4,7 +4,7 @@
* Defines operations for SeasonSponsorship aggregate persistence
*/
import type { SeasonSponsorship, SponsorshipTier } from '../entities/SeasonSponsorship';
import type { SeasonSponsorship, SponsorshipTier } from '../entities/season/SeasonSponsorship';
export interface ISeasonSponsorshipRepository {
findById(id: string): Promise<SeasonSponsorship | null>;

View File

@@ -1,7 +1,7 @@
import type { ChampionshipConfig } from '../types/ChampionshipConfig';
import type { SessionType } from '../types/SessionType';
import type { ParticipantRef } from '../types/ParticipantRef';
import type { Result } from '../entities/Result';
import type { Result } from '../entities/result/Result';
import type { Penalty } from '../entities/Penalty';
import type { BonusRule } from '../types/BonusRule';
import type { ChampionshipType } from '../types/ChampionshipType';
@@ -50,9 +50,9 @@ export class EventScoringService
const penaltyByDriver = new Map<string, number>();
for (const result of results) {
const driverId = result.driverId;
const driverId = result.driverId.toString();
const currentBase = baseByDriver.get(driverId) ?? 0;
const added = pointsTable.getPointsForPosition(result.position);
const added = pointsTable.getPointsForPosition(result.position.toNumber());
baseByDriver.set(driverId, currentBase + added);
}
@@ -112,7 +112,7 @@ export class EventScoringService
): void {
if (results.length === 0) return;
const sortedByLap = [...results].sort((a, b) => a.fastestLap - b.fastestLap);
const sortedByLap = [...results].sort((a, b) => a.fastestLap.toNumber() - b.fastestLap.toNumber());
const best = sortedByLap[0];
if (!best) {
@@ -121,13 +121,13 @@ export class EventScoringService
const requiresTop = rule.requiresFinishInTopN;
if (typeof requiresTop === 'number') {
if (best.position <= 0 || best.position > requiresTop) {
if (best.position.toNumber() <= 0 || best.position.toNumber() > requiresTop) {
return;
}
}
const current = bonusByDriver.get(best.driverId) ?? 0;
bonusByDriver.set(best.driverId, current + rule.points);
const current = bonusByDriver.get(best.driverId.toString()) ?? 0;
bonusByDriver.set(best.driverId.toString(), current + rule.points);
}
private aggregatePenalties(penalties: Penalty[]): Map<string, number> {

View File

@@ -82,4 +82,6 @@ export class RecurrenceStrategy implements IValueObject<RecurrenceStrategyProps>
return false;
}
}
}
}
export { RecurrenceStrategyFactory } from './RecurrenceStrategyFactory';

View File

@@ -0,0 +1,17 @@
import { WeekdaySet } from './WeekdaySet';
import { MonthlyRecurrencePattern } from './MonthlyRecurrencePattern';
import { RecurrenceStrategy } from './RecurrenceStrategy';
export class RecurrenceStrategyFactory {
static weekly(weekdays: WeekdaySet): RecurrenceStrategy {
return RecurrenceStrategy.weekly(weekdays);
}
static everyNWeeks(intervalWeeks: number, weekdays: WeekdaySet): RecurrenceStrategy {
return RecurrenceStrategy.everyNWeeks(intervalWeeks, weekdays);
}
static monthlyNthWeekday(pattern: MonthlyRecurrencePattern): RecurrenceStrategy {
return RecurrenceStrategy.monthlyNthWeekday(pattern);
}
}

View File

@@ -61,7 +61,7 @@ export class SeasonSchedule implements IValueObject<SeasonScheduleProps> {
a.startDate.getTime() === b.startDate.getTime() &&
a.timeOfDay.equals(b.timeOfDay) &&
a.timezone.equals(b.timezone) &&
a.recurrence.kind === b.recurrence.kind &&
a.recurrence.props.kind === b.recurrence.props.kind &&
a.plannedRounds === b.plannedRounds
);
}