Skip to content

Commit

Permalink
adding settings for warning limits
Browse files Browse the repository at this point in the history
  • Loading branch information
david-loe committed Aug 16, 2024
1 parent 3cb6c5a commit 8a69126
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 18 deletions.
2 changes: 2 additions & 0 deletions backend/data/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@
"lunch": 0.4
},
"maxTravelDayCount": 92,
"minHoursOfTravel": 8,
"minProfessionalShare": 0.5,
"secoundNightOnAirplaneLumpSumCountry": "AT",
"secoundNightOnShipOrFerryLumpSumCountry": "LU",
"toleranceStageDatesToApprovedTravelDates": 3,
Expand Down
6 changes: 4 additions & 2 deletions backend/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import Currency from './models/currency.js'
import HealthInsurance from './models/healthInsurance.js'
import Organisation from './models/organisation.js'
import Project from './models/project.js'
import { mergeDeep } from '../common/scripts.js'
import { getSettings } from './helper.js'

export async function connectDB() {
const first = mongoose.connection.readyState === 0
Expand All @@ -28,13 +30,13 @@ export function disconnectDB() {
}

export async function initDB() {
const DBsettings = (await mongoose.connection.collection('settings').findOne({})) as ISettings | null
const DBsettings = await getSettings()
if (DBsettings) {
if (DBsettings.version !== settings.version) {
DBsettings.migrateFrom = DBsettings.version
}
DBsettings.version = settings.version
const mergedSettings = Object.assign({}, settings, DBsettings)
const mergedSettings = mergeDeep({}, settings, DBsettings)
await mongoose.connection.collection('settings').findOneAndDelete({})
await mongoose.connection.collection('settings').insertOne(mergedSettings)
console.log(i18n.t('alerts.db.updatedSettings'))
Expand Down
2 changes: 1 addition & 1 deletion backend/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export async function checkForMigrations() {
fallBackLumpSumCountry: oldSettings.fallBackLumpSumCountry,
secoundNightOnAirplaneLumpSumCountry: oldSettings.secoundNightOnAirplaneLumpSumCountry,
secoundNightOnShipOrFerryLumpSumCountry: oldSettings.secoundNightOnShipOrFerryLumpSumCountry
}
} as any
await settings.save()
} else {
throw Error("Couldn't find settings")
Expand Down
4 changes: 3 additions & 1 deletion backend/models/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ export const settingsSchema = new Schema<Settings>({
factorOvernightLumpSumExceptions: { type: [{ type: String, ref: 'Country' }], required: true },
fallBackLumpSumCountry: { type: String, ref: 'Country', required: true },
secoundNightOnAirplaneLumpSumCountry: { type: String, ref: 'Country', required: true },
secoundNightOnShipOrFerryLumpSumCountry: { type: String, ref: 'Country', required: true }
secoundNightOnShipOrFerryLumpSumCountry: { type: String, ref: 'Country', required: true },
minHoursOfTravel: {type: Number, min: 0, required: true},
minProfessionalShare: {type: Number, min: 0, max: 1, required: true}
},
required: true
},
Expand Down
2 changes: 1 addition & 1 deletion common/forms/settings.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions common/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@
"balance": "Saldo",
"bankDetails": "Bankverbindung",
"breakfast": "Frühstück",
"breakfastCateringLumpSumCut": "Verpflegungspauschalenkürung fürs Frühstück",
"budget": "Budget",
"by": "von",
"cancel": "Abbrechen",
Expand Down Expand Up @@ -158,7 +157,6 @@
"description": "Beschreibung",
"destinationPlace": "Reiseziel",
"dinner": "Abendessen",
"dinnerCateringLumpSumCut": "Verpflegungspauschalenkürung fürs Abendessen",
"disableReportType": "Antragsarten deaktivieren",
"distance": "Entfernung [km]",
"distanceRefunds": "Entfernungspauschalen",
Expand Down Expand Up @@ -213,16 +211,18 @@
"location": "Ort",
"logo": "Logo",
"loseAccessAt": "Ablaufdatum",
"lumpSumCut": "Verpflegungspauschalenkürung",
"lumpSums": "Pauschalen",
"lumpSumsFrom": "Pauschalen von",
"lunch": "Mittagessen",
"lunchCateringLumpSumCut": "Verpflegungspauschalenkürung fürs Mittagessen",
"mailToInsurance": "E-Mail an Versicherung",
"mailXDaysBeforeDeletion": "Informationsmail vor dem Löschen - in Tagen",
"maxTravelDayCount": "Maximale Länge eine Dienstreise [Tage]",
"mergeUsers": "Benutzer zusammenführen",
"midnight": "24 Uhr",
"midnightCountries": "Erreichte Länder um Mitternacht",
"minHoursOfTravel": "Mindestdauer einer Reise [Stunden]",
"minProfessionalShare": "Minimaler betrieblicher Anteil einer Reise",
"mixed": "Gemischt",
"model": "Modell",
"models": "Modelle",
Expand Down Expand Up @@ -516,4 +516,4 @@
"5": "Fr",
"6": "Sa"
}
}
}
8 changes: 4 additions & 4 deletions common/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@
"balance": "Balance",
"bankDetails": "Bank details",
"breakfast": "Breakfast",
"breakfastCateringLumpSumCut": "Catering lump sum cut for breakfast",
"budget": "Budget",
"by": "by",
"cancel": "Cancel",
Expand Down Expand Up @@ -158,7 +157,6 @@
"description": "Description",
"destinationPlace": "Destination place",
"dinner": "Dinner",
"dinnerCateringLumpSumCut": "Catering flat rate reduction for dinner",
"disableReportType": "Deactivate application types",
"distance": "Distance [km]",
"distanceRefunds": "Distance refunds",
Expand Down Expand Up @@ -213,16 +211,18 @@
"location": "Location",
"logo": "Logo",
"loseAccessAt": "Expiration date",
"lumpSumCut": "Catering lump sum cut",
"lumpSums": "Lump sums",
"lumpSumsFrom": "Lump sums from",
"lunch": "Lunch",
"lunchCateringLumpSumCut": "Catering lump sum cut for lunch",
"mailToInsurance": "Mail to insurance",
"mailXDaysBeforeDeletion": "Receive notification mail before deletion - in days",
"maxTravelDayCount": "Maximum length of a business trip [days]",
"mergeUsers": "Merge Users",
"midnight": "12AM",
"midnightCountries": "Countries reached by midnight",
"minHoursOfTravel": "Minimum duration of a business trip [hours]",
"minProfessionalShare": "Minimum professional share of a business trip",
"mixed": "Mixed",
"model": "Model",
"models": "Models",
Expand Down Expand Up @@ -516,4 +516,4 @@
"5": "Fri",
"6": "Sat"
}
}
}
28 changes: 28 additions & 0 deletions common/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,31 @@ export class Base64 {
return string
}
}

/**
* Simple object check.
*/
export function isObject(item: any) {
return (item && typeof item === 'object' && !Array.isArray(item) && !(item instanceof Date));
}

/**
* Deep merge two objects.
*/
export function mergeDeep(target: any, ... sources:any) {
if (!sources.length) return target;
const source = sources.shift();

if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!isObject(target[key])) Object.assign(target, { [key]: {} });
mergeDeep(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
}
}
}

return mergeDeep(target, ...sources);
}
53 changes: 49 additions & 4 deletions common/travel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ export class TravelCalculator {

constructor(getCountryById: (id: CountryCode) => Promise<Country>, travelSettings: SettingsTravel) {
this.getCountryById = getCountryById
this.validator = new TravelValidator()
this.lumpSumCalculator = new LumpSumCalculator(this.getCountryById, travelSettings.fallBackLumpSumCountry)
this.validator = new TravelValidator(travelSettings)
this.updateSettings(travelSettings)
}

Expand All @@ -46,7 +47,8 @@ export class TravelCalculator {

updateSettings(travelSettings: SettingsTravel) {
this.travelSettings = travelSettings
this.lumpSumCalculator = new LumpSumCalculator(this.getCountryById, travelSettings.fallBackLumpSumCountry)
this.validator.updateSettings(travelSettings)
this.lumpSumCalculator.setFallBackLumpSumCountry(travelSettings.fallBackLumpSumCountry)
}

sort(travel: Travel) {
Expand Down Expand Up @@ -289,11 +291,28 @@ export class TravelCalculator {
}

type Invalid = { path: string; err: string | Error; val?: any }

type Warning = {name: string, val?: any, limit?: any}
export class TravelValidator {
travelSettings!: SettingsTravel

constructor(travelSettings: SettingsTravel) {
this.updateSettings(travelSettings)
}

updateSettings(travelSettings: SettingsTravel) {
this.travelSettings = travelSettings
}

validate(travel: Travel): Invalid[] {
return this.validateDates(travel).concat(this.validateCountries(travel))
}

/**
* checks a travel for warnings
*/
check(travel: Travel): Warning[]{
return this.checkProfessionalShare(travel).concat(this.checkTravelLength(travel))
}

validateDates(travel: Travel): Invalid[] {
const conflicts = new Set<Invalid>()
Expand Down Expand Up @@ -343,16 +362,42 @@ export class TravelValidator {
}
return conflicts
}

checkTravelLength(travel: Travel): Warning[] {
const warnings: Warning[] = []
const cs = travel.stages.length
if(cs > 0){
const travelLength = (new Date(travel.stages[cs - 1].arrival)).valueOf() - (new Date(travel.stages[0].departure)).valueOf()
const limit = this.travelSettings.minHoursOfTravel * 1000 *60 *60
if(travelLength < limit){
warnings.push({name: 'travelLengthToShort', val: travelLength, limit: limit})
}
}
return warnings
}

checkProfessionalShare(travel: Travel): Warning[] {
const warnings: Warning[] = []
if(travel.professionalShare !== null && travel.professionalShare < this.travelSettings.minProfessionalShare){
warnings.push({name:'professionalShareToSmall', val: travel.professionalShare, limit: this.travelSettings.minProfessionalShare})
}
return warnings
}
}

export default class LumpSumCalculator {
fallBackLumpSumCountry: CountryCode
fallBackLumpSumCountry!: CountryCode
getCountryById: (id: CountryCode) => Promise<Country>

constructor(getCountryById: (id: CountryCode) => Promise<Country>, fallBackLumpSumCountry: CountryCode) {
this.getCountryById = getCountryById
this.setFallBackLumpSumCountry(fallBackLumpSumCountry)
}

setFallBackLumpSumCountry(fallBackLumpSumCountry: CountryCode){
this.fallBackLumpSumCountry = fallBackLumpSumCountry
}

async getLumpSum(country: Country, date: Date, special: string | undefined = undefined): Promise<LumpSum> {
if (country.lumpSumsFrom) {
const lumpSumFrom = await this.getCountryById(country.lumpSumsFrom)
Expand Down
2 changes: 2 additions & 0 deletions common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export interface SettingsTravel {
fallBackLumpSumCountry: CountryCode
secoundNightOnAirplaneLumpSumCountry: CountryCode
secoundNightOnShipOrFerryLumpSumCountry: CountryCode
minHoursOfTravel: number
minProfessionalShare: number
}

/**
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/travel/TravelPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
<label class="form-check-label me-2" for="travelProfessionalShare">
{{ $t('labels.professionalShare') + ':' }}
</label>
<span id="travelProfessionalShare" :class="travel.professionalShare <= 0.5 ? 'text-danger' : ''">
<span id="travelProfessionalShare" :class="travel.professionalShare <= $root.settings.travelSettings.minProfessionalShare ? 'text-danger' : ''">
{{ Math.round(travel.professionalShare * 100) + '%' }}</span
>
<InfoPoint class="ms-1" :text="$t('info.professionalShare')" />
Expand Down

0 comments on commit 8a69126

Please sign in to comment.