Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] Employee weekly schedule planning #8741

Open
wants to merge 19 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
e00c602
Implementation of employee weekly schedule planning
samuelmbabhazi Jan 22, 2025
7c4e4f5
Feedback integration
samuelmbabhazi Jan 23, 2025
ff2bacb
Merge branch 'develop' into feat/#5293-weekly-schedule-planning
samuelmbabhazi Jan 23, 2025
c369a13
Feedback integration
samuelmbabhazi Jan 23, 2025
f7eb738
Feedback integration
samuelmbabhazi Jan 23, 2025
96052b1
Feedback integration
samuelmbabhazi Jan 23, 2025
6c3ba54
Fix deepscan
samuelmbabhazi Jan 23, 2025
49d09b7
Merge branch 'develop' into feat/#5293-weekly-schedule-planning
rahul-rocket Jan 24, 2025
2b926a6
refactor: updated employee availability feature
rahul-rocket Jan 24, 2025
55092e8
fix: entity metadata for Employee#availabilities was not found
rahul-rocket Jan 24, 2025
a6a6e4c
Integration of requested changes
samuelmbabhazi Jan 24, 2025
b1dd009
Merge branch 'develop' into feat/#5293-weekly-schedule-planning
rahul-rocket Jan 26, 2025
39e500f
fix: #5293 bulk insert method for employee availability
rahul-rocket Jan 26, 2025
9037f32
fix: #5293 bulk insert method for employee availability
rahul-rocket Jan 26, 2025
413bf4e
fix: #5293 apply validation and permissions guard
rahul-rocket Jan 26, 2025
043f77f
fix: property 'tenantId' does not exist on type 'IEmployeeAvailabilit…
rahul-rocket Jan 26, 2025
fdab334
feat: #5293 added permission for Employee Availability
rahul-rocket Jan 26, 2025
d51f3f7
feat: #5293 added permission for Employee Availability
rahul-rocket Jan 27, 2025
d8ece61
feat: [table migration] for employee availability for all DB types.
rahul-rocket Jan 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/contracts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export * from './lib/email-reset.model';
export * from './lib/email-template.model';
export * from './lib/email.model';
export * from './lib/employee-appointment.model';
export * from './lib/employee-availability.model';
export * from './lib/employee-award.model';
export * from './lib/employee-job.model';
export * from './lib/employee-phone.model';
Expand Down
64 changes: 64 additions & 0 deletions packages/contracts/src/lib/employee-availability.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { IBasePerTenantAndOrganizationEntityModel, ID } from './base-entity.model';
import { IEmployee } from './employee.model';

/**
* Enum representing different availability statuses.
*/
export enum AvailabilityStatusEnum {
Available = 'Available',
Partial = 'Partial',
Unavailable = 'Unavailable'
}

/**
* Enum mapping availability statuses to numerical values.
*/
export enum AvailabilityStatusValue {
Available = 0,
Partial = 1,
Unavailable = 2
}

/**
* A mapping object to relate status labels to their respective numerical values.
*/
export const AvailabilityStatusMap: Record<AvailabilityStatusEnum, AvailabilityStatusValue> = {
[AvailabilityStatusEnum.Available]: AvailabilityStatusValue.Available,
[AvailabilityStatusEnum.Partial]: AvailabilityStatusValue.Partial,
[AvailabilityStatusEnum.Unavailable]: AvailabilityStatusValue.Unavailable
};

/**
* Base interface for Employee Availability data.
* Includes common properties shared across different input types.
*/
interface IBaseEmployeeAvailability extends IBasePerTenantAndOrganizationEntityModel {
employeeId: ID;
startDate: Date;
endDate: Date;
dayOfWeek: number; // 0 = Sunday, 6 = Saturday
availabilityStatus: AvailabilityStatusEnum;
availabilityNotes?: string;
}

/**
* Represents an Employee Availability record.
*/
export interface IEmployeeAvailability extends IBaseEmployeeAvailability {
employee: IEmployee;
}

/**
* Input interface for finding Employee Availability records.
*/
export interface IEmployeeAvailabilityFindInput extends Partial<IBaseEmployeeAvailability> {}

/**
* Input interface for creating new Employee Availability records.
*/
export interface IEmployeeAvailabilityCreateInput extends IBaseEmployeeAvailability {}

/**
* Input interface for updating Employee Availability records.
*/
export interface IEmployeeAvailabilityUpdateInput extends Partial<IBaseEmployeeAvailability> {}
82 changes: 77 additions & 5 deletions packages/core/src/lib/core/crud/crud.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
import { Collection, CreateOptions, FilterQuery as MikroFilterQuery, RequiredEntityData, wrap } from '@mikro-orm/core';
import { AssignOptions } from '@mikro-orm/knex';
import { IPagination } from '@gauzy/contracts';
import { ID, IPagination } from '@gauzy/contracts';
import { BaseEntity, SoftDeletableBaseEntity } from '../entities/internal';
import { multiORMCreateQueryBuilder } from '../../core/orm/query-builder/query-builder.factory';
import { IQueryBuilder } from '../../core/orm/query-builder/iquery-builder';

Check warning on line 22 in packages/core/src/lib/core/crud/crud.service.ts

View workflow job for this annotation

GitHub Actions / Cspell

Unknown word (iquery)
import { MikroOrmBaseEntityRepository } from '../../core/repository/mikro-orm-base-entity.repository';
import {
MultiORM,
Expand All @@ -45,7 +45,6 @@
const ormType: MultiORM = getORMType();

export abstract class CrudService<T extends BaseEntity> implements ICrudService<T> {

constructor(
protected readonly typeOrmRepository: Repository<T>,
protected readonly mikroOrmRepository: MikroOrmBaseEntityRepository<T>
Expand Down Expand Up @@ -347,7 +346,7 @@
* @param options
* @returns
*/
public async findOneByIdString(id: T['id'], options?: IFindOneOptions<T>): Promise<T> {
public async findOneByIdString(id: ID, options?: IFindOneOptions<T>): Promise<T> {
let record: T;

switch (this.ormType) {
Expand Down Expand Up @@ -434,6 +433,79 @@
return this.serialize(record);
}

/**
* Bulk creates new entities or updates existing ones based on the provided entity data.
*
* @param entities The array of partial entity data for creation or update.
* @param createOptions Options for the creation of the entity in MikroORM.
* @param assignOptions Options for assigning existing entities in MikroORM.
* @returns The created or updated entities.
*/
public async bulkCreate(
partialEntities: IPartialEntity<T>[],
createOptions: CreateOptions<boolean> = {
partial: true,
managed: true
},
assignOptions: AssignOptions<boolean> = {
updateNestedEntities: false,
onlyOwnProperties: true
}
): Promise<T[]> {
try {
switch (this.ormType) {
case MultiORMEnum.MikroORM:
try {
const newEntities: T[] = [];

for (const partialEntity of partialEntities) {
if (partialEntity['id']) {
// Try to find the existing entity
const existingEntity = await this.mikroOrmRepository.findOne(partialEntity['id']);
if (existingEntity) {
// If found, perform an update (upsert)
this.mikroOrmRepository.assign(existingEntity, partialEntity as any, assignOptions);
newEntities.push(existingEntity);
continue;
}
}

// Create a new entity using MikroORM
const newEntity = this.mikroOrmRepository.create(
partialEntity as RequiredEntityData<T>,
createOptions
);
newEntities.push(newEntity);
}

// Persist all new entities and flush
await this.mikroOrmRepository.persistAndFlush(newEntities);
return newEntities.map(entity => this.serialize(entity));
} catch (error) {
console.error('Error during MikroORM bulk create transaction:', error);
}
break;

case MultiORMEnum.TypeORM:
try {
// Bulk insert using TypeORM's `save` method for better performance
const newEntities = this.typeOrmRepository.create(partialEntities as DeepPartial<T>[]);
return await this.typeOrmRepository.save(newEntities);
} catch (error) {
console.error('Error during TypeORM bulk create transaction:', error);
}
break;

default:
throw new Error(`Not implemented for ${this.ormType}`);
}
} catch (error) {
console.error('Error in CRUD service bulk create method:', error);
throw new BadRequestException(error);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve error handling in bulkCreate method.

The method has several issues that need to be addressed:

  1. Error handling in MikroORM and TypeORM blocks doesn't rethrow errors, causing undefined return.
  2. Missing return type annotation for error cases.
  3. Nested try-catch blocks add unnecessary complexity.

Apply this diff to fix the issues:

 public async bulkCreate(
   partialEntities: IPartialEntity<T>[],
   createOptions: CreateOptions<boolean> = {
     partial: true,
     managed: true
   },
   assignOptions: AssignOptions<boolean> = {
     updateNestedEntities: false,
     onlyOwnProperties: true
   }
 ): Promise<T[]> {
   try {
     switch (this.ormType) {
       case MultiORMEnum.MikroORM: {
-        try {
           const newEntities: T[] = [];

           for (const partialEntity of partialEntities) {
             if (partialEntity['id']) {
               // Try to find the existing entity
               const existingEntity = await this.mikroOrmRepository.findOne(partialEntity['id']);
               if (existingEntity) {
                 // If found, perform an update (upsert)
                 this.mikroOrmRepository.assign(existingEntity, partialEntity as any, assignOptions);
                 newEntities.push(existingEntity);
                 continue;
               }
             }

             // Create a new entity using MikroORM
             const newEntity = this.mikroOrmRepository.create(
               partialEntity as RequiredEntityData<T>,
               createOptions
             );
             newEntities.push(newEntity);
           }

           // Persist all new entities and flush
           await this.mikroOrmRepository.persistAndFlush(newEntities);
           return newEntities.map(entity => this.serialize(entity));
-        } catch (error) {
-          console.error('Error during MikroORM bulk create transaction:', error);
-        }
-        break;
+        }

       case MultiORMEnum.TypeORM: {
-        try {
           // Bulk insert using TypeORM's `save` method for better performance
           const newEntities = this.typeOrmRepository.create(partialEntities as DeepPartial<T>[]);
           return await this.typeOrmRepository.save(newEntities);
-        } catch (error) {
-          console.error('Error during TypeORM bulk create transaction:', error);
-        }
-        break;
+        }

       default:
         throw new Error(`Not implemented for ${this.ormType}`);
     }
   } catch (error) {
     console.error('Error in CRUD service bulk create method:', error);
     throw new BadRequestException(error);
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Bulk creates new entities or updates existing ones based on the provided entity data.
*
* @param entities The array of partial entity data for creation or update.
* @param createOptions Options for the creation of the entity in MikroORM.
* @param assignOptions Options for assigning existing entities in MikroORM.
* @returns The created or updated entities.
*/
public async bulkCreate(
partialEntities: IPartialEntity<T>[],
createOptions: CreateOptions<boolean> = {
partial: true,
managed: true
},
assignOptions: AssignOptions<boolean> = {
updateNestedEntities: false,
onlyOwnProperties: true
}
): Promise<T[]> {
try {
switch (this.ormType) {
case MultiORMEnum.MikroORM:
try {
const newEntities: T[] = [];
for (const partialEntity of partialEntities) {
if (partialEntity['id']) {
// Try to find the existing entity
const existingEntity = await this.mikroOrmRepository.findOne(partialEntity['id']);
if (existingEntity) {
// If found, perform an update (upsert)
this.mikroOrmRepository.assign(existingEntity, partialEntity as any, assignOptions);
newEntities.push(existingEntity);
continue;
}
}
// Create a new entity using MikroORM
const newEntity = this.mikroOrmRepository.create(
partialEntity as RequiredEntityData<T>,
createOptions
);
newEntities.push(newEntity);
}
// Persist all new entities and flush
await this.mikroOrmRepository.persistAndFlush(newEntities);
return newEntities.map(entity => this.serialize(entity));
} catch (error) {
console.error('Error during MikroORM bulk create transaction:', error);
}
break;
case MultiORMEnum.TypeORM:
try {
// Bulk insert using TypeORM's `save` method for better performance
const newEntities = this.typeOrmRepository.create(partialEntities as DeepPartial<T>[]);
return await this.typeOrmRepository.save(newEntities);
} catch (error) {
console.error('Error during TypeORM bulk create transaction:', error);
}
break;
default:
throw new Error(`Not implemented for ${this.ormType}`);
}
} catch (error) {
console.error('Error in CRUD service bulk create method:', error);
throw new BadRequestException(error);
}
}
/**
* Bulk creates new entities or updates existing ones based on the provided entity data.
*
* @param entities The array of partial entity data for creation or update.
* @param createOptions Options for the creation of the entity in MikroORM.
* @param assignOptions Options for assigning existing entities in MikroORM.
* @returns The created or updated entities.
*/
public async bulkCreate(
partialEntities: IPartialEntity<T>[],
createOptions: CreateOptions<boolean> = {
partial: true,
managed: true
},
assignOptions: AssignOptions<boolean> = {
updateNestedEntities: false,
onlyOwnProperties: true
}
): Promise<T[]> {
try {
switch (this.ormType) {
case MultiORMEnum.MikroORM: {
const newEntities: T[] = [];
for (const partialEntity of partialEntities) {
if (partialEntity['id']) {
// Try to find the existing entity
const existingEntity = await this.mikroOrmRepository.findOne(partialEntity['id']);
if (existingEntity) {
// If found, perform an update (upsert)
this.mikroOrmRepository.assign(existingEntity, partialEntity as any, assignOptions);
newEntities.push(existingEntity);
continue;
}
}
// Create a new entity using MikroORM
const newEntity = this.mikroOrmRepository.create(
partialEntity as RequiredEntityData<T>,
createOptions
);
newEntities.push(newEntity);
}
// Persist all new entities and flush
await this.mikroOrmRepository.persistAndFlush(newEntities);
return newEntities.map(entity => this.serialize(entity));
}
case MultiORMEnum.TypeORM: {
// Bulk insert using TypeORM's `save` method for better performance
const newEntities = this.typeOrmRepository.create(partialEntities as DeepPartial<T>[]);
return await this.typeOrmRepository.save(newEntities);
}
default:
throw new Error(`Not implemented for ${this.ormType}`);
}
} catch (error) {
console.error('Error in CRUD service bulk create method:', error);
throw new BadRequestException(error);
}
}



/**
* Creates a new entity or updates an existing one based on the provided entity data.
*
Expand Down Expand Up @@ -645,7 +717,7 @@
* @param saveOptions - Additional save options for the ORM operation (specific to TypeORM).
* @returns A promise that resolves to the softly removed entity.
*/
public async softRemove(id: T['id'], options?: IFindOneOptions<T>, saveOptions?: SaveOptions): Promise<T> {
public async softRemove(id: ID, options?: IFindOneOptions<T>, saveOptions?: SaveOptions): Promise<T> {
try {
switch (this.ormType) {
case MultiORMEnum.MikroORM: {
Expand Down Expand Up @@ -681,7 +753,7 @@
* @param options - Optional settings for database save operations.
* @returns A promise that resolves with the recovered entity.
*/
public async softRecover(id: T['id'], options?: IFindOneOptions<T>, saveOptions?: SaveOptions): Promise<T> {
public async softRecover(id: ID, options?: IFindOneOptions<T>, saveOptions?: SaveOptions): Promise<T> {
try {
switch (this.ormType) {
case MultiORMEnum.MikroORM: {
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/lib/core/crud/tenant-aware-crud.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NotFoundException } from '@nestjs/common';
import { DeleteResult, FindOptionsWhere, FindManyOptions, FindOneOptions, Repository, UpdateResult } from 'typeorm';
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
import { IPagination, IUser, PermissionsEnum } from '@gauzy/contracts';
import { ID, IPagination, IUser, PermissionsEnum } from '@gauzy/contracts';
import { isNotEmpty } from '@gauzy/utils';
import { MikroOrmBaseEntityRepository } from '../../core/repository/mikro-orm-base-entity.repository';
import { RequestContext } from '../context';
Expand Down Expand Up @@ -239,7 +239,7 @@ export abstract class TenantAwareCrudService<T extends TenantBaseEntity>
* @param options
* @returns
*/
public async findOneOrFailByIdString(id: T['id'], options?: FindOneOptions<T>): Promise<ITryRequest<T>> {
public async findOneOrFailByIdString(id: ID, options?: FindOneOptions<T>): Promise<ITryRequest<T>> {
return await super.findOneOrFailByIdString(id, this.findOneWithTenant(options));
}

Expand Down Expand Up @@ -282,7 +282,7 @@ export abstract class TenantAwareCrudService<T extends TenantBaseEntity>
* @param options
* @returns
*/
public async findOneByIdString(id: T['id'], options?: FindOneOptions<T>): Promise<T> {
public async findOneByIdString(id: ID, options?: FindOneOptions<T>): Promise<T> {
return await super.findOneByIdString(id, this.findOneWithTenant(options));
}

Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/lib/core/entities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
EmailTemplate,
Employee,
EmployeeAppointment,
EmployeeAvailability,
EmployeeAward,
EmployeeLevel,
EmployeePhone,
Expand Down Expand Up @@ -190,6 +191,7 @@ export const coreEntities = [
EmailTemplate,
Employee,
EmployeeAppointment,
EmployeeAvailability,
EmployeeAward,
EmployeeLevel,
EmployeePhone,
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/lib/core/entities/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export * from '../../email-history/email-history.entity';
export * from '../../email-reset/email-reset.entity';
export * from '../../email-template/email-template.entity';
export * from '../../employee-appointment/employee-appointment.entity';
export * from '../../employee-availability/employee-availability.entity';
export * from '../../employee-award/employee-award.entity';
export * from '../../employee-level/employee-level.entity';
export * from '../../employee-phone/employee-phone.entity';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ICommand } from '@nestjs/cqrs';
import { IEmployeeAvailabilityCreateInput } from '@gauzy/contracts';

export class EmployeeAvailabilityBulkCreateCommand implements ICommand {
static readonly type = '[Employee Availability] Bulk Create';

constructor(public readonly input: IEmployeeAvailabilityCreateInput[]) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ICommand } from '@nestjs/cqrs';
import { IEmployeeAvailabilityCreateInput } from '@gauzy/contracts';

export class EmployeeAvailabilityCreateCommand implements ICommand {
static readonly type = '[EmployeeAvailability] Create';

constructor(public readonly input: IEmployeeAvailabilityCreateInput) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { IEmployeeAvailability } from '@gauzy/contracts';
import { RequestContext } from '../../../core/context';
import { EmployeeAvailabilityService } from '../../employee-availability.service';
import { EmployeeAvailabilityBulkCreateCommand } from '../employee-availability.bulk.create.command';
import { EmployeeAvailability } from '../../employee-availability.entity';

/**
* Handles the bulk creation of employee availability records.
*/
@CommandHandler(EmployeeAvailabilityBulkCreateCommand)
export class EmployeeAvailabilityBulkCreateHandler implements ICommandHandler<EmployeeAvailabilityBulkCreateCommand> {
constructor(private readonly _availabilityService: EmployeeAvailabilityService) {}

/**
* Executes the bulk creation command for employee availability.
*
* @param command The command containing the list of availability records to create.
* @returns A promise resolving to the list of created employee availability records.
*/
public async execute(command: EmployeeAvailabilityBulkCreateCommand): Promise<IEmployeeAvailability[]> {
const { input } = command;
const tenantId = RequestContext.currentTenantId();

// Prepare employee availability records with tenantId
const employeeAvailabilities = input.map(item =>
new EmployeeAvailability({
...item,
tenantId
})
);

// Perform bulk insert using the availability service
return await this._availabilityService.bulkCreate(employeeAvailabilities);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { IEmployeeAvailability } from '@gauzy/contracts';
import { RequestContext } from '../../../core/context';
import { EmployeeAvailabilityService } from '../../employee-availability.service';
import { EmployeeAvailability } from '../../employee-availability.entity';
import { EmployeeAvailabilityCreateCommand } from '../employee-availability.create.command';

@CommandHandler(EmployeeAvailabilityCreateCommand)
export class EmployeeAvailabilityCreateHandler implements ICommandHandler<EmployeeAvailabilityCreateCommand> {
constructor(private readonly _availabilityService: EmployeeAvailabilityService) {}

/**
* Handles the creation of an employee availability record.
*
* @param {EmployeeAvailabilityCreateCommand} command - The command containing employee availability details.
* @returns {Promise<IEmployeeAvailability>} - The newly created employee availability record.
* @throws {BadRequestException} - If any validation fails (e.g., missing fields, invalid dates).
*/
public async execute(command: EmployeeAvailabilityCreateCommand): Promise<IEmployeeAvailability> {
const { input } = command;
const tenantId = RequestContext.currentTenantId();

return await this._availabilityService.create(new EmployeeAvailability({
...input,
tenantId
}));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { EmployeeAvailabilityBulkCreateHandler } from './employee-availability.bulk.create.handler';
import { EmployeeAvailabilityCreateHandler } from './employee-availability.create.handler';

/**
* Exports all command handlers for EmployeeAvailability.`
*/
export const CommandHandlers = [EmployeeAvailabilityBulkCreateHandler, EmployeeAvailabilityCreateHandler];
2 changes: 2 additions & 0 deletions packages/core/src/lib/employee-availability/commands/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './employee-availability.bulk.create.command';
export * from './employee-availability.create.command';
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { IEmployeeAvailabilityCreateInput } from '@gauzy/contracts';
import { EmployeeAvailability } from '../employee-availability.entity';
import { TenantOrganizationBaseDTO } from '../../core';
import { IntersectionType, PartialType, PickType } from '@nestjs/swagger';

export class CreateEmployeeAvailabilityDTO
extends IntersectionType(
PartialType(TenantOrganizationBaseDTO),
PickType(EmployeeAvailability, [
'dayOfWeek',
'startDate',
'endDate',
'availabilityNotes',
'availabilityStatus',
'employeeId'
])
)
implements IEmployeeAvailabilityCreateInput {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { PartialType } from '@nestjs/mapped-types';
import { IEmployeeAvailabilityUpdateInput } from '@gauzy/contracts';
import { CreateEmployeeAvailabilityDTO } from './create-employee-availability.dto';
import { IntersectionType } from '@nestjs/swagger';

export class UpdateEmployeeAvailabilityDTO
extends IntersectionType(PartialType(CreateEmployeeAvailabilityDTO))
implements IEmployeeAvailabilityUpdateInput {}
Loading
Loading