// 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 }, }, ); } }