DTP Base provides a scalable and secure Node.js application development harness ready for production service.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

252 lines
6.4 KiB

// client.js
// Copyright (C) 2024 DTP Technologies, LLC
// All Rights Reserved
'use strict';
import mongoose from 'mongoose';
const Client = mongoose.model('Client');
const ClientProject = mongoose.model('ClientProject');
import { SiteService/*, SiteError*/ } from '../../lib/site-lib.js';
export default class ClientService extends SiteService {
static get name ( ) { return 'ClientService'; }
static get slug () { return 'client'; }
constructor (dtp) {
super(dtp, ClientService);
}
async start ( ) {
const { user: userService } = this.dtp.services;
this.populateClient = [
{
path: 'user',
select: userService.USER_SELECT,
},
];
this.populateClientProject = [
{
path: 'user',
select: userService.USER_SELECT,
},
{
path: 'client',
populate: this.populateClient,
},
];
}
async createClient (user, clientDefinition) {
const { text: textService } = this.dtp.services;
const client = new Client();
client.user = user._id;
client.name = textService.filter(clientDefinition.name);
if (clientDefinition.description && clientDefinition.description.length > 0) {
client.description = textService.filter(clientDefinition.description);
}
client.hoursLimit = clientDefinition.hoursLimit;
await client.save();
return client.toObject();
}
async updateClient (client, clientDefinition) {
const { text: textService } = this.dtp.services;
const update = { $set: { }, $unset: { } };
let changed = false;
if (clientDefinition.name !== client.name) {
update.$set.name = textService.filter(clientDefinition.name);
changed = true;
}
if (clientDefinition.description && (clientDefinition.description.length > 0)) {
if (clientDefinition.description !== client.description) {
update.$set.description = textService.filter(clientDefinition.description);
changed = true;
}
} else {
update.$unset.description = 1;
changed = true;
}
if (clientDefinition.hoursLimit !== client.hoursLimit) {
update.$set.hoursLimit = clientDefinition.hoursLimit;
changed = true;
}
if (!changed) {
return;
}
await Client.updateOne({ _id: client._id }, update);
}
async getClientById (clientId) {
const client = Client
.findOne({ _id: clientId })
.populate(this.populateClient)
.lean();
return client;
}
async getClientsForUser (user) {
const clients = Client
.find({ user: user._id })
.sort({ name: 1 })
.populate(this.populateClient)
.lean();
return clients;
}
async createProject (client, projectDefinition) {
const { text: textService } = this.dtp.services;
const project = new ClientProject();
project.user = client.user._id;
project.client = client._id;
project.name = textService.filter(projectDefinition.name);
if (projectDefinition.description && (projectDefinition.description.length > 0)) {
project.description = textService.filter(projectDefinition.description);
}
project.hourlyRate = projectDefinition.hourlyRate;
await project.save();
return project.toObject();
}
async updateProject (project, projectDefinition) {
const { text: textService } = this.dtp.services;
const update = { $set: { }, $unset: { } };
let changed = false;
if (projectDefinition.name !== project.name) {
update.$set.name = textService.filter(projectDefinition.name);
changed = true;
}
if (projectDefinition.description !== project.description) {
update.$set.description = textService.filter(projectDefinition.description);
changed = true;
}
if (projectDefinition.hourlyRate !== project.hourlyRate) {
update.$set.hourlyRate = projectDefinition.hourlyRate;
changed = true;
}
if (!changed) {
return;
}
await ClientProject.updateOne({ _id: project._id }, update);
}
async getProjectById (projectId) {
const project = ClientProject
.findOne({ _id: projectId })
.populate(this.populateClientProject)
.lean();
return project;
}
async getProjectsForUser (user) {
const projects = ClientProject
.find({ user: user._id })
.sort({ created: -1 })
.populate(this.populateClientProject)
.lean();
return projects;
}
async getProjectsForClient (client) {
const projects = ClientProject
.find({ client: client._id })
.sort({ created: -1 })
.populate(this.populateClientProject)
.lean();
return projects;
}
async addTimeWorked (client, duration) {
const { task: taskService } = this.dtp.services;
const durationLimit = client.hoursLimit * 3600;
if ((client.weeklyTotals.timeWorked + duration) > durationLimit) {
this.log.alert('clamping time worked to weekly hours limit', {
user: {
_id: client.user._id,
username: client.user.username,
},
client: {
_id: client._id,
hoursLimit: client.hoursLimit,
},
});
await Client.updateOne(
{ _id: client._id },
{
$set: { 'weeklyTotals.timeWorked': durationLimit },
},
);
this.log.alert('Ending work sessions for user due to hours limit reached', {
user: {
_id: client.user._id,
username: client.user.username,
},
client: {
_id: client._id,
hoursLimit: client.hoursLimit,
},
});
await taskService.closeTaskSessionForUser(client.user);
const displayList = this.createDisplayList('session-control');
displayList.showNotification(
'Hours limit reached. The task work session has been closed.',
'danger',
'bottom-center',
5000,
);
this.dtp.emitter
.to(client.user._id.toString())
.emit('session-control', {
cmd: 'end-session',
displayList,
});
return;
}
this.log.info('adding time worked to client weekly totals', {
user: {
_id: client.user._id,
username: client.user.username,
},
client: {
_id: client._id,
hoursLimit: client.hoursLimit,
currentHours: client.weeklyTotals.timeWorked / 3600,
},
hours: duration / 3600,
});
await Client.updateOne(
{ _id: client._id },
{
$inc: { 'weeklyTotals.timeWorked': duration },
},
);
}
}