Files
fee-schedules/ts/feeschedules.classes.feeschedules.ts
T

136 lines
4.5 KiB
TypeScript
Raw Permalink Normal View History

2026-05-14 10:05:17 +00:00
import type {
ICountryFeeScheduleCatalog,
IFeeSchedule,
IFeeScheduleData,
IFeeScheduleFeeRow,
IFeeScheduleRuleSection,
} from './feeschedules.types.js';
import { GERMANY_FEE_SCHEDULE_CATALOG } from './feeschedules.germany.js';
import { GERMANY_FEE_SCHEDULE_DATA } from './germany/index.js';
export const FEE_SCHEDULE_CATALOGS: ICountryFeeScheduleCatalog[] = [
GERMANY_FEE_SCHEDULE_CATALOG,
];
export class FeeSchedules {
private catalogs: ICountryFeeScheduleCatalog[];
private data: IFeeScheduleData[];
constructor(
catalogs: ICountryFeeScheduleCatalog[] = FEE_SCHEDULE_CATALOGS,
data: IFeeScheduleData[] = GERMANY_FEE_SCHEDULE_DATA,
) {
this.catalogs = catalogs;
this.data = data;
}
public getCountries(): ICountryFeeScheduleCatalog[] {
return this.catalogs;
}
public getByCountry(countryCode: string): IFeeSchedule[] {
const catalog = this.getCatalog(countryCode);
return catalog?.schedules || [];
}
public getById(id: string): IFeeSchedule | undefined {
return this.getAll().find((schedule) => schedule.id === id);
}
public getDataByScheduleId(scheduleId: string): IFeeScheduleData | undefined {
return this.data.find((scheduleData) => scheduleData.scheduleId === scheduleId);
}
public getFeeRows(scheduleId: string): IFeeScheduleFeeRow[] {
return this.getDataByScheduleId(scheduleId)?.feeRows || [];
}
public getFeeRow(scheduleId: string, code: string): IFeeScheduleFeeRow | undefined {
const normalizedCode = normalizeSearchValue(code);
return this.getFeeRows(scheduleId).find((row) => {
return row.code ? normalizeSearchValue(row.code) === normalizedCode : false;
});
}
public getRuleSections(scheduleId: string): IFeeScheduleRuleSection[] {
return this.getDataByScheduleId(scheduleId)?.ruleSections || [];
}
public findByAbbreviation(abbreviation: string, countryCode?: string): IFeeSchedule | undefined {
const normalizedAbbreviation = normalizeSearchValue(abbreviation);
return this.getSchedules(countryCode).find(
(schedule) => normalizeSearchValue(schedule.abbreviation) === normalizedAbbreviation,
);
}
public search(query: string, countryCode?: string): IFeeSchedule[] {
const normalizedQuery = normalizeSearchValue(query);
if (!normalizedQuery) {
return [];
}
return this.getSchedules(countryCode).filter((schedule) => {
return [schedule.id, schedule.area, schedule.abbreviation, schedule.description]
.map((value) => normalizeSearchValue(value))
.some((value) => value.includes(normalizedQuery));
});
}
public searchFeeRows(query: string, scheduleId?: string): IFeeScheduleFeeRow[] {
const normalizedQuery = normalizeSearchValue(query);
if (!normalizedQuery) {
return [];
}
return this.getScheduleData(scheduleId)
.flatMap((scheduleData) => scheduleData.feeRows)
.filter((row) => {
return [row.id, row.code, row.description, ...row.cells]
.filter((value): value is string => Boolean(value))
.map((value) => normalizeSearchValue(value))
.some((value) => value.includes(normalizedQuery));
});
}
public searchRuleSections(query: string, scheduleId?: string): IFeeScheduleRuleSection[] {
const normalizedQuery = normalizeSearchValue(query);
if (!normalizedQuery) {
return [];
}
return this.getScheduleData(scheduleId)
.flatMap((scheduleData) => scheduleData.ruleSections)
.filter((section) => {
return [section.reference, section.title, section.text]
.filter((value): value is string => Boolean(value))
.map((value) => normalizeSearchValue(value))
.some((value) => value.includes(normalizedQuery));
});
}
private getAll(): IFeeSchedule[] {
return this.catalogs.flatMap((catalog) => catalog.schedules);
}
private getSchedules(countryCode?: string): IFeeSchedule[] {
return countryCode ? this.getByCountry(countryCode) : this.getAll();
}
private getScheduleData(scheduleId?: string): IFeeScheduleData[] {
return scheduleId
? this.data.filter((scheduleData) => scheduleData.scheduleId === scheduleId)
: this.data;
}
private getCatalog(countryCode: string): ICountryFeeScheduleCatalog | undefined {
const normalizedCountryCode = countryCode.toUpperCase();
return this.catalogs.find((catalog) => catalog.countryCode === normalizedCountryCode);
}
}
export const feeSchedules = new FeeSchedules();
const normalizeSearchValue = (value: string): string => {
return value.trim().toLocaleLowerCase('de-DE').replace(/\s+/g, ' ');
};