FEAT: Adicionado configuraçãoes de pausa e presença
All checks were successful
Deploy Dev / deploy (push) Successful in 3s
All checks were successful
Deploy Dev / deploy (push) Successful in 3s
This commit is contained in:
parent
e1a31f3f07
commit
1e28ecc349
@ -3,11 +3,14 @@ import { AdminAccessController } from './admin-access.controller';
|
|||||||
import { AdminAccessService } from './admin-access.service';
|
import { AdminAccessService } from './admin-access.service';
|
||||||
import { AgentNotesController } from './agent-notes.controller';
|
import { AgentNotesController } from './agent-notes.controller';
|
||||||
import { AgentNotesService } from './agent-notes.service';
|
import { AgentNotesService } from './agent-notes.service';
|
||||||
|
import { AgentPresenceController } from './agent-presence.controller';
|
||||||
|
import { AgentPresenceService } from './agent-presence.service';
|
||||||
import { CustomerContactsController } from './customer-contacts.controller';
|
import { CustomerContactsController } from './customer-contacts.controller';
|
||||||
import { CustomerContactsService } from './customer-contacts.service';
|
import { CustomerContactsService } from './customer-contacts.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [AdminAccessController, AgentNotesController, CustomerContactsController],
|
controllers: [AdminAccessController, AgentNotesController, AgentPresenceController, CustomerContactsController],
|
||||||
providers: [AdminAccessService, AgentNotesService, CustomerContactsService],
|
providers: [AdminAccessService, AgentNotesService, AgentPresenceService, CustomerContactsService],
|
||||||
|
exports: [AgentPresenceService],
|
||||||
})
|
})
|
||||||
export class AdminModule {}
|
export class AdminModule {}
|
||||||
|
|||||||
32
src/modules/admin/agent-presence.controller.ts
Normal file
32
src/modules/admin/agent-presence.controller.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { Body, Controller, Get, Post, Query } from '@nestjs/common';
|
||||||
|
import { AgentPresenceService } from './agent-presence.service';
|
||||||
|
|
||||||
|
@Controller('agent/presence')
|
||||||
|
export class AgentPresenceController {
|
||||||
|
constructor(private readonly agentPresenceService: AgentPresenceService) {}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
listPresence() {
|
||||||
|
return this.agentPresenceService.listPresence();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('me')
|
||||||
|
getPresence(@Query('userId') userId: string) {
|
||||||
|
return this.agentPresenceService.getPresence(Number(userId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('pause')
|
||||||
|
pause(@Body() body: { userId: number }) {
|
||||||
|
return this.agentPresenceService.pause(Number(body.userId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('resume')
|
||||||
|
resume(@Body() body: { userId: number }) {
|
||||||
|
return this.agentPresenceService.resume(Number(body.userId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('offline')
|
||||||
|
offline(@Body() body: { userId: number }) {
|
||||||
|
return this.agentPresenceService.offline(Number(body.userId));
|
||||||
|
}
|
||||||
|
}
|
||||||
260
src/modules/admin/agent-presence.service.ts
Normal file
260
src/modules/admin/agent-presence.service.ts
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
import { BadRequestException, Injectable, OnModuleInit } from '@nestjs/common';
|
||||||
|
import { DatabaseService } from '../../infra/database/database.service';
|
||||||
|
|
||||||
|
type AgentPresenceStatus = 'available' | 'paused' | 'offline';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AgentPresenceService implements OnModuleInit {
|
||||||
|
constructor(private readonly database: DatabaseService) {}
|
||||||
|
|
||||||
|
async onModuleInit() {
|
||||||
|
await this.ensureSchema();
|
||||||
|
}
|
||||||
|
|
||||||
|
async ensureSchema() {
|
||||||
|
await this.database.query(`
|
||||||
|
CREATE TABLE IF NOT EXISTS agent_presence (
|
||||||
|
user_id INTEGER PRIMARY KEY REFERENCES usuarios(id) ON DELETE CASCADE,
|
||||||
|
status VARCHAR(40) NOT NULL DEFAULT 'offline',
|
||||||
|
paused_at TIMESTAMP WITH TIME ZONE,
|
||||||
|
last_seen_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
await this.database.query(`
|
||||||
|
ALTER TABLE whatsapp_chat_atribuicoes
|
||||||
|
ADD COLUMN IF NOT EXISTS reserved_user_id INTEGER REFERENCES usuarios(id) ON DELETE SET NULL,
|
||||||
|
ADD COLUMN IF NOT EXISTS reserved_at TIMESTAMP WITH TIME ZONE,
|
||||||
|
ADD COLUMN IF NOT EXISTS pause_released_at TIMESTAMP WITH TIME ZONE;
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async listPresence() {
|
||||||
|
const result = await this.database.query(`
|
||||||
|
SELECT
|
||||||
|
u.id AS user_id,
|
||||||
|
u.nome,
|
||||||
|
u.email,
|
||||||
|
COALESCE(ap.status, 'offline') AS status,
|
||||||
|
ap.paused_at,
|
||||||
|
ap.last_seen_at,
|
||||||
|
ap.updated_at,
|
||||||
|
CASE
|
||||||
|
WHEN ap.status = 'paused' AND ap.paused_at IS NOT NULL
|
||||||
|
THEN FLOOR(EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - ap.paused_at)))::INTEGER
|
||||||
|
ELSE 0
|
||||||
|
END AS paused_seconds,
|
||||||
|
COUNT(DISTINCT assigned.chat_id)::INTEGER AS assigned_count,
|
||||||
|
COUNT(DISTINCT reserved.chat_id)::INTEGER AS reserved_count
|
||||||
|
FROM usuarios u
|
||||||
|
LEFT JOIN agent_presence ap ON ap.user_id = u.id
|
||||||
|
LEFT JOIN whatsapp_chat_atribuicoes assigned
|
||||||
|
ON assigned.user_id = u.id
|
||||||
|
AND assigned.status = 'assigned'
|
||||||
|
LEFT JOIN whatsapp_chat_atribuicoes reserved
|
||||||
|
ON reserved.reserved_user_id = u.id
|
||||||
|
AND reserved.status = 'queued'
|
||||||
|
AND reserved.user_id IS NULL
|
||||||
|
WHERE u.ativo = TRUE
|
||||||
|
GROUP BY u.id, u.nome, u.email, ap.status, ap.paused_at, ap.last_seen_at, ap.updated_at
|
||||||
|
ORDER BY u.nome ASC
|
||||||
|
`);
|
||||||
|
|
||||||
|
return result.rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getPresence(userId: number) {
|
||||||
|
this.assertUserId(userId);
|
||||||
|
await this.touchPresence(userId, 'available', false);
|
||||||
|
|
||||||
|
const result = await this.database.query(
|
||||||
|
`
|
||||||
|
SELECT
|
||||||
|
user_id,
|
||||||
|
status,
|
||||||
|
paused_at,
|
||||||
|
last_seen_at,
|
||||||
|
updated_at,
|
||||||
|
CASE
|
||||||
|
WHEN status = 'paused' AND paused_at IS NOT NULL
|
||||||
|
THEN FLOOR(EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - paused_at)))::INTEGER
|
||||||
|
ELSE 0
|
||||||
|
END AS paused_seconds
|
||||||
|
FROM agent_presence
|
||||||
|
WHERE user_id = $1
|
||||||
|
`,
|
||||||
|
[userId],
|
||||||
|
);
|
||||||
|
|
||||||
|
return result.rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async pause(userId: number) {
|
||||||
|
this.assertUserId(userId);
|
||||||
|
|
||||||
|
return this.database.transaction(async (client) => {
|
||||||
|
const presence = await client.query(
|
||||||
|
`
|
||||||
|
INSERT INTO agent_presence (user_id, status, paused_at, last_seen_at, updated_at)
|
||||||
|
VALUES ($1, 'paused', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||||
|
ON CONFLICT (user_id) DO UPDATE SET
|
||||||
|
status = 'paused',
|
||||||
|
paused_at = COALESCE(agent_presence.paused_at, CURRENT_TIMESTAMP),
|
||||||
|
last_seen_at = CURRENT_TIMESTAMP,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
RETURNING *
|
||||||
|
`,
|
||||||
|
[userId],
|
||||||
|
);
|
||||||
|
|
||||||
|
const released = await client.query(
|
||||||
|
`
|
||||||
|
UPDATE whatsapp_chat_atribuicoes
|
||||||
|
SET
|
||||||
|
reserved_user_id = $1,
|
||||||
|
reserved_at = CURRENT_TIMESTAMP,
|
||||||
|
pause_released_at = CURRENT_TIMESTAMP,
|
||||||
|
user_id = NULL,
|
||||||
|
status = 'queued',
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE user_id = $1
|
||||||
|
AND status = 'assigned'
|
||||||
|
RETURNING *
|
||||||
|
`,
|
||||||
|
[userId],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
presence: presence.rows[0],
|
||||||
|
releasedCount: released.rowCount,
|
||||||
|
releasedChats: released.rows,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async resume(userId: number) {
|
||||||
|
this.assertUserId(userId);
|
||||||
|
|
||||||
|
return this.database.transaction(async (client) => {
|
||||||
|
const presence = await client.query(
|
||||||
|
`
|
||||||
|
INSERT INTO agent_presence (user_id, status, paused_at, last_seen_at, updated_at)
|
||||||
|
VALUES ($1, 'available', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||||
|
ON CONFLICT (user_id) DO UPDATE SET
|
||||||
|
status = 'available',
|
||||||
|
paused_at = NULL,
|
||||||
|
last_seen_at = CURRENT_TIMESTAMP,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
RETURNING *
|
||||||
|
`,
|
||||||
|
[userId],
|
||||||
|
);
|
||||||
|
|
||||||
|
const restored = await client.query(
|
||||||
|
`
|
||||||
|
UPDATE whatsapp_chat_atribuicoes
|
||||||
|
SET
|
||||||
|
user_id = $1,
|
||||||
|
status = 'assigned',
|
||||||
|
assigned_at = CURRENT_TIMESTAMP,
|
||||||
|
reserved_user_id = NULL,
|
||||||
|
reserved_at = NULL,
|
||||||
|
pause_released_at = NULL,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE reserved_user_id = $1
|
||||||
|
AND status = 'queued'
|
||||||
|
AND user_id IS NULL
|
||||||
|
RETURNING *
|
||||||
|
`,
|
||||||
|
[userId],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
presence: presence.rows[0],
|
||||||
|
restoredCount: restored.rowCount,
|
||||||
|
restoredChats: restored.rows,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async offline(userId: number) {
|
||||||
|
this.assertUserId(userId);
|
||||||
|
|
||||||
|
return this.database.transaction(async (client) => {
|
||||||
|
const presence = await client.query(
|
||||||
|
`
|
||||||
|
INSERT INTO agent_presence (user_id, status, paused_at, last_seen_at, updated_at)
|
||||||
|
VALUES ($1, 'offline', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||||
|
ON CONFLICT (user_id) DO UPDATE SET
|
||||||
|
status = 'offline',
|
||||||
|
paused_at = NULL,
|
||||||
|
last_seen_at = CURRENT_TIMESTAMP,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
RETURNING *
|
||||||
|
`,
|
||||||
|
[userId],
|
||||||
|
);
|
||||||
|
|
||||||
|
const released = await client.query(
|
||||||
|
`
|
||||||
|
UPDATE whatsapp_chat_atribuicoes
|
||||||
|
SET
|
||||||
|
user_id = NULL,
|
||||||
|
status = 'queued',
|
||||||
|
reserved_user_id = NULL,
|
||||||
|
reserved_at = NULL,
|
||||||
|
pause_released_at = NULL,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE (user_id = $1 OR reserved_user_id = $1)
|
||||||
|
AND status IN ('assigned', 'queued')
|
||||||
|
RETURNING *
|
||||||
|
`,
|
||||||
|
[userId],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
presence: presence.rows[0],
|
||||||
|
releasedCount: released.rowCount,
|
||||||
|
releasedChats: released.rows,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async isAvailable(userId: number) {
|
||||||
|
this.assertUserId(userId);
|
||||||
|
const result = await this.database.query<{ status: AgentPresenceStatus }>(
|
||||||
|
`
|
||||||
|
SELECT COALESCE(ap.status, 'offline') AS status
|
||||||
|
FROM usuarios u
|
||||||
|
LEFT JOIN agent_presence ap ON ap.user_id = u.id
|
||||||
|
WHERE u.id = $1
|
||||||
|
AND u.ativo = TRUE
|
||||||
|
LIMIT 1
|
||||||
|
`,
|
||||||
|
[userId],
|
||||||
|
);
|
||||||
|
|
||||||
|
return result.rows[0]?.status === 'available';
|
||||||
|
}
|
||||||
|
|
||||||
|
private async touchPresence(userId: number, fallbackStatus: AgentPresenceStatus, updateStatus = true) {
|
||||||
|
await this.database.query(
|
||||||
|
`
|
||||||
|
INSERT INTO agent_presence (user_id, status, last_seen_at, updated_at)
|
||||||
|
VALUES ($1, $2, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||||
|
ON CONFLICT (user_id) DO UPDATE SET
|
||||||
|
status = CASE WHEN $3 THEN EXCLUDED.status ELSE agent_presence.status END,
|
||||||
|
last_seen_at = CURRENT_TIMESTAMP,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
`,
|
||||||
|
[userId, fallbackStatus, updateStatus],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private assertUserId(userId: number) {
|
||||||
|
if (!Number.isFinite(userId) || userId <= 0) {
|
||||||
|
throw new BadRequestException('Usuario invalido para controle de presenca.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
import { BadRequestException, Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||||
import { DatabaseService } from '../../infra/database/database.service';
|
import { DatabaseService } from '../../infra/database/database.service';
|
||||||
|
import { AgentPresenceService } from '../admin/agent-presence.service';
|
||||||
|
|
||||||
interface TransferInput {
|
interface TransferInput {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
@ -52,7 +53,10 @@ const SALES_KEYWORDS = [
|
|||||||
export class WhatsappAssignmentService implements OnModuleInit {
|
export class WhatsappAssignmentService implements OnModuleInit {
|
||||||
private readonly logger = new Logger(WhatsappAssignmentService.name);
|
private readonly logger = new Logger(WhatsappAssignmentService.name);
|
||||||
|
|
||||||
constructor(private readonly db: DatabaseService) {}
|
constructor(
|
||||||
|
private readonly db: DatabaseService,
|
||||||
|
private readonly agentPresenceService: AgentPresenceService,
|
||||||
|
) {}
|
||||||
|
|
||||||
async onModuleInit() {
|
async onModuleInit() {
|
||||||
await this.ensureSchema();
|
await this.ensureSchema();
|
||||||
@ -75,12 +79,16 @@ export class WhatsappAssignmentService implements OnModuleInit {
|
|||||||
ADD COLUMN IF NOT EXISTS last_routed_message_id VARCHAR(255),
|
ADD COLUMN IF NOT EXISTS last_routed_message_id VARCHAR(255),
|
||||||
ADD COLUMN IF NOT EXISTS last_bot_sent_at TIMESTAMP WITH TIME ZONE,
|
ADD COLUMN IF NOT EXISTS last_bot_sent_at TIMESTAMP WITH TIME ZONE,
|
||||||
ADD COLUMN IF NOT EXISTS awaiting_customer_reply BOOLEAN NOT NULL DEFAULT FALSE,
|
ADD COLUMN IF NOT EXISTS awaiting_customer_reply BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
ADD COLUMN IF NOT EXISTS reserved_user_id INTEGER REFERENCES usuarios(id) ON DELETE SET NULL,
|
||||||
|
ADD COLUMN IF NOT EXISTS reserved_at TIMESTAMP WITH TIME ZONE,
|
||||||
|
ADD COLUMN IF NOT EXISTS pause_released_at TIMESTAMP WITH TIME ZONE,
|
||||||
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP;
|
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP;
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async assignChat(chatId: string, userId: string | number, areaId?: string | number | null) {
|
async assignChat(chatId: string, userId: string | number, areaId?: string | number | null) {
|
||||||
this.logger.log(`Atribuindo chat ${chatId} ao usuario ${userId}`);
|
this.logger.log(`Atribuindo chat ${chatId} ao usuario ${userId}`);
|
||||||
|
await this.assertUserCanReceiveAssignment(Number(userId));
|
||||||
|
|
||||||
const query = `
|
const query = `
|
||||||
INSERT INTO whatsapp_chat_atribuicoes (
|
INSERT INTO whatsapp_chat_atribuicoes (
|
||||||
@ -92,6 +100,9 @@ export class WhatsappAssignmentService implements OnModuleInit {
|
|||||||
area_id = COALESCE(EXCLUDED.area_id, whatsapp_chat_atribuicoes.area_id),
|
area_id = COALESCE(EXCLUDED.area_id, whatsapp_chat_atribuicoes.area_id),
|
||||||
status = 'assigned',
|
status = 'assigned',
|
||||||
awaiting_customer_reply = FALSE,
|
awaiting_customer_reply = FALSE,
|
||||||
|
reserved_user_id = NULL,
|
||||||
|
reserved_at = NULL,
|
||||||
|
pause_released_at = NULL,
|
||||||
assigned_at = CURRENT_TIMESTAMP,
|
assigned_at = CURRENT_TIMESTAMP,
|
||||||
updated_at = CURRENT_TIMESTAMP
|
updated_at = CURRENT_TIMESTAMP
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
@ -111,6 +122,9 @@ export class WhatsappAssignmentService implements OnModuleInit {
|
|||||||
user_id = NULL,
|
user_id = NULL,
|
||||||
area_id = EXCLUDED.area_id,
|
area_id = EXCLUDED.area_id,
|
||||||
status = 'queued',
|
status = 'queued',
|
||||||
|
reserved_user_id = NULL,
|
||||||
|
reserved_at = NULL,
|
||||||
|
pause_released_at = NULL,
|
||||||
conversation_started_at = CASE
|
conversation_started_at = CASE
|
||||||
WHEN whatsapp_chat_atribuicoes.expires_at <= CURRENT_TIMESTAMP THEN CURRENT_TIMESTAMP
|
WHEN whatsapp_chat_atribuicoes.expires_at <= CURRENT_TIMESTAMP THEN CURRENT_TIMESTAMP
|
||||||
ELSE whatsapp_chat_atribuicoes.conversation_started_at
|
ELSE whatsapp_chat_atribuicoes.conversation_started_at
|
||||||
@ -130,6 +144,10 @@ export class WhatsappAssignmentService implements OnModuleInit {
|
|||||||
|
|
||||||
async transferChat(input: TransferInput) {
|
async transferChat(input: TransferInput) {
|
||||||
const status = input.userId ? 'assigned' : 'queued';
|
const status = input.userId ? 'assigned' : 'queued';
|
||||||
|
if (input.userId) {
|
||||||
|
await this.assertUserCanReceiveAssignment(input.userId);
|
||||||
|
}
|
||||||
|
|
||||||
const query = `
|
const query = `
|
||||||
INSERT INTO whatsapp_chat_atribuicoes (
|
INSERT INTO whatsapp_chat_atribuicoes (
|
||||||
chat_id, user_id, area_id, status, conversation_started_at, expires_at, transfer_note, assigned_at, updated_at
|
chat_id, user_id, area_id, status, conversation_started_at, expires_at, transfer_note, assigned_at, updated_at
|
||||||
@ -140,6 +158,9 @@ export class WhatsappAssignmentService implements OnModuleInit {
|
|||||||
area_id = EXCLUDED.area_id,
|
area_id = EXCLUDED.area_id,
|
||||||
status = EXCLUDED.status,
|
status = EXCLUDED.status,
|
||||||
transfer_note = EXCLUDED.transfer_note,
|
transfer_note = EXCLUDED.transfer_note,
|
||||||
|
reserved_user_id = NULL,
|
||||||
|
reserved_at = NULL,
|
||||||
|
pause_released_at = NULL,
|
||||||
assigned_at = CURRENT_TIMESTAMP,
|
assigned_at = CURRENT_TIMESTAMP,
|
||||||
updated_at = CURRENT_TIMESTAMP
|
updated_at = CURRENT_TIMESTAMP
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
@ -181,7 +202,13 @@ export class WhatsappAssignmentService implements OnModuleInit {
|
|||||||
this.logger.log(`Liberando chat ${chatId}`);
|
this.logger.log(`Liberando chat ${chatId}`);
|
||||||
const query = `
|
const query = `
|
||||||
UPDATE whatsapp_chat_atribuicoes
|
UPDATE whatsapp_chat_atribuicoes
|
||||||
SET user_id = NULL, status = 'queued', updated_at = CURRENT_TIMESTAMP
|
SET
|
||||||
|
user_id = NULL,
|
||||||
|
status = 'queued',
|
||||||
|
reserved_user_id = NULL,
|
||||||
|
reserved_at = NULL,
|
||||||
|
pause_released_at = NULL,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
WHERE chat_id = $1
|
WHERE chat_id = $1
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
`;
|
`;
|
||||||
@ -347,6 +374,13 @@ export class WhatsappAssignmentService implements OnModuleInit {
|
|||||||
return this.getAreaByName(targetName);
|
return this.getAreaByName(targetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async assertUserCanReceiveAssignment(userId: number) {
|
||||||
|
const canReceive = await this.agentPresenceService.isAvailable(userId);
|
||||||
|
if (!canReceive) {
|
||||||
|
throw new BadRequestException('Usuario indisponivel para receber atendimento.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async getAreaByName(targetName: string) {
|
private async getAreaByName(targetName: string) {
|
||||||
const result = await this.db.query<{ id: number; nome: string }>(
|
const result = await this.db.query<{ id: number; nome: string }>(
|
||||||
`SELECT id, nome FROM areas WHERE nome = $1 LIMIT 1`,
|
`SELECT id, nome FROM areas WHERE nome = $1 LIMIT 1`,
|
||||||
|
|||||||
@ -3,8 +3,10 @@ import { WhatsappService } from './whatsapp.service';
|
|||||||
import { WhatsappGateway } from './whatsapp.gateway';
|
import { WhatsappGateway } from './whatsapp.gateway';
|
||||||
import { WhatsappController } from './whatsapp.controller';
|
import { WhatsappController } from './whatsapp.controller';
|
||||||
import { WhatsappAssignmentService } from './whatsapp-assignment.service';
|
import { WhatsappAssignmentService } from './whatsapp-assignment.service';
|
||||||
|
import { AdminModule } from '../admin/admin.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
imports: [AdminModule],
|
||||||
providers: [WhatsappService, WhatsappGateway, WhatsappAssignmentService],
|
providers: [WhatsappService, WhatsappGateway, WhatsappAssignmentService],
|
||||||
controllers: [WhatsappController],
|
controllers: [WhatsappController],
|
||||||
exports: [WhatsappService, WhatsappAssignmentService],
|
exports: [WhatsappService, WhatsappAssignmentService],
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user