// Cotações — Solicitação de Orçamento para vários fornecedores de uma vez
//
// Primeira metade do fluxo de Compras:
// Evento -> Solicitar Orçamento -> Fornecedores respondem (link público)
// -> Comparar valores -> Escolher fornecedor -> gera a Ordem de Compra.
//
// O fornecedor responde em oc.html, que fala com a Edge Function
// 'oc-publica'. Aqui a equipe só dispara e compara.
const COT_STATUS_VARIANT = {
Pendente: 'default', Enviada: 'primary', Respondida: 'success', Recusada: 'danger',
};
// Texto padronizado que vai pro fornecedor — o mesmo no WhatsApp e no e-mail.
// Padronizar é metade do ganho: hoje cada pedido sai escrito de um jeito.
function mensagemCotacao({ pedido, fornecedor, link }) {
const dataEvento = pedido.evento_data
? new Date(pedido.evento_data + 'T00:00:00').toLocaleDateString('pt-BR') : null;
const prazo = pedido.prazo_resposta
? new Date(pedido.prazo_resposta + 'T00:00:00').toLocaleDateString('pt-BR') : null;
return [
`Olá, ${fornecedor.contato || fornecedor.nome}! Aqui é da Promoup.`,
'',
`Precisamos de um orçamento para: *${pedido.titulo}*`,
pedido.evento_nome ? `Evento: ${pedido.evento_nome}${dataEvento ? ` — ${dataEvento}` : ''}` : '',
pedido.evento_local ? `Local: ${pedido.evento_local}` : '',
'',
pedido.descricao || '',
'',
prazo ? `Precisamos da resposta até ${prazo}.` : '',
'',
'Envie sua proposta por aqui (leva 1 minuto, é só preencher o valor):',
link,
'',
`Referência: ${pedido.numero}`,
].join('\n').replace(/\n{3,}/g, '\n\n');
}
// ---------------------------------------------------------------------
// Modal de nova solicitação — chamado pelo módulo Fornecedores
// (botão "Solicitar orçamento" com os fornecedores já selecionados)
// e também pela própria tela de Cotações.
// ---------------------------------------------------------------------
function NovaCotacaoModal({ open, fornecedores = [], onClose, onCreated }) {
const [events, setEvents] = React.useState([]);
const [saving, setSaving] = React.useState(false);
const [erro, setErro] = React.useState(null);
const [resultado, setResultado] = React.useState(null);
const vazio = { event_id: '', titulo: '', descricao: '', categoria: '', prazo_resposta: '' };
const [form, setForm] = React.useState(vazio);
React.useEffect(() => {
if (!open) return;
setForm(vazio); setErro(null); setResultado(null);
sb.from('events').select('id, name, event_date, client_name, location')
.order('event_date', { ascending: false }).limit(200)
.then(({ data }) => setEvents(data || []));
}, [open]);
const criar = async () => {
if (!form.titulo.trim()) { setErro('Descreva o que você precisa orçar.'); return; }
if (!fornecedores.length) { setErro('Selecione pelo menos um fornecedor.'); return; }
setSaving(true); setErro(null);
const ev = events.find(e => String(e.id) === String(form.event_id));
const { data: pedido, error } = await sb.from('quote_requests').insert({
event_id: ev ? ev.id : null,
evento_nome: ev ? ev.name : null,
evento_data: ev ? ev.event_date : null,
evento_local: ev ? ev.location : null,
cliente_nome: ev ? ev.client_name : null,
titulo: form.titulo.trim(),
descricao: form.descricao.trim() || null,
categoria: form.categoria || null,
prazo_resposta: form.prazo_resposta || null,
}).select().single();
if (error) {
setSaving(false);
console.error('[Cotacoes.criar] erro:', error);
setErro('Não consegui criar a solicitação: ' + (error.message || 'erro desconhecido'));
return;
}
// Uma linha por fornecedor: cada um recebe o próprio token/link
const { data: linhas, error: errLinhas } = await sb.from('quote_request_suppliers').insert(
fornecedores.map(f => ({
request_id: pedido.id, fornecedor_id: f.id, fornecedor_nome: f.nome,
}))
).select();
if (errLinhas) {
setSaving(false);
console.error('[Cotacoes.criar] erro nos fornecedores:', errLinhas);
setErro('A solicitação foi criada, mas não consegui vincular os fornecedores.');
return;
}
// Dispara no WhatsApp de quem tem telefone. Quem não tem entra na lista
// de pendências para a equipe mandar por e-mail.
const enviados = [], pendentes = [];
for (const linha of linhas) {
const f = fornecedores.find(x => x.id === linha.fornecedor_id);
const link = publicDocUrl(linha.token);
const texto = mensagemCotacao({ pedido, fornecedor: f, link });
const r = await notifyFornecedorWhatsApp({ fornecedor: f, text: texto });
if (r.ok) enviados.push(linha.id);
else pendentes.push({ nome: f.nome, email: f.email, motivo: r.motivo, link, texto });
}
if (enviados.length) {
await sb.from('quote_request_suppliers')
.update({ status: 'Enviada', sent_at: new Date().toISOString(), sent_via: 'whatsapp' })
.in('id', enviados);
}
setSaving(false);
if (pendentes.length) {
// Não fecha o modal: mostra quem ficou de fora com o link pronto
setResultado({ pedido, enviados: enviados.length, pendentes });
} else {
onCreated?.(`${pedido.numero} enviada para ${enviados.length} fornecedor(es) no WhatsApp.`);
}
};
const copiar = (txt) => navigator.clipboard?.writeText(txt);
return (
{resultado ? (
{resultado.pedido.numero} criada. {resultado.enviados} fornecedor(es) receberam no WhatsApp.
Estes aqui não têm WhatsApp válido cadastrado. Mande o link por e-mail:
{resultado.pendentes.map(p => (
{p.nome}
{p.motivo}
abrirEmail({ to: p.email, subject: `Solicitação de orçamento — ${resultado.pedido.numero}`, body: p.texto })}>
{p.email ? 'Abrir e-mail' : 'Sem e-mail'}
copiar(p.link)}>Copiar link