From 03397ee6d0e6b374b82204a8316e727bf0458f8d Mon Sep 17 00:00:00 2001 From: rodolpho Date: Thu, 7 May 2026 18:59:09 -0300 Subject: [PATCH] docs: sync wiki with main repository content --- AGENTS.md | 29 + MCP_GUIDE.md | 56 ++ .../Biblioteca de Snippets/Snippets JAVA.md | 139 ++++ .../Snippets JAVASCRIPT.md | 720 ++++++++++++++++++ .../Biblioteca de Snippets/Snippets SQL.md | 192 +++++ index.md | 32 + 6 files changed, 1168 insertions(+) create mode 100644 AGENTS.md create mode 100644 MCP_GUIDE.md create mode 100644 fluig_rag_docs/Biblioteca de Snippets/Snippets JAVA.md create mode 100644 fluig_rag_docs/Biblioteca de Snippets/Snippets JAVASCRIPT.md create mode 100644 fluig_rag_docs/Biblioteca de Snippets/Snippets SQL.md create mode 100644 index.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..105c492 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,29 @@ +## How to investigate +Read highest-value sources first: +- `README*`, root manifests, workspace config, lockfiles +- build, test, lint, formatter, typecheck, and codegen config +- CI workflows and pre-commit / task runner config +- existing instruction files (`AGENTS.md`, `CLAUDE.md`, `.cursor/rules/`, `.cursorrules`, `.github/copilot-instructions.md`) +- repo-local OpenCode config such as `opencode.json` + +If architecture is unclear, inspect representative code files to find entrypoints and flow. Prefer executable sources of truth over prose. Trust executable source over conflicting docs. + +## What to extract +Look for high-signal facts: +- Exact developer commands (especially non-obvious ones) +- How to run a single test or focused verification step +- Required command order (e.g., `lint -> typecheck -> test`) +- Monorepo/multi-package boundaries and entrypoints +- Framework/toolchain quirks (codegen, build artifacts, dev servers) +- Repo-specific style or workflow conventions + +## Questions +Only ask if the repo cannot answer something important, such as undocumented team conventions or missing setup prerequisites. + +## Writing rules +Include only high-signal, repo-specific guidance: +- Exact commands and shortcuts that agents would otherwise guess wrong. +- Architecture notes not obvious from filenames. +- Conventions differing from language/framework defaults. +- Setup requirements, environment quirks, and operational gotchas. +Exclude generic advice or long tutorials. Be concise with short sections and bullets. \ No newline at end of file diff --git a/MCP_GUIDE.md b/MCP_GUIDE.md new file mode 100644 index 0000000..813b7f0 --- /dev/null +++ b/MCP_GUIDE.md @@ -0,0 +1,56 @@ +# Guia do Servidor MCP: Wiki Técnica Fluig + +Este guia explica como configurar e utilizar o servidor MCP (Model Context Protocol) para permitir que agentes de IA (como Claude Desktop, Cursor ou IDEs) interajam de forma inteligente com a documentação técnica do Fluig extraída pelo projeto `apitdn`. + +## 1. Pré-requisitos +* Python 3.9 ou superior. +* Dependências instaladas: + ```bash + pip install -r requirements.txt + ``` + +## 2. Arquitetura do MCP +O servidor (`mcp_server.py`) utiliza o framework **FastMCP** e expõe o conteúdo do arquivo `fluig_chunks.json` e da `Biblioteca de Snippets`. Ele opera via interface **STDIO**, que é o padrão para integração com a maioria dos clientes de IA. + +## 3. Ferramentas Disponíveis (Tools) +Ao conectar este MCP a um agente de IA, as seguintes ferramentas ficam disponíveis: + +* **`search_docs(query)`**: Realiza uma busca semântica por palavras-chave nos ~1.800 chunks da documentação. Ideal para dúvidas conceituais ou de configuração. +* **`get_code_snippets(language)`**: Retorna todos os exemplos de código para a linguagem solicitada (`javascript`, `java` ou `sql`). +* **Recurso `docs://all_titles`**: Fornece uma lista completa de todos os títulos de páginas disponíveis na base de conhecimento. + +## 4. Configuração no Claude Desktop +Para usar este MCP no Claude Desktop, adicione a seguinte configuração ao seu arquivo `claude_desktop_config.json`: + +**Caminho do arquivo (Windows):** `%APPDATA%\Claude\claude_desktop_config.json` + +```json +{ + "mcpServers": { + "fluig-wiki": { + "command": "python", + "args": ["C:/dev/apitdn/mcp_server.py"], + "env": { + "PYTHONPATH": "C:/dev/apitdn" + } + } + } +} +``` +*Substitua `C:/dev/apitdn` pelo caminho absoluto do seu repositório.* + +## 5. Como Testar +Você pode testar se o servidor está respondendo corretamente via linha de comando usando o `mcp-cli` (se instalado) ou apenas rodando o script para verificar erros de importação: +```bash +python mcp_server.py +``` +*(O comando acima não produzirá saída visível e ficará aguardando input STDIO, o que indica que está funcionando corretamente).* + +## 6. Sincronização com o Gitea +Sempre que novos documentos forem extraídos do TDN via `fluig_extractor.py`, lembre-se de rodar: +1. `python rag_processor.py` (para atualizar o `fluig_chunks.json`). +2. `python snippet_generator.py` (para atualizar a biblioteca de códigos). +3. `git commit -am "docs: update knowledge base"` +4. `git push origin master` + +Isso garantirá que o servidor MCP sempre forneça as informações mais recentes para a sua IA. diff --git a/fluig_rag_docs/Biblioteca de Snippets/Snippets JAVA.md b/fluig_rag_docs/Biblioteca de Snippets/Snippets JAVA.md new file mode 100644 index 0000000..f902c00 --- /dev/null +++ b/fluig_rag_docs/Biblioteca de Snippets/Snippets JAVA.md @@ -0,0 +1,139 @@ +# Biblioteca de Snippets: JAVA + +## Origem: Criando um aplicativo para enviar notificações +```java +package com.fluig; +import java.util.HashMap; +import javax.annotation.PostConstruct; +import javax.ejb.Singleton; +import javax.ejb.Startup; +import javax.jms.JMSException; +import javax.jms.ObjectMessage; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.QueueSender; +import javax.jms.QueueSession; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +/** + * Registra o aplicatico como listener para os alertas. + */ +@Startup +@Singleton +public class StartupLoader { + private transient Logger log = LoggerFactory.getLogger(StartupLoader.class); + /* + * Nome da fila que será usada para receber os alertas. + */ + private static final String QUEUE = "AlertSenderSampleQueue"; + /** + * ID do tenante para o qual será registrado. Quando houver mais de um + * tenante, deverá fazer uma chamada para cada tenante. + */ + private static final Long TENANT_ID = 10097l; + @PostConstruct + private void startup() { + log.info("Inicializando aplicativo"); + try { + InitialContext ic = new InitialContext(); + Queue q = (Queue) ic + .lookup("java:global/TOTVSTechAsyncQueue"); + QueueConnectionFactory factory = (QueueConnectionFactory) ic + .lookup("java:global/FluigRemoteXAConnectionFactory"); + QueueConnection connection = factory.createQueueConnection(); + QueueSession session = null; + QueueSender sender = null; + try { + session = connection.createQueueSession(false, + javax.jms.Session.AUTO_ACKNOWLEDGE); + sender = session.createSender(q); + HashMap values = new HashMap(); + // Código do aplicativo. + values.put("applicationKey", "alert.app.sender.sample"); + // Chave da descrição do aplicativo. + values.put("descriptionKey", + "alert.app.sender.sample.description"); + // ID do tenante. + values.put("tenantId", TENANT_ID); + ObjectMessage msg = session.createObjectMessage(); + msg.setObject(values); + msg.setStringProperty("action", "registerAlertAppSender"); + sender.send(msg); + log.info("Inicialização do aplicativo OK"); + } finally { + if (sender != null) { + sender.close(); + } + if (session != null) { + session.close(); + } + if (connection != null) { + connection.close(); + } + } + } catch (NamingException ex) { + log.error("Nao foi possivel registrar o serviço de notificação via whatsapp"); + ex.printStackTrace(); + } catch (JMSException ex) { + log.error("Nao foi possivel registrar o serviço de notificação via whatsapp"); + ex.printStackTrace(); + } + } +} +``` + +## Origem: Criando um aplicativo para enviar notificações +```java +package com.fluig; +import java.io.Serializable; +import java.util.Map; +import javax.ejb.ActivationConfigProperty; +import javax.ejb.EJB; +import javax.ejb.MessageDriven; +import javax.ejb.TransactionAttribute; +import javax.ejb.TransactionAttributeType; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.ObjectMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +/** + * Esta é a classe que será chamada pela Central de Notificações para enviar + * alertas por este aplicativo. + */ +@MessageDriven(name = "topic/FluigNotificationTopic", mappedName = "FluigNotificationTopic", activationConfig = { + @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"), + @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"), + @ActivationConfigProperty(propertyName = "destination", propertyValue = "FluigNotificationTopic") +}) +public class AlertSampleMDBBean implements MessageListener { + private static final Logger log = LoggerFactory + .getLogger(AlertSampleMDBBean.class); + @EJB(lookup = TxtSenderService.JNDI_REMOTE_NAME) + private TxtSenderService service; + @Override + @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) + public void onMessage(final Message message) { + if (message instanceof ObjectMessage) { + final ObjectMessage msg = (ObjectMessage) message; + try { + final Serializable obj = msg.getObject(); + if (log.isDebugEnabled()) { + log.debug("AlertSenderSampleQueue.onMessage - obj: " + obj); + } + service.sendAlert((Map) obj); + if (log.isDebugEnabled()) { + log.debug("AlertSenderSampleQueue.onMessage - FIM"); + } + } catch (final JMSException ex) { + log.error(ex.getMessage(), ex); + } + } + } +} +``` + diff --git a/fluig_rag_docs/Biblioteca de Snippets/Snippets JAVASCRIPT.md b/fluig_rag_docs/Biblioteca de Snippets/Snippets JAVASCRIPT.md new file mode 100644 index 0000000..34e6112 --- /dev/null +++ b/fluig_rag_docs/Biblioteca de Snippets/Snippets JAVASCRIPT.md @@ -0,0 +1,720 @@ +# Biblioteca de Snippets: JAVASCRIPT + +## Origem: Acessando Datasets +```javascript +var newDataset = DatasetBuilder.newDataset(); + newDataset.addColumn("Document ID"); + newDataset.addColumn("Document version"); + newDataset.addColumn("Document Name"); + newDataset.addColumn("Document Type"); + + var listDocuments = datasets.get("document").search({ + "documentType": ["1", "2"] + }); + + for(var index = 0; index < listDocuments.length; index++) { + newDataset.addRow([ + listDocuments[index]["documentPK.documentId"], + listDocuments[index]["documentPK.version"], + listDocuments[index].documentDescription, + listDocuments[index].documentType + ]); + } + + return newDataset; +``` + +## Origem: Acessando Datasets +```javascript +var newDataset = DatasetBuilder.newDataset(); + newDataset.addColumn("Document ID"); + newDataset.addColumn("Document version"); + newDataset.addColumn("Document Name"); + newDataset.addColumn("Document Type"); + + var listDocuments = datasets.get("document").search({ + "documentDescription": { + "value": "%API%", + "like": true + }, + "limit": 5 + }); + + for(var index = 0; index < listDocuments.length; index++) { + newDataset.addRow([ + listDocuments[index]["documentPK.documentId"], + listDocuments[index]["documentPK.version"], + listDocuments[index].documentDescription, + listDocuments[index]["documentType"] + ]); + } + + return newDataset; +``` + +## Origem: Construção do Dataset Avançado +```javascript +function createDataset(fields, constraints, sortFields) { + var dataset = DatasetBuilder.newDataset(); + + //Cria as colunas + dataset.addColumn("Sigla"); + dataset.addColumn("Estado"); + dataset.addColumn("Capital"); + dataset.addColumn("Area"); + + //Cria os registros + dataset.addRow(new Array("AM", "Amazonas", "Manaus", 1570746)); + dataset.addRow(new Array("PA", "Pará", "Belém", 1247690)); + dataset.addRow(new Array("MT", "Mato Grosso", "Cuiabá", 903358)); + dataset.addRow(new Array("TO", "Tocantins", "Palmas", 277621)); + dataset.addRow(new Array("PI", "Piauí", "Teresina", 251529)); + + return dataset; +} +``` + +## Origem: Construção do Dataset Avançado +```javascript +function createDataset(fields, constraints, sortFields) { + var company; + var initialDate; + var finalDate; + if (constraints != null) { + for (var i = 0; i < constraints.length; i++) { + if (constraints[i].fieldName == "company") {  + company = constraints[i].initialValue;  + } + else if (constraints[i].fieldName == "date") { + initialDate = constraints[i].initialValue;  + finalDate = constraints[i].finalValue; + } + } + } + . + . + . +} +``` + +## Origem: Construção do Dataset Avançado +```javascript +function createDataset(fields, constraints, sortFields) { + var dataset = DatasetBuilder.newDataset(); + dataset.addColumn("DDD"); + dataset.addColumn("Fone"); + dataset.addColumn("Nome"); + + var tempDataset = getDefaultValues(); // consulta a fonte de dados do dataset + + if(constraints!=null && constraints.length){ //se tiver constraint filtra + + if(constraints[0].constraintType==ConstraintType.MUST) { // implementação somente para o MUST + + for(var a=0;a< tempDataset.length;a++){ + // se o valor inicial da constraint for igual ao valor do campo na constraint adiciona a linha + if(constraints[0].initialValue==tempDataset[a][constraints[0].fieldName]){ + dataset.addRow(new Array(tempDataset[a]["DDD"], tempDataset[a]["Fone"],tempDataset[a]["Nome"])); + } + } + } + } else { // se não tiver constraint adiciona todas as linhas + for(var a=0;a< tempDataset.length;a++){ + dataset.addRow(new Array(tempDataset[a]["DDD"], tempDataset[a]["Fone"],tempDataset[a]["Nome"])); + } + } + + return dataset; +} + +function getDefaultValues(){ // retorna valores default para serem filtrados + return [{ + DDD: "47", + Fone: "1111-1111", + Nome: "Marcos" + }, + { + DDD: "47", + Fone: "2222-2222", + Nome: "Roberto" + }, + { + DDD: "41", + Fone: "3333-3333", + Nome: "Maria" + }, + { + DDD: "31", + Fone: "4444-4444", + Nome: "Francisco" + }, + { + DDD: "11", + Fone: "5555-5555", + Nome: "Michel" + }]; +} +``` + +## Origem: Construção do Dataset Avançado +```javascript +function createDataset(fields, constraints, sortFields) { + var c1 = DatasetFactory.createConstraint("DDD", "47", "47", ConstraintType.MUST); + + var dataset = DatasetFactory.getDataset("exemploFiltro", null, new Array(c1), null); + return dataset; +} +``` + +## Origem: Construção do Dataset Avançado +```javascript +function createDataset(fields, constraints, sortFields) { + var companyId = getValue("WKCompany"); + var currentUser = getValue("WKUser"); + . + . + . +} +``` + +## Origem: Construção do Dataset Avançado +```javascript +function createDataset(fields, constraints, sortFields) { + var newDataset = DatasetBuilder.newDataset(); + try{ + var dataset = ""; + var filter = []; + var currentUser = getValue("WKUser"); //Código do usuário logado + var currentCompany = getValue("WKCompany"); //Código da empresa do usuário logado + + var groupCode = "grupo"; //Código do grupo que o usuário precisa pertencer para passar na validação. + dataset = "colleagueGroup" //Nome do dataset que pesquisa a relação de grupos e usuários. + + filter= [DatasetFactory.createConstraint("colleagueGroupPK.companyId", currentCompany , currentCompany, ConstraintType.MUST), + DatasetFactory.createConstraint("colleagueGroupPK.colleagueId", currentUser , currentUser, ConstraintType.MUST), + DatasetFactory.createConstraint("colleagueGroupPK.groupId", groupCode, groupCode, ConstraintType.MUST)]; //Cria o filtro para empresa, usuário e grupo. + + /** Codigo para pesquisar por papel ao invés de grupo. + * + var roleCode = "papel"; //Código do papel que o usuário precisa pertencer para passar na validação. + dataset = "workflowColleagueRole" //Nome do dataset que pesquisa a relação de papéis e usuários. + + filter= [DatasetFactory.createConstraint("workflowColleagueRolePK.companyId", currentCompany , currentCompany, ConstraintType.MUST), + DatasetFactory.createConstraint("workflowColleagueRolePK.colleagueId", currentUser , currentUser, ConstraintType.MUST), + DatasetFactory.createConstraint("workflowColleagueRolePK.roleId", roleCode, roleCode, ConstraintType.MUST)]; + */ + var validation = DatasetFactory.getDataset(dataset, null, filter, null); //Realiza a chamada do dataset + + if(validation.rowsCount==1){ //Se tiver uma linha quer dizer que o usuário logado faz parte do grupo/papel informado + //Esse retorno é só para informar que passou da validação, mas aqui dentro ficaria o codigo que o usuário tem permissão de acesso. + newDataset.addColumn("SUCCESS"); + newDataset.addRow(["ok"]); + } else { + //Esse retorno é só para informar que o usuário não faz parte do grupo/papel. + newDataset.addColumn("ERROR"); + newDataset.addRow(["sem permissão"]); + } + + } catch(e) { + newDataset.addColumn("ERROR"); + newDataset.addRow(["chamada incorreta"]); + return newDataset; + } + return newDataset; +} +``` + +## Origem: Construção do Dataset Avançado +```javascript +function createDataset(fields, constraints, sortFields) { + var c1 = null; + var c2 = null; + var filter = null; + + if (constraints.length > 0) + { + c1 = DatasetFactory.createConstraint("mail", "%" + constraints[0].initialValue + "%" , "%" + constraints[0].finalValue + "%", ConstraintType.SHOULD); + c2 = DatasetFactory.createConstraint("mail", "%%", "%%", ConstraintType.SHOULD); + + + c1.setLikeSearch(true); + c2.setLikeSearch(true); + filter = new Array (c1, c2); + } + var dataset = DatasetFactory.getDataset("colleague", null, filter, sortFields); + + return dataset; +} +``` + +## Origem: Construção do Dataset Avançado +```javascript +function createDataset(fields, constraints, sortFields) { + + //Cria as colunas + var dataset = DatasetBuilder.newDataset(); + dataset.addColumn("NumFormulario"); + dataset.addColumn("Id"); + dataset.addColumn("Peca"); + dataset.addColumn("Quantidade"); + + //Cria a constraint para buscar os formulários ativos + var cst = DatasetFactory.createConstraint("metadata#active", true, true, ConstraintType.MUST); + var constraints = new Array(cst); + + var datasetPrincipal = DatasetFactory.getDataset("dsExemploPaiFilho", null, constraints, null); + + for (var i = 0; i < datasetPrincipal.rowsCount; i++) { + var documentId = datasetPrincipal.getValue(i, "metadata#id"); + var documentVersion = datasetPrincipal.getValue(i, "metadata#version"); + + //Cria as constraints para buscar os campos filhos, passando o tablename, número da formulário e versão + var c1 = DatasetFactory.createConstraint("tablename", "tabelaPecas" ,"tabelaPecas", ConstraintType.MUST); + var c2 = DatasetFactory.createConstraint("metadata#id", documentId, documentId, ConstraintType.MUST); + var c3 = DatasetFactory.createConstraint("metadata#version", documentVersion, documentVersion, ConstraintType.MUST); + var constraintsFilhos = new Array(c1, c2, c3); + + //Busca o dataset + var datasetFilhos = DatasetFactory.getDataset("dsExemploPaiFilho", null, constraintsFilhos, null); + + for (var j = 0; j < datasetFilhos.rowsCount; j++) { + //Adiciona os valores nas colunas respectivamente. + dataset.addRow(new Array( + documentId, + datasetFilhos.getValue(j, "wdk_sequence_id"), + datasetFilhos.getValue(j, "peca"), + datasetFilhos.getValue(j, "qtde"))); + } + } + + return dataset; +} +``` + +## Origem: Datasets acessando banco de dados externo +```javascript +function createDataset(fields, constraints, sortFields) { + var newDataset = DatasetBuilder.newDataset(); + log.info("QUERY: " + myQuery); + var dataSource = "/jdbc/MeuDataSet"; + var ic = new javax.naming.InitialContext(); + var ds = ic.lookup(dataSource); + var created = false; + var myQuery = "select * from pessoas"; + try { + var conn = ds.getConnection(); + var stmt = conn.createStatement(); + var rs = stmt.executeQuery(myQuery); + var columnCount = rs.getMetaData().getColumnCount(); + while (rs.next()) { + if (!created) { + for (var i = 1; i <= columnCount; i++) { + newDataset.addColumn(rs.getMetaData().getColumnName(i)); + } + created = true; + } + var Arr = new Array(); + for (var i = 1; i <= columnCount; i++) { + var obj = rs.getObject(rs.getMetaData().getColumnName(i)); + if (null != obj) { + Arr[i - 1] = rs.getObject(rs.getMetaData().getColumnName(i)).toString(); + } else { + Arr[i - 1] = "null"; + } + } + newDataset.addRow(Arr); + } + } catch (e) { + log.error("ERRO==============> " + e.message); + } finally { + if (rs != null) { + rs.close(); + } + if (stmt != null) { + stmt.close(); + } + if (conn != null) { + conn.close(); + } + } + return newDataset; +} +``` + +## Origem: Sincronização de datasets +```javascript +function onSync(lastSyncDate) { + var dataset = DatasetBuilder.newDataset(); + var integracao = ServiceManager.getService('FLUIG3'); + var serviceLocator = integracao + .instantiate('pkgWkfSolicPagamento.FLUIGLocator'); + var service = serviceLocator.getFLUIGSOAP(); + var cdEmp = 1; // código empresa pagadora + var cdFilial = 0; // todas as filiais + var cdTitulo = 0; // todos os titulos + var cdPrefixo = "" + var cnpj = 0; // cnpj fornecedor + var codForn = 0; // cod universal para todos os fornecedores + var lojaForn = 0; // loja fornecedor + // Invocando o servico passando a data da ultima sincronização com a plataforma. + // O webservice foi preparado para trazer apenas os dados desde a ultima + // sincronização. + var retorno = service.CONSPAG(cdEmp, cdFilial, cdTitulo, cdPrefixo, cnpj, + codForn.toString(), lojaForn.toString(), lastSyncDate); + var arrayListaTitulo = retorno.getLISTACPAG(); + for (var i = 0; i < arrayListaTitulo.length; i++) { + var r = arrayListaTitulo[i]; + if (r.getCE_TIPO() == "ADD") { + dataset.addRow(new Array(r.getCE_CODIGO(), r.getCE_LOJA(), r + .getCE_NUMTIT(), r.getCE_PARCELA(), r.getCE_PEFIXO(), r + .getCE_TIPO(), r.getCE_VALOR(), r.getCE_INSS(), r + .getCE_ISS(), r.getCE_IRRF(), new java.util.Date(r.getDT_TITULO()), r + .getCE_PIS(), r.getCE_COFINS())); + } else if (r.getCE_TIPO() == "MOD") { + + dataset.updateRow(new Array(r.getCE_CODIGO(), r.getCE_LOJA(), r + .getCE_NUMTIT(), r.getCE_PARCELA(), r.getCE_PEFIXO(), r + .getCE_TIPO(), r.getCE_VALOR(), r.getCE_INSS(), r + .getCE_ISS(), r.getCE_IRRF(), new java.util.Date(r.getDT_TITULO()), r + .getCE_PIS(), r.getCE_COFINS())); + + } else if (r.getCE_TIPO() == "DEL") { + + dataset.deleteRow(new Array(r.getCE_CODIGO(), r.getCE_LOJA(), r + .getCE_NUMTIT(), r.getCE_PARCELA(), r.getCE_PEFIXO(), r + .getCE_TIPO(), r.getCE_VALOR(), r.getCE_INSS(), r + .getCE_ISS(), r.getCE_IRRF(), new java.util.Date(r.getDT_TITULO()), r + .getCE_PIS(), r.getCE_COFINS())); + + } else { + // Estado do registro é desconhecido no cache + dataset.addOrUpdateRow(new Array(r.getCE_CODIGO(), r.getCE_LOJA(), r + .getCE_NUMTIT(), r.getCE_PARCELA(), r.getCE_PEFIXO(), r + .getCE_TIPO(), r.getCE_VALOR(), r.getCE_INSS(), r + .getCE_ISS(), r.getCE_IRRF(), new java.util.Date(r.getDT_TITULO()), r + .getCE_PIS(), r.getCE_COFINS())); + + + } + } + + return dataset; +} +``` + +## Origem: Sincronização de datasets +```javascript +function onSync(lastSyncDate) { + var dataset = DatasetBuilder.newDataset(); + dataset.addRow(new Array(2256, "SÃO PAULO", 1058, "6", "ESPORTE")); + dataset.addRow(new Array(1874, "RECIFE", 1258, "1247690", "2", "CALÇADOS")); + dataset.addRow(new Array(1205, "RIO DE JANEIRO", 2594, "10", "MOVEIS")); + dataset.addRow(new Array(985, "FLORIANOPOLIS", 2269, "10", , "ELETRONICOS")); + + return dataset; +} +``` + +## Origem: Eventos de Formulário +```javascript +function displayFields(form, customHTML) { + if ( form.getFormMode() == “MOD” ) { + form.setValue('RNC_colab_abertura', new java.lang.Integer(1)); + } +} +``` + +## Origem: Eventos de Formulário +```javascript +function displayFields(form, customHTML) { + form.setVisible("campoA", false); + form.setVisibleById("linha___1", false); +} +``` + +## Origem: Eventos de Formulário +```javascript +**displayFields.js - Clique para expandir** Expandir origem +``` + +## Origem: Eventos de Formulário +```javascript +Conforme explicado, o *customHTML* permite personalizar o formulário diretamente pelo método displayFields. Este exemplo, adaptado dos nos [Exemplos Avançados](../Plataforma Documentação técnica/Recurso de Processos (BPM).md)/Desenvolvimento de Workflow/Exemplos avançados.md), mostra como usar o displayFields para, no formulário, ter acesso ao modo de visualização, código do solicitante e número da atividade. Além de preencher alguns campos da solicitação com a data atual e o nome do solicitante: +``` + +## Origem: Eventos de Formulário +```javascript +Para que os dados sejam carregados e apresentados em tela, principalmente em dispositivos *mobile*, é necessário chamar as funções que irão carregá-los dentro de uma estrutura de *read*. + +A invocação dos métodos que irão popular o formulário deve estar contida dentro de uma chamada $(function(), garantindo assim o carregamento dos arquivos exigidos pelo formulário antes das funções. + +Por exemplo, deseja-se carregar dados de produtos em um formulário. Para que isto ocorra, foi criada uma função *loadProdutos()* que irá preencher um *grid* inserido no formulário HTML. Neste caso a chamada desta função dentro do *displayFields* ficaria: +``` + +## Origem: Eventos de Formulário - Exemplo de novo modelo +```javascript +function displayFields(form, customHTML) { + if ( form.getFormMode() == “MOD” ) { + form.setValue('RNC_colab_abertura', new java.lang.Integer(1)); + } +} +``` + +## Origem: Eventos de Formulário - Exemplo de novo modelo +```javascript +function displayFields(form, customHTML) { + form.setVisible("campoA", false); + form.setVisibleById("linha___1", false); +} +``` + +## Origem: Eventos de Formulário - Exemplo de novo modelo +```javascript +**displayFields.js - Clique para expandir** Expandir origem +``` + +## Origem: Eventos de Formulário - Exemplo de novo modelo +```javascript +Conforme explicado, o *customHTML* permite personalizar o formulário diretamente pelo método displayFields. Este exemplo, adaptado dos nos [Exemplos Avançados](../Plataforma Documentação técnica/Recurso de Processos (BPM).md)/Desenvolvimento de Workflow/Exemplos avançados.md), mostra como usar o displayFields para, no formulário, ter acesso ao modo de visualização, código do solicitante e número da atividade. Além de preencher alguns campos da solicitação com a data atual e o nome do solicitante: +``` + +## Origem: Eventos de Formulário - Exemplo de novo modelo +```javascript +Para que os dados sejam carregados e apresentados em tela, principalmente em dispositivos *mobile*, é necessário chamar as funções que irão carregá-los dentro de uma estrutura de *read*. + +A invocação dos métodos que irão popular o formulário deve estar contida dentro de uma chamada $(function(), garantindo assim o carregamento dos arquivos exigidos pelo formulário antes das funções. + +Por exemplo, deseja-se carregar dados de produtos em um formulário. Para que isto ocorra, foi criada uma função *loadProdutos()* que irá preencher um *grid* inserido no formulário HTML. Neste caso a chamada desta função dentro do *displayFields* ficaria: +``` + +## Origem: formController.getCardData() +```javascript +function displayFields(form, customHTML) { +   var mapaForm = new java.util.HashMap(); +   mapaForm = form.getCardData(); +   log.info("### getCardData ###: " + mapaForm); +} +``` + +## Origem: Integração de aplicativos externos com o Fluig +```javascript +function displayFields(form,customHTML){ + + var CURRENT_STATE = getValue("WKNumState") ? getValue("WKNumState") : 0; + var CURRENT_USER = getValue("WKUser"); + + customHTML.append(''); +} +``` + +## Origem: Básico - Integração Fluig x Protheus: Centro de custo +```javascript +function defineStructure() {} + +function onSync(lastSyncDate) {} + +function createDataset(fields, constraints, sortFields) { +    var dataset = DatasetBuilder.newDataset(); +     +    dataset.addColumn("InternalId"); +    dataset.addColumn("CompanyInternalId"); +    dataset.addColumn("CompanyId"); +    dataset.addColumn("RegisterSituation"); +    dataset.addColumn("Class"); +    dataset.addColumn("Code"); +    dataset.addColumn("Name"); + +    var sendData = {     +        companyId: String(fluigAPI.getSecurityService().getCurrentTenantId()), +        serviceCode: "API_PROTHEUS_REST", +        endpoint: "/api/ctb/v1/costcenters/", +        method: "GET" +    }; + +    // Fornece acesso aos serviços externos com autenticação oauth, documentação: http://127.0.0.1:8080/api/sdk/com/fluig/sdk/service/AuthorizeClientSdkService.html +    var clientService = fluigAPI.getAuthorizeClientService();  +     + // Realizar a integração + // Documentação da API: https://api.totvs.com.br/apidetails/CostCenter_v1_000.json +    var vo = clientService.invokeService(JSON.stringify(sendData)); + // Armazenar o status HTTP da integração, esse passo é muito importante para idenficar se tudo ocorreu como deveria! + // Fique atento!!! Cada API pode ter um retorno diferente, a melhor prática é consultar documentação oficial em api.totvs.com.br e checar  + // os seus respectivos métodos e retornos possíveis. + // O método getHttpStatusResult é da classe AuthorizeClientSdkServiceVO (Variavel clientService do nosso código) + // Documentação completa: http://127.0.0.1:8080/api/sdk/com/fluig/sdk/api/authorizeclient/AuthorizeClientSdkServiceVO.html +    var status = String(vo.getHttpStatusResult()); +    if (status == "200") { +        var jsonResponse = JSON.parse(vo.getResult());        +        if (jsonResponse.items && jsonResponse.items.length > 0) { +            for (var i = 0; i < jsonResponse.items.length; i++) { +                var item = jsonResponse.items[i];                 +                dataset.addRow(new Array( +                 item.InternalId, +                 item.CompanyInternalId, +                 item.CompanyId, +                 item.RegisterSituation, +                 item.Class, +                 item.Code, +                 item.Name +                )); +            } +        } +    } else { +        var errorMsg = "Erro desconhecido durante a integracao."; +        try { +            var parseResult = JSON.parse(vo.getResult()); +            var parseError = JSON.parse(parseResult.errorMessage); +            errorMsg = parseError.detailedMessage; +        } catch (e) { +            errorMsg = vo.getResult(); +        } +         +        dataset.addRow(new Array( +            status, +            errorMsg, +            "", "", "", "", "" +        )); +    } +   +    return dataset; +} + +function onMobileSync(user) {} +``` + +## Origem: Integração com Aplicativos Externos +```javascript +function createDataset(fields, constraints, sortFields) { + // Cria o dataset + var dataset = DatasetBuilder.newDataset(); + dataset.addColumn("Element Name"); + dataset.addColumn("Symbol"); + dataset.addColumn("Atomic Number"); + dataset.addColumn("Atomic Weight"); + // Conecta o servico e busca os livros + var periodicService = ServiceManager.getService('PeriodicTable'); + var serviceHelper = periodicService.getBean(); + var serviceLocator = periodicService.instantiate('net.webservicex.Periodictable'); + var service = serviceLocator.getPeriodictableSoap(); + // Invoca o serviço + try { + var result = service.getAtomicNumber("sodium"); // O termo "sodium" corresponde ao parâmetro do tipo String esperado na assinatura do método getAtomicNumber + var xml = new XML(result); + for ( var index in xml.Table) { + var element = xml.Table[index]; + dataset.addRow(new Array(element.ElementName.toString(), element.Symbol.toString(), element.AtomicNumber + .toString(), element.AtomicWeight.toString())); + } + } catch (erro) { + dataset.addRow(new Array(erro)); + } + return dataset; +} +``` + +## Origem: Métodos de contorno de lentidão na plataforma +```javascript +2022-11-23 15:59:03,511 WARN [com.fluig.monitoring.jschronos.JSChronos] (JSChronos.CustomizationManagerImpl.invokeFunction.createDataset) CustomizationManagerImpl.invokeFunction.createDataset ja esta sendo executado por 2211 segundos params: [[[Ljava.lang.String;@268d1e17, null, null], Thread = default task-6727, datasetId = dsDatabase] +2.211 segundos + +2022-11-24 08:51:22,088 WARN [com.fluig.monitoring.jschronos.JSChronos] (JSChronos.CustomizationManagerImpl.invokeFunction.createDataset) CustomizationManagerImpl.invokeFunction.createDataset ja esta sendo executado por 60 segundos params: [[[Ljava.lang.String;@7cec0760, [Lcom.totvs.technology.foundation.dataset.SearchConstraint;@64de871c, null], Thread = default task-35, datasetId = dsChecklistCRUD] + +2023-02-14 09:17:47,722 WARN [com.fluig.monitoring.jschronos.JSChronos] (JSChronos.CustomizationManagerImpl.invokeFunction.createDataset) CustomizationManagerImpl.invokeFunction.createDataset ja esta sendo executado por 300 segundos params: [[null, [Lcom.totvs.technology.foundation.dataset.SearchConstraint;@67eb8082, null], Thread = default task-389, datasetId = ds_sql_update] + +2023-02-14 09:17:56,587 WARN [com.fluig.monitoring.jschronos.JSChronos] (JSChronos.CustomizationManagerImpl.invokeFunction.servicetask64) CustomizationManagerImpl.invokeFunction.servicetask64 ja esta sendo executado por 120 segundos params: [[Process id = alteracao_de_preco, Process Version = 23, Process Current UserId = usuario.user], Thread = default task-413, datasetId = workflowColleagueRole] +``` + +## Origem: Métodos de contorno de lentidão na plataforma +```javascript +2023-05-29 09:30:53,414 WARN [com.fluig.monitoring.jschronos.JSChronos] (default task-39) CustomizationManagerImpl.invokeFunction.createDataset executou por 32 segundos +2023-05-29 09:30:53,414 WARN [com.fluig.monitoring.jschronos.JSChronos] (default task-39) params: [[[Ljava.lang.String;@6c45e716, [Lcom.totvs.technology.foundation.dataset.SearchConstraint;@a1b6a73, null], Thread = default task-39, datasetId = ds_RMConsulta] +2023-05-29 09:30:53,437 WARN [com.fluig.monitoring.jschronos.JSChronos] (default task-39) DatasetFactory.getDataset.ds_RMConsulta executou por 32 segundos +2023-05-29 09:30:53,437 WARN [com.fluig.monitoring.jschronos.JSChronos] (default task-39) params: [[TBC012.05, 1, T], [FIELD_NAME=COLIGADA; INITIAL_VALUE=1; FINAL_VALUE=1; CONSTRAINT_TYPE=MUST; IS_LIKE_SEARCH=false; ], null] +2023-05-29 09:31:24,672 INFO [com.datasul.technology.webdesk.dataset.business.DatasetBO] (default task-39) Executando Dataset com ID ds_RMConsulta do tipo Avançado. +2023-05-29 09:31:24,672 INFO [com.datasul.technology.webdesk.dataset.business.DatasetBO] (default task-39) Builder rodando sem o mobile +2023-05-29 09:31:24,719 INFO [com.datasul.technology.webdesk.customization.ScriptingLog] (default task-39) uf-log | Chamada do DataSet ds_RMConsulta +2023-05-29 09:31:24,734 INFO [com.datasul.technology.webdesk.dataset.business.DatasetBO] (default task-39) Executando Dataset com ID ds_RMConecta do tipo Avançado. +2023-05-29 09:31:24,735 INFO [com.datasul.technology.webdesk.dataset.business.DatasetBO] (default task-39) Builder rodando sem o mobile +2023-05-29 09:31:24,786 INFO [org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean] (default task-39) Creating Service {http://www.totvs.com/}wsConsultaSQL from WSDL: http://peg54p-prd-ws.totvscloud.com.br:8083/wsConsultaSQL/MEX?wsdl +2023-05-29 09:31:24,800 WARNING [org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean] (default task-39) No method was found for the WSDL operation {http://www.totvs.com/}RealizarConsultaSQLContexto. +2023-05-29 09:31:24,805 INFO [org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean] (default task-39) Creating Service {http://www.totvs.com/}IwsConsultaSQLService from class com.totvs.IwsConsultaSQL +2023-05-29 09:31:24,812 INFO [com.datasul.technology.webdesk.customization.ScriptingLog] (default task-39) uf-log | Dados da chamada ao serviço wsConsultaSQL: +2023-05-29 09:31:24,812 INFO [com.datasul.technology.webdesk.customization.ScriptingLog] (default task-39) uf-log | CODSENTECA: TBC012.03 +2023-05-29 09:31:24,812 INFO [com.datasul.technology.webdesk.customization.ScriptingLog] (default task-39) uf-log | CODCOLIGADA: 1 +2023-05-29 09:31:24,812 INFO [com.datasul.technology.webdesk.customization.ScriptingLog] (default task-39) uf-log | APLICACAO: T +2023-05-29 09:31:24,812 INFO [com.datasul.technology.webdesk.customization.ScriptingLog] (default task-39) uf-log | PARAMETRO: +2023-05-29 09:31:24,922 INFO [com.datasul.technology.webdesk.customization.ScriptingLog] (default task-39) uf-log | Chamada realizada com sucesso. +2023-05-29 09:31:24,923 INFO [com.datasul.technology.webdesk.customization.ScriptingLog] (default task-39) uf-log | Quantidade de registros retornados: 57 +``` + +## Origem: Conversão TOTVS ECM para plataforma TOTVS Fluig +```javascript +function createDataset(fields, constraints, sortFields) { + var query = "SELECT login,email FROM fdn_usertenant LIMIT 100"; + var dataSource = "jdbc/FluigDSRO"; + var newDataset = DatasetBuilder.newDataset(); + var ic = new javax.naming.InitialContext(); + var ds = ic.lookup(dataSource); + + try { + var conn = ds.getConnection(); + var stmt = conn.createStatement(); + var rs = stmt.executeQuery(query); + + newDataset.addColumn("Login"); + newDataset.addColumn("Email"); + + while (rs.next()) { + newDataset.addRow([ rs.getString("login"), rs.getString("email") ]); + } + + } catch(e) { + newDataset.addColumn("erro"); + newDataset.addRow([e.message]); + } finally { + if(rs != null) rs.close(); + if(stmt != null) stmt.close(); + if(conn != null) conn.close(); + } + + return newDataset; +} +``` + +## Origem: Personalização de formulários - Nova versão +```javascript +function displayFields(form,customHTML) { + // Obtendo o usuario via dataset + filter = new java.util.HashMap(); + filter.put("colleaguePK.colleagueId","adm"); + usuario = getDatasetValues('colleague',filter); + form.setValue('RNC_colab_abertura',usuario.get(0).get("colleaguePK.colleagueId")); +} +``` + +## Origem: Personalização de formulários - Nova versão +```javascript +function displayFields(form,customHTML) { + // Obtendo o usuario via dataset + filter = new java.util.HashMap(); + filter.put("RNC_nr_solicitacao",new java.lang.Integer(20)); + registrosform = DatasetFactory.getDatasetValues(Number(676),filter); + log.info("Usuário de Abertura: "+ registrosform.get(0).get("RNC_colab_abertura")); +} +``` + +## Origem: Personalização de formulários - Nova versão +```javascript +function displayFields(form,customHTML) { + // Obtendo o usuario via dataset + filter = new java.util.HashMap(); + filter.put("RNC_nr_solicitacao",new java.lang.Integer(20)); + registrosform = getDatasetValues(Number(676),filter); + log.info("Usuário de Abertura: "+ registrosform.get(0).get("RNC_colab_abertura")); +} +``` + diff --git a/fluig_rag_docs/Biblioteca de Snippets/Snippets SQL.md b/fluig_rag_docs/Biblioteca de Snippets/Snippets SQL.md new file mode 100644 index 0000000..ffa8a2c --- /dev/null +++ b/fluig_rag_docs/Biblioteca de Snippets/Snippets SQL.md @@ -0,0 +1,192 @@ +# Biblioteca de Snippets: SQL + +## Origem: Configuração do banco de dados Oracle +```sql +DECLARE AUX_USERCONNECTED VARCHAR2(30); +BEGIN + SELECT USER + INTO AUX_USERCONNECTED + FROM DUAL; + IF (AUX_USERCONNECTED <> 'SYS') AND (AUX_USERCONNECTED <> 'SYSTEM') THEN + EXECUTE IMMEDIATE ('CREATE OR REPLACE VIEW ' ||AUX_USERCONNECTED|| '.ALL_OBJECTS AS' || + ' SELECT * FROM SYS.ALL_OBJECTS WHERE OWNER IN (SELECT USER FROM DUAL)'); + EXECUTE IMMEDIATE ('CREATE OR REPLACE VIEW ' ||AUX_USERCONNECTED|| '.ALL_SYNONYMS AS' || + ' SELECT * FROM SYS.ALL_SYNONYMS WHERE OWNER IN (SELECT USER FROM DUAL)'); + EXECUTE IMMEDIATE ('CREATE OR REPLACE VIEW ' ||AUX_USERCONNECTED|| '.ALL_SEQUENCES AS' || + ' SELECT * FROM SYS.ALL_SEQUENCES WHERE SEQUENCE_OWNER IN (SELECT USER FROM DUAL)'); + EXECUTE IMMEDIATE ('CREATE OR REPLACE VIEW ' ||AUX_USERCONNECTED|| '.ALL_CONSTRAINTS AS' || + ' SELECT * FROM SYS.ALL_CONSTRAINTS WHERE OWNER IN (SELECT USER FROM DUAL)'); + EXECUTE IMMEDIATE ('CREATE OR REPLACE VIEW ' ||AUX_USERCONNECTED|| '.ALL_CONS_COLUMNS AS' || + ' SELECT * FROM SYS.ALL_CONS_COLUMNS WHERE OWNER IN (SELECT USER FROM DUAL)'); + EXECUTE IMMEDIATE ('CREATE OR REPLACE VIEW ' ||AUX_USERCONNECTED|| '.ALL_INDEXES AS' || + ' SELECT * FROM SYS.ALL_INDEXES WHERE OWNER IN (SELECT USER FROM DUAL)'); + EXECUTE IMMEDIATE ('CREATE OR REPLACE VIEW ' ||AUX_USERCONNECTED|| '.ALL_IND_COLUMNS AS' || + ' SELECT * FROM SYS.ALL_IND_COLUMNS WHERE TABLE_OWNER IN (SELECT USER FROM DUAL)'); + EXECUTE IMMEDIATE ('CREATE OR REPLACE VIEW ' ||AUX_USERCONNECTED|| '.ALL_TABLES AS' || + ' SELECT * FROM SYS.ALL_TABLES WHERE OWNER IN (SELECT USER FROM DUAL)'); + EXECUTE IMMEDIATE ('CREATE OR REPLACE VIEW ' ||AUX_USERCONNECTED|| '.ALL_TAB_COLUMNS AS' || + ' SELECT * FROM SYS.ALL_TAB_COLUMNS WHERE OWNER IN (SELECT USER FROM DUAL)'); + END IF; +END; +``` + +## Origem: Configuração do banco de dados SQL Server +```sql +SELECT suser_sname(owner_sid) FROM sys.databases WHERE name = 'nome_do_banco'; +``` + +## Origem: Configuração do banco de dados SQL Server +```sql +SELECT is_read_committed_snapshot_on FROM sys.databases WHERE name= 'nome_do_banco'; +``` + +## Origem: Transparent Data Encryption (TDE) +```sql +SELECT TABLE_SCHEMA, TABLE_NAME, CREATE_OPTIONS +FROM INFORMATION_SCHEMA.TABLES +WHERE CREATE_OPTIONS = 'ENCRYPTION="Y"'; +``` + +## Origem: Métodos de contorno de lentidão na plataforma +```sql +select COD_DATASET from serv_dataset where DSL_DATASET like '%FluigDS%';  + +select nr_documento, COD_EVENT from event_ficha where DSL_EVENT like '%FluigDS%';  + +select COD_EVENT from event_geral where DSL_EVENT like '%FluigDS%';  + +select event_proces.COD_DEF_PROCES, COD_EVENT from event_proces where DSL_EVENT like '%FluigDS%'; +``` + +## Origem: 10 dicas para turbinar seu TOTVS Fluig, melhorando desempenho e estabilidade +```sql +/* Anexos de processos nunca acessados */ + +SELECT nr_versao, nr_documento, nm_arquivo_fisico, num_tam_arq_fisic FROM documento d WHERE nr_acessos = 0 AND tp_documento=7 OR (tp_documento=2 AND EXISTS(SELECT ap.NR_DOCUMENTO FROM anexo_proces ap WHERE ap.NR_DOCUMENTO = d.NR_DOCUMENTO) ) ORDER BY num_tam_arq_fisic DESC, nr_documento DESC + +/* Documentos que não são anexos de processos, nunca acessados */ + +SELECT nr_versao, nr_documento, nm_arquivo_fisico, num_tam_arq_fisic FROM documento d WHERE nr_acessos = 0 AND tp_documento=2 AND not EXISTS(SELECT ap.NR_DOCUMENTO FROM anexo_proces ap WHERE ap.NR_DOCUMENTO = d.NR_DOCUMENTO ) ORDER BY num_tam_arq_fisic DESC, nr_documento DESC +``` + +## Origem: 10 dicas para turbinar seu TOTVS Fluig, melhorando desempenho e estabilidade +```sql +/* documentos com a data de expiração menor do que a data atual */ +SELECT distinct(nr_documento) FROM documento WHERE dt_expiracao < CURDATE() +``` + +## Origem: 10 dicas para turbinar seu TOTVS Fluig, melhorando desempenho e estabilidade +```sql +/* + log_type: +0 - LOGIN, +1 - LOGINERROR, +2 - LOGOUT + +access_date +Data no formato 'YYYY-MM-DD HH:mm:ss' +*/ +SELECT * FROM fdn_accesslog +``` + +## Origem: 10 dicas para turbinar seu TOTVS Fluig melhorando desempenho e estabilidade +```sql +/* Anexos de processos nunca acessados */ + +SELECT nr_versao, nr_documento, nm_arquivo_fisico, num_tam_arq_fisic FROM documento d WHERE nr_acessos = 0 AND tp_documento=7 OR (tp_documento=2 AND EXISTS(SELECT ap.NR_DOCUMENTO FROM anexo_proces ap WHERE ap.NR_DOCUMENTO = d.NR_DOCUMENTO) ) ORDER BY num_tam_arq_fisic DESC, nr_documento DESC + +/* Documentos que não são anexos de processos, nunca acessados */ + +SELECT nr_versao, nr_documento, nm_arquivo_fisico, num_tam_arq_fisic FROM documento d WHERE nr_acessos = 0 AND tp_documento=2 AND not EXISTS(SELECT ap.NR_DOCUMENTO FROM anexo_proces ap WHERE ap.NR_DOCUMENTO = d.NR_DOCUMENTO ) ORDER BY num_tam_arq_fisic DESC, nr_documento DESC +``` + +## Origem: 10 dicas para turbinar seu TOTVS Fluig melhorando desempenho e estabilidade +```sql +/* documentos com a data de expiração menor do que a data atual */ +SELECT distinct(nr_documento) FROM documento WHERE dt_expiracao < CURDATE() +``` + +## Origem: 10 dicas para turbinar seu TOTVS Fluig melhorando desempenho e estabilidade +```sql +/* + log_type: +0 - LOGIN, +1 - LOGINERROR, +2 - LOGOUT + +access_date +Data no formato 'YYYY-MM-DD HH:mm:ss' +*/ +SELECT * FROM fdn_accesslog +``` + +## Origem: Desenvolvimento de relatórios +```sql +SELECT vol_fisic.CD_VOL_FISIC, + vol_fisic.COD_EMPRESA, + vol_fisic.NOM_DIR_FISIC, + vol_fisic.ID_TIP_VOL_FISIC +FROM vol_fisic +WHERE vol_fisic.COD_EMPRESA = ${WKCompany} +``` + +## Origem: Desenvolvimento de relatórios +```sql +importPackage(Packages.com.datasul.technology.webdesk.dataset.service); +importPackage(Packages.java.util); + + +var qd = null; +var rs = null; +var rowMap = null; +var sqlJpa = ""; +qd = new QueryDelegate(); + +sqlJpa = "SELECT count(d.documentPK.documentId), d.publisherId from Document d WHERE +d.documentPK.companyId = ${WKCompany} GROUP BY d.publisherId"; + +rs = qd.getResultQuery(sqlJpa); + +var rowMap = rs.get(0); + +//Busca o valor do Count +rowMap.get("d.publisherId"); + +//Busca o Código do documento +rowMap.get("count(d.documentPK.documentId)"); +``` + +## Origem: Como salvar Imagens e Vídeos locais em formulários usando o componente FLUIGC.richeditor +```sql +async function saveFilesECM(files, type) { + let currentHTML = editor?.getData() || ''; + const parser = new DOMParser(); + const doc = parser.parseFromString(currentHTML, 'text/html'); + const parentId = '37'; // Código da pasta do ECM + + for (const file of files) { + try { + const fileUrl = file.url; + const fileName = file.alt; + const data = await uploadFileECM(fileName, parentId); + const newUrl = `/content-management/api/v2/documents/${data.documentId}/stream`; + const filesInDoc = doc.querySelectorAll(type); + + filesInDoc.forEach(target => { + const idx = target.src.indexOf('/webdesk'); + const normalizedFileUrl = encodeURI(fileUrl); + + if (idx >= 0 && target.src.substring(idx) === normalizedFileUrl) { + target.src = newUrl; + } + }); + + } catch (error) { + console.error('Erro ao processar arquivo:', error); + } + } + + return doc.body.innerHTML; +} +``` + diff --git a/index.md b/index.md new file mode 100644 index 0000000..bcd4020 --- /dev/null +++ b/index.md @@ -0,0 +1,32 @@ +# Wiki Técnica Fluig Offline & MCP Server + +Esta é uma base de conhecimento técnica completa da plataforma TOTVS Fluig, extraída automaticamente do TDN e otimizada para desenvolvedores e sistemas de IA. + +## 🚀 Funcionalidades Principais +* **Extração Inteligente:** Motor assíncrono que mantém a documentação sempre atualizada com o TDN. +* **Wiki Offline:** Interface visual moderna via MkDocs para consulta rápida sem internet. +* **Biblioteca de Snippets:** Todos os exemplos de código (JS, Java, SQL) extraídos e categorizados. +* **Pronto para IA (RAG):** Documentação dividida em chunks semânticos para alimentar modelos de linguagem. +* **Servidor MCP:** Interface nativa para integrar o conhecimento do Fluig diretamente no seu chat de IA. + +## 📂 Estrutura do Projeto +* `fluig_extractor.py`: O motor de extração (Async + Incremental). +* `fluig_rag_docs/`: A base de arquivos Markdown e imagens. +* `mcp_server.py`: O servidor para conexão com IAs. +* `rag_processor.py`: Gerador de chunks para sistemas RAG. +* `snippet_generator.py`: Extrator de exemplos de código. +* `Dockerfile`: Ambiente pronto para deploy da Wiki. + +## 🛠️ Como Começar +1. **Instalação:** `pip install -r requirements.txt` +2. **Ver a Wiki:** `mkdocs serve` e acesse `http://localhost:8000` +3. **Configurar MCP:** Veja o [Guia do MCP](MCP_GUIDE.md). + +--- +### 🔗 Atalhos Rápidos +* [Desenvolvimento de Datasets](Plataforma Documentação técnica/Desenvolvimento sobre a plataforma/Desenvolvimento de Datasets/Construção do Dataset Avançado.md) +* [Eventos de Processo (BPM)](Plataforma Documentação técnica/Recurso de Processos (BPM).md) +* [Biblioteca de Snippets JS](Biblioteca de Snippets/Snippets JAVASCRIPT.md) + +--- +*Este projeto visa acelerar o desenvolvimento na plataforma Fluig através de engenharia de conhecimento avançada.*