fix issues in core

This commit is contained in:
2025-12-23 15:38:50 +01:00
parent df5c20c5cc
commit 120d3bb1a1
125 changed files with 1005 additions and 793 deletions

View File

@@ -3,11 +3,14 @@
* Represents a monetary amount with currency and platform fee calculation
*/
import { RacingDomainValidationError } from '../errors/RacingDomainError';
import type { IValueObject } from '@core/shared/domain';
import { RacingDomainValidationError } from '../errors/RacingDomainError';
export type Currency = 'USD' | 'EUR' | 'GBP';
export const isCurrency = (value: string): value is Currency =>
value === 'USD' || value === 'EUR' || value === 'GBP';
export interface MoneyProps {
amount: number;
currency: Currency;
@@ -34,6 +37,7 @@ export class Money implements IValueObject<MoneyProps> {
return new Money(amount, currency);
}
// TODO i dont think platform fee must be coupled
/**
* Calculate platform fee (10%)
*/

View File

@@ -90,7 +90,51 @@ export class RaceIncidents implements IValueObject<IncidentRecord[]> {
return this.incidents.length === 0;
}
// Removed getSeverityScore, getSummary, and getIncidentTypeLabel to eliminate static data in core
/**
* Backwards-compatible helper for legacy "incident count" fields.
* Creates `count` placeholder incidents of type `other`.
*/
static fromLegacyIncidentsCount(count: number): RaceIncidents {
if (!Number.isFinite(count) || count <= 0) {
return new RaceIncidents();
}
const incidents: IncidentRecord[] = Array.from({ length: Math.floor(count) }, (_, index) => ({
type: 'other',
lap: index + 1,
penaltyPoints: 0,
}));
return new RaceIncidents(incidents);
}
/**
* A coarse severity score for incidents.
* Kept intentionally data-light: derived only from `penaltyPoints`.
*/
getSeverityScore(): number {
return this.getTotalPenaltyPoints();
}
/**
* Human-readable summary without hardcoded incident labels.
*/
getSummary(): string {
const total = this.getTotalCount();
if (total === 0) return 'Clean race';
const countsByType = new Map<IncidentType, number>();
for (const incident of this.incidents) {
countsByType.set(incident.type, (countsByType.get(incident.type) ?? 0) + 1);
}
const typeSummary = Array.from(countsByType.entries())
.sort(([a], [b]) => a.localeCompare(b))
.map(([type, n]) => `${type}:${n}`)
.join(', ');
return typeSummary.length > 0 ? `${total} incidents (${typeSummary})` : `${total} incidents`;
}
equals(other: IValueObject<IncidentRecord[]>): boolean {
const otherIncidents = other.props;

View File

@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest';
import { SessionType } from './SessionType';
import { SessionType, type SessionTypeValue } from './SessionType';
describe('SessionType', () => {
it('should create session type', () => {
@@ -9,8 +9,8 @@ describe('SessionType', () => {
});
it('should throw for invalid session type', () => {
expect(() => new SessionType('invalid' as any)).toThrow();
expect(() => new SessionType('' as any)).toThrow();
expect(() => new SessionType('invalid' as unknown as SessionTypeValue)).toThrow();
expect(() => new SessionType('' as unknown as SessionTypeValue)).toThrow();
});
it('should have static factory methods', () => {