Como Estender a Lógica em um BO Interface
O requisito mais antigo do mundo SAP, com resposta nova
"Precisamos de um campo a mais no pedido, e uma regra que impeça de salvar quando ele estiver errado." Todo ABAP já recebeu essa frase. No mundo clássico, a resposta era um combo conhecido: append na tabela, campo na tela via exit de dynpro, regra num user exit ou BAdI — e a torcida para o próximo upgrade não quebrar nada.
No ABAP Cloud, esse requisito tem uma resposta formal: os business objects standard que a SAP libera para extensão (contrato C0) aceitam uma behavior definition extension — um artefato seu, em pacote seu, que adiciona comportamento ao BO standard: campos com field control, validations que bloqueiam o save de verdade, determinations que rodam na mesma transação, actions, functions e até eventos derivados. Tudo sem tocar uma linha do objeto original, com estabilidade de upgrade garantida por contrato — e funcionando inclusive no S/4HANA Cloud Public Edition, onde modificação nem é opção.
Aqui um exemplo da documentação da sap do fluxo de extensão do BO:

Este post cobre as quatro perguntas do título da pauta: como estender, quando estender, qual caso pede qual mecanismo, e onde está o ganho de verdade.
Primeiro, o vocabulário: C0, C1 e a arquitetura em camadas
Um BO standard extensível vem em camadas, e cada uma tem um papel na extensão:
Camada | Exemplo | Papel na extensão |
|---|---|---|
BO transacional (base) |
| Onde a BDEF extension é criada — o comportamento novo entra aqui |
RAP BO interface (released) |
| O contrato de acesso: sua implementação lê/modifica o BO por ela (EML) |
Projections / consumo |
| Extensão de projeção expõe o que você adicionou ( |
E os contratos de estabilidade que regem:
Contrato | Significado | O que te permite |
|---|---|---|
C1 — Use System-Internal | Liberado para uso no mesmo sistema | Chamar/ler o objeto no seu código ABAP Cloud |
C0 — Extend | Liberado para extensão | Criar BDEF extensions, estender o modelo de dados, derivar eventos |
Dois detalhes finos da documentação que valem registrar: a extensibilidade é opt-in e granular — o provedor marca com a palavra-chave extensible o que pode ser estendido, no header do BDEF, por nó, por determine action e até no mapping (necessário para os campos de extensão); e a sua BDEF extension não precisa de release C0 próprio — ela herda o contrato do BO original automaticamente.
Como descobrir se um BO é extensível? No ADT, as propriedades do objeto mostram o API state — procure "Extend (C0)" — e a árvore de Released Objects lista o que está liberado no seu sistema.
O que dá para adicionar numa BDEF extension
Extensão | O que entrega | Caso típico |
|---|---|---|
Field control de campos custom |
| Campo ZZ obrigatório na criação; readonly após aprovação |
Validation | Bloqueia o save do processo standard com sua regra | Impedir gravar pedido quando o campo custom viola a política |
Determination | Deriva/preenche valores na mesma transação | Calcular o campo ZZ a partir de dados do documento |
Action / Function | Verbo de negócio novo no objeto standard | Botão custom na Fiori standard; consulta parametrizada |
Derived event | Evento custom com payload enriquecido a partir do evento standard | O payload standard só traz a chave; o consumidor precisa de mais (guia completo no post de Business Events) |
Node extension | Nó filho novo na hierarquia de composição | Uma tabela de itens custom pendurada no documento standard |
Determine action Prepare (draft) | Suas validations no pacote pré-Activate | Mensagens de estado no fluxo draft standard |
Repare no que não está na lista: mudar comportamento existente. Extensão adiciona — ela não desliga a validation standard, não reescreve a determination da SAP, não intercepta o create. Essa assimetria é o preço (e a garantia) da estabilidade.
Como estender: o passo a passo
O cenário-guia: adicionar ao pedido de venda standard um campo ZZ_CreditProfile, obrigatório na criação, com uma validação de política e uma action de reavaliação. (Nomes de campos custom levam o prefixo ZZ por convenção da extensibilidade.)
1. O campo custom no modelo de dados
Dois caminhos, conforme o cenário: pelo app Custom Fields (key user, Tier 1) ou por developer extensibility, estendendo a persistência e as views liberadas. Em ambos, o ponto de atenção documentado: para usar o campo no field control e na lógica, ele precisa estar presente no data model do RAP BO interface liberado — no exemplo do blog oficial de field control, os campos são adicionados às views I_SalesOrderTP / I_SalesOrderItemTP:
extend view entity I_SalesOrderTP with
{
zz_credit_profile as ZZ_CreditProfile
}2. A BDEF extension no BO
Botão direito na behavior definition standard → New Behavior Definition Extension.
Exemplo de criação no wizard da Doc da SAP.
O artefato declara a classe de implementação própria e estende o comportamento da entidade — referenciando o RAP BO interface liberado para o acesso:
extension implementation in class zbp_r_salesordertp_ext unique;
use interface I_SalesOrderTP;
extend behavior for SalesOrder
{
// field control estático do campo custom
field ( mandatory : create ) ZZ_CreditProfile;
// regra que bloqueia o save do processo standard
validation zz_validateCreditProfile on save { create; field ZZ_CreditProfile; }
// derivação na mesma transação
determination zz_defaultCreditProfile on modify { create; }
// verbo de negócio novo sobre o objeto standard
action zz_reevaluateCredit result [1] $self;
}Campo mandatory pede validação própria: regra explícita da documentação — declarar field (mandatory) controla a UI (o asterisco, o erro de tela), mas a garantia de consistência exige a validation correspondente checando o campo. UI valida por cortesia; quem garante é o BO.
3. A implementação — acessando pelo interface liberado
A classe da extensão é um behavior pool como outro qualquer; a diferença é que todo EML passa pelo RAP BO interface (o C1 do objeto):
CLASS lhc_salesorder IMPLEMENTATION.
METHOD zz_validateCreditProfile.
READ ENTITIES OF I_SalesOrderTP IN LOCAL MODE
ENTITY SalesOrder
FIELDS ( ZZ_CreditProfile SoldToParty ) WITH CORRESPONDING #( keys )
RESULT DATA(orders).
LOOP AT orders INTO DATA(order)
WHERE ZZ_CreditProfile IS INITIAL OR ZZ_CreditProfile = 'X'.
APPEND VALUE #( %tky = order-%tky ) TO failed-salesorder.
APPEND VALUE #( %tky = order-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Perfil de crédito inválido para este cliente' ) )
TO reported-salesorder.
ENDLOOP.
ENDMETHOD.
ENDCLASS.E aqui mora o ganho que nenhum outro mecanismo entrega igual: essa validation roda dentro da save sequence do BO standard. Usuário na Fiori standard, chamada de API, outro processo interno — se a regra falhar, o pedido não grava. Não é uma reação depois do fato; é participação na transação.
4. A extensão de projeção — expondo para o consumo
O que nasceu no BO precisa subir a pilha: uma extensão da projection BDEF publica a action no serviço (e, se for o caso, ajusta field control específico daquela projeção, como readonly):
extension for projection;
extend behavior for C_SalesOrderManage
{
use action zz_reevaluateCredit;
}Fecha com a metadata extension para o botão/campo aparecer na Fiori standard — e o círculo está completo: campo, regra, verbo e UI, tudo em artefatos seus, zero modificação.
Casos de uso reais: o que dá para construir com a extensão
O passo a passo acima mostrou a mecânica; esta seção mostra o que ela vira na prática — dois cenários completos, direto dos blogs oficiais de referência.
Caso 1: field control dinâmico — o campo custom que reage ao estado do documento
O cenário do blog oficial da SAP: um campo custom ZZPrefQuantityPerDeliverySDI no item do pedido de venda que deve ficar readonly quando o status geral de remessa estiver concluído — e editável antes disso. Ou seja: não é o readonly estático do passo a passo; a propriedade do campo depende do estado da instância, avaliada em runtime.
Na BDEF extension, o campo é declarado com feature control dinâmico:
extension implementation in class zbp_r_salesordertp_ext unique;
use interface I_SalesOrderTP;
extend behavior for SalesOrderItem
{
field ( features : instance ) ZZPrefQuantityPerDeliverySDI;
}E aqui um detalhe fino que o blog registra: ao declarar features : instance, o método get_instance_features é gerado na classe da extensão para cada entidade relevante — você só preenche a lógica:
METHOD get_instance_features.
READ ENTITIES OF I_SalesOrderTP IN LOCAL MODE
ENTITY SalesOrderItem
FIELDS ( OverallSDProcessStatus ) WITH CORRESPONDING #( keys )
RESULT DATA(items).
result = VALUE #( FOR item IN items
( %tky = item-%tky
%field-ZZPrefQuantityPerDeliverySDI =
COND #( WHEN item-OverallSDProcessStatus = 'C' " concluído
THEN if_abap_behv=>fc-f-read_only
ELSE if_abap_behv=>fc-f-unrestricted ) ) ).
ENDMETHOD.O efeito: na Fiori standard de pedidos, o campo custom abre editável durante o processamento e trava sozinho quando a remessa conclui — comportamento indistinguível de um campo nativo da SAP. E como a regra vive no BO, vale para todos os canais, não só para a tela.
A regra de camadas do field control (documentada no blog): readonly e readonly:update podem ser definidos também na extensão da projection — ou seja, específicos para uma Fiori app ou serviço OData, sem afetar os demais consumidores. Já o mandatory só existe no nível da base: obrigatório é obrigatório para todo mundo, não por projeção. Escolha a camada conforme o alcance que a regra deve ter.
Caso 2: derived event — enriquecer o payload do evento standard e filtrar o que sai
O problema clássico de arquitetura de eventos: o evento standard (ex.: de ordem de manutenção) dispara certinho, mas o payload só carrega a chave — e o consumidor no BTP/CPI precisa de tipo da ordem, centro, status... A saída ingênua é o consumidor fazer callback de API a cada evento; a saída elegante é um derived event na extensão: um evento seu, derivado do standard já implementado, com payload definido por você.
Passo 1 — a CDS do payload enriquecido, selecionando da view standard com os campos que o consumidor precisa. E com o pulo do gato do blog: a anotação @Event.context.attribute promove um campo a atributo de contexto do evento — utilizável como filtro no tópico:
define view entity ZMAINT_ORDER_DATASOURCE
as select from I_MaintenanceOrder
{
key MaintenanceOrder,
@Event.context.attribute: 'xsapordtype' " vira filtro do evento!
MaintenanceOrderType,
MaintenancePlant,
MaintenanceOrderDesc
}Passo 2 — o derived event na BDEF extension, referenciando o evento standard já implementado:
extension implementation in class zbp_r_maintenanceordertp_be unique;
extend behavior for MaintenanceOrder
{
event ZZ_OrderChangedEnriched
derived from event Changed
parameter ZMAINT_ORDER_DATASOURCE;
}Sem uma linha de RAISE: quando o evento standard Changed disparar, o framework publica também o seu derivado — com o payload da sua CDS. E o filtro fecha o cenário: nas transações /IWXBE/EVENT_MONITOR e /IWXBE/EVENT_FILTER, o atributo de contexto (xsapordtype) permite configurar que só ordens do tipo relevante saiam para o Event Mesh — os demais eventos morrem na origem, sem tráfego nem processamento inútil no consumidor.
O resultado combinado: consumidor recebe evento já completo (sem callback de API), já filtrado (sem descartar 90% das mensagens), sobre um objeto que você não modificou. A mecânica completa de eventos — tópicos, binding, QoS, consumo — está no post de Business Events do hub; os pré-requisitos do derived (evento exposto no contrato, CDS do payload liberada) estão lá também.
O padrão que os dois casos revelam
Repare no que os cenários têm em comum: nenhum deles "muda o SAP". O campo custom que trava sozinho e o evento enriquecido e filtrado são capacidades novas orbitando o objeto standard — usando a infraestrutura dele (o ciclo de feature control, o disparo do evento original) como plataforma. É esse o jeito certo de pensar a extensão: não "onde enfio meu código no processo da SAP", mas "que capacidade nova o processo standard passa a ter".
Quando estender — e quando NÃO: a matriz de decisão
Extensão de BO é uma ferramenta, não a resposta universal. A matriz que uso em desenho de solução:
O caso | O mecanismo certo | Por quê |
|---|---|---|
Campo custom sem lógica (só armazenar/exibir) | Key user / Custom Fields (Tier 1) | Zero código; a extensão developer seria canhão para mosca |
Campo custom com regra que decide o save | BDEF extension (validation + field control) | Só quem participa da transação bloqueia a transação |
Derivar/preencher valores no fluxo standard | BDEF extension (determination) | Mesma LUW, sem corrida com o processo |
Reagir depois do fato (integrar, notificar, replicar) | Business event (consumo local ou Event Mesh) / derived event | Desacoplado, assíncrono, não segura o save — extensão aqui seria acoplamento desnecessário |
Ponto de intervenção que a SAP previu no processo | BAdI released | Se existe o gancho oficial daquele passo, ele é mais específico que a extensão genérica |
Funcionalidade nova com ciclo de vida próprio | BO custom (que referencia o standard via C1) | Estender o standard para pendurar um subsistema inteiro é inversão de dependência |
UI muito diferente / orquestração multi-sistema / carga pesada | Side-by-side (Tier 3, BTP) | O que não é do domínio do BO não pertence à extensão dele |
BO standard sem C0 | APIs released + BAdIs + eventos; em último caso, avaliar side-by-side | Sem contrato de extensão, não há extensão estável — não force |
A régua resumida: a BDEF extension é para lógica que pertence ao objeto e precisa valer dentro da transação dele. Antes dela na fila está o key user (quando não há lógica); depois dela estão os eventos (quando a reação pode ser assíncrona) e o side-by-side (quando o assunto nem é do objeto).
Por que é benéfico: os pontos que justificam o mecanismo
Estabilidade de upgrade por contrato. O C0 não é uma promessa vaga — é o compromisso de lifecycle que faz sua extensão sobreviver a releases. O contraste com o mundo append+exit dispensa comentário: o teste de regressão do upgrade deixa de ser loteria.
Sua regra vale para TODOS os canais. A validation na extensão roda na save sequence do BO — Fiori standard, API OData, EML de outro programa: todo caminho de gravação passa por ela. User exit de tela valia para a tela; isto vale para o objeto.
Você herda a infraestrutura do standard. Draft, lock, autorização, ETag, UI Fiori Elements, exposição OData: o aparato inteiro do BO standard trabalha para o seu campo e sua action. Compare com reconstruir isso num app paralelo.
Clean Core de verdade, auditável. Artefatos seus, em pacotes seus, sobre contratos liberados — o relatório de Clean Core do projeto fecha sem asteriscos. E é o único caminho no Public Cloud, onde a alternativa "modificar" não existe.
Mesma linguagem do resto do hub: a extensão usa exatamente o que você já domina — validations, determinations, actions, field control, eventos. Estender BO standard não é uma disciplina nova; é o RAP que você conhece, apontado para um alvo liberado.
Limites e pegadinhas
Só o que o provedor habilitou. O opt-in é granular: pode ser que o BO aceite actions mas não validations, ou aceite validations só com certas triggers. O header do BDEF standard (e a documentação do objeto) dizem o que está aberto — leia antes de prometer a solução.
Extensão adiciona, não substitui. Se o requisito é "mudar como a SAP calcula X", o caminho não é extensão — é BAdI (se houver), configuração, ou conversa de processo.
Mandatory sem validation é meia solução — a dupla anda junta, sempre.
Cuidado com lógica pesada em determination on modify: ela roda a cada roundtrip relevante do usuário no draft. Derivação cara pertence ao on save.
Derived event exige o evento exposto no C0/C1 e a CDS do payload C1-released — os pré-requisitos completos estão no post de Business Events.
Perguntas frequentes
Como sei se um BO standard é extensível?
No ADT: propriedades do objeto → API state. "Extend (C0)" é o sinal verde para extensão; "Use System-Internal (C1)" libera só o consumo. A árvore de Released Objects do projeto ABAP lista tudo que está liberado no sistema — e o header do BDEF standard mostra, via extensible, exatamente o que está aberto.
Minha extensão precisa ser liberada (C0) também?
Não — a documentação é explícita: a BDEF extension herda automaticamente o contrato C0 do BO original. Você só libera artefatos seus se você for provedor de extensibilidade para outros.
Posso desativar uma validation standard que atrapalha?
Não — extensão é aditiva por design. Comportamento standard indesejado se resolve por configuração, BAdI prevista ou requisito revisto; nunca por extensão.
Isso funciona no S/4HANA Cloud Public Edition?
É o habitat natural: no Public Cloud, developer extensibility sobre objetos released é o caminho on-stack (Tier 2), ao lado do key user (Tier 1) e do side-by-side (Tier 3). No private/on-premise vale igual — com a vantagem de preparar o código para qualquer destino futuro.
E quando o BO que preciso estender não tem C0?
Não force. O plano B documentado: consumir as APIs/BAdIs released que existirem, reagir via eventos standard (inclusive com o padrão de consumo local + re-disparo enriquecido do post de events), ou levar a funcionalidade para side-by-side. E vale registrar o gap no canal de influência da SAP — a lista de objetos C0 cresce a cada release.
BDEF extension substitui BAdI?
São complementares: BAdI é um gancho pontual que a SAP previu num passo específico do processo; a extensão é comportamento estrutural novo no objeto (campo, regra, verbo, evento). Quando os dois servem, prefira o mais específico — costuma ser a BAdI para intervir num cálculo, a extensão para adicionar capacidade.
Conclusão
Estender um BO standard no RAP é o user exit crescido e formalizado: em vez de um gancho informal na esperança de sobreviver ao upgrade, um contrato (C0), um artefato próprio (a BDEF extension) e o vocabulário completo do RAP — field control, validation que bloqueia o save de verdade, determination na mesma LUW, action, evento derivado — operando dentro da transação do objeto standard. A decisão de quando usar cabe numa frase: lógica que pertence ao objeto e precisa valer na transação dele; para o resto, key user, eventos ou side-by-side. E o benefício central é o que o mundo clássico nunca entregou junto: poder de intervenção e estabilidade de upgrade, no mesmo pacote.
Referências oficiais
Comentários 0
Ainda sem comentários
Seja o primeiro a comentar este artigo.
Entre na conversa
Faça login para deixar seu comentário neste artigo.