refactor(erp): integração direta com banco ERP — schema sar
Revoga ADR 0006 (BD-por-workspace separado). O SAR agora conecta ao banco PostgreSQL do ERP (módulo SIG) e usa o schema `sar` para tudo. PRISMA - Remove: Client, Product, Order, OrderItem, OrderStatusHistory, RepTarget, RepDiscountLimit, PushSubscription (modelos isolados) - Adiciona: Pedido, PedidoItem, HistoricoPedido, AlcadaDesconto, MetaRepresentante, PushSubscription (mapeados para sar.*) - IDs: id_cliente/cod_vendedor/id_empresa são INTEGER (ERP) - situa: Int (1=Pendente 2=Aprovado 3=Cancelado 4=Faturado) - JWT: workspace_id:string → id_empresa:number - URL: inclui ?schema=sar para Prisma rotear ao schema ERP SERVICES - ClientsService: $queryRawUnsafe contra sar.vw_clientes + sar.pedidos - CatalogService: $queryRawUnsafe contra sar.vw_produtos + sar.vw_estoque - OrdersService: Prisma models Pedido/PedidoItem/HistoricoPedido/AlcadaDesconto - DashboardService: MetaRepresentante + queries raw para inativos - NotificationsService: PushSubscription com codVendedor + idEmpresa CONTRATOS (api-interface) - client.contract: campos ERP (idCliente, nome, cgcpf, cod_vendedor…) - order.contract: PedidoSummary/PedidoDetail/CreatePedido + SITUA_LABEL - product.contract: ProdutoSummary/ProdutoDetail (vw_produtos) - auth.contract: workspaceId:string → idEmpresa:number WEB - Todos os cockpits e queries atualizados para os novos tipos Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ClsService } from 'nestjs-cls';
|
||||
import { OrderStatus } from '@prisma/client';
|
||||
import type { SubscribePayload, PendingCountResponse } from '@sar/api-interface';
|
||||
import type { WorkspaceClsStore } from '../workspace/workspace.types';
|
||||
import { PushService, type PushPayload } from './push.service';
|
||||
|
||||
// Situa: 1=Pendente Aprovação
|
||||
const SITUA_PENDENTE = 1;
|
||||
|
||||
@Injectable()
|
||||
export class NotificationsService {
|
||||
constructor(
|
||||
@@ -15,12 +17,21 @@ export class NotificationsService {
|
||||
async subscribe(userId: string, role: string, dto: SubscribePayload): Promise<void> {
|
||||
const prisma = this.cls.get('prisma');
|
||||
if (!prisma) throw new Error('prisma não disponível no CLS');
|
||||
const idEmpresa = this.cls.get('idEmpresa');
|
||||
const codVendedor = userId ? parseInt(userId, 10) : null;
|
||||
|
||||
await prisma.pushSubscription.upsert({
|
||||
where: { endpoint: dto.endpoint },
|
||||
update: { userId, role, p256dh: dto.keys.p256dh, auth: dto.keys.auth },
|
||||
update: {
|
||||
codVendedor,
|
||||
idEmpresa,
|
||||
role,
|
||||
p256dh: dto.keys.p256dh,
|
||||
auth: dto.keys.auth,
|
||||
},
|
||||
create: {
|
||||
userId,
|
||||
codVendedor,
|
||||
idEmpresa,
|
||||
role,
|
||||
endpoint: dto.endpoint,
|
||||
p256dh: dto.keys.p256dh,
|
||||
@@ -39,10 +50,11 @@ export class NotificationsService {
|
||||
async pendingCount(userId: string, role: string): Promise<PendingCountResponse> {
|
||||
const prisma = this.cls.get('prisma');
|
||||
if (!prisma) throw new Error('prisma não disponível no CLS');
|
||||
const idEmpresa = this.cls.get('idEmpresa');
|
||||
|
||||
if (role === 'supervisor' || role === 'manager' || role === 'admin') {
|
||||
const count = await prisma.order.count({
|
||||
where: { status: OrderStatus.pending_approval, deletedAt: null },
|
||||
const count = await prisma.pedido.count({
|
||||
where: { situa: SITUA_PENDENTE, idEmpresa },
|
||||
});
|
||||
return { count };
|
||||
}
|
||||
@@ -50,24 +62,32 @@ export class NotificationsService {
|
||||
return { count: 0 };
|
||||
}
|
||||
|
||||
// Envia push para todos os supervisores/managers/admin do workspace.
|
||||
// Envia push para todos os supervisores/managers/admin da empresa.
|
||||
async notifySupervisors(payload: PushPayload): Promise<void> {
|
||||
const prisma = this.cls.get('prisma');
|
||||
if (!prisma) return;
|
||||
const idEmpresa = this.cls.get('idEmpresa');
|
||||
|
||||
const subs = await prisma.pushSubscription.findMany({
|
||||
where: { role: { in: ['supervisor', 'manager', 'admin'] } },
|
||||
where: {
|
||||
idEmpresa,
|
||||
role: { in: ['supervisor', 'manager', 'admin'] },
|
||||
},
|
||||
});
|
||||
|
||||
await Promise.allSettled(subs.map((s) => this.push.send(s, payload)));
|
||||
}
|
||||
|
||||
// Envia push para um userId específico (todos os dispositivos registrados).
|
||||
// Envia push para um codVendedor específico (todos os dispositivos registrados).
|
||||
async notifyUser(userId: string, payload: PushPayload): Promise<void> {
|
||||
const prisma = this.cls.get('prisma');
|
||||
if (!prisma) return;
|
||||
const idEmpresa = this.cls.get('idEmpresa');
|
||||
const codVendedor = parseInt(userId, 10);
|
||||
|
||||
const subs = await prisma.pushSubscription.findMany({ where: { userId } });
|
||||
const subs = await prisma.pushSubscription.findMany({
|
||||
where: { idEmpresa, codVendedor },
|
||||
});
|
||||
await Promise.allSettled(subs.map((s) => this.push.send(s, payload)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user