Blog SAPienteSAPiente
RAP

Como Estender a Lógica em um BO Interface

SAPiente8 de jul. de 2026· 11 min read

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:

Fluxograma ilustrando a extensão de um BO Interface

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)

R_SalesOrderTP

Onde a BDEF extension é criada — o comportamento novo entra aqui

RAP BO interface (released)

I_SalesOrderTP

O contrato de acesso: sua implementação lê/modifica o BO por ela (EML)

Projections / consumo

C_* + serviços

Extensão de projeção expõe o que você adicionou (use action ...)

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.

Imagem do API State no ADT Mostrando que o contrato C0 está relesead

O que dá para adicionar numa BDEF extension

Extensão

O que entrega

Caso típico

Field control de campos custom

field (readonly), field (mandatory), feature control dinâmico

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.

georg_wilhelm_4-1732630120011.png

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

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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

TagsADTBDEFBO InterfaceClean CoreDesenvolvedorEMLEclipse
Avalie este conteúdo
para avaliar
SAPiente
@sapiente

Blog sobre SAP, ABAP, BTP, Fiori e tudo que envolve o ecossistema SAP.

Ver perfil →
FacebookInstagramYouTubeTwitter

Comentários 0

Entre na conversa

Faça login para deixar seu comentário neste artigo.

Ainda sem comentários

Seja o primeiro a comentar este artigo.