mirror of
https://github.com/ever-co/ever-gauzy.git
synced 2026-10-02 01:54:50 +08:00
* chore(nx): migrate @nx/workspace to version 20.3.0 * chore(material): run migration-v19 for Angular Material update * chore(packages): run explicit-standalone-flag migration for Angular v19 * chore(deps): downgrade TypeScript to 5.5.4 for Angular compatibility * chore(deps): bump Angular ESLint dependencies to version 19 * chore(deps): bump @ng-select/ng-select to version 14.1.0 * chore(deps): bump @commitlint packages to latest versions * fix(cspell): typo spelling :-) * chore(packages): migrate initializers to new provider functions * chore(deps): update the @angular/cli package version to ~19.0.0 * chore(deps): update packages to support Angular v19 * chore(packages): migrate initializers to new provider functions * fix: correct Sentry.TraceService injection in AppInitializer * Update yarn.lock * Update yarn.lock * fix: update yarn.lock * fix(cspell): typo spelling :-) * fix: update yarn.lock * chore(deps): bump @angular/common to version 19.0.0 * chore(nx): migrate @nx/workspace to version 20.4.2 * chore(deps): update yarn.lock * chore(nx): migrate @nx/workspace to version 20.4.4 * chore(deps): bump @angular/core from 19.1.5 to 19.1.6 * chore(deps): upgrade @nebular/auth and @nebular/theme to v15 - Upgrade @nebular/auth from ^14.0.2 to ^15.0.0 - Upgrade @nebular/theme from ^14.0.2 to ^15.0.0 * chore(deps): bump @angular-slider/ngx-slider from ^18.0.0 to ^19.0.0 * chore(deps): bump ngx-page-scroll and ngx-page-scroll-core to v14 - Bump ngx-page-scroll from ^13.0.0 to ^14.0.0 - Bump ngx-page-scroll-core from ^13.0.0 to ^14.0.0 * chore(deps): bump ngx-permissions from ^17.1.0 to ^19.0.0 * chore(deps): bump @ng-select/ng-select from ^14.1.0 to ^14.2.2 * chore(deps): bump @fortawesome/angular-fontawesome from 0.15.0 to 1.0.0 * fix: desktop build (make component standalone disabled) * chore(deps): bump @angular/core from 18.2.12 to 19.1.6 * chore(nx): migrate @nx/workspace to version 20.8.0 * chore(deps): bump ng2-file-upload to version ^8.0.0 * chore(deps): bump @angular/core from 19.1.6 to 19.2.7 * chore(deps): bump @fullcalendar/core from ^6.1.15 to ^6.1.17 * chore(deps): bump @angular-eslint packages to v19.3.0 * fix: add `standalone: false` to angular components * chore(deps): downgrade @angular-builders/custom-webpack from v19.0.1 to v18.0.0 * chore(deps): bump angular2-smart-table from ^3.5.0 to ^3.6.1 * refactor(styles): replace @import with @use for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * chore(deps): bump @angular/core from 19.0.0 to 19.2.0 * chore(deps): updated dependencies for `@fullcalendar/angular` * fix(cspell): typo spelling :-) * Revert "chore(deps): updated dependencies for `@fullcalendar/angular`" This reverts commit4b34d72071. * chore(deps): switch @angular/* to ^19.2.7 * fix: revert nx migrations.json * Revert "chore(deps): switch @angular/* to ^19.2.7" This reverts commitedd9105c51. * fix: align @angular/cdk version with @angular/core version * chore(deps): bump @angular-builders/custom-webpack from 18.0.0 to 19.0.1 * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * refactor(styles): replace `@import` with `@use` for SCSS module * chore(deps): bump typescript from 5.5.4 to ^5.8.3 * fix(server-dashboard): remove redundant nullish coalescing from autoStart check * fix: add suggestions from greptile-apps bot review * fix: add suggestions from greptile-apps bot review
232 lines
6.6 KiB
TypeScript
232 lines
6.6 KiB
TypeScript
import { Component, OnDestroy, OnInit } from '@angular/core';
|
|
import { Router } from '@angular/router';
|
|
import {
|
|
BonusTypeEnum,
|
|
EmployeeStatisticsHistoryEnum,
|
|
IDateRangePicker,
|
|
IMonthAggregatedEmployeeStatistics,
|
|
IOrganization,
|
|
ISelectedEmployee
|
|
} from '@gauzy/contracts';
|
|
import { NbDialogService } from '@nebular/theme';
|
|
import { combineLatest } from 'rxjs';
|
|
import { debounceTime, filter, tap } from 'rxjs/operators';
|
|
import { Subject } from 'rxjs/internal/Subject';
|
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
|
import { distinctUntilChange, toUTC } from '@gauzy/ui-core/common';
|
|
import { DateRangePickerBuilderService, EmployeeStatisticsService, Store } from '@gauzy/ui-core/core';
|
|
import { ProfitHistoryComponent, RecordsHistoryComponent } from '@gauzy/ui-core/shared';
|
|
|
|
@UntilDestroy({ checkProperties: true })
|
|
@Component({
|
|
selector: 'ga-human-resources',
|
|
templateUrl: './human-resources.component.html',
|
|
styleUrls: ['./human-resources.component.scss'],
|
|
standalone: false
|
|
})
|
|
export class HumanResourcesComponent implements OnInit, OnDestroy {
|
|
loading: boolean;
|
|
|
|
selectedDate: Date;
|
|
selectedEmployee: ISelectedEmployee;
|
|
selectedOrganization: IOrganization;
|
|
selectedDateRange: IDateRangePicker;
|
|
|
|
defaultCurrency: string;
|
|
|
|
incomePermissionsError = false;
|
|
expensePermissionError = false;
|
|
|
|
employeeStatistics: IMonthAggregatedEmployeeStatistics[];
|
|
expense = 0;
|
|
expenseWithoutSalary: number;
|
|
income: number;
|
|
nonBonusIncome: number;
|
|
profit: number;
|
|
directIncomeBonus: number;
|
|
bonus: number;
|
|
calculatedBonus: number;
|
|
bonusType: BonusTypeEnum;
|
|
bonusPercentage: number;
|
|
salary: number;
|
|
averageBonus: number;
|
|
statistics$: Subject<any> = new Subject();
|
|
|
|
constructor(
|
|
private readonly store: Store,
|
|
private readonly dialogService: NbDialogService,
|
|
private readonly router: Router,
|
|
private readonly employeeStatisticsService: EmployeeStatisticsService,
|
|
private readonly dateRangePickerBuilderService: DateRangePickerBuilderService
|
|
) {}
|
|
|
|
async ngOnInit() {
|
|
this.statistics$
|
|
.pipe(
|
|
debounceTime(300),
|
|
tap(() => this.getEmployeeStatistics()),
|
|
untilDestroyed(this)
|
|
)
|
|
.subscribe();
|
|
const storeOrganization$ = this.store.selectedOrganization$;
|
|
const selectedDateRange$ = this.dateRangePickerBuilderService.selectedDateRange$;
|
|
const selectedEmployee$ = this.store.selectedEmployee$;
|
|
combineLatest([storeOrganization$, selectedDateRange$, selectedEmployee$])
|
|
.pipe(
|
|
debounceTime(300),
|
|
distinctUntilChange(),
|
|
filter(([organization, dateRange, employee]) => !!organization && !!dateRange && !!employee),
|
|
tap(([organization, dateRange, employee]) => {
|
|
this.selectedOrganization = organization;
|
|
this.selectedDateRange = dateRange;
|
|
this.selectedEmployee = employee;
|
|
}),
|
|
tap(() => {
|
|
if (!this.selectedEmployee || !this.selectedEmployee.id) {
|
|
this.navigateToAccounting();
|
|
return;
|
|
}
|
|
}),
|
|
tap(([organization]) => {
|
|
this.bonusType = organization.bonusType as BonusTypeEnum;
|
|
this.bonusPercentage = organization.bonusPercentage;
|
|
this.defaultCurrency = organization.currency;
|
|
}),
|
|
tap(() => this.statistics$.next(true)),
|
|
untilDestroyed(this)
|
|
)
|
|
.subscribe();
|
|
}
|
|
|
|
async getEmployeeStatistics() {
|
|
if (!this.selectedOrganization) {
|
|
return;
|
|
}
|
|
const { tenantId } = this.store.user;
|
|
const { id: organizationId } = this.selectedOrganization;
|
|
const { startDate, endDate } = this.selectedDateRange;
|
|
|
|
this.loading = true;
|
|
|
|
this.employeeStatistics = await this.employeeStatisticsService.getAggregatedStatisticsByEmployeeId({
|
|
employeeId: this.selectedEmployee.id,
|
|
startDate: toUTC(startDate).format('YYYY-MM-DD HH:mm:ss'),
|
|
endDate: toUTC(endDate).format('YYYY-MM-DD HH:mm:ss'),
|
|
organizationId,
|
|
tenantId
|
|
});
|
|
this.income = this._statsSum(this.employeeStatistics, 'income');
|
|
this.expenseWithoutSalary = this._statsSum(this.employeeStatistics, 'expenseWithoutSalary');
|
|
this.expense = this._statsSum(this.employeeStatistics, 'expense');
|
|
this.directIncomeBonus = this._statsSum(this.employeeStatistics, 'directIncomeBonus');
|
|
this.nonBonusIncome = this.income - this.directIncomeBonus;
|
|
this.profit = this._statsSum(this.employeeStatistics, 'profit');
|
|
this.bonus = this._statsSum(this.employeeStatistics, 'bonus');
|
|
this.calculatedBonus = +(this.bonus - this.directIncomeBonus).toFixed(2);
|
|
this.salary = +(this.expense - this.expenseWithoutSalary).toFixed(2);
|
|
|
|
this.loading = false;
|
|
}
|
|
|
|
async openHistoryDialog(type: EmployeeStatisticsHistoryEnum) {
|
|
if (!this.selectedOrganization) {
|
|
return;
|
|
}
|
|
const { id: organizationId, tenantId } = this.selectedOrganization;
|
|
const { startDate, endDate } = this.selectedDateRange;
|
|
|
|
this.dialogService.open(RecordsHistoryComponent, {
|
|
context: {
|
|
type,
|
|
records: await this.employeeStatisticsService.getEmployeeStatisticsHistory({
|
|
employeeId: this.selectedEmployee.id,
|
|
startDate,
|
|
endDate,
|
|
type,
|
|
organizationId,
|
|
tenantId
|
|
})
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @returns
|
|
*/
|
|
async openProfitDialog() {
|
|
if (!this.selectedOrganization) {
|
|
return;
|
|
}
|
|
|
|
const { id: organizationId, tenantId } = this.selectedOrganization;
|
|
const { startDate, endDate } = this.selectedDateRange;
|
|
|
|
const incomes = await this.employeeStatisticsService.getEmployeeStatisticsHistory({
|
|
employeeId: this.selectedEmployee.id,
|
|
startDate,
|
|
endDate,
|
|
type: EmployeeStatisticsHistoryEnum.INCOME,
|
|
organizationId,
|
|
tenantId
|
|
});
|
|
const expenses = await this.employeeStatisticsService.getEmployeeStatisticsHistory({
|
|
employeeId: this.selectedEmployee.id,
|
|
startDate,
|
|
endDate,
|
|
type: EmployeeStatisticsHistoryEnum.EXPENSES,
|
|
organizationId,
|
|
tenantId
|
|
});
|
|
|
|
this.dialogService.open(ProfitHistoryComponent, {
|
|
context: {
|
|
records: {
|
|
incomes,
|
|
expenses,
|
|
incomeTotal: this.income,
|
|
expenseTotal: this.expense,
|
|
profit: this.profit
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param employeeStatistics
|
|
* @param key
|
|
* @returns
|
|
*/
|
|
private _statsSum = (employeeStatistics: IMonthAggregatedEmployeeStatistics[], key: string): number => {
|
|
return Number(employeeStatistics.reduce((a, b) => a + b[key], 0).toFixed(2));
|
|
};
|
|
|
|
/**
|
|
*
|
|
*/
|
|
navigateToAccounting() {
|
|
this.router.navigate(['/pages/dashboard/accounting']);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
edit() {
|
|
this.router.navigate(['/pages/employees/edit/' + this.selectedEmployee.id]);
|
|
}
|
|
|
|
/**
|
|
* GET Employee Position Accessor
|
|
*/
|
|
get employeePosition() {
|
|
if (!this.selectedEmployee) {
|
|
return;
|
|
}
|
|
const { shortDescription, employeeLevel } = this.selectedEmployee;
|
|
return [shortDescription, employeeLevel].filter(Boolean).join(' | ');
|
|
}
|
|
|
|
ngOnDestroy() {}
|
|
}
|