Cria, revisa e refatora regras de negócio Sankhya com `@BusinessRule` (interface `Regra` + `ContextoRegra`) para barramento de eventos, liberação de limite e regras transacionais. Use ao criar, alterar, revisar, auditar ou padronizar regras de negócio, ao implementar `beforeInsert`/`beforeUpdate`/`beforeDelete`/`afterInsert`/`afterUpdate`/`afterDelete`, ao trabalhar com arquivos `*Regra.java`, ou ao tocar em código com `@BusinessRule`.
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Cria, revisa e refatora regras de negócio Sankhya com `@BusinessRule` (interface `Regra` + `ContextoRegra`) para barramento de eventos, liberação de limite e regras transacionais. Use ao criar, alterar, revisar, auditar ou padronizar regras de negócio, ao implementar `beforeInsert`/`beforeUpdate`/`beforeDelete`/`afterInsert`/`afterUpdate`/`afterDelete`, ao trabalhar com arquivos `*Regra.java`, ou ao tocar em código com `@BusinessRule`.
Regra de Negocio (@BusinessRule) — Addon Studio 2.0
@BusinessRule implementa logica automatica disparada por eventos do ciclo de vida comercial — principalmente confirmacao e faturamento de documentos (Pedidos, Notas de Venda). Disponivel a partir do Addon Studio 2.0.
Referencias complementares:
addon-studio — Stack + restricoes Java 8
dependency-injection — Injecao de dependencia (Guice)
1. Quando usar — @BusinessRule vs @Callback vs @Listener
Hook
Escopo
Quando usar
@BusinessRule
Notas de Saida e Mov. Interna (Vendas, Remessas, etc.)
Logica que interage com barramento de regras (ContextoRegra): liberacoes de limite, validacoes complexas na confirmacao/faturamento.
@Callback
Todos documentos comerciais, incluindo Notas de Entrada
Eventos de negocio onde @BusinessRule nao atua (ex: notas de compra) ou quando barramento nao e necessario.
@Listener
Operacoes CRUD (insert/update/delete) em qualquer entidade
Validacoes e modificacoes de campo disparadas ao salvar/excluir. Preferir para CRUD simples.
Regra rapida:
Liberacao de limite em nota de venda? @BusinessRule.
Validar nota de compra na confirmacao? @Callback.
Logica ao salvar/excluir qualquer registro? @Listener.
2. Anatomia de um @BusinessRule
import br.com.sankhya.jape.vo.DynamicVO;
import br.com.sankhya.modelcore.comercial.Regra;
import br.com.sankhya.modelcore.comercial.ContextoRegra;
import br.com.sankhya.studio.annotations.hooks.BusinessRule;
import com.google.inject.Inject;
@BusinessRule(description = "Valida desconto na confirmacao")publicclassValidacaoDescontoRegraimplementsRegra {
privatefinal DescontoService descontoService;
@InjectpublicValidacaoDescontoRegra(DescontoService descontoService) {
this.descontoService = descontoService;
}
@OverridepublicvoidbeforeUpdate(ContextoRegra ctx)throws Exception {
DynamicVOnotaVO= (DynamicVO) ctx.getPrePersistEntityState().getNewVO();
// logica de negocio delegada ao Service
descontoService.validar(notaVO, ctx.getBarramentoRegra());
}
// A interface exige os 6 metodos (sem default) — deixe vazios os que nao usar@OverridepublicvoidbeforeInsert(ContextoRegra ctx)throws Exception {}
@OverridepublicvoidafterInsert(ContextoRegra ctx)throws Exception {}
@OverridepublicvoidafterUpdate(ContextoRegra ctx)throws Exception {}
@OverridepublicvoidbeforeDelete(ContextoRegra ctx)throws Exception {}
@OverridepublicvoidafterDelete(ContextoRegra ctx)throws Exception {}
}
3. Atributo da anotacao @BusinessRule
Atributo
Obrigatorio
Descricao
description
Sim
Descricao legivel da regra — aparece nos logs e configuracoes.
4. Interface Regra — Metodos disponíveis
A interface declara 6 metodos abstratos, sem default — toda classe implements Regra precisa declarar os 6. Implemente a logica nos necessarios e deixe corpo vazio nos demais.
Metodo
Quando dispara
Foco da @BusinessRule
beforeInsert(ctx)
Antes de inserir o documento
Raramente usado — prefira @Listener
afterInsert(ctx)
Apos inserir o documento
Raramente usado — prefira @Listener
beforeUpdate(ctx)
Antes de atualizar (inclui confirmacao/faturamento)
Caso de uso principal
afterUpdate(ctx)
Apos atualizar (inclui confirmacao/faturamento)
Integracoes assincronas pos-confirmacao
beforeDelete(ctx)
Antes de excluir o documento
Raramente usado — prefira @Listener
afterDelete(ctx)
Apos excluir o documento
Raramente usado — prefira @Listener
5. ContextoRegra — API
Imports usados nos trechos: br.com.sankhya.jape.vo.DynamicVO e, para propriedades de sessao, br.com.sankhya.jape.core.JapeSession.
Acessar dados da nota
// Estado atual (com modificacoes do evento)DynamicVOnotaVO= (DynamicVO) ctx.getPrePersistEntityState().getNewVO();
// Estado anterior (disponivel em beforeUpdate e beforeDelete)DynamicVOoldNotaVO= (DynamicVO) ctx.getPrePersistEntityState().getOldVO();
// Leitura de campos do DynamicVOBigDecimalnuNota= notaVO.asBigDecimal("NUNOTA");
Stringconfirmada= notaVO.asString("CONFIRMADA");
BigDecimalpercDesc= notaVO.asBigDecimal("PERCDESC");
// Escrita de campo (modificacao em memoria, persiste com a transacao)
notaVO.setProperty("OBSERVACAO", "Conferido automaticamente.");
Interagir com barramento de regras
// Aviso nao bloqueante para o usuario
ctx.getBarramentoRegra().addMensagem("Desconto acima do limite — aviso gerado.");
// Solicitacao de liberacao de limite (evento deve estar cadastrado no sistema)LiberacaoSolicitadalib=newLiberacaoSolicitada(
notaVO.asBigDecimal("NUNOTA"), // numero da nota"TGFCAB", // tabela2000, // ID do evento de liberacao
BigDecimal.ONE // ID do usuario solicitante
);
lib.setPendente(true);
ctx.getBarramentoRegra().addLiberacaoSolicitada(lib);
Bloquear a operacao
// Lance excecao — mensagem exibida ao usuario e transacao revertidathrownewException("Limite de credito excedido. Operacao bloqueada.");
6. Detectar o momento da confirmacao
O evento beforeUpdate dispara em varios momentos. Para agir somente na confirmacao:
@OverridepublicvoidbeforeUpdate(ContextoRegra ctx)throws Exception {
DynamicVOnotaVO= (DynamicVO) ctx.getPrePersistEntityState().getNewVO();
DynamicVOoldNotaVO= (DynamicVO) ctx.getPrePersistEntityState().getOldVO();
// Abordagem 1: comparar campo CONFIRMADA entre old e newbooleanisConfirmando="S".equals(notaVO.asString("CONFIRMADA"))
&& (oldNotaVO == null || !"S".equals(oldNotaVO.asString("CONFIRMADA")));
if (!isConfirmando) return;
// ... logica especifica da confirmacao
}
7. Exemplos completos
Exemplo 1: Solicitacao de liberacao de limite
import br.com.sankhya.jape.core.JapeSession;
import br.com.sankhya.jape.vo.DynamicVO;
import br.com.sankhya.modelcore.comercial.Regra;
import br.com.sankhya.modelcore.comercial.ContextoRegra;
import br.com.sankhya.modelcore.comercial.LiberacaoSolicitada;
import br.com.sankhya.studio.annotations.hooks.BusinessRule;
import com.google.inject.Inject;
import java.math.BigDecimal;
@BusinessRule(description = "Solicita liberacao para vendas com desconto alto")publicclassLiberacaoDescontoRegraimplementsRegra {
@OverridepublicvoidbeforeUpdate(ContextoRegra ctx)throws Exception {
DynamicVOnotaVO= (DynamicVO) ctx.getPrePersistEntityState().getNewVO();
BooleanisConfirmando= (Boolean) JapeSession.getProperty("CabecalhoNota.confirmando.nota");
if (!Boolean.TRUE.equals(isConfirmando)) return;
BigDecimalpercDesc= notaVO.asBigDecimal("PERCDESC");
if (percDesc == null || percDesc.compareTo(newBigDecimal("10")) <= 0) return;
LiberacaoSolicitadalib=newLiberacaoSolicitada(
notaVO.asBigDecimal("NUNOTA"),
"TGFCAB",
2000, // ID do evento de liberacao cadastrado no sistema
BigDecimal.ONE
);
lib.setPendente(true);
ctx.getBarramentoRegra().addLiberacaoSolicitada(lib);
ctx.getBarramentoRegra().addMensagem("Solicitacao de liberacao enviada para desconto acima de 10%.");
}
// interface exige os 6; deixe vazios os que nao usar@OverridepublicvoidbeforeInsert(ContextoRegra ctx)throws Exception {}
@OverridepublicvoidafterInsert(ContextoRegra ctx)throws Exception {}
@OverridepublicvoidafterUpdate(ContextoRegra ctx)throws Exception {}
@OverridepublicvoidbeforeDelete(ContextoRegra ctx)throws Exception {}
@OverridepublicvoidafterDelete(ContextoRegra ctx)throws Exception {}
}
Velocidade: Regra roda dentro da transacao da confirmacao. Deve executar em milissegundos.
Assincronismo para integracoes: Chamadas a APIs externas = sempre CompletableFuture, ExecutorService ou JMS. Nunca sincrono.
Logica em Services: Mantenha a classe da @BusinessRule enxuta — delegue para @Component.
Feedback ao usuario: Use addMensagem() para informar acoes automaticas executadas.
Excecoes para bloqueio: Lance Exception com mensagem clara para impedir a operacao.
9. Anti-Patterns (PROIBIDO)
Anti-Pattern
Correcao
Usar para CRUD simples (salvar/excluir)
Usar @Listener
Chamada sincrona a API/Web Service
Usar CompletableFuture ou JMS
Logica de negocio no metodo da interface
Mover para Service (@Component)
Usar afterInsert para validacao
Validar em beforeInsert — apos salvar e tarde demais
new em dependencias gerenciadas
Injetar via construtor com @Inject
Usar para Notas de Entrada (compras)
Usar @Callback
10. Checklist: Novo @BusinessRule
Confirmar que o caso de uso e especifico de nota de saida/mov. interna — senao usar @Callback ou @Listener.
Criar classe implementando Regra (nomear <Feature>Regra).
Anotar com @BusinessRule(description = "...").
Injetar dependencias via construtor com @Inject (Guice).
Implementar apenas os metodos de evento necessarios.
Detectar o momento correto (confirmacao, faturamento) via comparacao oldVO/newVO ou JapeSession.
Delegar logica de negocio para Service (@Component).
Integracoes externas: usar mecanismo assincrono.
Fornecer feedback ao usuario via addMensagem() ou excecao com mensagem clara.
Registrar no modulo Guice os services/dependencias injetados na classe — a classe da regra em si nao precisa de binding (o SDK a descobre pela anotacao @BusinessRule). Ver dependency-injection.
Skills relacionadas
action-button — botão dispara fluxo que pode invocar regra
controller — controller pode invocar regra via barramento
entity — entidade alvo do evento
repository — acesso a dados dentro da regra
dependency-injection — wiring Guice dos services injetados na regra