Primeiro commit fluig

This commit is contained in:
2025-08-26 14:12:50 -03:00
commit 8b7a079235
726 changed files with 319231 additions and 0 deletions
Binary file not shown.
@@ -0,0 +1,236 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Criar Solicitação de Compras</title>
<!-- Fluig SG + deps -->
<link rel="stylesheet" href="/style-guide/css/fluig-style-guide.min.css">
<link rel="stylesheet" href="/style-guide/css/fluig-style-guide-filter.min.css"> <!-- ADICIONE -->
<script src="/portal/resources/js/jquery/jquery.js"></script>
<script src="/portal/resources/js/jquery/jquery-ui.min.js"></script>
<script src="/style-guide/js/fluig-style-guide.min.js"></script>
<script src="/style-guide/js/fluig-style-guide-filter.min.js"></script> <!-- ADICIONE -->
<!-- seu JS/CSS -->
<link rel="stylesheet" href="form.css">
<script src="compras.js"></script>
</head>
<body>
<div class="fluig-style-guide">
<form name="form" role="form">
<div class="fs-display-block">
<!-- PAINEL: Dados da solicitação -->
<div class="panel panel-info">
<div class="panel-heading"><strong>Dados da Solicitação</strong></div>
<div class="panel-body">
<div class="row">
<div class="col-sm-6">
<label>Empresa</label>
<span class="required text-danger"><strong> * </strong></span>
<input type="zoom" class="form-control requiredInput" name="estabelecimento" id="estabelecimento"
data-zoom="{
'displayKey':'LOJA',
'datasetId':'dsSysCompany',
'placeholder': 'Pesquisar por nome do estabelecimento.',
'fields':[
{
'field':'BPCS',
'label':'Filial',
'standard':'true',
'search':'true'
},
{
'field':'DESCRICAO',
'label':'estabelecimento',
'search':'true'
}
]
}" />
<p class="text-danger text-error">
Preenchimento obrigatório.
</p>
</div>
<div class="col-sm-2">
<label>Filial Entrega</label>
<input type="text" name="filialDesc" id="filialDesc" class="form-control zoom"
placeholder="Selecione..." readonly>
</div>
<div class="col-sm-4">
<label>Tipo de Solicitação <span class="text-danger">*</span></label>
<select name="tipoSolicitacao" id="tipoSolicitacao" class="form-control" required>
<option value="">Selecione</option>
<option>Material</option>
<option>Serviço</option>
</select>
</div>
</div>
<div class="row m-t-15">
<div class="col-sm-6">
<label>Produto/Serviço <span class="text-danger">*</span></label>
<div class="input-group">
<input type="hidden" name="produtoCod" id="produtoCod">
<input type="text" name="produtoDesc" id="produtoDesc" class="form-control zoom" data-zoom="produto"
placeholder="Buscar..." readonly required>
<span class="input-group-btn">
<button class="btn btn-default" type="button" id="btnBuscaProd">
<span class="fluigicon fluigicon-search"></span>
</button>
<button class="btn btn-danger" type="button" id="btnLimpaProd">
<span class="fluigicon fluigicon-trash"></span>
</button>
</span>
</div>
</div>
<div class="col-sm-2">
<label>Último Preço</label>
<input type="text" name="ultimoPreco" id="ultimoPreco" class="form-control text-right" value="0,00"
readonly>
</div>
<div class="col-sm-2">
<label>Quantidade <span class="text-danger">*</span></label>
<div class="input-group">
<span class="input-group-btn">
<button type="button" class="btn btn-default" id="qtdMenos"></button>
</span>
<input type="number" min="0" step="1" name="quantidade" id="quantidade"
class="form-control text-center" value="0" required>
<span class="input-group-btn">
<button type="button" class="btn btn-default" id="qtdMais">+</button>
</span>
</div>
</div>
<div class="col-sm-2">
<label>Data da Necessidade <span class="text-danger">*</span></label>
<input type="text" name="dataNec" id="dataNec" class="form-control" placeholder="dd/mm/aaaa" required>
</div>
</div>
<div class="row m-t-10">
<div class="col-sm-6">
<label>Centro de Custo <span class="text-danger">*</span></label>
<input type="zoom" name="ccDesc" id="ccDesc" class="form-control" data-zoom="{
'displayKey':'centroCusto',
'datasetId':'ds_centroCusto',
'placeholder': 'Pesquisar número ou nome do centro de custo.',
'fields':[
{
'field':'codigoCentroCusto',
'label':'Código',
'standard':'true',
'search':'true'
},
{
'field':'centroCusto',
'label':'Centro de custo',
'search':'true'
},
{
'field': 'gestorCentroCusto',
'label': 'Gestor',
'visible': 'false'
},
{
'field': 'emailGestor',
'label': 'Email do gestor',
'visible': 'false'
},
{
'field': 'idGestor',
'label': 'Id do gestor',
'visible': 'false'
}
]
}" />
</div>
<div class="col-sm-3">
<label>Compra Emergencial?</label>
<select name="emergencial" id="emergencial" class="form-control">
<option>Não</option>
<option>Sim</option>
</select>
</div>
<div class="col-sm-3">
<label>Total</label>
<input type="text" name="total" id="total" class="form-control text-right" value="R$ 0,00" readonly>
</div>
</div> <!-- aqui sim fecha corretamente a row -->
<div class="row m-t-20">
<div class="col-sm-12">
<button type="button" class="btn btn-success" id="btnAddAnexo">
<span class="fluigicon fluigicon-upload"></span> Adicionar Anexo
</button>
</div>
<div class="col-sm-12">
<label>Observação do Item</label>
<textarea name="obs" id="obs" class="form-control" rows="2"></textarea>
</div>
</div>
<div class="text-center m-t-15">
<button type="button" id="btnAddItem" class="btn btn-primary">
<span class="fluigicon fluigicon-add"></span> Adicionar Item
</button>
</div>
</div>
</div>
<!-- PAINEL: Itens -->
<div class="panel panel-default">
<div class="panel-heading"><strong>Itens</strong></div>
<div class="panel-body">
<table id="tbItens" tablename="tbItens" class="table table-bordered">
<thead>
<tr>
<th>Produto</th>
<th>Centro de Custo</th>
<th>Qtd</th>
<th>Preço Ref.</th>
<th>Total</th>
<th>Ação</th>
</tr>
</thead>
<tbody>
<!-- LINHA MODELO (detail=true) -->
<tr class="tableRow" detail="true">
<td>
<input type="hidden" name="CodProd" class="form-control">
<input type="text" name="DescProd" class="form-control" readonly>
</td>
<td>
<input type="hidden" name="Codcc" class="form-control">
<input type="text" name="Desccc" class="form-control" readonly>
</td>
<td><input type="number" name="qtd" class="form-control text-right" min="0" step="1" value="0"></td>
<td><input type="text" name="Refpreco" class="form-control text-right" value="0,00"></td>
<td><input type="text" name="totalProd" class="form-control text-right" value="R$ 0,00" readonly></td>
<td class="text-center">
<button type="button" class="btn btn-link" onclick="fnWdkRemoveChild(this)">
<span class="fluigicon fluigicon-trash"></span>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</form>
</div>
</body>
</html>
+203
View File
@@ -0,0 +1,203 @@
// ======== DATASETS (troque aqui se o id for diferente) ========
const DS_EMPRESAS = 'dsSyscompany';
const DS_FILIAIS = 'dsFiliais'; // se o seu for outro, troque aqui
const DS_CC = 'ds_centroCusto';
const DS_PRODUTOS = 'ProdutoTI'; // se o id for "ProdutosTI", troque aqui
// ======== MAPEAMENTO DE CAMPOS (ajuste se seus datasets usam nomes diferentes) ========
// Empresas / Filiais / Centro de Custo
const EMP_FIELDS = { code: 'codigo', desc: 'descricao' };
const FIL_FIELDS = { code: 'codigo', desc: 'descricao' };
const CC_FIELDS = { code: 'codigo', desc: 'descricao' };
// Produtos (inclui alternativas típicas do Protheus)
const PROD_FIELDS = {
code: ['codigo','B1_COD','CODIGO'],
desc: ['descricao','B1_DESC','DESCRICAO'],
um: ['um','B1_UM','UM'],
lastPrice: ['ultimoPreco','ULTIMO_PRECO','ULT_PRECO','ULTIMOPRECO']
};
// ======== INIT ========
$(document).ready(function () {
FLUIGC.calendar('#dataNec');
// qty/preço
$('#precoRef').on('blur', recalcTotal);
$('#quantidade').on('input', recalcTotal);
$('#qtdMais').on('click', () => stepQtd(1));
$('#qtdMenos').on('click', () => stepQtd(-1));
// produto
$('#btnBuscaProd').on('click', openZoomProduto);
$('#btnLimpaProd').on('click', () => {
$('#produtoCod,#produtoDesc').val('');
$('#ultimoPreco').val('0,00');
recalcTotal();
});
// zooms
bindZoom($('#empresaDesc'), DS_EMPRESAS, EMP_FIELDS, 'empresaCodigo','empresaDesc');
bindZoom($('#filialDesc'), DS_FILIAIS, FIL_FIELDS, 'filialCodigo','filialDesc');
bindZoom($('#ccDesc'), DS_CC, CC_FIELDS, 'ccCod','ccDesc');
// itens
$('#btnAddItem').on('click', addItem);
});
// ======== HELPERS ========
function stepQtd(n){
const $q = $('#quantidade');
let v = parseInt($q.val()||'0',10)+n;
if (v < 0) v = 0;
$q.val(v);
recalcTotal();
}
function parseMoneyBR(s){
if(!s) return 0;
s = (''+s).replace(/[^\d,,-]/g,'').replace(/\./g,'').replace(',', '.');
const v = Number(s);
return isNaN(v) ? 0 : v;
}
function formatMoneyBR(v){
return v.toLocaleString('pt-BR',{style:'currency',currency:'BRL'});
}
function recalcTotal(){
const qtd = parseFloat($('#quantidade').val()||'0');
const preco = parseMoneyBR($('#precoRef').val());
const tot = (qtd * preco) || 0;
$('#total').val(formatMoneyBR(tot));
}
// Compat: usa filtermodal OU filterModal, dependendo da versão do SG
function openFilterModalCompat(opts){
var fn = (FLUIGC && (FLUIGC.filtermodal || FLUIGC.filterModal));
if (!fn) {
FLUIGC.toast({
title: 'Erro: ',
message: 'Plugin de filtro (filtermodal) não está carregado. Verifique os includes do Style Guide.',
type: 'danger'
});
return { onSelected: function(){} };
}
return fn(opts);
}
// pega a primeira chave existente no item
function pick(obj, keys){
if (!Array.isArray(keys)) return obj[keys];
for (const k of keys) if (obj[k] !== undefined && obj[k] !== null) return obj[k];
return '';
}
function firstKey(keys){ return Array.isArray(keys) ? keys[0] : keys; }
// ======== ZOOMS GENÉRICOS (empresa, filial, centro de custo) ========
function bindZoom($input, datasetId, fieldsMap, hiddenIdFld, displayFld){
const codeK = fieldsMap.code, descK = fieldsMap.desc;
$input.on('click', function(){
openFilterModalCompat({
title: 'Selecionar',
size: 'large',
filterFields: codeK + ', ' + descK,
source: {
url: '/api/public/ecm/dataset/search',
contentType: 'application/json',
root: 'content',
limit: 50,
pattern: '',
param: { datasetId: datasetId }
},
columns: [
{ title: 'Código', data: codeK },
{ title: 'Descrição', data: descK }
],
onSelected: function(data){
$('#'+hiddenIdFld).val(data[codeK]);
$('#'+displayFld).val(data[codeK] + ' - ' + data[descK]);
}
});
});
}
// ======== ZOOM DE PRODUTO ========
function openZoomProduto(){
openFilterModalCompat({
title: 'Buscar Produto/Serviço',
size: 'large',
filterFields: firstKey(PROD_FIELDS.code) + ', ' + firstKey(PROD_FIELDS.desc),
source: {
url: '/api/public/ecm/dataset/search',
contentType: 'application/json',
root: 'content',
limit: 50,
param:{ datasetId: DS_PRODUTOS }
},
columns: [
{ title: 'Código', data: firstKey(PROD_FIELDS.code) },
{ title: 'Descrição', data: firstKey(PROD_FIELDS.desc) },
{ title: 'UM', data: firstKey(PROD_FIELDS.um) },
{ title: 'Último Preço', data: firstKey(PROD_FIELDS.lastPrice) }
],
onSelected: function(item){
const cod = pick(item, PROD_FIELDS.code);
const desc = pick(item, PROD_FIELDS.desc);
const ult = pick(item, PROD_FIELDS.lastPrice);
$('#produtoCod').val(cod);
$('#produtoDesc').val(cod + ' - ' + desc);
$('#ultimoPreco').val(ult || '0,00');
recalcTotal();
}
});
}
// ======== ITENS (tabela filha) ========
function addItem(){
if(!$('#produtoCod').val()){
FLUIGC.toast({title:'Atenção: ', message:'Selecione um produto.', type:'warning'}); return;
}
if(!$('#ccCod').val()){
FLUIGC.toast({title:'Atenção: ', message:'Selecione o centro de custo.', type:'warning'}); return;
}
const qtd = parseFloat($('#quantidade').val()||'0');
if(qtd <= 0){
FLUIGC.toast({title:'Atenção: ', message:'Quantidade deve ser > 0.', type:'warning'}); return;
}
const row = wdkAddChild('tbItens');
$('#produtoCod___'+row).val($('#produtoCod').val());
$('#produtoDesc___'+row).val($('#produtoDesc').val());
$('#ccCod___'+row).val($('#ccCod').val());
$('#ccDesc___'+row).val($('#ccDesc').val());
$('#qtd___'+row).val(qtd);
$('#precoRef___'+row).val($('#precoRef').val());
$('#total___'+row).val($('#total').val());
}
// ======== VALIDAÇÃO (se usar o hook validateForm) ========
function validateForm(form){
var msgs = [];
function req(id, label){ if(!form.getValue(id)) msgs.push('Preencha "'+label+'".'); }
req('tipoSolicitacao','Tipo de Solicitação');
req('produtoCod','Produto/Serviço');
req('quantidade','Quantidade');
req('dataNec','Data da Necessidade');
req('ccCod','Centro de Custo');
if(msgs.length){ throw msgs.join('\n'); }
}
function setSelectedZoomItem(selectedItem) {
var name_item = selectedItem.inputId;
var ehItem = name_item.indexOf("___") >= 0;
var indice = "";
if (ehItem){
var valores = name_item.split("___");
name_item = valores[0];
indice = valores[1];
}
if (name_item == "estabelecimento")
{ $("#filialDesc").val(selectedItem["CODIGO"]); }
}
@@ -0,0 +1,3 @@
.m-t-10 { margin-top: 10px; }
.m-t-15 { margin-top: 15px; }
.text-right { text-align: right; }