---
name: fluig-eventos-formulario
description: "Eventos server-side e client-side de formularios Fluig (inputFields, beforeSendValidate, afterSaveNew, gravaHistorico). Use quando precisar transformar dados antes de salvar, gravar historico de atividades, validar no navegador ou integrar pos-save. Ativa com: 'inputFields', 'gravar historico', 'beforeSendValidate', 'afterSaveNew', 'evento de formulario'."
license: MIT
metadata:
  author: Nevoa
  version: "1.0.0"
  category: development
  platform: totvs-fluig
---

# Skill: Eventos Avancados de Formulario Fluig

Gera eventos de formulario alem dos basicos (displayFields, enableFields, validateForm que estao na skill fluig-formularios).

## Eventos Cobertos

| Evento | Lado | Quando Executa | Uso Principal |
|---|---|---|---|
| `inputFields` | Server | Antes de salvar dados | Transformacao de dados, historico, roteamento |
| `beforeSendValidate` | Client | Antes de enviar form | Validacao rapida no navegador |
| `afterSaveNew` | Server | Apos primeiro save | Inserir dados em sistemas externos |
| `afterSaveUpdate` | Server | Apos update existente | Atualizar dados em sistemas externos |
| `gravaHistorico` | Server (helper) | Chamado pelo inputFields | Trilha de auditoria formatada |

## 1. inputFields â€” Transformacao e Historico

### Quando Usar
- Converter formatos de data (BR dd/mm/yyyy para EN yyyy-mm-dd)
- Gravar historico de atividades (trilha de auditoria)
- Calcular valores derivados antes de salvar
- Definir roteamento condicional (qual aprovador)
- Limpar/formatar dados antes de persistir

### Assinatura
```javascript
function inputFields(form, customHTML) {
    // form.getValue(campo) - ler campo
    // form.setValue(campo, valor) - gravar campo
    // getValue("WKNumState") - atividade atual
    // getValue("WKUser") - usuario logado
}
```

### Padrao de Producao (VIPal)
```javascript
function inputFields(form, customHTML) {
    var WKNumState = parseInt(getValue("WKNumState"));
    var WKUser = getValue("WKUser");

    // Atividade 4: Solicitante preenche dados
    if (WKNumState == 4) {
        // Converter data BR para EN
        var dataBR = form.getValue("data_necessidade");
        if (dataBR != null && dataBR != "") {
            form.setValue("data_necessidade_EN", fnInverteData(dataBR));
        }

        // Gravar historico
        var obs = form.getValue("observacao");
        obs = fnLimpaCaracteres(obs);
        gravaHistorico(form, WKNumState, obs, "");
    }

    // Atividade 5: Aprovador decide
    if (WKNumState == 5) {
        var decisao = form.getValue("aprovacao_5");
        var obs = form.getValue("obs_5");
        obs = fnLimpaCaracteres(obs);
        var acao = (decisao == "S") ? "Aprovado" : "Reprovado";
        gravaHistorico(form, WKNumState, obs, acao);
    }
}
```

### Regras
- MUST: ES5 obrigatorio (roda no servidor Rhino)
- MUST: Usar form.getValue/setValue (NAO hAPI neste evento)
- MUST: Limpar caracteres especiais antes de gravar historico (#, ", ', <, >)
- SHOULD: Converter datas para formato EN (yyyy-mm-dd) para ordenacao
- SHOULD: Chamar gravaHistorico() como funcao separada
- MUST NOT: Usar jQuery ou DOM (roda no servidor)

## 2. gravaHistorico â€” Trilha de Auditoria

### Padrao de Producao
Funcao auxiliar chamada pelo inputFields. Monta registro com data + hora + usuario + observacao e concatena com historico anterior.

### Dois Padroes Encontrados

**Padrao 1: Separador # (simples)**
```javascript
// Historico fica: "05/12/2024 - 13:22 - Joao - Aprovado - obs#01/12/2024 - 10:00 - Maria - Solicitacao"
hist = histNovo + "#" + histAnterior;
form.setValue("histAtiv_" + atividade, hist);
```

**Padrao 2: HTML formatado (VIPal avancado)**
```javascript
// Historico fica com labels Bootstrap por data e blocos por atividade
histGeral = labelData + '<br><b>Atividade: ' + descricao + '</b><br>' + histInic + ' - ' + obs + '<br>';
histGeral = histGeral + histGeralAnterior;
form.setValue("histGeral", histGeral);
```

### Campos Hidden Necessarios no HTML
```html
<input type="hidden" name="histGeral" id="histGeral" />
<input type="hidden" name="histAtiv_${ATIV}" id="histAtiv_${ATIV}" />
<input type="hidden" name="dtUltimoHistorico_EN" id="dtUltimoHistorico_EN" />
```

## 3. beforeSendValidate â€” Validacao Client-Side

### Quando Usar
- Validacao rapida antes de enviar (feedback imediato ao usuario)
- Complementa validateForm (server-side) - NAO substitui
- Validacoes que dependem de estado visual (tabs, modais)

### Assinatura
```javascript
function beforeSendValidate(numState, nextState) {
    // numState = atividade atual
    // nextState = proxima atividade
    // return true = permite envio
    // return false = bloqueia envio
}
```

### Padrao de Producao
```javascript
function beforeSendValidate(numState, nextState) {
    // Atividade 4: Solicitante
    if (numState == 4) {
        if (!$('#campo_obrigatorio').val()) {
            FLUIGC.toast({
                title: 'Campo obrigatorio',
                message: 'Preencha o campo antes de enviar.',
                type: 'danger'
            });
            return false;
        }
    }

    // Atividade 5: Aprovador deve selecionar radio
    if (numState == 5) {
        if (!$('input[name="aprovacao_5"]:checked').val()) {
            FLUIGC.toast({
                title: 'Aprovacao',
                message: 'Selecione Aprovar ou Reprovar.',
                type: 'danger'
            });
            return false;
        }
    }

    return true;
}
```

### Regras
- Roda no NAVEGADOR (ES6 permitido)
- MUST: Sempre retornar true ou false
- MUST: Usar FLUIGC.toast() para mensagens de erro
- SHOULD: Validar mesmos campos do validateForm (dupla validacao)
- MUST NOT: Confiar APENAS nesta validacao (pode ser burlada)

## 4. afterSaveNew / afterSaveUpdate â€” Integracao Pos-Save

### Quando Usar
- Inserir/atualizar dados em banco externo (RM, Protheus)
- Chamar APIs apos salvar formulario
- Sincronizar dados entre Fluig e ERP

### Assinatura
```javascript
function afterSaveNew(documentId, version, cardId) {
    // documentId = ID do documento
    // version = versao do documento
    // cardId = ID do card (registro)
}

function afterSaveUpdate(documentId, version, cardId) {
    // Mesmos parametros
}
```

### Padrao de Producao (CELI)
```javascript
function afterSaveNew(documentId, version, cardId) {
    try {
        var c1 = DatasetFactory.createConstraint("campo1", valor1, valor1, ConstraintType.MUST);
        var c2 = DatasetFactory.createConstraint("campo2", valor2, valor2, ConstraintType.MUST);
        var ds = DatasetFactory.getDataset("dsInsertDados", null, new Array(c1, c2), null);

        if (ds == null || ds.rowsCount == 0) {
            throw "Erro ao inserir dados no sistema externo.";
        }
    } catch (e) {
        log.error("afterSaveNew erro: " + e.message);
        throw e.message;
    }
}
```

### Regras
- MUST: ES5 obrigatorio (servidor)
- MUST: try/catch em toda chamada externa
- MUST: Logar erros com log.error()
- SHOULD: Usar DatasetFactory para chamar datasets de integracao
- MUST NOT: Fazer queries SQL diretas (usar datasets)

## 5. Funcoes Helper Padrao

Helpers disponiveis: `fnLimpaCaracteres`, `replaceAll`, `fnInverteData`, `fnBuscarDataHora`, `fnReplaceNovaLinha`, `constraintValue`.

> Codigo completo dos helpers: [references/helpers-comuns.md](./references/helpers-comuns.md)

## Checklist de Geracao

- [ ] inputFields.js com branches por WKNumState
- [ ] gravaHistorico() como funcao separada
- [ ] Campos hidden no HTML (histGeral, histAtiv_N, dtUltimoHistorico_EN)
- [ ] beforeSendValidate com FLUIGC.toast()
- [ ] afterSaveNew/afterSaveUpdate se houver integracao
- [ ] Funcoes helper (fnLimpaCaracteres, replaceAll, fnInverteData)
- [ ] Tudo em ES5 no server-side
- [ ] Log de erros com log.info/log.error

## Prompts Estrategicos Disponiveis

- `implementar-inputfields-gravahistorico-matriz.md` - Implementacao de `inputFields` + `gravaHistorico` por atividade.
- `projetar-before-send-validate-alinhado-validateform.md` - Validacao client-side alinhada ao `validateForm`.
- `implementar-after-save-idempotente-seguro.md` - Pos-save com integracao segura e idempotente.
- `diagnosticar-falhas-eventos-formulario.md` - Diagnostico de execucao/persistencia/ordem dos eventos.

Use estes prompts para implementar e manter eventos avancados de formulario com foco em confiabilidade.
## Skills Relacionadas

- [fluig-formularios](../fluig-formularios/SKILL.md) — HTML base, displayFields, enableFields, validateForm
- [fluig-eventos-processo](../fluig-eventos-processo/SKILL.md) — Eventos de workflow (hAPI, ciclo de vida do processo)
- [fluig-datasets](../fluig-datasets/SKILL.md) — Datasets chamados via afterSaveNew/afterSaveUpdate

## Templates Disponiveis
- [inputFields-base.js](./templates/inputFields-base.js) â€” Template completo com historico
- [beforeSendValidate-base.js](./templates/beforeSendValidate-base.js) â€” Validacao client-side
- [afterSaveNew-base.js](./templates/afterSaveNew-base.js) â€” Integracao pos-save
- [gravaHistorico-base.js](./templates/gravaHistorico-base.js) â€” Funcao de historico completa

## Recursos Adicionais
- Para templates base, consulte os arquivos em [templates/](./templates/)
- Para exemplos de implementaÃ§Ã£o real, consulte [examples/](./examples/)
### Exemplos recomendados
- [exemplo_01_wf0035_matriz_atividades_historico](./examples/exemplo_01_wf0035_matriz_atividades_historico/): matriz de atividades com `displayFields`, `inputFields`, `validateForm` e historico.
- [exemplo_02_aprovacao_pedido_multiaprovador](./examples/exemplo_02_aprovacao_pedido_multiaprovador/): pacote com validacoes e helpers para fluxo de aprovacao multiaprovador.
- Para referÃªncia tÃ©cnica detalhada, consulte [references/](./references/)

---

## Complemento Integrado com Eventos Basicos

Para alinhar `beforeSendValidate` com a mesma regra server-side de `validateForm`, use a base complementar da skill de formularios:

- Guia: [../fluig-formularios/references/displayfields-validateform-base-felice.md](../fluig-formularios/references/displayfields-validateform-base-felice.md)
- Template `displayFields`: [../fluig-formularios/templates/displayFields-base-felice.js](../fluig-formularios/templates/displayFields-base-felice.js)
- Template `validateForm`: [../fluig-formularios/templates/validateForm-base-felice.js](../fluig-formularios/templates/validateForm-base-felice.js)

## Curadoria de Contexto Local

Para buscar exemplos reais no acervo local `Contexto`, consulte [references/contexto-curadoria.md](./references/contexto-curadoria.md).
Abra essa referencia quando a tarefa exigir aderencia a legado/producao ou comparacao com implementacoes existentes.
