88 lines
2.9 KiB
TypeScript
88 lines
2.9 KiB
TypeScript
/**
|
|
* Temporal Activities — operações com efeitos colaterais (banco, APIs, I/O).
|
|
* Activities são executadas pelo Worker e podem ser re-tentadas automaticamente.
|
|
*/
|
|
import { prisma } from '../database/prisma'
|
|
import { logger } from '../../config/logger'
|
|
|
|
// ─── Conflito de Agenda: liberar slot após timeout ────────────────────────────
|
|
|
|
export async function liberarSlotAgenda(input: {
|
|
solicitanteId: string
|
|
tituloSlot: string
|
|
chatIdSolicitante: string
|
|
}): Promise<void> {
|
|
logger.info(input, '[Temporal] Slot liberado por timeout — notificando solicitante')
|
|
|
|
// Aqui você envia mensagem via WhatsApp avisando o solicitante
|
|
// Implementação real acoplada ao WhatsAppConnectionManager via NATS
|
|
// Por ora, marca no banco como disponível
|
|
await prisma.protocol.updateMany({
|
|
where: {
|
|
contactId: input.solicitanteId,
|
|
status: 'WAITING_CLIENT',
|
|
},
|
|
data: { status: 'OPEN' },
|
|
})
|
|
}
|
|
|
|
export async function notificarConflito(input: {
|
|
chatIdB: string
|
|
solicitanteNome: string
|
|
tituloSlot: string
|
|
}): Promise<void> {
|
|
logger.info(input, '[Temporal] Notificando pessoa B sobre solicitação de slot')
|
|
// Dispara mensagem via NATS → WhatsApp handler
|
|
}
|
|
|
|
// ─── Gestão de Reputação ──────────────────────────────────────────────────────
|
|
|
|
export async function decrementarScore(input: {
|
|
contactId: string
|
|
motivo: string
|
|
pontos: number
|
|
}): Promise<{ novoScore: number; restrito: boolean }> {
|
|
const contact = await prisma.contact.findUnique({
|
|
where: { id: input.contactId },
|
|
})
|
|
if (!contact) throw new Error(`Contato ${input.contactId} não encontrado`)
|
|
|
|
const novoScore = Math.max(0, contact.scoreReputacao - input.pontos)
|
|
const restrito = novoScore <= 20
|
|
|
|
await prisma.contact.update({
|
|
where: { id: input.contactId },
|
|
data: {
|
|
scoreReputacao: novoScore,
|
|
flagRestricao: restrito,
|
|
},
|
|
})
|
|
|
|
logger.info({ contactId: input.contactId, novoScore, restrito, motivo: input.motivo },
|
|
'[Temporal] Score de reputação atualizado')
|
|
|
|
return { novoScore, restrito }
|
|
}
|
|
|
|
export async function bloquearAgendamentosAutomaticos(input: {
|
|
contactId: string
|
|
}): Promise<void> {
|
|
await prisma.contact.update({
|
|
where: { id: input.contactId },
|
|
data: { flagRestricao: true },
|
|
})
|
|
logger.warn({ contactId: input.contactId },
|
|
'[Temporal] Contato marcado como RESTRITO — agendamentos automáticos bloqueados')
|
|
}
|
|
|
|
export async function buscarScoreContato(contactId: string): Promise<{
|
|
score: number
|
|
restrito: boolean
|
|
}> {
|
|
const c = await prisma.contact.findUnique({
|
|
where: { id: contactId },
|
|
select: { scoreReputacao: true, flagRestricao: true },
|
|
})
|
|
return { score: c?.scoreReputacao ?? 100, restrito: c?.flagRestricao ?? false }
|
|
}
|