From dbb3061cac2a9956d26a936c6636887ed3a9a611 Mon Sep 17 00:00:00 2001 From: Andrey Cunha Date: Mon, 11 May 2026 00:18:03 -0300 Subject: [PATCH] att --- compras_digital/.vscode/servers.json | 4 +- .../src/main/resources/view.ftl | 58 +- .../resources/css/widget_solicitacoes.css | 463 ++++++++++++- .../resources/js/widget_solicitacoes.js | 655 +++++++++++++++++- 4 files changed, 1117 insertions(+), 63 deletions(-) diff --git a/compras_digital/.vscode/servers.json b/compras_digital/.vscode/servers.json index 934d36f..f9eff71 100644 --- a/compras_digital/.vscode/servers.json +++ b/compras_digital/.vscode/servers.json @@ -2,13 +2,13 @@ "version": "1.0.0", "configurations": [ { - "id": "o9cixezp329movgapv2risawf8wvym", + "id": "qhvjkjcxlzmp0m9vw6iehyg3gadm", "name": "Ginseng Produção", "host": "comerciode188006.fluig.cloudtotvs.com.br", "ssl": true, "port": 443, "username": "andrey.cunha", - "password": "eyJpdiI6IjM5MGNhMzMwMWIyNWI2ZDMyYmVmM2FiNDg5NzQ3NzZhIiwic2FsdCI6ImU1ZWE3MDZhOWE0NGMyMjExNmE3NjIyYmRmZTdmMjNhIiwidGV4dCI6ImZkMTY4MTAwNjM0ZmQ3NmI5M2MwZjQ1YmE4NDJmMjRhIn0=", + "password": "eyJpdiI6IjI2NmJlZWRhYTE1NTk0M2ZkOTM4MWJlMDBlODlhMjFkIiwic2FsdCI6IjJlNzAwM2FiMzM3NTMzODEwMTk4Mzk0ODAxOGM0N2YwIiwidGV4dCI6IjliOWI2OGQ5MWFkNDNjOWU5ZDE4NjdjNWEyYWU5YzRlIn0=", "userCode": "andrey.cunha", "confirmExporting": false, "hasBrowser": false, diff --git a/compras_digital/wcm/widget/widget_solicitacoes/src/main/resources/view.ftl b/compras_digital/wcm/widget/widget_solicitacoes/src/main/resources/view.ftl index cfc1483..b0880d0 100644 --- a/compras_digital/wcm/widget/widget_solicitacoes/src/main/resources/view.ftl +++ b/compras_digital/wcm/widget/widget_solicitacoes/src/main/resources/view.ftl @@ -1,39 +1,51 @@ -
-
-
Consultar Solicitações
-
+
+
+
+

Tracker da Solicitacao de Compra

+

Acompanhe SC, cotacao, pedido, aprovacao e entrega em uma unica tela.

+
+ +
+
diff --git a/compras_digital/wcm/widget/widget_solicitacoes/src/main/webapp/resources/css/widget_solicitacoes.css b/compras_digital/wcm/widget/widget_solicitacoes/src/main/webapp/resources/css/widget_solicitacoes.css index a23359a..b9c22f4 100644 --- a/compras_digital/wcm/widget/widget_solicitacoes/src/main/webapp/resources/css/widget_solicitacoes.css +++ b/compras_digital/wcm/widget/widget_solicitacoes/src/main/webapp/resources/css/widget_solicitacoes.css @@ -1 +1,462 @@ -/* Coloque aqui seu codigo CSS */ +.compras-tracker-widget { + color: #172033; +} + +.tracker-shell { + background: #f7f9fc; + border: 1px solid #dfe6ef; + border-radius: 8px; + padding: 18px; +} + +.tracker-header { + align-items: center; + display: flex; + gap: 16px; + justify-content: space-between; + margin-bottom: 16px; +} + +.tracker-header h2 { + color: #101828; + font-size: 22px; + font-weight: 700; + line-height: 1.2; + margin: 0 0 4px; +} + +.tracker-header p { + color: #667085; + font-size: 13px; + margin: 0; +} + +.tracker-search, +.tracker-card, +.tracker-table-wrap { + background: #fff; + border: 1px solid #d9e2ec; + border-radius: 8px; + box-shadow: 0 8px 22px rgba(16, 24, 40, .05); +} + +.tracker-search { + margin-bottom: 14px; + padding: 16px; +} + +.tracker-search label { + color: #344054; + font-size: 12px; + font-weight: 700; +} + +.tracker-search-actions .btn { + margin-top: 0; +} + +.tracker-refresh { + align-items: center; + display: inline-flex; + gap: 6px; + white-space: nowrap; +} + +.tracker-message:empty { + display: none; +} + +.tracker-results { + margin-bottom: 14px; +} + +.tracker-table-wrap { + overflow-x: auto; +} + +.tracker-table { + margin: 0; +} + +.tracker-table > thead > tr > th { + background: #f8fafc; + border-bottom: 1px solid #d9e2ec; + color: #344054; + font-size: 12px; + white-space: nowrap; +} + +.tracker-table > tbody > tr > td { + color: #344054; + font-size: 13px; + vertical-align: middle; +} + +.tracker-detail { + margin-top: 14px; +} + +.tracker-card { + margin-bottom: 14px; + padding: 16px; +} + +.tracker-card-main { + padding: 18px; +} + +.tracker-title-row, +.tracker-section-head { + align-items: center; + display: flex; + gap: 12px; + justify-content: space-between; +} + +.tracker-title-row { + margin-bottom: 16px; +} + +.tracker-title-row h3 { + color: #101828; + font-size: 20px; + font-weight: 700; + margin: 0 0 3px; +} + +.tracker-title-row span { + color: #667085; + font-size: 12px; +} + +.tracker-summary-grid { + display: grid; + gap: 12px; + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.tracker-info { + background: #fbfcfe; + border: 1px solid #e6edf5; + border-radius: 6px; + min-height: 68px; + padding: 10px 12px; +} + +.tracker-info span { + color: #667085; + display: block; + font-size: 11px; + font-weight: 700; + margin-bottom: 7px; + text-transform: uppercase; +} + +.tracker-info strong { + color: #172033; + display: block; + font-size: 14px; + line-height: 1.25; + overflow-wrap: anywhere; +} + +.tracker-steps { + align-items: flex-start; + display: grid; + grid-template-columns: repeat(5, minmax(96px, 1fr)); + position: relative; +} + +.tracker-steps:before { + background: #cfd8e3; + content: ""; + height: 2px; + left: 10%; + position: absolute; + right: 10%; + top: 22px; +} + +.tracker-step { + align-items: center; + display: flex; + flex-direction: column; + gap: 4px; + min-width: 0; + position: relative; + text-align: center; + z-index: 1; +} + +.tracker-step-icon { + align-items: center; + background: #d0d5dd; + border-radius: 999px; + color: #475467; + display: flex; + height: 44px; + justify-content: center; + margin-bottom: 4px; + width: 44px; +} + +.tracker-step.is-done .tracker-step-icon { + background: #2563eb; + color: #fff; +} + +.tracker-step strong { + color: #172033; + font-size: 12px; + line-height: 1.2; +} + +.tracker-step span { + color: #667085; + font-size: 11px; + line-height: 1.2; + max-width: 120px; + overflow-wrap: anywhere; +} + +.tracker-grid { + display: grid; + gap: 14px; + grid-template-columns: minmax(0, 1.2fr) minmax(320px, .8fr); +} + +.tracker-section-head { + border-bottom: 1px solid #e6edf5; + margin: -2px -16px 12px; + padding: 0 16px 12px; +} + +.tracker-section-head h4 { + color: #172033; + font-size: 16px; + font-weight: 700; + margin: 0; +} + +.tracker-section-head > span { + align-items: center; + background: #eef2f7; + border-radius: 999px; + color: #344054; + display: inline-flex; + font-size: 12px; + font-weight: 700; + height: 24px; + justify-content: center; + min-width: 24px; + padding: 0 8px; +} + +.tracker-mini-table { + overflow-x: auto; +} + +.tracker-mini-table .table { + margin: 0; +} + +.tracker-mini-table th { + color: #344054; + font-size: 12px; + white-space: nowrap; +} + +.tracker-mini-table td { + color: #344054; + font-size: 12px; + vertical-align: middle; +} + +.tracker-badge { + border-radius: 999px; + display: inline-flex; + font-size: 12px; + font-weight: 700; + line-height: 1; + padding: 7px 10px; + white-space: nowrap; +} + +.tracker-badge.is-success { + background: #dcfce7; + color: #15803d; +} + +.tracker-badge.is-warning { + background: #fef3c7; + color: #b45309; +} + +.tracker-badge.is-danger { + background: #fee2e2; + color: #b42318; +} + +.tracker-badge.is-info { + background: #dbeafe; + color: #1d4ed8; +} + +.tracker-order-line { + align-items: center; + border: 1px solid #e6edf5; + border-radius: 6px; + display: grid; + gap: 10px; + grid-template-columns: 120px minmax(0, 1fr) auto; + padding: 10px 12px; +} + +.tracker-order-line span { + color: #344054; + overflow-wrap: anywhere; +} + +.tracker-order-line em { + color: #172033; + font-style: normal; + font-weight: 700; +} + +.tracker-muted, +.tracker-updated { + color: #667085; + font-size: 12px; + margin-top: 10px; +} + +.tracker-approval-list { + list-style: none; + margin: 0; + padding: 0; +} + +.tracker-approval-list li { + align-items: flex-start; + display: flex; + gap: 10px; + padding: 9px 0; +} + +.tracker-approval-list li + li { + border-top: 1px solid #eef2f7; +} + +.tracker-approval-dot { + align-items: center; + border-radius: 999px; + display: inline-flex; + flex: 0 0 24px; + font-size: 12px; + font-weight: 700; + height: 24px; + justify-content: center; + width: 24px; +} + +.tracker-approval-list .is-approved .tracker-approval-dot { + background: #16a34a; + color: #fff; +} + +.tracker-approval-list .is-waiting .tracker-approval-dot { + background: #fef3c7; + color: #b45309; +} + +.tracker-approval-list strong { + color: #172033; + display: block; + font-size: 13px; +} + +.tracker-approval-list small { + color: #667085; + display: block; + font-size: 12px; + margin-top: 3px; +} + +.tracker-resume { + display: grid; + gap: 10px 16px; + grid-template-columns: 150px minmax(0, 1fr); + margin: 0; +} + +.tracker-resume dt { + color: #667085; + font-weight: 600; +} + +.tracker-resume dd { + color: #172033; + font-weight: 600; + margin: 0; + overflow-wrap: anywhere; +} + +.tracker-state, +.tracker-empty-inline { + align-items: center; + background: #fff; + border: 1px dashed #cfd8e3; + border-radius: 8px; + color: #667085; + display: flex; + gap: 8px; + justify-content: center; + min-height: 80px; + padding: 16px; + text-align: center; +} + +.tracker-empty-inline { + background: #fbfcfe; + min-height: 74px; +} + +@media (max-width: 992px) { + .tracker-summary-grid, + .tracker-grid { + grid-template-columns: 1fr; + } + + .tracker-steps { + gap: 12px; + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + + .tracker-steps:before { + display: none; + } +} + +@media (max-width: 640px) { + .tracker-shell { + padding: 12px; + } + + .tracker-header { + align-items: flex-start; + flex-direction: column; + } + + .tracker-refresh { + width: 100%; + } + + .tracker-steps { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .tracker-order-line, + .tracker-resume { + grid-template-columns: 1fr; + } +} diff --git a/compras_digital/wcm/widget/widget_solicitacoes/src/main/webapp/resources/js/widget_solicitacoes.js b/compras_digital/wcm/widget/widget_solicitacoes/src/main/webapp/resources/js/widget_solicitacoes.js index 36c640d..2ae7491 100644 --- a/compras_digital/wcm/widget/widget_solicitacoes/src/main/webapp/resources/js/widget_solicitacoes.js +++ b/compras_digital/wcm/widget/widget_solicitacoes/src/main/webapp/resources/js/widget_solicitacoes.js @@ -1,55 +1,636 @@ var MyWidget = SuperWidget.extend({ - - // Variáveis do widget (se precisar salvar estado entre chamadas) instanceId: null, - // Método iniciado quando o widget é carregado init: function() { - this.instanceId = this.instanceId || new Date().getTime(); - console.log("Widget Solicitações carregado, instância:", this.instanceId); + this.clearMessage(); + $("#detalheSolicitacao_" + this.instanceId).hide(); }, - - // BIND de eventos + bindings: { local: { - 'pesquisar': ['click_consultarSolicitacoes'] + "pesquisar": ["click_consultarSolicitacoes"], + "acompanhar": ["click_acompanharSolicitacao"], + "limpar": ["click_limparConsulta"] }, global: {} }, - - // Função chamada ao clicar em "Pesquisar" + consultarSolicitacoes: function(htmlElement, event) { - var numero = $("#filtroNumero_" + this.instanceId).val(); - var solicitante = $("#filtroSolicitante_" + this.instanceId).val(); - var status = $("#filtroStatus_" + this.instanceId).val(); + if (event) event.preventDefault(); - var constraints = []; - if (numero) constraints.push(DatasetFactory.createConstraint("C1_NUM", numero, numero, ConstraintType.MUST)); - if (solicitante) constraints.push(DatasetFactory.createConstraint("C1_SOLICIT", solicitante, solicitante, ConstraintType.MUST)); - if (status) constraints.push(DatasetFactory.createConstraint("STATUS", status, status, ConstraintType.MUST)); + var numero = this.normalizarTexto($("#filtroNumero_" + this.instanceId).val()); + var solicitante = this.normalizarTexto($("#filtroSolicitante_" + this.instanceId).val()); + var status = this.normalizarTexto($("#filtroStatus_" + this.instanceId).val()); - var ds = DatasetFactory.getDataset("dsSolicitacoesCompra", null, constraints, null); + this.clearMessage(); + $("#detalheSolicitacao_" + this.instanceId).hide().empty(); - let html = ` - - - `; - - if (ds && ds.values.length) { - ds.values.forEach(sc => { - html += ` - - - - - - `; - }); - } else { - html += ``; + if (numero) { + this.renderizarConsultaPorNumero(numero); + return; } - html += `
NúmeroSolicitanteDataStatusPedido
${sc.C1_NUM}${sc.C1_SOLICIT}${sc.C1_EMISSAO}${sc.STATUS}${sc.C1_PEDIDO || '-'}
Nenhuma solicitação encontrada
`; - $("#listaSolicitacoes_" + this.instanceId).html(html); + this.renderizarListaGenerica(solicitante, status); + }, + + acompanharSolicitacao: function(htmlElement, event) { + if (event) event.preventDefault(); + + var numero = $(htmlElement).attr("data-numero-sc"); + if (!numero) return; + + $("#filtroNumero_" + this.instanceId).val(numero); + this.renderizarTracker(numero); + }, + + limparConsulta: function(htmlElement, event) { + if (event) event.preventDefault(); + + $("#filtroNumero_" + this.instanceId).val(""); + $("#filtroSolicitante_" + this.instanceId).val(""); + $("#filtroStatus_" + this.instanceId).val(""); + $("#listaSolicitacoes_" + this.instanceId).empty(); + $("#detalheSolicitacao_" + this.instanceId).hide().empty(); + this.clearMessage(); + }, + + bindDynamicActions: function() { + var self = this; + $("#listaSolicitacoes_" + this.instanceId) + .find("[data-acompanhar]") + .off("click.tracker") + .on("click.tracker", function(event) { + self.acompanharSolicitacao(this, event); + }); + }, + + renderizarConsultaPorNumero: function(numero) { + var dados = this.consultarSC(numero); + + if (!dados || !dados.rows.length || !this.temSCValida(dados.rows[0])) { + $("#listaSolicitacoes_" + this.instanceId).html(this.emptyState("Nenhuma solicitacao encontrada para a SC informada.")); + return; + } + + $("#listaSolicitacoes_" + this.instanceId).html(this.montarTabelaSolicitacoes(dados.rows)); + this.bindDynamicActions(); + this.renderizarTracker(numero, dados); + }, + + renderizarListaGenerica: function(solicitante, status) { + var ds = null; + var constraints = []; + + try { + if (solicitante) constraints.push(this.criarConstraint("C1_SOLICIT", solicitante, solicitante)); + if (status) constraints.push(this.criarConstraint("STATUS", status, status)); + ds = this.buscarDataset("dsSolicitacoesCompra", null, constraints, null); + } catch (e) { + ds = null; + } + + if (!ds || !ds.values || !ds.values.length) { + this.showMessage("Informe o numero da SC para abrir o tracker. A listagem geral depende de um dataset de consulta de solicitacoes no ambiente Fluig.", "info"); + $("#listaSolicitacoes_" + this.instanceId).html(this.emptyState("Digite uma SC e clique em Pesquisar.")); + return; + } + + $("#listaSolicitacoes_" + this.instanceId).html(this.montarTabelaSolicitacoes(ds.values)); + this.bindDynamicActions(); + }, + + consultarSC: function(numero) { + var constraints = [ + this.criarConstraint("numeroSCProtheus", numero, numero) + ]; + var ds = this.buscarDataset("ds_consultaSC", null, constraints, null); + + return { + dataset: ds, + rows: ds && ds.values ? ds.values : [] + }; + }, + + criarConstraint: function(campo, valorInicial, valorFinal) { + if (typeof DatasetFactory !== "undefined" && typeof ConstraintType !== "undefined") { + return DatasetFactory.createConstraint(campo, valorInicial, valorFinal, ConstraintType.MUST); + } + + return { + _field: campo, + _initialValue: valorInicial, + _finalValue: valorFinal, + _type: 1, + fieldName: campo, + initialValue: valorInicial, + finalValue: valorFinal, + constraintType: 1 + }; + }, + + buscarDataset: function(nome, fields, constraints, sortFields) { + if (typeof DatasetFactory !== "undefined") { + return DatasetFactory.getDataset(nome, fields, constraints, sortFields); + } + + var retorno = { values: [] }; + + $.ajax({ + url: "/api/public/ecm/dataset/datasets", + type: "POST", + async: false, + contentType: "application/json", + dataType: "json", + data: JSON.stringify({ + name: nome, + fields: fields || null, + constraints: constraints || [], + order: sortFields || null + }), + success: function(response) { + var content = response && response.content ? response.content : response; + retorno = { + values: content && content.values ? content.values : [] + }; + }, + error: function(xhr) { + var mensagem = xhr && xhr.responseText ? xhr.responseText : "Falha ao consultar dataset " + nome; + throw new Error(mensagem); + } + }); + + return retorno; + }, + + renderizarTracker: function(numero, dadosConsulta) { + var detalhe = $("#detalheSolicitacao_" + this.instanceId); + detalhe.show().html(this.loadingState("Consultando dados da SC " + this.escapeHTML(numero) + "...")); + + try { + var dados = dadosConsulta || this.consultarSC(numero); + if (!dados || !dados.rows.length || !this.temSCValida(dados.rows[0])) { + detalhe.html(this.emptyState("Nao foi possivel carregar o tracker desta SC.")); + return; + } + + var resumo = this.montarResumoSC(dados.rows); + detalhe.html(this.montarTracker(resumo)); + } catch (e) { + detalhe.html(this.emptyState("Erro ao carregar o tracker: " + this.escapeHTML(String(e)))); + } + }, + + montarTabelaSolicitacoes: function(rows) { + var exibidos = {}; + var html = [ + '
', + '', + '', + '', + '', + '', + '', + '', + '', + '' + ]; + + for (var i = 0; i < rows.length; i++) { + var row = rows[i] || {}; + var numero = this.primeiroValor(row.C1_NUM, row.numero, row.NUMERO); + if (!numero) continue; + if (exibidos[numero]) continue; + exibidos[numero] = true; + + html.push( + '', + '', + '', + '', + '', + '', + '', + '' + ); + } + + html.push('
SolicitacaoSolicitanteDataStatusPedidoAcao
SC ' + this.escapeHTML(numero) + '' + this.escapeHTML(this.primeiroValor(row.C1_SOLICIT, row.solicitante, "-")) + '' + this.escapeHTML(this.formatarData(this.primeiroValor(row.C1_EMISSAO, row.data, ""))) + '' + this.montarBadge(this.primeiroValor(row.STATUS, row.status, "-")) + '' + this.escapeHTML(this.formatarDocumento(this.primeiroValor(row.C1_PEDIDO, row.pedido, "-"))) + '', + '', + '
'); + return html.join(""); + }, + + montarResumoSC: function(rows) { + var base = rows[0] || {}; + var cotacoes = this.parseJsonArray(base.COTACOES_JSON); + var pedidos = this.parseJsonArray(base.PEDIDO_JSON); + var totalSC = this.somarCampo(rows, "C1_TOTAL"); + var menorCotacao = this.encontrarMenorCotacao(cotacoes); + var pedido = this.formatarDocumento(this.primeiroValor(base.C1_PEDIDO, menorCotacao ? menorCotacao.C8_NUMPED : "")); + var cotacao = this.formatarDocumento(this.primeiroValor(base.C1_COTACAO, menorCotacao ? menorCotacao.C8_NUM : "")); + var status = this.definirStatus(base, cotacao, pedido); + var assinaturas = this.extrairAssinaturasPedido(pedidos); + + return { + numero: this.primeiroValor(base.C1_NUM, ""), + solicitante: this.primeiroValor(base.C1_SOLICIT, "-"), + data: this.formatarData(base.C1_EMISSAO), + valor: totalSC > 0 ? this.formatarMoeda(totalSC) : this.formatarMoeda(this.numeroBR(base.C1_TOTAL)), + status: status, + cotacao: cotacao, + pedido: pedido, + fornecedor: menorCotacao ? this.primeiroValor(menorCotacao.A2_NOME, menorCotacao.C8_FORNOME, menorCotacao.C8_FORNECE, "-") : "-", + menorValor: menorCotacao ? this.formatarMoeda(this.numeroBR(menorCotacao.C8_TOTAL)) : "-", + itens: rows, + cotacoes: cotacoes, + pedidos: pedidos, + assinaturas: assinaturas, + cotacaoErro: base.COTACAO_ERRO || "", + pedidoErro: base.PEDIDO_ERRO || "", + atualizadoEm: this.montarDataHora(base.data_consulta, base.hora_consulta) + }; + }, + + montarTracker: function(resumo) { + var etapas = this.montarEtapas(resumo); + + return [ + '
', + '
', + '
', + '

SC ' + this.escapeHTML(resumo.numero || "-") + '

', + 'Acompanhamento completo da solicitacao', + '
', + this.montarBadge(resumo.status), + '
', + '
', + this.montarInfo("Solicitante", resumo.solicitante), + this.montarInfo("Data da solicitacao", resumo.data || "-"), + this.montarInfo("Valor estimado", resumo.valor || "-"), + this.montarInfo("Cotacao", resumo.cotacao || "-"), + this.montarInfo("Pedido", resumo.pedido || "-"), + this.montarInfo("Fornecedor sugerido", resumo.fornecedor || "-"), + '
', + '
', + '
', + '
' + etapas.join("") + '
', + '
', + '
', + '
', + this.montarCotacoes(resumo), + this.montarPedidos(resumo), + this.montarItens(resumo), + '
', + '
', + this.montarAprovacoes(resumo), + this.montarResumoFinal(resumo), + '
', + '
' + ].join(""); + }, + + montarEtapas: function(resumo) { + var temCotacao = this.documentoValido(resumo.cotacao); + var temPedido = this.documentoValido(resumo.pedido); + var aprovado = resumo.assinaturas.length > 0 && this.todasAssinaturasAprovadas(resumo.assinaturas); + + return [ + this.montarEtapa("Solicitacao", "Criada", true, "fluigicon-shopping-cart"), + this.montarEtapa("Cotacao", temCotacao ? resumo.cotacao : "Pendente", temCotacao, "fluigicon-link"), + this.montarEtapa("Pedido", temPedido ? resumo.pedido : "Aguardando", temPedido, "fluigicon-file"), + this.montarEtapa("Aprovacao", aprovado ? "Aprovado" : "Pendente", aprovado, "fluigicon-ok-circle"), + this.montarEtapa("Entrega", "Aguardando", false, "fluigicon-truck") + ]; + }, + + montarEtapa: function(titulo, detalhe, concluida, icone) { + return [ + '
', + '
', + '' + this.escapeHTML(titulo) + '', + '' + this.escapeHTML(detalhe || "-") + '', + '
' + ].join(""); + }, + + montarCotacoes: function(resumo) { + var cotacoes = resumo.cotacoes || []; + var html = [ + '
', + '

Cotacoes

' + cotacoes.length + '
' + ]; + + if (!cotacoes.length) { + html.push(this.emptyInline(resumo.cotacaoErro || "Nenhuma cotacao vinculada ate o momento.")); + } else { + html.push('
'); + for (var i = 0; i < Math.min(cotacoes.length, 5); i++) { + var c = cotacoes[i] || {}; + html.push( + '', + '', + '', + '', + '', + '' + ); + } + html.push('
FornecedorItemValorPedido
' + this.escapeHTML(this.primeiroValor(c.A2_NOME, c.C8_FORNOME, c.C8_FORNECE, "-")) + '' + this.escapeHTML(this.primeiroValor(c.C8_ITEM, c.C8_ITEMSC, "-")) + '' + this.escapeHTML(this.formatarMoeda(this.numeroBR(c.C8_TOTAL))) + '' + this.escapeHTML(this.formatarDocumento(c.C8_NUMPED || "-")) + '
'); + } + + html.push('
'); + return html.join(""); + }, + + montarPedidos: function(resumo) { + var pedidos = resumo.pedidos || []; + var html = [ + '
', + '

Pedidos

' + (this.documentoValido(resumo.pedido) ? "1" : "0") + '
' + ]; + + if (!this.documentoValido(resumo.pedido)) { + html.push(this.emptyInline(resumo.pedidoErro || "Pedido ainda nao gerado.")); + } else { + html.push('
PED ' + this.escapeHTML(resumo.pedido) + '' + this.escapeHTML(resumo.fornecedor) + '' + this.escapeHTML(resumo.menorValor) + '
'); + if (pedidos.length) { + html.push('
' + this.escapeHTML(pedidos.length + " registro(s) retornado(s) pela consulta do pedido.") + '
'); + } + } + + html.push('
'); + return html.join(""); + }, + + montarAprovacoes: function(resumo) { + var assinaturas = resumo.assinaturas || []; + var html = [ + '
', + '

Aprovacoes

' + assinaturas.length + '
' + ]; + + if (!assinaturas.length) { + html.push(this.emptyInline("Sem alcadas retornadas para o pedido.")); + } else { + html.push('
    '); + for (var i = 0; i < assinaturas.length; i++) { + var a = assinaturas[i] || {}; + var aprovado = this.statusAprovado(a.status); + html.push( + '
  1. ', + '' + (aprovado ? "✓" : "!") + '', + '
    ' + this.escapeHTML(this.primeiroValor(a.nivel, "Nivel " + (i + 1))) + ' - ' + this.escapeHTML(this.primeiroValor(a.usuario, a.nome, "-")) + '', + '' + this.escapeHTML(this.primeiroValor(a.status, a.descricao, "Pendente")) + '
    ', + '
  2. ' + ); + } + html.push('
'); + } + + html.push('
'); + return html.join(""); + }, + + montarItens: function(resumo) { + var itens = resumo.itens || []; + var html = [ + '
', + '

Itens da solicitacao

' + itens.length + '
', + '
' + ]; + + for (var i = 0; i < itens.length; i++) { + var item = itens[i] || {}; + html.push( + '', + '', + '', + '', + '', + '' + ); + } + + html.push('
ItemDescricaoQtd.Total
' + this.escapeHTML(this.primeiroValor(item.C1_ITEM, "-")) + '' + this.escapeHTML(this.primeiroValor(item.C1_DESCRI, item.C1_PRODUTO, "-")) + '' + this.escapeHTML(this.primeiroValor(item.C1_QUANT, "-")) + '' + this.escapeHTML(this.formatarMoeda(this.numeroBR(item.C1_TOTAL))) + '
'); + return html.join(""); + }, + + montarResumoFinal: function(resumo) { + return [ + '
', + '

Resumo

', + '
', + '
Status da SC
' + this.montarBadge(resumo.status) + '
', + '
Menor valor encontrado
' + this.escapeHTML(resumo.menorValor || "-") + '
', + '
Fornecedor sugerido
' + this.escapeHTML(resumo.fornecedor || "-") + '
', + '
Pedido gerado
' + this.escapeHTML(resumo.pedido || "-") + '
', + '
Previsao de entrega
A definir
', + '
', + resumo.atualizadoEm ? '
Ultima atualizacao: ' + this.escapeHTML(resumo.atualizadoEm) + '
' : '', + '
' + ].join(""); + }, + + montarInfo: function(label, valor) { + return '
' + this.escapeHTML(label) + '' + this.escapeHTML(valor || "-") + '
'; + }, + + montarBadge: function(texto) { + var t = this.primeiroValor(texto, "-"); + var c = "tracker-badge"; + var s = String(t).toLowerCase(); + + if (s.indexOf("aprov") >= 0 || s.indexOf("gerad") >= 0 || s.indexOf("liberad") >= 0 || s.indexOf("sucesso") >= 0) c += " is-success"; + else if (s.indexOf("aguard") >= 0 || s.indexOf("pend") >= 0 || s.indexOf("cotacao") >= 0) c += " is-warning"; + else if (s.indexOf("reprov") >= 0 || s.indexOf("erro") >= 0) c += " is-danger"; + else c += " is-info"; + + return '' + this.escapeHTML(t) + ''; + }, + + definirStatus: function(row, cotacao, pedido) { + if (this.documentoValido(pedido)) return "Pedido gerado"; + if (this.documentoValido(cotacao)) return "Cotacao gerada"; + + var aprov = String(row.C1_APROV || "").toUpperCase(); + if (aprov === "L") return "Liberada"; + if (aprov === "R") return "Reprovada"; + if (aprov === "B") return "Aguardando cotacao"; + + return this.primeiroValor(row.STATUS, "Aguardando acompanhamento"); + }, + + encontrarMenorCotacao: function(cotacoes) { + var menor = null; + var menorValor = null; + + for (var i = 0; i < cotacoes.length; i++) { + var atual = cotacoes[i] || {}; + var valor = this.numeroBR(atual.C8_TOTAL); + if (!valor && valor !== 0) continue; + + if (menor === null || valor < menorValor) { + menor = atual; + menorValor = valor; + } + } + + return menor; + }, + + extrairAssinaturasPedido: function(pedidos) { + var assinaturas = []; + + for (var i = 0; i < pedidos.length; i++) { + var p = pedidos[i] || {}; + var candidatos = [p.ALCADAS, p.alcadas, p.aprovacoes, p.APROVACOES, p.assinaturas, p.ASSINATURAS]; + + for (var j = 0; j < candidatos.length; j++) { + var lista = candidatos[j]; + if (typeof lista === "string") lista = this.parseJsonArray(lista); + if (lista && lista.length) { + for (var k = 0; k < lista.length; k++) { + var a = lista[k] || {}; + assinaturas.push({ + nivel: this.primeiroValor(a.NIVEL, a.nivel, a.SEQUENCIA, a.sequencia), + usuario: this.primeiroValor(a.USUARIO, a.usuario, a.NOME, a.nome, a.APROVADOR, a.aprovador), + status: this.primeiroValor(a.STATUS, a.status, a.SITUACAO, a.situacao, a.DESCRICAO, a.descricao) + }); + } + } + } + } + + return assinaturas; + }, + + todasAssinaturasAprovadas: function(assinaturas) { + for (var i = 0; i < assinaturas.length; i++) { + if (!this.statusAprovado(assinaturas[i].status)) return false; + } + return assinaturas.length > 0; + }, + + statusAprovado: function(status) { + var s = String(status || "").toLowerCase(); + return s.indexOf("aprov") >= 0 || s === "03" || s.indexOf("liberad") >= 0; + }, + + temSCValida: function(row) { + return !!(row && this.primeiroValor(row.C1_NUM, row.numero, row.NUMERO)); + }, + + documentoValido: function(valor) { + var v = String(valor || "").replace(/\s/g, ""); + if (!v || v === "-") return false; + if (/^0+$/.test(v)) return false; + if (/^x+$/i.test(v)) return false; + return true; + }, + + parseJsonArray: function(valor) { + if (!valor) return []; + if (Object.prototype.toString.call(valor) === "[object Array]") return valor; + + try { + var parsed = JSON.parse(valor); + if (Object.prototype.toString.call(parsed) === "[object Array]") return parsed; + if (parsed && parsed.pedidos) return parsed.pedidos; + if (parsed && parsed.cotacoes) return parsed.cotacoes; + if (parsed && parsed.values) return parsed.values; + } catch (e) { + return []; + } + + return []; + }, + + somarCampo: function(rows, campo) { + var total = 0; + for (var i = 0; i < rows.length; i++) { + total += this.numeroBR((rows[i] || {})[campo]); + } + return total; + }, + + numeroBR: function(valor) { + if (typeof valor === "number") return valor; + var v = String(valor || "").trim(); + if (!v) return 0; + + v = v.replace(/[R$\s]/g, ""); + if (v.indexOf(",") >= 0) v = v.replace(/\./g, "").replace(",", "."); + var n = parseFloat(v); + return isNaN(n) ? 0 : n; + }, + + formatarMoeda: function(valor) { + var n = typeof valor === "number" ? valor : this.numeroBR(valor); + if (!n && n !== 0) return "-"; + return "R$ " + n.toLocaleString("pt-BR", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); + }, + + formatarData: function(valor) { + var v = String(valor || "").trim(); + if (!v) return "-"; + if (/^\d{8}$/.test(v)) return v.substr(6, 2) + "/" + v.substr(4, 2) + "/" + v.substr(0, 4); + return v; + }, + + formatarDocumento: function(valor) { + var v = String(valor || "").trim(); + if (!this.documentoValido(v)) return "-"; + return v; + }, + + montarDataHora: function(data, hora) { + var d = this.formatarData(data); + var h = String(hora || "").trim(); + if (d === "-" && !h) return ""; + return h ? d + " " + h : d; + }, + + primeiroValor: function() { + for (var i = 0; i < arguments.length; i++) { + var v = arguments[i]; + if (v !== null && v !== undefined && String(v).trim() !== "") return String(v).trim(); + } + return ""; + }, + + normalizarTexto: function(valor) { + return String(valor || "").trim(); + }, + + showMessage: function(texto, tipo) { + var classe = tipo === "danger" ? "alert-danger" : tipo === "success" ? "alert-success" : "alert-info"; + $("#mensagemSolicitacoes_" + this.instanceId).html('
' + this.escapeHTML(texto) + '
'); + }, + + clearMessage: function() { + $("#mensagemSolicitacoes_" + this.instanceId).empty(); + }, + + loadingState: function(texto) { + return '
' + this.escapeHTML(texto) + '
'; + }, + + emptyState: function(texto) { + return '
' + this.escapeHTML(texto) + '
'; + }, + + emptyInline: function(texto) { + return '
' + this.escapeHTML(texto) + '
'; + }, + + escapeHTML: function(valor) { + return String(valor === null || valor === undefined ? "" : valor) + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); } });