implement latest changes to employee payroll process
- Add ContractDaysWeek - Add Sickness Days to employee export sheet - Add Gesundheitsbonus value per employee - Additional fixes
This commit is contained in:
+2
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "DyflexisEmployee" ADD COLUMN "contractDaysWeek" INTEGER NOT NULL DEFAULT 0;
|
||||
@@ -553,6 +553,7 @@ model DyflexisEmployee {
|
||||
surname String
|
||||
contractStart DateTime
|
||||
contractEnd DateTime?
|
||||
contractDaysWeek Int @default(0)
|
||||
contractHoursWeek Float
|
||||
contractSalaryHour Float
|
||||
contractTypeName String?
|
||||
|
||||
@@ -109,6 +109,7 @@ export type DyflexisEmployee = {
|
||||
surname: string;
|
||||
contractStart: Timestamp;
|
||||
contractEnd: Timestamp | null;
|
||||
contractDaysWeek: Generated<number>;
|
||||
contractHoursWeek: number;
|
||||
contractSalaryHour: number;
|
||||
contractTypeName: string | null;
|
||||
|
||||
+79
-12
@@ -1,9 +1,9 @@
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { SourceRepository } from './source.repository';
|
||||
import { ConfigService } from 'src/core/config/config.service';
|
||||
import { format, Interval } from 'date-fns';
|
||||
import {
|
||||
catchError,
|
||||
combineLatest,
|
||||
EMPTY,
|
||||
expand,
|
||||
forkJoin,
|
||||
@@ -12,11 +12,15 @@ import {
|
||||
Observable,
|
||||
of,
|
||||
reduce,
|
||||
switchMap,
|
||||
tap,
|
||||
switchMap
|
||||
} from 'rxjs';
|
||||
import { format, Interval } from 'date-fns';
|
||||
import { HolidayRaw, SickDaysRaw } from './source.interface';
|
||||
import { ConfigService } from 'src/core/config/config.service';
|
||||
import {
|
||||
EmployeeContractRaw,
|
||||
HolidayRaw,
|
||||
SickDaysRaw,
|
||||
} from './source.interface';
|
||||
import { SourceRepository } from './source.repository';
|
||||
|
||||
interface DyflexisAuthHeader {
|
||||
Cookie: string;
|
||||
@@ -40,11 +44,72 @@ export class DyflexisUserAccessExtractorsService {
|
||||
) {}
|
||||
|
||||
loadData(): Observable<any> {
|
||||
// return this.extractSicknessDays({
|
||||
// start: new Date('2025-01-01T00:00:00.000Z'),
|
||||
// end: new Date('2025-12-31T23:59:59.999Z'),
|
||||
// });
|
||||
return this.extractHolidays(new Date('2025-01-01T00:00:00.000Z'));
|
||||
return combineLatest([
|
||||
// this.extractWorkdays(),
|
||||
// this.extractSicknessDays({
|
||||
// start: new Date('2025-01-01T00:00:00.000Z'),
|
||||
// end: new Date('2025-12-31T23:59:59.999Z'),
|
||||
// }),
|
||||
this.extractHolidays(new Date('2025-01-01T00:00:00.000Z')),
|
||||
]);
|
||||
}
|
||||
|
||||
extractWorkdays(): Observable<any> {
|
||||
return this.dyflexisLogin(
|
||||
this.config.dyflexisAppUsername(),
|
||||
this.config.dyflexisAppPassword(),
|
||||
).pipe(
|
||||
switchMap((authHeader) =>
|
||||
forkJoin({
|
||||
authHeader: of(authHeader),
|
||||
employees: this.fetchEmployees(authHeader),
|
||||
}),
|
||||
),
|
||||
switchMap(({ authHeader, employees }) =>
|
||||
forkJoin(
|
||||
employees.map((employee) =>
|
||||
this.fetchWorkdaysForEmployee(authHeader, employee.id),
|
||||
),
|
||||
),
|
||||
),
|
||||
map((workdaysPerEmployee) => workdaysPerEmployee.flat(1)),
|
||||
switchMap((workdays) => from(this.repository.createWorkdays(workdays))),
|
||||
map((res) => {
|
||||
return { count: Number(res.at(0).numUpdatedRows) };
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
private fetchWorkdaysForEmployee(
|
||||
authHeader: DyflexisAuthHeader,
|
||||
employeeId: number,
|
||||
): Observable<{ employeeId: number; daysPerWeek: number }> {
|
||||
const endpoint = (employeeId: number) =>
|
||||
`hamburg/employees/contract/data/${employeeId}`;
|
||||
|
||||
return this.http
|
||||
.get<{
|
||||
contracts: EmployeeContractRaw[];
|
||||
}>(`${this.config.dyflexisAppBaseUrl()}${endpoint(employeeId)}`, {
|
||||
headers: {
|
||||
...authHeader,
|
||||
},
|
||||
})
|
||||
.pipe(
|
||||
map((response) =>
|
||||
response.data.contracts
|
||||
.sort(
|
||||
({ startDate: dateA }, { startDate: dateB }) =>
|
||||
new Date(dateB).getTime() - new Date(dateA).getTime(),
|
||||
)
|
||||
.map(({ daysPerWeek }) => daysPerWeek)
|
||||
.at(0),
|
||||
),
|
||||
map((daysPerWeek) => ({
|
||||
employeeId,
|
||||
daysPerWeek,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
extractHolidays(year: Date): Observable<any> {
|
||||
@@ -101,6 +166,9 @@ export class DyflexisUserAccessExtractorsService {
|
||||
return { bookDate, isLocked, isExcludedFromPayroll, employeeId };
|
||||
}),
|
||||
),
|
||||
catchError(() => {
|
||||
return [[]];
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -115,7 +183,6 @@ export class DyflexisUserAccessExtractorsService {
|
||||
employees: this.fetchEmployees(authHeader),
|
||||
}),
|
||||
),
|
||||
tap(({ employees }) => console.log(employees.length)),
|
||||
switchMap(({ authHeader, employees }) =>
|
||||
forkJoin(
|
||||
employees.map((employee) =>
|
||||
|
||||
+23
-3
@@ -67,7 +67,7 @@ export interface TourRaw {
|
||||
beifahrer?: string; // ID
|
||||
fahrerName?: string;
|
||||
fahrer?: string; // ID
|
||||
|
||||
|
||||
overRTW?: string;
|
||||
firmName?: string;
|
||||
schwerlast?: string;
|
||||
@@ -184,7 +184,6 @@ export interface FahrzeugItemDto {
|
||||
verordnungsart: string;
|
||||
}
|
||||
|
||||
|
||||
export interface SickDaysRaw {
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
@@ -198,4 +197,25 @@ export interface HolidayRaw {
|
||||
bookDate: string;
|
||||
isLocked: boolean;
|
||||
isExcludedFromPayroll: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export interface EmployeeContractRaw {
|
||||
id: number;
|
||||
officeId: number;
|
||||
employeeId: number;
|
||||
typeId: number;
|
||||
serial: string;
|
||||
daysPerWeek: number;
|
||||
hoursPerWeek: number;
|
||||
upperLimit: any;
|
||||
startDate: string;
|
||||
endDate: any;
|
||||
salaryAmount: number;
|
||||
salaryPeriod: number;
|
||||
salaryType: number;
|
||||
hourlySalary: number;
|
||||
active: boolean;
|
||||
workingPattern: any;
|
||||
isSyncedWithPayroll: boolean;
|
||||
lastLockDate: string;
|
||||
}
|
||||
|
||||
+18
-1
@@ -22,7 +22,7 @@ import {
|
||||
TourRaw,
|
||||
WorkTimeRaw,
|
||||
} from './source.interface';
|
||||
import { Kysely } from 'kysely';
|
||||
import { Kysely, sql } from 'kysely';
|
||||
import { KYSELY_CLIENT_PROVIDER_TOKEN } from 'src/core/database/database.module';
|
||||
import { DB } from 'src/core/database/types';
|
||||
|
||||
@@ -112,6 +112,23 @@ export class SourceRepository {
|
||||
});
|
||||
}
|
||||
|
||||
createWorkdays(workdays: { employeeId: number; daysPerWeek: number }[]) {
|
||||
const values = workdays.map(
|
||||
({ employeeId, daysPerWeek }) =>
|
||||
sql`(${employeeId}::int4, ${daysPerWeek}::int4)`,
|
||||
);
|
||||
|
||||
return this.db
|
||||
.with('v(id, days)', () => sql`(VALUES ${sql.join(values)})`)
|
||||
.updateTable('DyflexisEmployee as e')
|
||||
.set({
|
||||
contractDaysWeek: sql.ref('v.days'),
|
||||
})
|
||||
.from('v')
|
||||
.whereRef('e.id', '=', 'v.id')
|
||||
.execute();
|
||||
}
|
||||
|
||||
createPatients(
|
||||
patients: PatientRaw[],
|
||||
jobId: string,
|
||||
|
||||
Reference in New Issue
Block a user