Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class NewAgentTicketUseCase {
if (!foundedTicket) {
throw new Error('Ticket not found.');
}

foundedTicket.assignToAgent(input.agentId);

const updatedTicket = await this.repository.save(foundedTicket);
Expand All @@ -37,7 +37,10 @@ export class NewAgentTicketUseCase {
}

try {
await this.chatService.updateAgentByTicketId(updatedTicket.id, updatedTicket.agentId);
await this.chatService.updateAgentByTicketId(
updatedTicket.id,
updatedTicket.agentId,
);
} catch (e) {
console.warn('Chat não pôde ser atualizado ou não existe:', e);
}
Expand All @@ -48,4 +51,4 @@ export class NewAgentTicketUseCase {
status: updatedTicket.status,
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ describe('ReadAllTicketUseCase', () => {
});
expect(output).toBeDefined();
expect(Array.isArray(output)).toBe(true);
expect(output[0].clientId).toBe(ticket.clientId);
expect(repository.readAll).toHaveBeenCalledWith({
clientId: ticket.clientId,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Injectable } from '@nestjs/common';
import {
Ticket,
AgentField,
ClientField,
TicketPriority,
TicketStatus,
} from '../../../domain/entities/ticket.entity';
Expand All @@ -13,13 +14,13 @@ export interface ReadAllTicketOutput {
category: string;
priority: TicketPriority;
description: string;
clientId: string;
client: ClientField | null;
status: TicketStatus;
agentId: string | null;
escalationLevel: number;
createdAt: Date;
updatedAt: Date | null;
closedAt: Date | null;
agent?: AgentField | null;
}

@Injectable()
Expand Down Expand Up @@ -50,7 +51,7 @@ export class ReadAllTicketUseCase {
onlyMine: input.onlyMine,
});

const convertedTickets = foundedTickets.map((t: Ticket) => {
const convertedTickets = foundedTickets.map((t) => {
const primitive = t.toPrimitives();

return {
Expand All @@ -59,13 +60,13 @@ export class ReadAllTicketUseCase {
category: primitive.category,
priority: primitive.priority,
description: primitive.description,
clientId: primitive.clientId,
client: primitive.client,
status: primitive.status,
agentId: primitive.agentId,
escalationLevel: primitive.escalationLevel,
createdAt: primitive.createdAt,
updatedAt: primitive.updatedAt,
closedAt: primitive.closedAt,
agent: primitive.agent,
};
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Injectable } from '@nestjs/common';
import {
AgentField,
ClientField,
TicketPriority,
TicketStatus,
} from '../../../domain/entities/ticket.entity';
Expand All @@ -11,9 +13,9 @@ export interface ReadByIdTicketOutput {
category: string;
priority: TicketPriority;
description: string;
clientId: string;
client: ClientField | null;
status: TicketStatus;
agentId: string | null;
agent: AgentField | null;
groupId: string | null;
escalationLevel: number;
createdAt: Date;
Expand All @@ -40,9 +42,9 @@ export class ReadByIdTicketUseCase {
category: primitive.category,
priority: primitive.priority,
description: primitive.description,
clientId: primitive.clientId,
client: primitive.client,
status: primitive.status,
agentId: primitive.agentId,
agent: primitive.agent,
groupId: primitive.groupId,
escalationLevel: primitive.escalationLevel,
createdAt: primitive.createdAt,
Expand Down
22 changes: 21 additions & 1 deletion backend/src/modules/ticket/domain/entities/ticket.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,25 @@ export type TicketHistoryEntry = {
occurredAt: Date;
};

export type AgentField = {
id: string | null;
name: string;
};

export type ClientField = {
id: string | null;
name: string;
};

export class Ticket {
// Strutucture definition
private _id: string;

private _status: TicketStatus = TicketStatus.OPEN;
private _agentId: string | null = null;
private agent: AgentField | null = null;
private client: ClientField | null = null;

private _groupId: string | null = null;
private escalationLevel: number = 1;
private attachmentsUrls: string[] = [];
Expand Down Expand Up @@ -135,7 +148,9 @@ export class Ticket {
fileUrls?: string[];
status: TicketStatus;
clientId: string;
agentId?: string;
client?: ClientField | null;
agentId?: string | null;
agent?: AgentField | null;
groupId?: string;
escalationLevel: number;
history: TicketHistoryEntry[];
Expand All @@ -153,6 +168,9 @@ export class Ticket {
ticket._id = props._id;

ticket._agentId = props.agentId ?? null;
ticket.agent = props.agent ?? null;
ticket.client = props.client ?? null;

ticket._groupId = props.groupId ?? null;
ticket.attachmentsUrls = props.fileUrls ?? [];

Expand All @@ -177,9 +195,11 @@ export class Ticket {
priority: this.priority,
description: this.description,
clientId: this._clientId,
client: this.client ? { ...this.client } : null,
fileUrls: this.attachmentsUrls,
status: this.status,
agentId: this._agentId,
agent: this.agent ? { ...this.agent } : null,
groupId: this._groupId,
escalationLevel: this.escalationLevel,
history: this.history,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ describe('ITicketRepository', () => {
const primitiveResult = resultById?.toPrimitives();

expect(primitiveResult?.title).toBe('chamado 3');
expect(primitiveResult?.category).toBe(categoryId);
expect(primitiveResult?.priority).toBe(TicketPriority.LOW);
expect(primitiveResult?.description).toBe('descricao do chamado 3');
});
Expand All @@ -148,7 +147,6 @@ describe('ITicketRepository', () => {
const ticket = await repository.create(ticketToCreate);

expect(ticket).toBeDefined();
expect(ticket.agentId).toBe(null);
expect(ticket.status).toBe(TicketStatus.OPEN);

const newAgentId = randomUUID();
Expand Down
130 changes: 130 additions & 0 deletions backend/src/modules/ticket/infra/helpers/ticket.aggregate.builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
export class TicketAggregateBuilder {
static agentLookup() {
return [
{
$lookup: {
from: 'users',
let: { agentId: '$agentId' },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $ne: ['$$agentId', null] },
{ $eq: [{ $toString: '$_id' }, '$$agentId'] },
],
},
},
},
],
as: 'agentData',
},
},
{
$addFields: {
agent: {
$cond: {
if: { $gt: [{ $size: '$agentData' }, 0] },
then: {
id: { $toString: { $arrayElemAt: ['$agentData._id', 0] } },
name: { $arrayElemAt: ['$agentData.name', 0] },
},
else: null,
},
},
},
},
];
}

static categoryLookup() {
return [
{
$lookup: {
from: 'categories',
let: { categoryId: '$category' },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $ne: ['$$categoryId', null] },
{ $eq: [{ $toString: '$_id' }, '$$categoryId'] },
],
},
},
},
],
as: 'categoryData',
},
},
{
$addFields: {
category: {
$cond: {
if: { $gt: [{ $size: '$categoryData' }, 0] },
then: {
id: { $toString: { $arrayElemAt: ['$categoryData._id', 0] } },
name: { $arrayElemAt: ['$categoryData.name', 0] },
},
else: null,
},
},
},
},
];
}

static clientLookup() {
return [
{
$lookup: {
from: 'users',
let: { id: '$clientId' },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $ne: ['$$id', null] },
{ $eq: [{ $toString: '$_id' }, '$$id'] },
],
},
},
},
],
as: 'clientData',
},
},
{
$addFields: {
client: {
$cond: {
if: { $gt: [{ $size: '$clientData' }, 0] },
then: {
id: { $toString: { $arrayElemAt: ['$clientData._id', 0] } },
name: { $arrayElemAt: ['$clientData.name', 0] },
},
else: null,
},
},
},
},
];
}

static cleanup() {
return {
$unset: ['agentData', 'agentId', 'categoryData', '__v'],
};
}

static buildAggregate() {
return [
...this.agentLookup(),
...this.categoryLookup(),
...this.clientLookup(),
this.cleanup(),
];
}
}
14 changes: 11 additions & 3 deletions backend/src/modules/ticket/infra/mappers/ticket.mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@ import {
TicketStatus,
TicketHistoryEntry,
} from '../../domain/entities/ticket.entity';
import { TicketDocument, TicketLean } from '../schemas/ticket.mongo.schema';
import {
TicketAggregate,
TicketDocument,
TicketLean,
} from '../schemas/ticket.mongo.schema';

export class TicketMapper {
static toDomain(doc: TicketDocument | TicketLean): Ticket {
static toDomain(doc: TicketDocument | TicketLean | TicketAggregate): Ticket {
const aggregated = doc as TicketAggregate;

return Ticket.restore({
_id: doc._id.toString(),
title: doc.title,
Expand All @@ -18,7 +24,9 @@ export class TicketMapper {
status: doc.status as TicketStatus,
description: doc.description,
clientId: doc.clientId,
agentId: doc.agentId ?? undefined,
client: aggregated.client ?? null,
agentId: doc.agentId ?? null,
agent: aggregated.agent ?? null,
escalationLevel: doc.escalationLevel,
fileUrls: doc.attachmentsUrls,
history: doc.history.map(
Expand Down
Loading
Loading