mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 21:30:31 +00:00
add server to monorepo.
This commit is contained in:
72
packages/server/src/services/Projects/Times/CreateTime.ts
Normal file
72
packages/server/src/services/Projects/Times/CreateTime.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import {
|
||||
IProjectTimeCreatedEventPayload,
|
||||
IProjectTimeCreateDTO,
|
||||
IProjectTimeCreateEventPayload,
|
||||
IProjectTimeCreatePOJO,
|
||||
IProjectTimeCreatingEventPayload,
|
||||
} from '@/interfaces';
|
||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||
import UnitOfWork from '@/services/UnitOfWork';
|
||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||
import events from '@/subscribers/events';
|
||||
|
||||
@Service()
|
||||
export class CreateTimeService {
|
||||
@Inject()
|
||||
private uow: UnitOfWork;
|
||||
|
||||
@Inject()
|
||||
private tenancy: HasTenancyService;
|
||||
|
||||
@Inject()
|
||||
private eventPublisher: EventPublisher;
|
||||
|
||||
/**
|
||||
* Creates a new time.
|
||||
* @param {number} taskId -
|
||||
* @param {IProjectTimeCreateDTO} timeDTO -
|
||||
* @returns {Promise<IProjectTimeCreatePOJO>}
|
||||
*/
|
||||
public createTime = async (
|
||||
tenantId: number,
|
||||
taskId: number,
|
||||
timeDTO: IProjectTimeCreateDTO
|
||||
): Promise<IProjectTimeCreatePOJO> => {
|
||||
const { Time, Task } = this.tenancy.models(tenantId);
|
||||
|
||||
const task = await Task.query().findById(taskId).throwIfNotFound();
|
||||
|
||||
// Triggers `onProjectTimeCreate` event.
|
||||
await this.eventPublisher.emitAsync(events.projectTime.onCreate, {
|
||||
tenantId,
|
||||
timeDTO,
|
||||
} as IProjectTimeCreateEventPayload);
|
||||
|
||||
// Creates a new project under unit-of-work envirement.
|
||||
return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
|
||||
// Triggers `onProjectTimeCreating` event.
|
||||
await this.eventPublisher.emitAsync(events.projectTime.onCreating, {
|
||||
tenantId,
|
||||
timeDTO,
|
||||
trx,
|
||||
} as IProjectTimeCreatingEventPayload);
|
||||
|
||||
const time = await Time.query().insert({
|
||||
...timeDTO,
|
||||
taskId,
|
||||
projectId: task.projectId,
|
||||
});
|
||||
|
||||
// Triggers `onProjectTimeCreated` event.
|
||||
await this.eventPublisher.emitAsync(events.projectTime.onCreated, {
|
||||
tenantId,
|
||||
time,
|
||||
trx,
|
||||
} as IProjectTimeCreatedEventPayload);
|
||||
|
||||
return time;
|
||||
});
|
||||
};
|
||||
}
|
||||
61
packages/server/src/services/Projects/Times/DeleteTime.ts
Normal file
61
packages/server/src/services/Projects/Times/DeleteTime.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import {
|
||||
IProjectTimeDeletedEventPayload,
|
||||
IProjectTimeDeleteEventPayload,
|
||||
IProjectTimeDeletingEventPayload,
|
||||
} from '@/interfaces';
|
||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||
import UnitOfWork from '@/services/UnitOfWork';
|
||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||
import events from '@/subscribers/events';
|
||||
|
||||
@Service()
|
||||
export class DeleteTimeService {
|
||||
@Inject()
|
||||
private uow: UnitOfWork;
|
||||
|
||||
@Inject()
|
||||
private tenancy: HasTenancyService;
|
||||
|
||||
@Inject()
|
||||
private eventPublisher: EventPublisher;
|
||||
|
||||
/**
|
||||
* Deletes the give task's time that associated to the given project.
|
||||
* @param {number} projectId -
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public deleteTime = async (tenantId: number, timeId: number) => {
|
||||
const { Time } = this.tenancy.models(tenantId);
|
||||
|
||||
// Validate customer existance.
|
||||
const oldTime = await Time.query().findById(timeId).throwIfNotFound();
|
||||
|
||||
// Triggers `onProjectDelete` event.
|
||||
await this.eventPublisher.emitAsync(events.projectTime.onDelete, {
|
||||
tenantId,
|
||||
timeId,
|
||||
} as IProjectTimeDeleteEventPayload);
|
||||
|
||||
// Deletes the given project under unit-of-work envirement.
|
||||
return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
|
||||
// Triggers `onProjectDeleting` event.
|
||||
await this.eventPublisher.emitAsync(events.projectTime.onDeleting, {
|
||||
tenantId,
|
||||
oldTime,
|
||||
trx,
|
||||
} as IProjectTimeDeletingEventPayload);
|
||||
|
||||
// Upsert the project object.
|
||||
await Time.query(trx).findById(timeId).delete();
|
||||
|
||||
// Triggers `onProjectDeleted` event.
|
||||
await this.eventPublisher.emitAsync(events.projectTime.onDeleted, {
|
||||
tenantId,
|
||||
oldTime,
|
||||
trx,
|
||||
} as IProjectTimeDeletedEventPayload);
|
||||
});
|
||||
};
|
||||
}
|
||||
76
packages/server/src/services/Projects/Times/EditTime.ts
Normal file
76
packages/server/src/services/Projects/Times/EditTime.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import {
|
||||
IProjectTimeEditDTO,
|
||||
IProjectTimeEditedEventPayload,
|
||||
IProjectTimeEditEventPayload,
|
||||
IProjectTimeEditingEventPayload,
|
||||
IProjectTimeEditPOJO,
|
||||
} from '@/interfaces';
|
||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||
import UnitOfWork from '@/services/UnitOfWork';
|
||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||
import events from '@/subscribers/events';
|
||||
|
||||
@Service()
|
||||
export class EditTimeService {
|
||||
@Inject()
|
||||
private uow: UnitOfWork;
|
||||
|
||||
@Inject()
|
||||
private tenancy: HasTenancyService;
|
||||
|
||||
@Inject()
|
||||
private eventPublisher: EventPublisher;
|
||||
|
||||
/**
|
||||
* Edits the given project's time that associated to the given task.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {number} taskId - Task id.
|
||||
* @returns {Promise<IProjectTimeEditPOJO>}
|
||||
*/
|
||||
public editTime = async (
|
||||
tenantId: number,
|
||||
timeId: number,
|
||||
timeDTO: IProjectTimeEditDTO
|
||||
): Promise<IProjectTimeEditPOJO> => {
|
||||
const { Time } = this.tenancy.models(tenantId);
|
||||
|
||||
// Validate customer existance.
|
||||
const oldTime = await Time.query().findById(timeId).throwIfNotFound();
|
||||
|
||||
// Triggers `onProjectEdit` event.
|
||||
await this.eventPublisher.emitAsync(events.projectTime.onEdit, {
|
||||
tenantId,
|
||||
oldTime,
|
||||
timeDTO,
|
||||
} as IProjectTimeEditEventPayload);
|
||||
|
||||
// Edits the given project under unit-of-work envirement.
|
||||
return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
|
||||
// Triggers `onProjectEditing` event.
|
||||
await this.eventPublisher.emitAsync(events.projectTime.onEditing, {
|
||||
tenantId,
|
||||
timeDTO,
|
||||
oldTime,
|
||||
trx,
|
||||
} as IProjectTimeEditingEventPayload);
|
||||
|
||||
// Upsert the task's time object.
|
||||
const time = await Time.query(trx).upsertGraphAndFetch({
|
||||
id: timeId,
|
||||
...timeDTO,
|
||||
});
|
||||
// Triggers `onProjectEdited` event.
|
||||
await this.eventPublisher.emitAsync(events.projectTime.onEdited, {
|
||||
tenantId,
|
||||
oldTime,
|
||||
timeDTO,
|
||||
time,
|
||||
trx,
|
||||
} as IProjectTimeEditedEventPayload);
|
||||
|
||||
return time;
|
||||
});
|
||||
};
|
||||
}
|
||||
37
packages/server/src/services/Projects/Times/GetTime.ts
Normal file
37
packages/server/src/services/Projects/Times/GetTime.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { IProjectTimeGetPOJO } from '@/interfaces';
|
||||
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
|
||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { TimeTransformer } from './TimeTransformer';
|
||||
|
||||
@Service()
|
||||
export class GetTimeService {
|
||||
@Inject()
|
||||
private tenancy: HasTenancyService;
|
||||
|
||||
@Inject()
|
||||
private transformer: TransformerInjectable;
|
||||
|
||||
/**
|
||||
* Retrieve the tasks list.
|
||||
* @param {number} tenantId - Tenant Id.
|
||||
* @param {number} taskId - Task Id.
|
||||
* @returns {Promise<IProjectTimeGetPOJO>}
|
||||
*/
|
||||
public getTime = async (
|
||||
tenantId: number,
|
||||
timeId: number
|
||||
): Promise<IProjectTimeGetPOJO> => {
|
||||
const { Time } = this.tenancy.models(tenantId);
|
||||
|
||||
// Retrieve the project.
|
||||
const time = await Time.query()
|
||||
.findById(timeId)
|
||||
.withGraphFetched('project.contact')
|
||||
.withGraphFetched('task')
|
||||
.throwIfNotFound();
|
||||
|
||||
// Transformes and returns object.
|
||||
return this.transformer.transform(tenantId, time, new TimeTransformer());
|
||||
};
|
||||
}
|
||||
36
packages/server/src/services/Projects/Times/GetTimes.ts
Normal file
36
packages/server/src/services/Projects/Times/GetTimes.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { IProjectTimeGetPOJO } from '@/interfaces';
|
||||
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
|
||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||
import { TimeTransformer } from './TimeTransformer';
|
||||
|
||||
@Service()
|
||||
export class GetTimelineService {
|
||||
@Inject()
|
||||
private tenancy: HasTenancyService;
|
||||
|
||||
@Inject()
|
||||
private transformer: TransformerInjectable;
|
||||
|
||||
/**
|
||||
* Retrieve the tasks list.
|
||||
* @param {number} tenantId - Tenant Id.
|
||||
* @param {number} taskId - Task Id.
|
||||
* @returns {Promise<IProjectTimeGetPOJO[]>}
|
||||
*/
|
||||
public getTimeline = async (
|
||||
tenantId: number,
|
||||
projectId: number
|
||||
): Promise<IProjectTimeGetPOJO[]> => {
|
||||
const { Time } = this.tenancy.models(tenantId);
|
||||
|
||||
// Retrieve the project.
|
||||
const times = await Time.query()
|
||||
.where('projectId', projectId)
|
||||
.withGraphFetched('project.contact')
|
||||
.withGraphFetched('task');
|
||||
|
||||
// Transformes and returns object.
|
||||
return this.transformer.transform(tenantId, times, new TimeTransformer());
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Service } from 'typedi';
|
||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||
|
||||
@Service()
|
||||
export class SyncActualTimeTask {
|
||||
@Inject()
|
||||
private tenancy: HasTenancyService;
|
||||
|
||||
/**
|
||||
* Increases the actual time of the given task.
|
||||
* @param {number} tenantId
|
||||
* @param {number} taskId
|
||||
* @param {number} actualHours
|
||||
* @param {Knex.Transaction} trx
|
||||
*/
|
||||
public increaseActualTimeTask = async (
|
||||
tenantId: number,
|
||||
taskId: number,
|
||||
actualHours: number,
|
||||
trx?: Knex.Transaction
|
||||
) => {
|
||||
const { Task } = this.tenancy.models(tenantId);
|
||||
|
||||
await Task.query(trx)
|
||||
.findById(taskId)
|
||||
.increment('actualHours', actualHours);
|
||||
};
|
||||
|
||||
/**
|
||||
* Decreases the actual time of the given task.
|
||||
* @param {number} tenantId
|
||||
* @param {number} taskId
|
||||
* @param {number} actualHours
|
||||
* @param {Knex.Transaction} trx
|
||||
*/
|
||||
public decreaseActualTimeTask = async (
|
||||
tenantId: number,
|
||||
taskId: number,
|
||||
actualHours: number,
|
||||
trx?: Knex.Transaction
|
||||
) => {
|
||||
const { Task } = this.tenancy.models(tenantId);
|
||||
|
||||
await Task.query(trx)
|
||||
.findById(taskId)
|
||||
.decrement('actualHours', actualHours);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import {
|
||||
IProjectTimeCreatedEventPayload,
|
||||
IProjectTimeDeletedEventPayload,
|
||||
IProjectTimeEditedEventPayload,
|
||||
} from '@/interfaces';
|
||||
import events from '@/subscribers/events';
|
||||
import { SyncActualTimeTask } from './SyncActualTimeTask';
|
||||
|
||||
@Service()
|
||||
export class SyncActualTimeTaskSubscriber {
|
||||
@Inject()
|
||||
private syncActualTimeTask: SyncActualTimeTask;
|
||||
|
||||
/**
|
||||
* Attaches events with handlers.
|
||||
* @param bus
|
||||
*/
|
||||
attach(bus) {
|
||||
bus.subscribe(
|
||||
events.projectTime.onCreated,
|
||||
this.handleIncreaseActualTimeOnTimeCreate
|
||||
);
|
||||
bus.subscribe(
|
||||
events.projectTime.onDeleted,
|
||||
this.handleDecreaseActaulTimeOnTimeDelete
|
||||
);
|
||||
bus.subscribe(
|
||||
events.projectTime.onEdited,
|
||||
this.handleAdjustActualTimeOnTimeEdited
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles increasing the actual time of the task once time entry be created.
|
||||
* @param {IProjectTimeCreatedEventPayload} payload -
|
||||
*/
|
||||
private handleIncreaseActualTimeOnTimeCreate = async ({
|
||||
tenantId,
|
||||
time,
|
||||
trx,
|
||||
}: IProjectTimeCreatedEventPayload) => {
|
||||
await this.syncActualTimeTask.increaseActualTimeTask(
|
||||
tenantId,
|
||||
time.taskId,
|
||||
time.duration,
|
||||
trx
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle decreasing the actual time of the tsak once time entry be deleted.
|
||||
* @param {IProjectTimeDeletedEventPayload} payload
|
||||
*/
|
||||
private handleDecreaseActaulTimeOnTimeDelete = async ({
|
||||
tenantId,
|
||||
oldTime,
|
||||
trx,
|
||||
}: IProjectTimeDeletedEventPayload) => {
|
||||
await this.syncActualTimeTask.decreaseActualTimeTask(
|
||||
tenantId,
|
||||
oldTime.taskId,
|
||||
oldTime.duration,
|
||||
trx
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle adjusting the actual time of the task once time be edited.
|
||||
* @param {IProjectTimeEditedEventPayload} payload -
|
||||
*/
|
||||
private handleAdjustActualTimeOnTimeEdited = async ({
|
||||
tenantId,
|
||||
time,
|
||||
oldTime,
|
||||
trx,
|
||||
}: IProjectTimeEditedEventPayload) => {
|
||||
await this.syncActualTimeTask.decreaseActualTimeTask(
|
||||
tenantId,
|
||||
oldTime.taskId,
|
||||
oldTime.duration,
|
||||
trx
|
||||
);
|
||||
await this.syncActualTimeTask.increaseActualTimeTask(
|
||||
tenantId,
|
||||
time.taskId,
|
||||
time.duration,
|
||||
trx
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { Transformer } from '@/lib/Transformer/Transformer';
|
||||
import Time from 'models/Time';
|
||||
import { formatMinutes } from 'utils/formatMinutes';
|
||||
|
||||
export class TimeTransformer extends Transformer {
|
||||
/**
|
||||
* Include these attributes to sale invoice object.
|
||||
* @returns {Array}
|
||||
*/
|
||||
public includeAttributes = (): string[] => {
|
||||
return ['projectName', 'taskName', 'customerName', 'durationFormatted'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Exclude attributes.
|
||||
* @returns {string[]}
|
||||
*/
|
||||
public excludeAttributes = (): string[] => {
|
||||
return ['project', 'task'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the project name that associated to the time entry.
|
||||
* @param {Time} time
|
||||
* @returns {string}
|
||||
*/
|
||||
public projectName = (time: Time) => {
|
||||
return time.project.name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the task name that associated to the time entry.
|
||||
* @param {Time} time
|
||||
* @returns {string}
|
||||
*/
|
||||
public taskName = (time: Time) => {
|
||||
return time.task.name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the customer name that associated to the task of the time entry.
|
||||
* @param {Time} time
|
||||
* @returns {string}
|
||||
*/
|
||||
public customerName = (time: Time) => {
|
||||
return time?.project?.contact?.displayName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the formatted duration.
|
||||
* @param {Time} time
|
||||
* @returns {string}
|
||||
*/
|
||||
public durationFormatted = (time: Time) => {
|
||||
return formatMinutes(time.duration);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { CreateTimeService } from './CreateTime';
|
||||
import { EditTimeService } from './EditTime';
|
||||
import { GetTimelineService } from './GetTimes';
|
||||
import { GetTimeService } from './GetTime';
|
||||
import { DeleteTimeService } from './DeleteTime';
|
||||
import {
|
||||
IProjectTimeCreateDTO,
|
||||
IProjectTimeCreatePOJO,
|
||||
IProjectTimeEditDTO,
|
||||
IProjectTimeEditPOJO,
|
||||
IProjectTimeGetPOJO,
|
||||
} from '@/interfaces';
|
||||
|
||||
@Service()
|
||||
export class TimesApplication {
|
||||
@Inject()
|
||||
private createTimeService: CreateTimeService;
|
||||
|
||||
@Inject()
|
||||
private editTimeService: EditTimeService;
|
||||
|
||||
@Inject()
|
||||
private deleteTimeService: DeleteTimeService;
|
||||
|
||||
@Inject()
|
||||
private getTimeService: GetTimeService;
|
||||
|
||||
@Inject()
|
||||
private getTimelineService: GetTimelineService;
|
||||
|
||||
/**
|
||||
* Creates a new time for specific project's task.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {IProjectTimeCreateDTO} timeDTO - Create project's time DTO.
|
||||
* @return {Promise<IProjectTimeCreatePOJO>}
|
||||
*/
|
||||
public createTime = (
|
||||
tenantId: number,
|
||||
taskId: number,
|
||||
timeDTO: IProjectTimeCreateDTO
|
||||
): Promise<IProjectTimeCreatePOJO> => {
|
||||
return this.createTimeService.createTime(tenantId, taskId, timeDTO);
|
||||
};
|
||||
|
||||
/**
|
||||
* Edits details of the given task.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {number} vendorId - Vendor id.
|
||||
* @param {IProjectCreateDTO} projectDTO - Create project DTO.
|
||||
* @returns {Promise<IProjectTimeEditPOJO>}
|
||||
*/
|
||||
public editTime = (
|
||||
tenantId: number,
|
||||
timeId: number,
|
||||
taskDTO: IProjectTimeEditDTO
|
||||
): Promise<IProjectTimeEditPOJO> => {
|
||||
return this.editTimeService.editTime(tenantId, timeId, taskDTO);
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes the given task.
|
||||
* @param {number} tenantId
|
||||
* @param {number} taskId
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
public deleteTime = (tenantId: number, timeId: number): Promise<void> => {
|
||||
return this.deleteTimeService.deleteTime(tenantId, timeId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the given task details.
|
||||
* @param {number} tenantId
|
||||
* @param {number} timeId
|
||||
* @returns {Promise<IProjectTimeGetPOJO>}
|
||||
*/
|
||||
public getTime = (
|
||||
tenantId: number,
|
||||
timeId: number
|
||||
): Promise<IProjectTimeGetPOJO> => {
|
||||
return this.getTimeService.getTime(tenantId, timeId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the vendors paginated list.
|
||||
* @param {number} tenantId
|
||||
* @param {IVendorsFilter} filterDTO
|
||||
* @returns {Promise<IProjectTimeGetPOJO[]>}
|
||||
*/
|
||||
public getTimeline = (
|
||||
tenantId: number,
|
||||
projectId: number
|
||||
): Promise<IProjectTimeGetPOJO[]> => {
|
||||
return this.getTimelineService.getTimeline(tenantId, projectId);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user