feat: implement new costTypes

Grundpreis auf Zeit, sowie Privat Versicherung
This commit is contained in:
Marcel Arndt 2025-06-12 17:14:51 +02:00
parent 068fa9519c
commit 0fa97c53b1
12 changed files with 69 additions and 41 deletions

View File

@ -0,0 +1,8 @@
-- AlterEnum
ALTER TYPE "CostTypeVariant" ADD VALUE 'GRUNDPREIS_ZEIT';
-- AlterTable
ALTER TABLE "_AvicennaTenantToTariffGroup" ADD CONSTRAINT "_AvicennaTenantToTariffGroup_AB_pkey" PRIMARY KEY ("A", "B");
-- DropIndex
DROP INDEX "_AvicennaTenantToTariffGroup_AB_unique";

View File

@ -0,0 +1,2 @@
-- AlterEnum
ALTER TYPE "CostTypeVariant" ADD VALUE 'PRIVATVERSICHERUNG';

View File

@ -1,3 +1,3 @@
# Please do not edit this file manually # Please do not edit this file manually
# It should be added in your version-control system (i.e. Git) # It should be added in your version-control system (e.g., Git)
provider = "postgresql" provider = "postgresql"

View File

@ -526,6 +526,8 @@ enum CostTypeVariant {
FAHRZEUGZUSCHLAG FAHRZEUGZUSCHLAG
TSWDIFFERENZIERUNG TSWDIFFERENZIERUNG
GRUNDPREIS GRUNDPREIS
GRUNDPREIS_ZEIT
PRIVATVERSICHERUNG
} }
model AvicennaTenant { model AvicennaTenant {

View File

@ -192,19 +192,19 @@ export const BTW_AOK_TARIFFS = [
costTypes: [ costTypes: [
{ {
description: 'Grundpauschale je Fahrt', description: 'Grundpauschale je Fahrt',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.GRUNDPREIS_ZEIT,
costAmount: 4250, costAmount: 4250,
timeRange: '00:00-14:29', timeRange: '00:00-14:29',
}, },
{ {
description: 'Grundpauschale je Fahrt', description: 'Grundpauschale je Fahrt',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.GRUNDPREIS_ZEIT,
costAmount: 4250, costAmount: 4250,
timeRange: '18:01-23:59', timeRange: '18:01-23:59',
}, },
{ {
description: 'Grundpauschale je Fahrt (14:30-18:00)', description: 'Grundpauschale je Fahrt (14:30-18:00)',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.GRUNDPREIS_ZEIT,
costAmount: 5000, costAmount: 5000,
timeRange: '14:30-18:00', timeRange: '14:30-18:00',
}, },
@ -239,19 +239,19 @@ export const BTW_AOK_TARIFFS = [
costTypes: [ costTypes: [
{ {
description: 'Grundpauschale je Fahrt', description: 'Grundpauschale je Fahrt',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.GRUNDPREIS_ZEIT,
costAmount: 4500, costAmount: 4500,
timeRange: '00:00-14:29', timeRange: '00:00-14:29',
}, },
{ {
description: 'Grundpauschale je Fahrt', description: 'Grundpauschale je Fahrt',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.GRUNDPREIS_ZEIT,
costAmount: 4500, costAmount: 4500,
timeRange: '18:01-23:59', timeRange: '18:01-23:59',
}, },
{ {
description: 'Grundpauschale je Fahrt (14:30-18:00)', description: 'Grundpauschale je Fahrt (14:30-18:00)',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.GRUNDPREIS_ZEIT,
costAmount: 5000, costAmount: 5000,
timeRange: '14:30-18:00', timeRange: '14:30-18:00',
}, },

View File

@ -358,7 +358,7 @@ export const KTW_AOK_TARIFFS = [
costAmount: 940, costAmount: 940,
}, },
{ {
description: 'Desinfektionszuschlag pauschal', description: 'Desinfektionpauschale',
variant: CostTypeVariant.GRUNDPREIS, variant: CostTypeVariant.GRUNDPREIS,
costAmount: 2610, costAmount: 2610,
}, },
@ -369,10 +369,10 @@ export const KTW_AOK_TARIFFS = [
kmInclusive: 18, kmInclusive: 18,
}, },
{ {
description: 'Nachtzuschlag 19:00-07:00', description: 'Nachtzuschlag 18:30-06:30',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.NACHTZUSCHLAG,
costAmount: 8875, costAmount: 8875,
timeRange: '19:00-07:00', timeRange: '18:30-06:30',
}, },
{ {
description: 'Wochenendzuschlag', description: 'Wochenendzuschlag',

View File

@ -77,13 +77,13 @@ export const KTW_PRIVAT_TARIFFS = [
}, },
{ {
description: 'QMS Zuschlag', description: 'QMS Zuschlag',
variant: CostTypeVariant.GRUNDPREIS, variant: CostTypeVariant.PRIVATVERSICHERUNG,
costAmount: 3300, costAmount: 3300,
}, },
{ {
description: 'Hygienemaßnahmen', description: 'Hygienemaßnahmen',
variant: CostTypeVariant.GRUNDPREIS, variant: CostTypeVariant.PRIVATVERSICHERUNG,
costAmount: 1500, costAmount: 2000,
}, },
{ {
description: 'ab dem 16. km', description: 'ab dem 16. km',

View File

@ -185,19 +185,19 @@ export const TSW_AOK_TARIFFS = [
costTypes: [ costTypes: [
{ {
description: 'Grundpauschale je Fahrt', description: 'Grundpauschale je Fahrt',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.GRUNDPREIS_ZEIT,
costAmount: 6250, costAmount: 6250,
timeRange: '00:00-14:29', timeRange: '00:00-14:29',
}, },
{ {
description: 'Grundpauschale je Fahrt', description: 'Grundpauschale je Fahrt',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.GRUNDPREIS_ZEIT,
costAmount: 6250, costAmount: 6250,
timeRange: '18:01-23:59', timeRange: '18:01-23:59',
}, },
{ {
description: 'Nachmittagspauschale 14:30-18:00', description: 'Nachmittagspauschale 14:30-18:00',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.GRUNDPREIS_ZEIT,
costAmount: 7500, costAmount: 7500,
timeRange: '14:30-18:00', timeRange: '14:30-18:00',
}, },
@ -232,13 +232,19 @@ export const TSW_AOK_TARIFFS = [
costTypes: [ costTypes: [
{ {
description: 'Grundpauschale je Fahrt', description: 'Grundpauschale je Fahrt',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.GRUNDPREIS_ZEIT,
costAmount: 6500, costAmount: 6500,
timeRange: '00:00-14:29', timeRange: '00:00-14:29',
}, },
{
description: 'Nachmittagspauschale 14:30-18:00',
variant: CostTypeVariant.GRUNDPREIS_ZEIT,
costAmount: 7500,
timeRange: '14:30-18:00',
},
{ {
description: 'Grundpauschale je Fahrt', description: 'Grundpauschale je Fahrt',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.GRUNDPREIS_ZEIT,
costAmount: 6500, costAmount: 6500,
timeRange: '18:01-23:59', timeRange: '18:01-23:59',
}, },
@ -248,12 +254,6 @@ export const TSW_AOK_TARIFFS = [
costAmount: 200, costAmount: 200,
kmInclusive: 20, kmInclusive: 20,
}, },
{
description: 'Nachmittagszuschlag 14:30-18:00',
variant: CostTypeVariant.NACHTZUSCHLAG,
costAmount: 7500,
timeRange: '14:30-18:00',
},
{ {
description: 'Nachtzuschlag 18:00-07:30', description: 'Nachtzuschlag 18:00-07:30',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.NACHTZUSCHLAG,

View File

@ -77,13 +77,14 @@ export const TSW_DAK_VDEK_TARIFFS = [
}, },
{ {
description: 'Fallmanagementzuschlag', description: 'Fallmanagementzuschlag',
variant: CostTypeVariant.GRUNDPREIS, variant: CostTypeVariant.NACHTZUSCHLAG,
costAmount: 750, costAmount: 750,
timeRange: '14:30-18:00',
}, },
{ {
description: 'Morgenzuschlag 05:00-07:00', description: 'Morgenzuschlag 05:00-07:00',
variant: CostTypeVariant.NACHTZUSCHLAG, variant: CostTypeVariant.NACHTZUSCHLAG,
costAmount: 450, costAmount: 445,
timeRange: '05:00-07:00', timeRange: '05:00-07:00',
}, },
{ {

View File

@ -37,7 +37,9 @@ export const CostTypeVariant = {
KILOMETERZUSCHLAG: "KILOMETERZUSCHLAG", KILOMETERZUSCHLAG: "KILOMETERZUSCHLAG",
FAHRZEUGZUSCHLAG: "FAHRZEUGZUSCHLAG", FAHRZEUGZUSCHLAG: "FAHRZEUGZUSCHLAG",
TSWDIFFERENZIERUNG: "TSWDIFFERENZIERUNG", TSWDIFFERENZIERUNG: "TSWDIFFERENZIERUNG",
GRUNDPREIS: "GRUNDPREIS" GRUNDPREIS: "GRUNDPREIS",
GRUNDPREIS_ZEIT: "GRUNDPREIS_ZEIT",
PRIVATVERSICHERUNG: "PRIVATVERSICHERUNG"
} as const; } as const;
export type CostTypeVariant = (typeof CostTypeVariant)[keyof typeof CostTypeVariant]; export type CostTypeVariant = (typeof CostTypeVariant)[keyof typeof CostTypeVariant];
export type Anomaly = { export type Anomaly = {

View File

@ -17,6 +17,7 @@ import {
calculateFeiertagszuschlag, calculateFeiertagszuschlag,
calculateKilometerzuschlag, calculateKilometerzuschlag,
calculateNachtzuschlag, calculateNachtzuschlag,
calculatePrivatVersicherung,
calculateTSW, calculateTSW,
calculateWochenendzuschlag, calculateWochenendzuschlag,
} from './cost-type-calculations'; } from './cost-type-calculations';
@ -51,7 +52,7 @@ export class CalculationService {
); );
if (!tariff) { if (!tariff) {
this.logger.warn( this.logger.warn(
`No tariff found for tour ${tour.operationId} (${tour.healthInsurance})`, `No tariff found for tour ${tour.operationId} (${healthInsurance}, ${ordinanceType})`,
); );
return 0; return 0;
} }
@ -78,7 +79,7 @@ export class CalculationService {
); );
if (!tariff) { if (!tariff) {
this.logger.warn( this.logger.warn(
`No tariff found for tour ${tour.operationId} (${healthInsurance}, ${ordinanceType}, ${startDate})`, `No tariff found for tour ${tour.operationId} (${healthInsurance}, ${ordinanceType})`,
); );
return { tariff: undefined, servicePositions: [] }; return { tariff: undefined, servicePositions: [] };
} }
@ -206,20 +207,17 @@ export class CalculationService {
): [CostType, number][] { ): [CostType, number][] {
const highestZuschlag = this.getHighestZuschlag(tour, tariff); const highestZuschlag = this.getHighestZuschlag(tour, tariff);
// if TariffGroup is VDEK KTW, sum up costTypes // if TariffGroup is VDEK KTW, sum up costTypes
const isVdek = tariff.tariffGroup?.description?.indexOf('VDEK KTW') > -1; const sumZuschlaege =
tariff.tariffGroup?.description?.indexOf('VDEK KTW') > -1 ||
tariff.tariffGroup?.description?.indexOf('Privat') > -1;
return tariff.costTypes return tariff.costTypes
.map((costType) => { .map((costType) => {
switch (costType.variant) { switch (costType.variant) {
case CostTypeVariant.GRUNDPREIS: case CostTypeVariant.GRUNDPREIS:
// TODO: decide if you need a CostTypeVariant for QMS Zuschlag and exclude the category there
if (
costType.description.indexOf('QMS') > -1 &&
tour.category === 'Privatfahrt Rechnung'
) {
return [costType, 0];
}
return [costType, costType.costAmount]; return [costType, costType.costAmount];
case CostTypeVariant.PRIVATVERSICHERUNG:
return [costType, calculatePrivatVersicherung(tour, costType)];
case CostTypeVariant.TSWDIFFERENZIERUNG: case CostTypeVariant.TSWDIFFERENZIERUNG:
return [costType, calculateTSW(tour, costType)]; return [costType, calculateTSW(tour, costType)];
case CostTypeVariant.DESINFEKTIONSZUSCHLAG: case CostTypeVariant.DESINFEKTIONSZUSCHLAG:
@ -228,15 +226,20 @@ export class CalculationService {
return [costType, calculateKilometerzuschlag(tour, costType)]; return [costType, calculateKilometerzuschlag(tour, costType)];
case CostTypeVariant.FAHRZEUGZUSCHLAG: case CostTypeVariant.FAHRZEUGZUSCHLAG:
return [costType, calculateFahrzeugzuschlag(tour, costType)]; return [costType, calculateFahrzeugzuschlag(tour, costType)];
case CostTypeVariant.GRUNDPREIS_ZEIT:
case CostTypeVariant.NACHTZUSCHLAG: case CostTypeVariant.NACHTZUSCHLAG:
if (highestZuschlag === CostTypeVariant.NACHTZUSCHLAG || isVdek) { if (
sumZuschlaege ||
highestZuschlag === CostTypeVariant.NACHTZUSCHLAG ||
costType.variant !== CostTypeVariant.NACHTZUSCHLAG
) {
return [costType, calculateNachtzuschlag(tour, costType)]; return [costType, calculateNachtzuschlag(tour, costType)];
} }
return [costType, 0]; return [costType, 0];
case CostTypeVariant.WOCHENENDZUSCHLAG: case CostTypeVariant.WOCHENENDZUSCHLAG:
if ( if (
highestZuschlag === CostTypeVariant.WOCHENENDZUSCHLAG || highestZuschlag === CostTypeVariant.WOCHENENDZUSCHLAG ||
isVdek sumZuschlaege
) { ) {
return [costType, calculateWochenendzuschlag(tour, costType)]; return [costType, calculateWochenendzuschlag(tour, costType)];
} }
@ -244,7 +247,7 @@ export class CalculationService {
case CostTypeVariant.FEIERTAGSZUSCHLAG: case CostTypeVariant.FEIERTAGSZUSCHLAG:
if ( if (
highestZuschlag === CostTypeVariant.FEIERTAGSZUSCHLAG || highestZuschlag === CostTypeVariant.FEIERTAGSZUSCHLAG ||
isVdek sumZuschlaege
) { ) {
return [costType, calculateFeiertagszuschlag(tour, costType)]; return [costType, calculateFeiertagszuschlag(tour, costType)];
} }

View File

@ -5,6 +5,16 @@ import { generateIntervalForTimeRange } from 'src/utils';
import { INFECTION_TYPES } from './infection-types'; import { INFECTION_TYPES } from './infection-types';
import { PUBLIC_HOLIDAYS_HH } from './public-holidays'; import { PUBLIC_HOLIDAYS_HH } from './public-holidays';
export function calculatePrivatVersicherung(tour: Tour, costType: CostType): number {
if(tour.category?.indexOf('Privatfahrt Rechnung') === -1 && tour.category?.indexOf('Barzahlung') === -1) {
if(costType.description === 'Hygienemaßnahmen' && tour.hasInfection) {
return 0;
}
return costType.costAmount;
}
return 0;
}
export function calculateDesinfektionszuschlag( export function calculateDesinfektionszuschlag(
tour: Tour, tour: Tour,
costType: CostType, costType: CostType,