Commit 336e7041 by Augusto

comment and occurrence update

parent 41932462
......@@ -22,6 +22,7 @@ export const occurrenceStatusEnum = mysqlEnum('status', [
'OPEN',
'IN_PROGRESS',
'RESOLVED',
'PAUSED',
'CLOSED',
'PARCIAL_RESOLVED',
'CANCELLED',
......@@ -99,7 +100,7 @@ export const comments = mysqlTable(
id: varchar('id', { length: 25 }).primaryKey(),
content: text('content').notNull(),
isInternal: boolean('isInternal').notNull().default(false),
status: occurrenceStatusEnum('status'),
status: occurrenceStatusEnum,
occurrenceId: varchar('occurrenceId', { length: 25 }).notNull(),
authorId: varchar('authorId', { length: 25 }).notNull(),
createdAt: timestamp('createdAt').notNull().defaultNow(),
......
......@@ -76,4 +76,24 @@ export class CommentResponseDto {
example: '2024-01-15T10:30:00.000Z',
})
updatedAt: Date;
@ApiProperty({
description: 'Status of the occurrence when this comment was made',
enum: [
'OPEN',
'IN_PROGRESS',
'RESOLVED',
'CLOSED',
'PARCIAL_RESOLVED',
'CANCELLED',
],
example: 'OPEN',
})
status:
| 'OPEN'
| 'IN_PROGRESS'
| 'RESOLVED'
| 'CLOSED'
| 'PARCIAL_RESOLVED'
| 'CANCELLED';
}
import { IsString, IsNotEmpty, IsOptional, IsBoolean } from 'class-validator';
import {
IsString,
IsNotEmpty,
IsOptional,
IsBoolean,
IsEnum,
} from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
export class CreateCommentDto {
......@@ -28,4 +34,33 @@ export class CreateCommentDto {
@IsOptional()
@IsBoolean()
isInternal?: boolean = false;
@ApiPropertyOptional({
description: 'Status of the occurrence when this comment was made',
enum: [
'OPEN',
'IN_PROGRESS',
'RESOLVED',
'CLOSED',
'PARCIAL_RESOLVED',
'CANCELLED',
],
example: 'OPEN',
})
@IsOptional()
@IsEnum([
'OPEN',
'IN_PROGRESS',
'RESOLVED',
'CLOSED',
'PARCIAL_RESOLVED',
'CANCELLED',
])
status?:
| 'OPEN'
| 'IN_PROGRESS'
| 'RESOLVED'
| 'CLOSED'
| 'PARCIAL_RESOLVED'
| 'CANCELLED';
}
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
import {
IsNotEmpty,
IsOptional,
IsString,
ValidateIf,
IsDefined,
} from 'class-validator';
export class DualAssignOccurrenceDto {
@ApiProperty({
@ApiPropertyOptional({
description:
'ID of the user to assign the occurrence to (worker/technician)',
'ID of the user to assign the occurrence to (worker/technician). If not provided, only manager will be updated.',
example: 'clxyz123abc456def',
})
@IsNotEmpty()
@IsOptional()
@IsString()
assigneeId: string;
assigneeId?: string;
@ApiProperty({
description: 'ID of the manager/admin to oversee the occurrence',
@ApiPropertyOptional({
description:
'ID of the manager/admin to oversee the occurrence. If not provided, only assignee will be updated.',
example: 'clxyz789def012ghi',
})
@IsNotEmpty()
@IsOptional()
@IsString()
managerId: string;
managerId?: string;
@ApiPropertyOptional({
description: 'Optional note about the dual assignment',
......
......@@ -415,9 +415,9 @@ export class OccurrenceController {
@Roles(UserRoleEnum.ADMIN, UserRoleEnum.MODERATOR)
@ApiOperation({
summary:
'Dual assign occurrence to both a user and a manager (Admin/Moderator only)',
'Flexible assignment of occurrence to assignee and/or manager (Admin/Moderator only)',
description:
'Assigns an occurrence to both a worker/technician (assignee) and a manager/admin (manager) for dual oversight',
'Assigns an occurrence to a worker/technician (assignee), manager/admin (manager), or both. At least one field must be provided. You can update just the assignee, just the manager, or both at the same time.',
})
@ApiParam({
name: 'id',
......@@ -427,7 +427,7 @@ export class OccurrenceController {
@ApiBody({ type: DualAssignOccurrenceDto })
@ApiResponse({
status: 200,
description: 'Occurrence dual assigned successfully',
description: 'Occurrence assigned successfully',
type: OccurrenceResponseDto,
})
@ApiResponse({
......@@ -436,7 +436,8 @@ export class OccurrenceController {
})
@ApiResponse({
status: 400,
description: 'Assignee or manager user not found',
description:
'At least one of assigneeId or managerId must be provided, or user not found',
})
@ApiResponse({
status: 403,
......
......@@ -533,57 +533,104 @@ export class OccurrenceService {
// Check if occurrence exists
await this.findOne(occurrenceId);
// Validate that assignee exists
const [assignee] = await this.drizzle.db
.select()
.from(users)
.where(eq(users.id, dualAssignOccurrenceDto.assigneeId))
.limit(1);
// Validate that at least one field is provided
if (
!dualAssignOccurrenceDto.assigneeId &&
!dualAssignOccurrenceDto.managerId
) {
throw new BadRequestException(
'At least one of assigneeId or managerId must be provided',
);
}
if (!assignee) {
throw new BadRequestException('Assignee user not found');
let assignee: any = null;
let manager: any = null;
// Validate that assignee exists (if provided)
if (dualAssignOccurrenceDto.assigneeId) {
[assignee] = await this.drizzle.db
.select()
.from(users)
.where(eq(users.id, dualAssignOccurrenceDto.assigneeId))
.limit(1);
if (!assignee) {
throw new BadRequestException('Assignee user not found');
}
}
// Validate that manager exists
const [manager] = await this.drizzle.db
.select()
.from(users)
.where(eq(users.id, dualAssignOccurrenceDto.managerId))
.limit(1);
// Validate that manager exists (if provided)
if (dualAssignOccurrenceDto.managerId) {
[manager] = await this.drizzle.db
.select()
.from(users)
.where(eq(users.id, dualAssignOccurrenceDto.managerId))
.limit(1);
if (!manager) {
throw new BadRequestException('Manager user not found');
if (!manager) {
throw new BadRequestException('Manager user not found');
}
}
// Update occurrence with both assignee and manager
// Prepare update object with only provided fields
const updateData: any = {};
if (dualAssignOccurrenceDto.assigneeId) {
updateData.assigneeId = dualAssignOccurrenceDto.assigneeId;
}
if (dualAssignOccurrenceDto.managerId) {
updateData.managerId = dualAssignOccurrenceDto.managerId;
}
// Set status to IN_PROGRESS if either assignee or manager is being assigned
updateData.status = OccurrenceStatusEnum.IN_PROGRESS;
// Update occurrence with provided fields
await this.drizzle.db
.update(occurrences)
.set({
assigneeId: dualAssignOccurrenceDto.assigneeId,
managerId: dualAssignOccurrenceDto.managerId,
status: OccurrenceStatusEnum.IN_PROGRESS,
})
.set(updateData)
.where(eq(occurrences.id, occurrenceId));
// If there's an assignment note, create a comment
if (dualAssignOccurrenceDto.assignmentNote) {
const commentId = this.drizzle.generateId();
const authorId =
dualAssignOccurrenceDto.managerId ||
dualAssignOccurrenceDto.assigneeId ||
performedBy;
await this.drizzle.db.insert(comments).values({
id: commentId,
content: `Dual assignment note: ${dualAssignOccurrenceDto.assignmentNote}`,
content: `Assignment note: ${dualAssignOccurrenceDto.assignmentNote}`,
isInternal: true,
occurrenceId: occurrenceId,
authorId: dualAssignOccurrenceDto.managerId, // Manager creates the note
authorId: authorId,
});
}
// Log the dual assignment
await this.logService.logDualAssignment(
occurrenceId,
performedBy,
`${assignee.firstName} ${assignee.lastName}`,
`${manager.firstName} ${manager.lastName}`,
);
// Log the assignment based on what was updated
if (assignee && manager) {
// Both assigned - dual assignment
await this.logService.logDualAssignment(
occurrenceId,
performedBy,
`${assignee.firstName} ${assignee.lastName}`,
`${manager.firstName} ${manager.lastName}`,
);
} else if (assignee) {
// Only assignee assigned
await this.logService.logAssignment(
occurrenceId,
performedBy,
`${assignee.firstName} ${assignee.lastName}`,
);
} else if (manager) {
// Only manager assigned
await this.logService.logAssignment(
occurrenceId,
performedBy,
`Manager: ${manager.firstName} ${manager.lastName}`,
);
}
return this.getOccurrenceWithRelations(occurrenceId);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment