Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ChatService } from '../../../../chat/application/chat.service';
export interface EscalateTicketInput {
id: string;
groupId: string;
escalationLevel?: number;
category: string;
whatWasDone: string;
}
Expand Down Expand Up @@ -41,7 +42,7 @@ export class EscalateTicketUseCase {
throw new Error('Ticket not found');
}

foundedTicket.escalate(input.groupId, input.category, input.whatWasDone);
foundedTicket.escalate(input.groupId, input.escalationLevel, input.category, input.whatWasDone);

const escalatedTicket = await this.repository.save(foundedTicket);

Expand Down
25 changes: 22 additions & 3 deletions backend/src/modules/ticket/domain/entities/tickect.entity.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,12 @@ describe('Ticket entity', () => {
ticket.assignToAgent(newAgentId);

const newGroupId = randomUUID();
ticket.escalate(newGroupId, 'ia');

ticket.escalate(newGroupId, 1, 'ia');

expect(ticket.status).toBe(TicketStatus.ESCALATED);
expect(ticket.history.length).toBe(3);

expect(ticket.history[2]).toMatchObject({
event: TicketEvents.ESCALATE,
responsibleAgent: newAgentId,
Expand All @@ -84,18 +86,35 @@ describe('Ticket entity', () => {

expect(primitiveTicket.groupId).toBe(newGroupId);
expect(primitiveTicket.category).toBe('ia');

// categoria alterada => nível volta para 1
expect(primitiveTicket.escalationLevel).toBe(1);

expect(primitiveTicket.agentId).toBeNull();
expect(primitiveTicket.updatedAt).toBeInstanceOf(Date);
expect(primitiveTicket.updatedAt).not.toBeNull();
});

it('Should throw an error when escalating a ticket without a responsible agent', () => {
expect(() => ticket.escalate(randomUUID(), 'iot')).toThrow(
expect(() =>
ticket.escalate(randomUUID(), 1, 'iot'),
).toThrow(
TicketValidationErrors.ECALATE_WITH_NO_AGENT_ERROR,
);
});

it('Should throw an error when closing a ticket with ESCALATED status', () => {
ticket.assignToAgent(randomUUID());

ticket.escalate(randomUUID(), 1, 'web_app');

expect(ticket.status).toBe(TicketStatus.ESCALATED);

expect(() => ticket.close('Test solution')).toThrow(
TicketValidationErrors.CLOSE_WITH_WRONG_STATUS_ERROR,
);
});

it('Close a ticket should change the status and closedAt field, and add the event to history', () => {
ticket.assignToAgent(randomUUID());
ticket.close('Solução exemplo...');
Expand Down Expand Up @@ -123,7 +142,7 @@ describe('Ticket entity', () => {

it('Should throw an error when closing a ticket with ESCALATED status', () => {
ticket.assignToAgent(randomUUID());
ticket.escalate(randomUUID(), 'web_app');
ticket.escalate(randomUUID(),1, 'web_app');

expect(ticket.status).toBe(TicketStatus.ESCALATED);
expect(() => ticket.close('Test solution')).toThrow(
Expand Down
26 changes: 19 additions & 7 deletions backend/src/modules/ticket/domain/entities/ticket.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,13 @@ export class Ticket {
}

// Escalates the ticket to a new responsible group and optionally changes the category
escalate(groupId: string, category?: string, whatWasDone?: string): void {
escalate(
groupId: string,
escalationLevel?: number,
category?: string,
whatWasDone?: string,
): void {

if (!this._agentId) {
throw new Error(TicketValidationErrors.ECALATE_WITH_NO_AGENT_ERROR);
}
Expand All @@ -233,17 +239,23 @@ export class Ticket {

this._groupId = groupId;

if (category && category !== this.category) {
// ALTERA A CATEGORIA
if (category) {
this.category = category;
this.escalationLevel = 1;
} else {
if (this.escalationLevel >= 3) {
throw new Error(TicketValidationErrors.ESCALATION_LEVEL_MAX_ERROR);
}

// ALTERA O NÍVEL
if (escalationLevel !== undefined) {

if (![1, 2, 3].includes(escalationLevel)) {
throw new Error('Invalid escalation level');
}
this.escalationLevel++;

this.escalationLevel = escalationLevel;
}

const previousAgentId = this._agentId;

this._agentId = null;

this._status = TicketStatus.ESCALATED;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ describe('TicketController', () => {

const payload = {
groupUD: randomUUID(),
escalationLevel: 1,
category: 'iot',
};

Expand All @@ -331,7 +332,7 @@ describe('TicketController', () => {
const groupId = randomUUID();

ticket.assignToAgent(agentId);
ticket.escalate(groupId, 'iot');
ticket.escalate(groupId,1, 'iot');

const primitives = ticket.toPrimitives();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ export class TicketController {
}
const data = TicketMapper.toEscalateTicketInput(id, {
groupId: body.groupId,
escalationLevel: body.escalationLevel,
category: body.category || '',
whatWasDone: body.whatWasDone || '',
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IsNotEmpty, IsString } from 'class-validator';
import { IsNotEmpty, IsString, IsNumber, IsOptional } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
import { randomUUID } from 'crypto';

Expand All @@ -8,6 +8,15 @@ export class EscalateTicketRequest {
@IsNotEmpty()
groupId!: string;

@ApiProperty({
example: 2,
description: 'Nível de escalonamento',
required: false,
})
@IsNumber()
@IsOptional()
escalationLevel?: number;

@ApiProperty({ example: 'web_app', description: 'Categoria do ticket' })
@IsString()
@IsNotEmpty()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty, IsEnum, IsOptional } from 'class-validator';
import { IsString, IsNotEmpty, IsEnum, IsOptional, IsNumber } from 'class-validator';
import { TicketStatus } from '../../domain/entities/ticket.entity';

export class UpdateTicketStatusRequest {
Expand Down Expand Up @@ -42,4 +42,13 @@ export class UpdateTicketStatusRequest {
@IsString()
@IsOptional()
whatWasDone?: string;
}

@ApiProperty({
example: 2,
required: false,
description: 'Nível do escalonamento',
})
@IsNumber()
@IsOptional()
escalationLevel?: number;
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class TicketMapper {
return {
id: id,
groupId: req.groupId,
escalationLevel: req.escalationLevel,
category: req.category,
whatWasDone: req.whatWasDone,
};
Expand Down
Loading