$(document).ready(function () { try { FLUIGC.calendar('#dataNec'); } catch (e) { console.warn("Erro ao iniciar calendário:", e); } toggleBotaoAddItem(); // inicia escondido /* ========= Eventos ========= */ $('#precoRef, #quantidade').on('input', recalcTotal); // formata o teto de preço só quando o usuário sair do campo $('#precoRef').on('blur', function() { const p = brMoneyToFloat($(this).val()); $(this).val(floatToBRL(p)); recalcTotal(); }); $('#qtdMais').on('click', function () { let v = parseInt($('#quantidade').val() || '0', 10); $('#quantidade').val(v + 1); recalcTotal(); }); $('#qtdMenos').on('click', function () { let v = parseInt($('#quantidade').val() || '0', 10); v = Math.max(0, v - 1); $('#quantidade').val(v); recalcTotal(); }); $('#btnBuscaProd').on('click', consultarProdutos); $('#btnLimpaProd').on('click', limparCamposPrincipais); $('#btnAddItem').on('click', adicionarItem); }); /* ========= Total / Quantidade ========= */ function recalcTotal() { const q = parseFloat($('#quantidade').val() || '0'); const p = brMoneyToFloat($('#precoRef').val()); const t = (q * p) || 0; $('#total').val(floatToBRL(t)); } /* Parse "fieldName___index" IDs used by Fluig Zoom child items */ function parseZoomItemId(rawId) { const sep = (rawId || "").indexOf("___"); if (sep >= 0) { return { inputId: rawId.substring(0, sep), indice: rawId.substring(sep + 3) }; } return { inputId: rawId || "", indice: "" }; } function setSelectedZoomItem(selectedItem) { const { inputId, indice } = parseZoomItemId(selectedItem.inputId); if (inputId === "estabelecimento") { const codigoProtheus = String(selectedItem.PROTHEUS || selectedItem.protheus || "").trim(); const gestorLoja = String(selectedItem.COLLEAGUE_ID || selectedItem.LOGIN_LOJA || "").trim(); $("#filialdest").val(selectedItem.LOJA || ""); $("#filialest").val(selectedItem.UF || ""); $("#filialprotheus").val(codigoProtheus); $("#centro_custo").val(selectedItem.RESPONSAVEL_LOJA || selectedItem.LOJA || ""); $("#codigocentroCusto").val(codigoProtheus); $("#gestor_cc").val(gestorLoja); if (!codigoProtheus) { console.warn("[ZoomHandler] Filial sem PROTHEUS:", selectedItem); } } if (inputId === "centroCusto") { $("#gestorNome").val(selectedItem.gestorCentroCusto || ""); $("#gestorEmail").val(selectedItem.emailGestor || ""); $("#gestor_cc").val(selectedItem.idGestor || ""); } if (inputId === "userSolicitante") { $("#emailSolicitante").val(selectedItem.mail || ""); } if (inputId === "descricao") { $("#codigoItem___" + indice).val(selectedItem.descricao || ""); } } function removedZoomItem(removedItem) { const { inputId, indice } = parseZoomItemId(removedItem.inputId); if (inputId === "estabelecimento") { $("#filialdest, #filialest, #filialprotheus, #centro_custo, #codigocentroCusto, #gestor_cc").val(""); } if (inputId === "centroCusto") { $("#gestorNome, #gestorEmail, #gestor_cc").val(""); } if (inputId === "userSolicitante") { $("#emailSolicitante").val(""); } if (inputId === "descricao") { $("#codigoItem___" + indice + ", #quantidadeItem___" + indice).val(""); } } /* ========= Config (centralizada em compras_config.js) ========= */ const DATASET_PRODUTOS = (typeof ComprasConfig !== "undefined") ? ComprasConfig.datasets.produtos : "dsComprasProdutos"; let todosProdutos = []; let paginaAtual = 1; const itensPorPagina = 10; /* ========= Utils ========= */ function escapeHTML(txt) { return $('
').text(txt == null ? '' : String(txt)).html(); } function brMoneyToFloat(v) { if (!v) return 0; return parseFloat( String(v) .replace(/R\$/g, '') // remove "R$" .replace(/\s/g, '') // remove espaços .replace(/\./g, '') // remove pontos de milhar .replace(',', '.') // troca vírgula por ponto ) || 0; } function floatToBRL(n) { try { return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(n || 0); } catch (_) { return 'R$ ' + (n || 0).toFixed(2).replace('.', ','); } } /* ========= Modal Consulta Produtos ========= */ function consultarProdutos() { FLUIGC.modal({ title: 'Consulta de Produtos', content: '
' + '' + '
' + '
' + '
', id: 'modalConsultaProdutos', size: 'large', actions: [{ 'label': 'Fechar', 'autoClose': true }] }, function (err) { if (!err) carregaListaProdutos(); }); } function carregaListaProdutos(filtro) { // Só chama o dataset se ainda não carregou nada if (todosProdutos.length === 0) { let dataset = DatasetFactory.getDataset(DATASET_PRODUTOS, null, null, null); const values = dataset && dataset.values ? dataset.values : []; todosProdutos = values .map(normalizarProduto) .filter(p => p.codigo && p.descricao); console.log("Produtos carregados do dataset:", todosProdutos.length); } paginaAtual = 1; renderizaProdutos(filtro); } function filtrarProdutos() { paginaAtual = 1; renderizaProdutos(); } function renderizaProdutos(filtro) { filtro = (filtro || $('#filtroDescricao').val() || '').toLowerCase(); // Agora filtra no cache (sem chamar dataset de novo) const produtosFiltrados = todosProdutos.filter(p => (p.descricao || '').toLowerCase().includes(filtro) || (p.codigo || '').toLowerCase().includes(filtro) || (p.medida || '').toLowerCase().includes(filtro) ); const inicio = (paginaAtual - 1) * itensPorPagina; const fim = inicio + itensPorPagina; const produtosPagina = produtosFiltrados.slice(inicio, fim); let html = ` `; if (produtosPagina.length === 0) { html += ` `; } else { produtosPagina.forEach(produto => { const codigo = escapeHTML(produto.codigo); const descricao = escapeHTML(produto.descricao); const um = escapeHTML(produto.medida || ''); const preco = produto.ultimo_preco || '0,00'; html += ` `; }); } html += `
Codigo Descricao UM Ultimo Preco Acao
Nenhum produto encontrado
${codigo} ${descricao} ${um} ${preco}
`; $('#listaProdutos').html(html); renderizaPaginacao(produtosFiltrados.length); } function normalizarProduto(row) { return { codigo: String(row.B1_COD || row.codigo || "").trim(), descricao: String(row.B1_DESC || row.descricao || "").trim(), medida: String(row.B1_UM || row.medida || "").trim(), ultimo_preco: String(row.B1_UPRC || row.ultimo_preco || "0,00").trim() }; } function renderizaPaginacao(totalItens) { const totalPaginas = Math.ceil(totalItens / itensPorPagina); let html = ''; if (totalPaginas > 1) { if (paginaAtual > 1) { html += ' '; } html += ' Pagina ' + paginaAtual + ' de ' + totalPaginas + ' '; if (paginaAtual < totalPaginas) { html += ''; } } $('#paginacaoProdutos').html(html); } function mudarPagina(n) { paginaAtual = n; renderizaProdutos(); } /* ========= Seleção ========= */ function selecionarProduto(codigo, descricao, preco) { $('#produtoCod').val(codigo); $('#descProduto').val(codigo + ' - ' + descricao); $('#ultimoPreco').val(preco); FLUIGC.toast({ title: 'Produto', message: 'Selecionado: ' + descricao, type: 'success' }); $('#modalConsultaProdutos').modal('hide'); toggleBotaoAddItem(); // 👈 mostra botão } function toggleBotaoAddItem() { const temProduto = $('#produtoCod').val() || $('#descProduto').val(); if (temProduto && temProduto.trim() !== "") { $('#btnAddItem').show(); } else { $('#btnAddItem').hide(); } } /* ========= Adicionar Item ========= */ function adicionarItem() { const cod = $('#produtoCod').val(); const desc = $('#descProduto').val(); const qtd = $('#quantidade').val() || '1'; if (!cod) { FLUIGC.toast({ title: 'Atenção', message: 'Selecione um produto/serviço', type: 'warning' }); return; } const idx = wdkAddChild('tbItens'); setTimeout(function () { $('input[name="Codproduto___' + idx + '"]').val(cod); const somenteDesc = desc.indexOf('-') >= 0 ? desc.split('-').slice(1).join('-').trim() : desc; $('input[name="produtoDesc___' + idx + '"]').val(somenteDesc); $('input[name="qtd___' + idx + '"]').val(qtd); atualizarIndex(); }, 0); FLUIGC.toast({ title: 'Item', message: 'Adicionado à lista', type: 'success' }); limparCamposPrincipais(); } /* ========= Limpar campos principais ========= */ function limparCamposPrincipais() { $('#produtoCod, #descProduto').val(''); $('#quantidade').val('0'); $('#precoRef').val('0,00'); $('#fnComprovante').val(''); toggleBotaoAddItem(); // 👈 mostra botão } /* ========= Eventos delegados ========= */ $(document).on('click', '.selecionar-produto', function () { const codigo = $(this).data('codigo'); const descricao = $(this).data('descricao'); const preco = $(this).data('preco'); selecionarProduto(codigo, descricao, preco); }); /* ========= Index das linhas ========= */ function atualizarIndex() { $('#tbItens tbody tr.tableRow').each(function (i) { if (!$(this).is('[detail=true]')) { $(this).find('.tableIndex').text(i); } }); } /* ========= Remover linha ========= */ function fnWdkRemoveChild(el) { $(el).closest('tr').remove(); atualizarIndex(); atualizarTotais(); } /* ========= Link do produto ========= */ function handleProductLink(el) { const $row = $(el).closest("tr"); const $hidden = $row.find("input.produto-link"); let linkAtual = $hidden.val(); if (!linkAtual) { // ainda não tem link → pedir ao usuário let novoLink = prompt("Insira o link do produto:"); if (novoLink && novoLink.trim() !== "") { $hidden.val(novoLink.trim()); // grava no hidden (vai persistir no Fluig) } } else { // já existe link → abrir window.open(linkAtual, "_blank"); } } $(function () { var steps = [ { state: 1, label: "Solicitação" }, { state: 121, label: "Validando Necessidade" }, { state: 82, label: "Enviando pedido" }, { state: 114, label: "Cotação Iniciada" }, { state: 105, label: "Indicar Cotação" }, { state: 137, label: "Confirmação da cotação" }, { state: 133, label: "Aprovação Gestor" }, { state: 147, label: "Aprovação Ger. Financeiro" }, { state: 158, label: "Aprovação CEO" }, { state: 18, label: "Recebimento do Produto" }, { state: 24, label: "Problema" }, { state: 52, label: "Fim" } ]; var current = parseInt($("#activity").val() || "0", 10); var idxAtual = steps.findIndex(function (s) { return s.state === current; }); if (idxAtual < 0) idxAtual = 0; $("#wizard-steps .step-item").each(function (i) { if (i < idxAtual) $(this).addClass("done"); if (i === idxAtual) $(this).addClass("active"); }); // clique nos steps $("#wizard-steps .step-item").on("click", function () { var index = $(this).index(); var step = steps[index]; if (!step) return; // se já estava ativo, mostra tudo de novo if ($(this).hasClass("active") && $(".activity:visible").length === 1) { $(".activity").css("display", "block"); $("#wizard-steps .step-item").removeClass("active"); return; } // senão, mostra só a activity clicada $(".activity").css("display", "none"); $(".activity-" + step.state).css("display", "block"); $("#wizard-steps .step-item").removeClass("active"); $(this).addClass("active"); }); }); function valorCampo(id) { return String($("#" + id).val() || "").trim(); } function setLabel(id, valor) { var texto = String(valor || "").trim(); $("#" + id).text(texto || "-"); } function badgeClassByStatus(status) { var s = String(status || "").toLowerCase(); if (!s || s === "sem cotacao" || s === "sem pedido" || s === "-") return "badge-status badge-waiting"; if (s.indexOf("erro") >= 0 || s.indexOf("reprov") >= 0 || s.indexOf("cancel") >= 0) return "badge-status badge-rejected"; if (s.indexOf("bloque") >= 0 || s.indexOf("rejeit") >= 0) return "badge-status badge-blocked"; if (s.indexOf("aguard") >= 0 || s.indexOf("pend") >= 0) return "badge-status badge-pending"; if (s.indexOf("sucesso") >= 0 || s.indexOf("aprov") >= 0 || s.indexOf("gerad") >= 0 || s.indexOf("liberad") >= 0 || s.indexOf("conclui") >= 0) return "badge-status badge-approved"; return "badge-status badge-processing"; } var BADGE_VARIANTS = "badge-waiting badge-pending badge-approved badge-rejected badge-blocked badge-processing"; function setBadge(selector, valor) { var texto = String(valor || "").trim() || "-"; var textoLower = texto.toLowerCase(); var classe = badgeClassByStatus(texto); // Mantém badges de resumo da SC como "em andamento" para não inflar expectativa visual. if ( (selector === "#statusSCProtheus_label" && textoLower.indexOf("sc cadastrada com sucesso") >= 0) || (selector === "#statusSC_label" && textoLower.indexOf("pedido gerado") >= 0) ) { classe = "badge-status badge-processing"; } $(selector) .text(texto) .removeClass(BADGE_VARIANTS) .addClass(classe); } function normalizarStatusCadastro(statusCadastro, numeroSC) { var numero = String(numeroSC || "").trim(); var status = String(statusCadastro || "").trim(); var s = status.toLowerCase(); if (!numero) return status; if (!status) return "SC cadastrada com sucesso"; if (s.indexOf("sucesso") >= 0 || s.indexOf("cadastr") >= 0) return "SC cadastrada com sucesso"; return status; } function normalizarAndamento(andamento, cotacao, pedido) { var atual = String(andamento || "").trim(); if (pedido) return "Pedido gerado"; if (cotacao && (!atual || atual.toLowerCase().indexOf("pedido") < 0)) return "Cotacao gerada"; return atual; } function normalizarDataProtheus(data) { var d = String(data || "").trim(); if (/^\d{8}$/.test(d)) { return d.substring(6, 8) + "/" + d.substring(4, 6) + "/" + d.substring(0, 4); } return d; } function limparNumeroDocumento(valor) { var v = String(valor || "").trim(); if (!v || /^0+$/.test(v)) return ""; return v; } function normalizarCodigoComparacao(valor) { var v = String(valor || "").trim(); if (!v) return ""; return v.replace(/^0+/, ""); } function documentoEhPlaceholder(valor) { var v = String(valor || "").trim().toUpperCase(); if (!v) return true; if (v === "XXXX" || v === "XXXXXX") return true; return /^X+$/.test(v); } function linhaCotacaoVencedora(row) { var pedido = String(row.C8_NUMPED || "").trim(); var itemPedido = String(row.C8_ITEMPED || "").trim(); var fornece = String(row.C8_FORNECE || "").trim(); var loja = String(row.C8_LOJA || "").trim(); if (documentoEhPlaceholder(pedido)) return false; if (documentoEhPlaceholder(itemPedido)) return false; if (!fornece || !loja) return false; return true; } function possuiFornecedorCotacao(row) { var fornece = String(row.C8_FORNECE || "").trim(); var loja = String(row.C8_LOJA || "").trim(); return !!(fornece && loja); } function textoUtilFornecedor(valor) { var txt = String(valor || "").trim(); if (!txt) return ""; if (txt === "-" || txt === "--") return ""; if (txt.toUpperCase() === "NULL") return ""; return txt; } function obterNomeFornecedorCompleto(row) { var candidatos = [ textoUtilFornecedor(row.C8_FORNOME), textoUtilFornecedor(row.A2_NOME), textoUtilFornecedor(row.A2_NREDUZ) ].filter(function (v) { return !!v; }); if (!candidatos.length) return ""; candidatos.sort(function (a, b) { if (b.length !== a.length) return b.length - a.length; return a.localeCompare(b); }); return candidatos[0]; } function classificarLinhaCotacao(row) { var status = String(row.STATUS || "").trim().toUpperCase(); if (linhaCotacaoVencedora(row)) { return { tipo: "PEDIDO_GERADO", label: "GANHOU", badge: "badge bg-success", tipoFornecedor: "Fornecedor homologado" }; } if (possuiFornecedorCotacao(row)) { return { tipo: "FORNECEDOR_HOMOLOGADO", label: "Homologado", badge: "badge bg-info", tipoFornecedor: "Fornecedor homologado" }; } if (status.indexOf("PEDIDO_GERADO") >= 0) { return { tipo: "PERDEDOR", label: "", badge: "badge bg-warning", tipoFornecedor: "-" }; } if (!possuiFornecedorCotacao(row)) { return { tipo: "NOVO_FORNECEDOR", label: "Novo", badge: "badge bg-primary", tipoFornecedor: "Novo fornecedor" }; } return { tipo: "EM_COTACAO", label: "EM COTACAO", badge: "badge bg-secondary", tipoFornecedor: "-" }; } function formatarValorCotacao(valor) { var txt = String(valor || "").trim(); if (!txt) return "-"; return floatToBRL(parseNumeroCotacao(txt)); } function formatarDocumentoVisual(valor) { var txt = String(valor || "").trim(); if (!txt || documentoEhPlaceholder(txt)) return "-"; return txt; } function classeCardCotacao(tipo) { if (tipo === "PEDIDO_GERADO") return "sc-cotacao-card sc-cotacao-card--winner"; if (tipo === "FORNECEDOR_HOMOLOGADO") return "sc-cotacao-card sc-cotacao-card--homologado"; if (tipo === "NOVO_FORNECEDOR") return "sc-cotacao-card sc-cotacao-card--novo"; if (tipo === "PERDEDOR") return "sc-cotacao-card sc-cotacao-card--perdedor"; return "sc-cotacao-card"; } function renderizarResumoCotacao(totalCotacoes, totalComPedido, menorTotal) { var alvo = $("#cotacaoResultadoResumo"); if (!alvo.length) return; var menorTxt = (menorTotal !== null) ? floatToBRL(menorTotal) : "-"; alvo.html([ '
', ' Quantidade', ' ' + escapeHTML(String(totalCotacoes || 0)) + "", "
", '
', ' Pedidos Gerados', ' ' + escapeHTML(String(totalComPedido || 0)) + "", "
", '
', ' Menor Valor', ' ' + escapeHTML(menorTxt) + "", "
" ].join("")); } function comporDataHora(data, hora) { var d = String(data || "").trim(); var h = String(hora || "").trim(); if (d && h && h !== "-") return d + " as " + h; return d || h || ""; } function montarEventosTimelineSC(dados) { var eventos = []; var momentoSolicitacao = comporDataHora(dados.dataCadastro, dados.horaCadastro); var momentoSC = dados.emissao || momentoSolicitacao; eventos.push({ classe: (dados.numero || dados.solicitante || momentoSolicitacao) ? "done" : "pending", titulo: "Solicitacao criada", momento: momentoSolicitacao, detalhe: dados.solicitante ? "Solicitante: " + dados.solicitante : "" }); if (dados.numero) { eventos.push({ classe: "done", titulo: "SC " + dados.numero + " cadastrada", momento: momentoSC, detalhe: dados.statusCadastro ? "Status: " + dados.statusCadastro : "" }); } else { eventos.push({ classe: "pending", titulo: "Aguardando geracao da SC", momento: "", detalhe: "A SC sera exibida assim que for criada no Protheus." }); } if (dados.cotacao) { eventos.push({ classe: "done", titulo: "Cotacao " + dados.cotacao + " gerada", momento: "", detalhe: "Cotacao disponivel para analise." }); } else { eventos.push({ classe: "pending", titulo: "Aguardando cotacao", momento: "", detalhe: "Ainda nao existe cotacao vinculada a SC." }); } if (dados.pedido) { eventos.push({ classe: "done", titulo: "Pedido " + dados.pedido + " gerado", momento: "", detalhe: "Compra convertida em pedido." }); } else { eventos.push({ classe: "pending", titulo: "Aguardando pedido", momento: "", detalhe: "O pedido sera criado apos a aprovacao final da cotacao." }); } return eventos; } function renderizarTimelineSC(dados) { var eventos = montarEventosTimelineSC(dados); var html = eventos.map(function (evento) { var titulo = escapeHTML(evento.titulo); var momento = escapeHTML(evento.momento || ""); var detalhe = escapeHTML(evento.detalhe || ""); var classe = evento.classe === "done" ? "done" : "pending"; return [ '
  • ', '
    ', ' ' + titulo + '', momento ? (' ' + momento + '') : "", "
    ", detalhe ? ('
    ' + detalhe + "
    ") : "", "
  • " ].join(""); }).join(""); $("#scTimeline").html(html); } function renderizarResultadoCotacao(resumo) { var badge = $("#cotacaoResultado_label"); var lista = $("#cotacaoResultadoLista"); if (!badge.length || !lista.length) return; if (!resumo || !resumo.detalhes || !resumo.detalhes.length) { setBadge("#cotacaoResultado_label", "Sem cotacao"); renderizarResumoCotacao(0, 0, null); lista.html('
    Aguardando vinculo da cotacao na SC.
    '); return; } var statusResumo = "Sem fornecedor definido"; if ((resumo.qtdPedidoGerado || 0) > 0) { statusResumo = "Cotacao concluida"; } else if ((resumo.qtdFornecedorHomologado || 0) > 0) { statusResumo = "Fornecedor homologado em " + resumo.qtdFornecedorHomologado + " item(ns)"; } else if ((resumo.qtdNovoFornecedor || 0) > 0) { statusResumo = "Novo fornecedor em " + resumo.qtdNovoFornecedor + " item(ns)"; } setBadge("#cotacaoResultado_label", statusResumo); var detalhesOrdenados = resumo.detalhes.slice().sort(function (a, b) { var pesoA = (a.tipo === "PEDIDO_GERADO") ? 0 : 1; var pesoB = (b.tipo === "PEDIDO_GERADO") ? 0 : 1; if (pesoA !== pesoB) return pesoA - pesoB; var totalA = parseNumeroCotacao(a.total); var totalB = parseNumeroCotacao(b.total); if (totalA === totalB) return 0; return totalA - totalB; }); var menorTotal = null; var totalComPedido = 0; for (var i = 0; i < detalhesOrdenados.length; i++) { var t = parseNumeroCotacao(detalhesOrdenados[i].total); if (t > 0 && (menorTotal === null || t < menorTotal)) menorTotal = t; if (!documentoEhPlaceholder(detalhesOrdenados[i].pedido)) totalComPedido++; } renderizarResumoCotacao(detalhesOrdenados.length, totalComPedido, menorTotal); var html = detalhesOrdenados.map(function (linha) { var numeroTxt = escapeHTML(linha.numero || "-"); var itemTxt = escapeHTML(linha.item || "-"); var produtoTxt = escapeHTML(linha.produto || "-"); var fornecedorNomeTxt = escapeHTML(linha.fornecedorNome || linha.fornecedor || "Fornecedor nao informado"); var fornecedorTxt = escapeHTML(linha.fornecedor || "-"); var tipoFornecedorTxt = escapeHTML(linha.tipoFornecedor || "-"); var precoTxt = escapeHTML(formatarValorCotacao(linha.preco)); var totalTxt = escapeHTML(formatarValorCotacao(linha.total)); var pedidoTxt = escapeHTML(formatarDocumentoVisual(linha.pedido)); var statusApiTxt = escapeHTML(linha.statusApi || "-"); var statusRaw = String(linha.label || "").trim(); var statusTxt = escapeHTML(statusRaw); var badgeStatus = linha.badge || "badge-status badge-waiting"; var classeCard = classeCardCotacao(linha.tipo); var qtdTxt = escapeHTML(String(linha.quantidade || "-")); var entregaTxt = escapeHTML(normalizarDataProtheus(linha.dataPrevista || "")); var condicaoTxt = escapeHTML(linha.condicao || "-"); return [ '
    ', '
    ', "
    ", '
    ' + fornecedorNomeTxt + "
    ", '
    Fornecedor: ' + fornecedorTxt + " | Tipo: " + tipoFornecedorTxt + "
    ", "
    ", statusRaw ? (' ' + statusTxt + "") : "", "
    ", '
    ', '
    Preco unitario' + precoTxt + "
    ", '
    Total' + totalTxt + "
    ", "
    ", ' ", "
    " ].join(""); }).join(""); lista.html(html); } function renderizarErroCotacao(mensagem) { var lista = $("#cotacaoResultadoLista"); if (!lista.length) return; setBadge("#cotacaoResultado_label", "Erro consulta cotacao"); renderizarResumoCotacao(0, 0, null); lista.html( '
    ' + escapeHTML(mensagem || "Nao foi possivel carregar a cotacao no momento.") + "
    " ); } function mapearStatusAlcada(codigo) { var status = String(codigo || "").trim(); if (status === "01") return { label: "Pendente em niveis anteriores", badge: "badge bg-warning", classe: "pendente" }; if (status === "02") return { label: "Pendente", badge: "badge bg-warning", classe: "pendente" }; if (status === "03") return { label: "Aprovado", badge: "badge bg-success", classe: "aprovado" }; if (status === "04") return { label: "Bloqueado", badge: "badge bg-danger", classe: "bloqueado" }; if (status === "05") return { label: "Aprovado/rejeitado pelo nivel", badge: "badge bg-info", classe: "pendente" }; if (status === "06") return { label: "Rejeitado", badge: "badge bg-danger", classe: "bloqueado" }; if (status === "07") return { label: "Documento rejeitado ou bloqueado por outro usuario", badge: "badge bg-danger", classe: "bloqueado" }; return { label: status ? ("Status " + status) : "Sem status", badge: "badge bg-secondary", classe: "" }; } function primeiroTextoPreenchido() { for (var i = 0; i < arguments.length; i++) { var txt = String(arguments[i] || "").trim(); if (txt) return txt; } return ""; } function montarResumoRastreioPedido(pedidos, numeroPedido) { if (!pedidos || !pedidos.length) return null; var pedidoFiltro = normalizarCodigoComparacao(numeroPedido); var pedidoBase = null; for (var i = 0; i < pedidos.length; i++) { var num = normalizarCodigoComparacao(String((pedidos[i] || {}).C7_NUM || "")); if (!pedidoFiltro || num === pedidoFiltro) { pedidoBase = pedidos[i]; break; } } if (!pedidoBase) pedidoBase = pedidos[0]; var assinaturas = []; var vistos = {}; for (var j = 0; j < pedidos.length; j++) { var ped = pedidos[j] || {}; var alcadas = ped.ALCADAS || []; for (var k = 0; k < alcadas.length; k++) { var a = alcadas[k] || {}; var chave = [ String(a.CR_TIPO || "").trim(), String(a.CR_USER || "").trim(), String(a.CR_USERLIB || "").trim(), String(a.CR_STATUS || "").trim(), String(a.CR_PRAZO || "").trim(), String(a.CR_DATALIB || "").trim() ].join("|"); if (vistos[chave]) continue; vistos[chave] = true; var statusInfo = mapearStatusAlcada(a.CR_STATUS); assinaturas.push({ statusCodigo: String(a.CR_STATUS || "").trim(), statusLabel: statusInfo.label, badge: statusInfo.badge, classe: statusInfo.classe, tipo: String(a.CR_TIPO || "").trim(), prazo: normalizarDataProtheus(a.CR_PRAZO), dataLiberacao: normalizarDataProtheus(a.CR_DATALIB), usuario: primeiroTextoPreenchido(a.CR_USER_NOME, a.AK_NOME, a.CR_USER), usuarioLiberacao: primeiroTextoPreenchido(a.CR_USERLIB_NOME, a.AK_NOME_USERLIB, a.CR_USERLIB) }); } } var resumo = { numero: String(pedidoBase.C7_NUM || "").trim(), statusPedido: String(pedidoBase.STATUS || "").trim(), fornecedor: primeiroTextoPreenchido(pedidoBase.A2_NOME, pedidoBase.A2_NREDUZ, pedidoBase.C7_FORNECE), emissao: normalizarDataProtheus(pedidoBase.C7_EMISSAO), entrega: normalizarDataProtheus(pedidoBase.C7_DATPRF), assinaturas: assinaturas }; return resumo; } function renderizarErroRastreioPedido(mensagem) { setBadge("#pedidoRastreio_label", "Erro no rastreio"); $("#pedidoRastreioResumo").text("Nao foi possivel consultar o rastreio do pedido."); $("#pedidoRastreioAssinaturas").html( '
    ' + escapeHTML(mensagem || "Erro ao consultar rastreio.") + "
    " ); } function renderizarRastreioPedido(resumo) { var badge = $("#pedidoRastreio_label"); var resumoEl = $("#pedidoRastreioResumo"); var lista = $("#pedidoRastreioAssinaturas"); if (!badge.length || !resumoEl.length || !lista.length) return; if (!resumo || !resumo.numero) { setBadge("#pedidoRastreio_label", "Sem pedido"); resumoEl.text("Sem pedido vinculado."); lista.html('
    Sem assinaturas para exibir.
    '); return; } var possuiBloqueio = resumo.assinaturas.some(function (a) { return a.classe === "bloqueado"; }); var possuiPendente = resumo.assinaturas.some(function (a) { return a.classe === "pendente"; }); var todosAprovados = resumo.assinaturas.length > 0 && resumo.assinaturas.every(function (a) { return a.statusCodigo === "03"; }); var statusTopo = "Pedido pendente"; if (possuiBloqueio) statusTopo = "Pedido bloqueado"; else if (todosAprovados) statusTopo = "Pedido aprovado"; else if (!possuiPendente && resumo.statusPedido) statusTopo = resumo.statusPedido; setBadge("#pedidoRastreio_label", statusTopo); var resumoTxt = "Pedido " + (resumo.numero || "-"); if (resumo.fornecedor) resumoTxt += " | Fornecedor: " + resumo.fornecedor; if (resumo.emissao) resumoTxt += " | Emissao: " + resumo.emissao; if (resumo.entrega) resumoTxt += " | Entrega: " + resumo.entrega; resumoEl.text(resumoTxt); if (!resumo.assinaturas.length) { lista.html('
    Pedido encontrado, mas sem alcadas retornadas pela API.
    '); return; } var html = resumo.assinaturas.map(function (a, idx) { var classeCard = "sc-pedido-ass-card" + (a.classe ? (" " + a.classe) : ""); var nivel = "Nivel " + (idx + 1); var usuario = escapeHTML(a.usuario || "-"); var usuarioLib = escapeHTML(a.usuarioLiberacao || "-"); var prazo = escapeHTML(a.prazo || "-"); var dataLib = escapeHTML(a.dataLiberacao || "-"); var tipo = escapeHTML(a.tipo || "-"); var statusLabel = escapeHTML(a.statusLabel || "-"); var badgeStatus = a.badge || "badge bg-secondary"; return [ '
    ', '
    ', '
    ' + nivel + " - " + usuario + "
    ", ' ' + statusLabel + "", "
    ", '
    ', ' Tipo: ' + tipo + "", ' Prazo: ' + prazo + "", ' Data liberacao: ' + dataLib + "", ' Liberado por: ' + usuarioLib + "", "
    ", "
    " ].join(""); }).join(""); lista.html(html); } function montarResumoCotacaoPorLinhas(rows, cotacao) { if (!rows || !rows.length) return null; var filtroCotacao = normalizarCodigoComparacao(cotacao); var filtradas = rows.filter(function (row) { var erro = String(row.erro || row.ERRO || "").trim(); if (erro) return false; var sucesso = String(row.sucesso || row.SUCESSO || "").trim().toLowerCase(); if (sucesso === "false") return false; var numeroLinha = normalizarCodigoComparacao(row.C8_NUM || ""); if (filtroCotacao && numeroLinha && numeroLinha !== filtroCotacao) return false; var item = String(row.C8_ITEM || row.C8_ITEMSC || "").trim(); var fornecedor = String(row.C8_FORNECE || "").trim(); var pedido = String(row.C8_NUMPED || "").trim(); return !!(item || fornecedor || pedido); }); if (!filtradas.length) return null; var porItem = {}; var detalhes = []; filtradas.forEach(function (row) { var item = String(row.C8_ITEM || row.C8_ITEMSC || "").trim(); if (!item) return; if (!porItem[item]) porItem[item] = []; porItem[item].push(row); var classif = classificarLinhaCotacao(row); detalhes.push({ numero: String(row.C8_NUM || "").trim(), item: item, produto: String(row.B1_DESC || row.C8_DESCRI || row.C8_PRODUTO || "").trim(), quantidade: String(row.C8_QUANT || "").trim(), condicao: String(row.C8_COND || "").trim(), dataPrevista: String(row.C8_DATPRF || "").trim(), fornecedor: possuiFornecedorCotacao(row) ? (String(row.C8_FORNECE || "").trim() + "/" + String(row.C8_LOJA || "").trim()) : "", fornecedorNome: obterNomeFornecedorCompleto(row), preco: row.C8_PRECO, total: row.C8_TOTAL, pedido: String(row.C8_NUMPED || "").trim(), statusApi: String(row.STATUS || "").trim(), tipo: classif.tipo, label: classif.label, badge: classif.badge, tipoFornecedor: classif.tipoFornecedor }); }); var itens = []; var qtdPedidoGerado = 0; var qtdFornecedorHomologado = 0; var qtdNovoFornecedor = 0; Object.keys(porItem).sort().forEach(function (item) { var linhas = porItem[item]; var vencedorPedido = null; var fornecedorHomologado = null; var fornecedorNovo = null; for (var i = 0; i < linhas.length; i++) { if (linhaCotacaoVencedora(linhas[i])) { vencedorPedido = linhas[i]; break; } var fornece = String(linhas[i].C8_FORNECE || "").trim(); var loja = String(linhas[i].C8_LOJA || "").trim(); if (!fornecedorHomologado && fornece && loja) { fornecedorHomologado = linhas[i]; } if (!fornecedorNovo && !fornece && !loja) { fornecedorNovo = linhas[i]; } } if (vencedorPedido) { qtdPedidoGerado++; itens.push({ item: item, fornecedor: String(vencedorPedido.C8_FORNECE || "").trim() + "/" + String(vencedorPedido.C8_LOJA || "").trim(), pedido: String(vencedorPedido.C8_NUMPED || "").trim(), tipo: "PEDIDO_GERADO" }); return; } if (fornecedorHomologado) { qtdFornecedorHomologado++; itens.push({ item: item, fornecedor: String(fornecedorHomologado.C8_FORNECE || "").trim() + "/" + String(fornecedorHomologado.C8_LOJA || "").trim(), pedido: String(fornecedorHomologado.C8_NUMPED || "").trim(), tipo: "FORNECEDOR_HOMOLOGADO" }); return; } if (fornecedorNovo) { qtdNovoFornecedor++; itens.push({ item: item, fornecedor: String(fornecedorNovo.A2_NOME || fornecedorNovo.A2_NREDUZ || "").trim(), pedido: String(fornecedorNovo.C8_NUMPED || "").trim(), tipo: "NOVO_FORNECEDOR" }); return; } itens.push({ item: item, fornecedor: "", pedido: "", tipo: "EM_COTACAO" }); }); return { itens: itens, detalhes: detalhes, qtdPedidoGerado: qtdPedidoGerado, qtdFornecedorHomologado: qtdFornecedorHomologado, qtdNovoFornecedor: qtdNovoFornecedor }; } function consultarResultadoCotacao(cotacao) { if (!cotacao || typeof DatasetFactory === "undefined" || typeof ConstraintType === "undefined") { renderizarResultadoCotacao(null); return; } try { var cCotacao = DatasetFactory.createConstraint("numCotacao", cotacao, cotacao, ConstraintType.MUST); var ds = DatasetFactory.getDataset("dsComprasCotacao", null, [cCotacao], null); var rows = (ds && ds.values) ? ds.values : []; if (!rows.length) { renderizarResultadoCotacao(null); return; } var erroLinha = rows.find(function (row) { return String(row.erro || row.ERRO || "").trim(); }); if (erroLinha) { renderizarErroCotacao(String(erroLinha.erro || erroLinha.ERRO || "").trim()); return; } renderizarResultadoCotacao(montarResumoCotacaoPorLinhas(rows, cotacao)); } catch (e) { console.warn("Nao foi possivel consultar resultado da cotacao no dsComprasCotacao:", e); renderizarResultadoCotacao(null); } } function focarTimelineSC() { var secao = $("#scTimelineSection"); if (!secao.length) return; secao.addClass("is-focus"); setTimeout(function () { secao.removeClass("is-focus"); }, 900); try { secao.get(0).scrollIntoView({ behavior: "smooth", block: "nearest" }); } catch (e) { // fallback para navegadores sem smooth scroll secao.get(0).scrollIntoView(); } } function abrirTimelineSC() { var secao = $("#scTimelineSection"); if (!secao.length) return; secao.addClass("is-open"); $("#cardNumeroSCHint").text("Clique para ocultar a linha do tempo"); } function fecharTimelineSC() { var secao = $("#scTimelineSection"); if (!secao.length) return; secao.removeClass("is-open is-focus"); $("#cardNumeroSCHint").text("Clique para ver a linha do tempo"); } function alternarTimelineSC() { var secao = $("#scTimelineSection"); if (!secao.length) return; if (secao.hasClass("is-open")) { fecharTimelineSC(); return; } abrirTimelineSC(); focarTimelineSC(); } function montarStatusAndamento(scRow, cotacao, pedido) { if (pedido) return "Pedido gerado"; if (cotacao) return "Cotacao gerada"; var statusApi = String(scRow.STATUS || "").trim(); if (statusApi) return statusApi; var aprov = String(scRow.C1_APROV || "").trim().toUpperCase(); if (aprov === "B") return "Aguardando cotacao"; if (aprov === "L") return "Liberada"; if (aprov === "R") return "Reprovada"; if (aprov) return "Status Protheus: " + aprov; return ""; } function preencherResumoSC(resumoCotacao, erroCotacao, resumoPedido, erroPedido) { var numero = valorCampo("numeroSCProtheus"); var statusCadastro = valorCampo("statusSCProtheus"); var solicitante = valorCampo("solicitanteSCProtheus"); var emissao = normalizarDataProtheus(valorCampo("emissaoSCProtheus")); var qtdItens = valorCampo("qtdItensSCProtheus"); var dataCadastro = normalizarDataProtheus(valorCampo("dataCadastroSCProtheus")); var horaCadastro = valorCampo("horaCadastroSCProtheus"); var cotacao = limparNumeroDocumento(valorCampo("cotacaoSCProtheus")); var pedido = limparNumeroDocumento(valorCampo("pedidoSCProtheus")); var andamento = valorCampo("statusAtendimento"); var statusCadastroPadrao = normalizarStatusCadastro(statusCadastro, numero); if (!andamento && numero) { if (pedido) andamento = "Pedido gerado"; else if (cotacao) andamento = "Cotacao gerada"; else andamento = "Em andamento"; } andamento = normalizarAndamento(andamento, cotacao, pedido); setLabel("numeroSCProtheus_label", numero); setLabel("solicitanteSCProtheus_label", solicitante); setLabel("emissaoSCProtheus_label", emissao); setLabel("qtdItensSCProtheus_label", qtdItens); setLabel("dataCadastroSCProtheus_label", dataCadastro); setLabel("horaCadastroSCProtheus_label", horaCadastro); setLabel("cotacaoSC_label", cotacao); setLabel("pedidoSC_label", pedido); setBadge("#statusSCProtheus_label", statusCadastroPadrao || (numero ? "SC cadastrada com sucesso" : "")); setBadge("#statusSC_label", andamento); renderizarTimelineSC({ numero: numero, statusCadastro: statusCadastroPadrao, andamento: andamento, solicitante: solicitante, emissao: emissao, dataCadastro: dataCadastro, horaCadastro: horaCadastro, cotacao: cotacao, pedido: pedido }); if (erroCotacao) { renderizarErroCotacao(erroCotacao); } else if (resumoCotacao && resumoCotacao.itens && resumoCotacao.itens.length) { renderizarResultadoCotacao(resumoCotacao); } else if (cotacao) { consultarResultadoCotacao(cotacao); } else { renderizarResultadoCotacao(null); } if (erroPedido) { renderizarErroRastreioPedido(erroPedido); } else if (resumoPedido && resumoPedido.numero) { renderizarRastreioPedido(resumoPedido); } else { renderizarRastreioPedido(null); } } function consultarAndamentoSC() { var numero = valorCampo("numeroSCProtheus"); if (!numero || typeof DatasetFactory === "undefined" || typeof ConstraintType === "undefined") { return; } try { var cNumero = DatasetFactory.createConstraint("numeroSCProtheus", numero, numero, ConstraintType.MUST); var ds = DatasetFactory.getDataset("ds_consultaSC", null, [cNumero], null); var row = (ds && ds.values && ds.values.length > 0) ? ds.values[0] : null; if (!row) return; if (String(row.sucesso || "").toLowerCase() !== "true") return; var cotacao = limparNumeroDocumento(row.C1_COTACAO); var pedido = limparNumeroDocumento(row.C1_PEDIDO); if (cotacao) $("#cotacaoSCProtheus").val(cotacao); if (pedido) $("#pedidoSCProtheus").val(pedido); if (row.C1_SOLICIT) $("#solicitanteSCProtheus").val(String(row.C1_SOLICIT).trim()); if (row.C1_EMISSAO) $("#emissaoSCProtheus").val(normalizarDataProtheus(row.C1_EMISSAO)); var andamento = montarStatusAndamento(row, cotacao, pedido); if (andamento) $("#statusAtendimento").val(andamento); var resumoCotacao = null; var erroCotacao = String(row.COTACAO_ERRO || "").trim(); var jsonCotacoes = String(row.COTACOES_JSON || "").trim(); if (jsonCotacoes) { try { var cotacoes = JSON.parse(jsonCotacoes); resumoCotacao = montarResumoCotacaoPorLinhas(cotacoes, cotacao); } catch (eCot) { if (!erroCotacao) erroCotacao = "Falha ao ler cotacoes retornadas pelo ds_consultaSC"; } } var resumoPedido = null; var erroPedido = String(row.PEDIDO_ERRO || "").trim(); var jsonPedido = String(row.PEDIDO_JSON || "").trim(); if (jsonPedido) { try { var pedidos = JSON.parse(jsonPedido); resumoPedido = montarResumoRastreioPedido(pedidos, pedido); } catch (ePed) { if (!erroPedido) erroPedido = "Falha ao ler rastreio do pedido retornado pelo ds_consultaSC"; } } preencherResumoSC(resumoCotacao, erroCotacao, resumoPedido, erroPedido); } catch (e) { console.warn("Nao foi possivel consultar andamento da SC no ds_consultaSC:", e); } } $(document).ready(function () { preencherResumoSC(); consultarAndamentoSC(); $(document).on("click", "#cardNumeroSC", function () { alternarTimelineSC(); }); }); function parseNumeroCotacao(valor) { var texto = String(valor || "").trim(); if (!texto) return 0; if (texto.indexOf(",") >= 0) { texto = texto.replace(/\./g, "").replace(",", "."); } texto = texto.replace(/[^\d.-]/g, ""); return parseFloat(texto) || 0; } // garante que o total seja salvo antes de enviar a atividade function beforeSendValidate(numState, nextState) { var campoTotal = $("#valorTotalCotacao"); if (campoTotal.length && !String(campoTotal.val() || "").trim()) { campoTotal.val("0").trigger("change"); } return true; } /* ── Accordion de histórico de atividades ───────────────────────── Chamada pelo script.js após cada showAndBlock() para colapsar as seções de atividades já concluídas. ----------------------------------------------------------------- */ var ACTIVITY_META = { "0": { titulo: "Dados da Solicitação", campos: ["usuarioSolicitante", "estabelecimento", "tipoSolicitacao"] }, "1": { titulo: "Dados da Solicitação", campos: ["usuarioSolicitante", "estabelecimento"] }, "4": { titulo: "Análise do Gestor", campos: ["userValidacaoGestor", "dataValidacaoGestor"] }, "6": { titulo: "Validação Compras", campos: ["userValidacaoCompras", "dataValidacaoCompras"] }, "24": { titulo: "Problema na Compra", campos: [] }, "31": { titulo: "Realização da Compra", campos: ["userRealizacaoCompras", "dataRealizacaoCompras"] }, "57": { titulo: "Aprovação p/ Cotação", campos: ["userCotacaoGestor", "dataAprovCompras"] }, "114": { titulo: "SC no Protheus", campos: [] }, "121": { titulo: "Validação da Diretoria", campos: ["user_validacao_gestor", "data_validacao_gestor"] } }; function _lerCampoResumo(id) { var $el = $("#" + id); if (!$el.length) return ""; var val = $el.is("span, div") ? $el.text().trim() : String($el.val() || "").trim(); return (val && val !== "-") ? val : ""; } function colapsarAtividadesAnteriores(numeros) { for (var i = 0; i < numeros.length; i++) { var num = numeros[i]; var $secao = $(".activity-" + num); if (!$secao.length || $secao.hasClass("accordion-pronto")) continue; var meta = ACTIVITY_META[String(num)] || { titulo: "Etapa " + num, campos: [] }; // Envolve o conteúdo inteiro num .activity-body colapsável $secao.children().wrapAll('
    '); // Monta texto de resumo a partir dos campos da etapa já preenchida var partes = []; for (var c = 0; c < meta.campos.length && partes.length < 2; c++) { var val = _lerCampoResumo(meta.campos[c]); if (val) partes.push(escapeHTML(val)); } var resumo = partes.length ? partes.join(" · ") : "Concluído"; // Injeta cabeçalho clicável antes do body $secao.prepend( '
    ' + '' + '' + escapeHTML(meta.titulo) + '' + '' + resumo + '' + '' + '
    ' ); $secao.addClass("accordion-pronto is-collapsed"); // Fecha sobre si mesmo para manter contexto correto no closure (function ($s) { $s.on("click.accordion", ".activity-header", function () { $s.toggleClass("is-collapsed"); }); }($secao)); } }