fix issues in core

This commit is contained in:
2025-12-23 14:43:49 +01:00
parent 11492d1ff2
commit df5c20c5cc
62 changed files with 480 additions and 334 deletions

View File

@@ -2,13 +2,13 @@
* Enhanced Result entity with detailed incident tracking
*/
import { RacingDomainValidationError } from '../errors/RacingDomainError';
import type { IEntity } from '@core/shared/domain';
import { RacingDomainValidationError } from '../errors/RacingDomainError';
import { RaceIncidents, type IncidentRecord } from '../value-objects/RaceIncidents';
import { RaceId } from './RaceId';
import { DriverId } from './DriverId';
import { Position } from './result/Position';
import { RaceId } from './RaceId';
import { LapTime } from './result/LapTime';
import { Position } from './result/Position';
export class ResultWithIncidents implements IEntity<string> {
readonly id: string;
@@ -66,6 +66,7 @@ export class ResultWithIncidents implements IEntity<string> {
});
}
// TODO WE DONT NEED ANY LEGACY CODE WE ARE NOT EVEN LIVE
/**
* Create from legacy Result data (with incidents as number)
*/

View File

@@ -8,9 +8,9 @@ describe('SponsorshipRequest', () => {
const validProps = {
id: 'request-123',
sponsorId: 'sponsor-456',
entityType: 'driver',
entityType: 'driver' as SponsorableEntityType,
entityId: 'driver-789',
tier: 'main',
tier: 'main' as SponsorshipTier,
offeredAmount: validMoney,
};

View File

@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';
import { LeagueWallet } from './LeagueWallet';
import { Money } from '../value-objects/Money';
import { Money } from '../../value-objects/Money';
describe('LeagueWallet', () => {
it('should create a league wallet', () => {

View File

@@ -11,7 +11,7 @@ import type { Money } from '../../value-objects/Money';
import { Position } from '../championship/Position';
import { PrizeId } from './PrizeId';
import { PrizeStatus } from './PrizeStatus';
import { SeasonId } from '../SeasonId';
import { SeasonId } from '../season/SeasonId';
import { DriverId } from '../DriverId';
export interface PrizeProps {

View File

@@ -78,9 +78,9 @@ export class Sponsor implements IEntity<SponsorId> {
id: this.id,
name,
contactEmail,
logoUrl,
websiteUrl,
createdAt: this.createdAt,
...(logoUrl !== undefined ? { logoUrl } : {}),
...(websiteUrl !== undefined ? { websiteUrl } : {}),
});
}
}

View File

@@ -4,13 +4,14 @@
* Defines operations for Prize entity persistence
*/
import type { Prize, PrizeStatus } from '../entities/Prize';
import type { Prize } from '../entities/prize/Prize';
import type { PrizeStatusValue } from '../entities/prize/PrizeStatus';
export interface IPrizeRepository {
findById(id: string): Promise<Prize | null>;
findBySeasonId(seasonId: string): Promise<Prize[]>;
findByDriverId(driverId: string): Promise<Prize[]>;
findByStatus(status: PrizeStatus): Promise<Prize[]>;
findByStatus(status: PrizeStatusValue): Promise<Prize[]>;
findBySeasonAndPosition(seasonId: string, position: number): Promise<Prize | null>;
create(prize: Prize): Promise<Prize>;
update(prize: Prize): Promise<Prize>;

View File

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

View File

@@ -6,12 +6,12 @@ import type { SessionType } from '@core/racing/domain/types/SessionType';
import { PointsTable } from '@core/racing/domain/value-objects/PointsTable';
import type { BonusRule } from '@core/racing/domain/types/BonusRule';
import type { ChampionshipConfig } from '@core/racing/domain/types/ChampionshipConfig';
import { Result } from '@core/racing/domain/entities/Result';
import { Result } from '@core/racing/domain/entities/result/Result';
import type { Penalty } from '@core/racing/domain/entities/Penalty';
import type { ChampionshipType } from '@core/racing/domain/types/ChampionshipType';
import { makeDriverRef } from '../../testing/factories/racing/DriverRefFactory';
import { makePointsTable } from '../../testing/factories/racing/PointsTableFactory';
import { makeChampionshipConfig } from '../../testing/factories/racing/ChampionshipConfigFactory';
import { makeDriverRef } from '../../../testing/factories/racing/DriverRefFactory';
import { makePointsTable } from '../../../testing/factories/racing/PointsTableFactory';
import { makeChampionshipConfig } from '../../../testing/factories/racing/ChampionshipConfigFactory';
describe('EventScoringService', () => {

View File

@@ -6,6 +6,7 @@ import { RaceTimeOfDay } from '../value-objects/RaceTimeOfDay';
import type { Weekday } from '../types/Weekday';
import { weekdayToIndex } from '../types/Weekday';
import type { IDomainCalculationService } from '@core/shared/domain';
import { RacingDomainValidationError } from '../errors/RacingDomainError';
function cloneDate(date: Date): Date {
return new Date(date.getTime());
@@ -63,15 +64,15 @@ function generateWeeklyOrEveryNWeeksSlots(
const result: ScheduledRaceSlot[] = [];
const recurrence = schedule.recurrence;
const weekdays =
recurrence.kind === 'weekly' || recurrence.kind === 'everyNWeeks'
? recurrence.weekdays.getAll()
recurrence.props.kind === 'weekly' || recurrence.props.kind === 'everyNWeeks'
? recurrence.props.weekdays.getAll()
: [];
if (weekdays.length === 0) {
throw new RacingDomainValidationError('RecurrenceStrategy has no weekdays');
}
const intervalWeeks = recurrence.kind === 'everyNWeeks' ? recurrence.intervalWeeks : 1;
const intervalWeeks = recurrence.props.kind === 'everyNWeeks' ? recurrence.props.intervalWeeks : 1;
let anchorWeekStart = cloneDate(schedule.startDate);
let roundNumber = 1;
@@ -123,11 +124,11 @@ function findNthWeekdayOfMonth(base: Date, ordinal: 1 | 2 | 3 | 4, weekday: Week
function generateMonthlySlots(schedule: SeasonSchedule, maxRounds: number): ScheduledRaceSlot[] {
const result: ScheduledRaceSlot[] = [];
const recurrence = schedule.recurrence;
if (recurrence.kind !== 'monthlyNthWeekday') {
if (recurrence.props.kind !== 'monthlyNthWeekday') {
return result;
}
const { ordinal, weekday } = recurrence.monthlyPattern;
const { ordinal, weekday } = recurrence.props.monthlyPattern;
let currentMonthDate = new Date(
schedule.startDate.getFullYear(),
schedule.startDate.getMonth(),
@@ -168,7 +169,7 @@ export class SeasonScheduleGenerator {
const recurrence: RecurrenceStrategy = schedule.recurrence;
if (recurrence.kind === 'monthlyNthWeekday') {
if (recurrence.props.kind === 'monthlyNthWeekday') {
return generateMonthlySlots(schedule, maxRounds);
}

View File

@@ -4,12 +4,12 @@
* Utility functions for working with league membership roles.
*/
import type { MembershipRole } from '../entities/LeagueMembership';
import type { MembershipRoleValue } from '../entities/MembershipRole';
/**
* Role hierarchy (higher number = more authority)
*/
const ROLE_HIERARCHY: Record<MembershipRole, number> = {
const ROLE_HIERARCHY: Record<MembershipRoleValue, number> = {
member: 0,
steward: 1,
admin: 2,
@@ -19,21 +19,21 @@ const ROLE_HIERARCHY: Record<MembershipRole, number> = {
/**
* Check if a role is at least steward level
*/
export function isLeagueStewardOrHigherRole(role: MembershipRole): boolean {
export function isLeagueStewardOrHigherRole(role: MembershipRoleValue): boolean {
return ROLE_HIERARCHY[role] >= ROLE_HIERARCHY.steward;
}
/**
* Check if a role is at least admin level
*/
export function isLeagueAdminOrHigherRole(role: MembershipRole): boolean {
export function isLeagueAdminOrHigherRole(role: MembershipRoleValue): boolean {
return ROLE_HIERARCHY[role] >= ROLE_HIERARCHY.admin;
}
/**
* Check if a role is owner
*/
export function isLeagueOwnerRole(role: MembershipRole): boolean {
export function isLeagueOwnerRole(role: MembershipRoleValue): boolean {
return role === 'owner';
}
@@ -41,33 +41,33 @@ export function isLeagueOwnerRole(role: MembershipRole): boolean {
* Compare two roles
* Returns positive if role1 > role2, negative if role1 < role2, 0 if equal
*/
export function compareRoles(role1: MembershipRole, role2: MembershipRole): number {
export function compareRoles(role1: MembershipRoleValue, role2: MembershipRoleValue): number {
return ROLE_HIERARCHY[role1] - ROLE_HIERARCHY[role2];
}
/**
* Get role display name
*/
export function getRoleDisplayName(role: MembershipRole): string {
const names: Record<MembershipRole, string> = {
export function getRoleDisplayName(role: MembershipRoleValue): string {
const names: Record<MembershipRoleValue, string> = {
member: 'Member',
steward: 'Steward',
admin: 'Admin',
owner: 'Owner',
};
return names[role];
return names[role] || role;
}
/**
* Get all roles in order of hierarchy
*/
export function getAllRolesOrdered(): MembershipRole[] {
export function getAllRolesOrdered(): MembershipRoleValue[] {
return ['member', 'steward', 'admin', 'owner'];
}
/**
* Get roles that can be assigned (excludes owner as it's transferred, not assigned)
*/
export function getAssignableRoles(): MembershipRole[] {
export function getAssignableRoles(): MembershipRoleValue[] {
return ['member', 'steward', 'admin'];
}

View File

@@ -0,0 +1,21 @@
/**
* Domain Types: LeagueScoringPreset
*
* Local type definition for league scoring presets to avoid cross-module dependencies
*/
export type LeagueScoringPresetPrimaryChampionshipType =
| 'driver'
| 'team'
| 'nations'
| 'trophy';
export interface LeagueScoringPreset {
id: string;
name: string;
description: string;
primaryChampionshipType: LeagueScoringPresetPrimaryChampionshipType;
dropPolicySummary: string;
sessionSummary: string;
bonusSummary: string;
}

View File

@@ -104,10 +104,10 @@ export class RaceIncidents implements IValueObject<IncidentRecord[]> {
return sortedThis.every((incident, index) => {
const otherIncident = sortedOther[index];
return incident.type === otherIncident.type &&
incident.lap === otherIncident.lap &&
incident.description === otherIncident.description &&
incident.penaltyPoints === otherIncident.penaltyPoints;
return incident.type === otherIncident?.type &&
incident.lap === otherIncident?.lap &&
incident.description === otherIncident?.description &&
incident.penaltyPoints === otherIncident?.penaltyPoints;
});
}