Skip to main content

Usage

At its core, mdVC integrates into AVC through the enhancement spot vch_hl_es_core.
This BADI provides several filter values:

  • configuration_context: Context of the calling variant configuration
  • cfg_object_type: Name of the database table for the object
  • cfg_object_key: Key of the configurable object
  • plant: Plant

These filters help determine the correct implementation and whether mdVC should be activated for a specific use case.

Configuration

We generally recommend keeping your configuration model as lean as possible.
Complex logic and dependencies should be encapsulated in mdVC instead.

PMEVC example

Implementation

To integrate mdVC, create an implementation of the BADI vch_hl_es_core-vch_hl_post_validate_assign and assign suitable filter values as required.
Within your implementation class, the key method is if_vch_hl_post_validate_assign~assign_values, which triggers your mdVC logic.

Trigger and Timeline

The method if_vch_hl_post_validate_assign~assign_values is executed by AVC after the standard configuration model has been evaluated and validated.
As mentioned earlier, this model should be kept minimal, shifting most logic into mdVC.

Framework

The BADI implementation acts as the glue between AVC and mdVC, defining the control flow.
Every mdVC invocation follows a consistent pattern:

/mxp/vcha_cl_va_engine=>factory(
i_badi_implementation = me
i_explosion_date = ref #( explosion_date )
i_hierarchy = ref #( hierarchy )
i_characteristics = ref #( characteristics )
i_values = ref #( values )
i_bill_of_materials = ref #( bill_of_materials )
i_assign_by_value = ref #( assign_by_value )
i_assign_by_key = ref #( assign_by_key )
i_unassign = ref #( unassign )
)->process( new /mxp/vcha_cl_va_task_composite( value #( "task list, one after each other
( new zcl_your_task( ) ) "task implementation(s) to be replaced
) ) ).

The class /mxp/vcha_cl_va_engine serves as the main entry point for mdVC, encapsulating all related logic.
It maintains access to the configuration and executes tasks — either simple or composite — that define thebehavior.
In the example above, zcl_your_task refers to a customer specifc class implementing a single task with custom logic.

Task

The mdVC framework includes several predefined task types that help define the execution flow.
These are intentionally kept free of business logic. For adding logic, use Connectors or add a custom Simple Task.

Below is an overview of the available task types, with key classes highlighted:

Simple Task

A simple task is ideal for adding custom logic in your own Z classes.
Each task serves a focused purpose—like validation or value calculation — and extends from /mxp/vcha_cl_va_task_simple.

You must redefine the method /mxp/vcha_if_va_task~execute, which is invoked by the framework and provides access to the relevant context.
Below is an example implementation:

class zcl_your_task definition public create public inheriting from /mxp/vcha_cl_va_task_simple.
public section.
methods /mxp/vcha_if_va_task~execute redefinition.
endclass.

class zcl_your_task implementation.
method /mxp/vcha_if_va_task~execute.
"get THICKNESS
data(l_thickness) = i_engine->m_container->get_characteristic_by_name( i_instance_id = i_engine->m_container->m_root_instance_id i_cstic_name = 'THICKNESS' ).
data(l_thickness_val) = i_engine->m_container->get_assigned_value_for_cstic( l_thickness->key ).

"get THICKNESS2
data(l_thickness2) = i_engine->m_container->get_characteristic_by_name( i_instance_id = i_engine->m_container->m_root_instance_id i_cstic_name = 'THICKNESS2' ).
data(l_thickness2_val) = i_engine->m_container->get_assigned_value_for_cstic( l_thickness2->key ).

"write max of THICKNESS or THICKNESS2 to THICKNESS_MAX
i_engine->m_container->assign_value(
value #( key = i_engine->m_container->get_characteristic_by_name( i_instance_id = i_engine->m_container->m_root_instance_id i_cstic_name = 'THICKNESS_MAX' )->key
value_float = cond #( when l_thickness_val->value_float_min > l_thickness2_val->value_float_min
then l_thickness_val->value_float_min
else l_thickness2_val->value_float_min ) ) ).
endmethod.
endclass.

Implementation hints:

  • When working with characteristics, prefer accessing them by name using get_characteristic_by_name.
    If the characteristic is not returned, it likely doesn’t exist in the configuration model—this usually points to a modeling issue.
  • To exit task processing early (regardless of whether the task is standalone or part of a composite), you can raise the exception /mxp/vcha_cx_skip_proc.
    This will skip the remaining execution logic without triggering an error.
Value Get/Set

Access to characteristic values is provided by the interface /mxp/vcha_if_va_container.
This container manages the configuration context and all characteristic values—assigned or not.

To read or assign values, use i_engine->m_container.
For practical examples, see the example above.

info

Different assignment types exist (e.g., user input vs. determination).
Typically, user input takes precedence. If needed, check and manage the assignment type using /mxp/vcha_if_va_container=>c_assignment_types-user_input.

Influence UI

In the AVC UI, characteristics can be controlled via:

  • Read-only
  • Hidden
  • Mandatory
  • Value exclusion

These can be managed using /mxp/vcha_if_va_session_bridge, which connects mdVC to the AVC session.

Use i_engine->m_session to access the session bridge.
Below is an example showing how to hide a characteristic based on a condition:

class zcl_my_task definition public create public inheriting from /mxp/vcha_cl_va_task_simple.
public section.
methods /mxp/vcha_if_va_task~execute redefinition.
protected section.
private section.
endclass.

class zcl_my_task implementation.
method /mxp/vcha_if_va_task~execute.
"get product type value
data(l_product_type) = i_engine->m_container->get_assigned_value_for_cstic(
i_engine->m_container->get_characteristic_by_name( i_instance_id = i_engine->m_container->m_root_instance_id i_cstic_name = 'PRODUCT_TYPE' )->key ).

"determine whether to hide attribute and hide it or not
i_engine->m_session->set_cstic_hidden(
i_key = i_engine->m_container->get_characteristic_by_name( i_instance_id = i_engine->m_container->m_root_instance_id i_cstic_name = 'LENGTH' )->key
i_is_hidden = cond #( when l_product_type->value_string = 'COIL' then if_vch_hl_post_validate_assign=>gc_boolean-true ) ).
endmethod.
endclass.
note

This example focuses solely on hiding a characteristic.
If values are already assigned, unassignment may be necessary as well.

Log

To write custom messages into the AVC log, use the interface /mxp/vcha_if_log.
Access the log via i_engine->m_session->m_log.

Here’s an example that logs a custom error message:

class zcl_my_task definition public create public inheriting from /mxp/vcha_cl_va_task_simple.
public section.
methods /mxp/vcha_if_va_task~execute redefinition.
protected section.
private section.
endclass.

class zcl_my_task implementation.
method /mxp/vcha_if_va_task~execute.
message e899(v1) with 'test message' into data(l_message_text).
i_engine->m_session->m_log->add_sy_message( ).
endmethod.
endclass.
info

Adding an error message does not automatically change the configuration status.
Refer to the Status Best Practice section to see how to manage status explicitly based on messages.

The log messages appear in the standard AVC message popover:
Message Popover

Trace

Use the interface /mxp/vcha_if_trace to write additional context or technical information into the AVC trace—helpful for debugging or advanced analysis.
Access it through i_engine->m_session->m_trace.

Example:

class zcl_my_task definition create public inheriting from /mxp/vcha_cl_va_task_simple.
public section.
methods /mxp/vcha_if_va_task~execute redefinition.
protected section.
private section.
endclass.

class zcl_my_task implementation.
method /mxp/vcha_if_va_task~execute.
message e899(v1) with 'test trace message' into data(l_message_text).
i_engine->m_session->m_trace->add_sy_message( ).
endmethod.
endclass.

trace in AVC (on the right side you can see the "test trace message")

tip

If your logic is complex and performance is a concern, check if the trace is active using /mxp/vcha_if_trace->is_active( ) before writing to it.

Status

The configuration status can be influenced programmatically using /mxp/vcha_if_status, accessible via i_engine->m_session->m_status.

Here’s an example of how to set the configuration status:

class zcl_my_task definition create public inheriting from /mxp/vcha_cl_va_task_simple.
public section.
methods /mxp/vcha_if_va_task~execute redefinition.
protected section.
private section.
endclass.

class zcl_my_task implementation.
method /mxp/vcha_if_va_task~execute.
data(l_thickness) = i_engine->m_container->get_assigned_value_for_cstic( i_engine->m_container->get_characteristic_by_name( i_instance_id = i_engine->m_container->m_root_instance_id i_cstic_name = 'THICKNESS' )->key ).

if l_thickness is not bound or l_thickness->value_float_min <= 0.
i_engine->m_session->m_status->set_locked( ).
else.
i_engine->m_session->m_status->set_released( ).
endif.
endmethod.
endclass.
It is only allowed by aVC standard to programatically change to status `Locked` or `Released`.
Best Practice

Users typically expect an error message if the configuration is incomplete.
Our recommended approach is to use a Composite Task at the top level.
Handle message generation in a simple task, and then finalize with /mxp/vcha_cl_va_log_to_status, which derives the status based on the presence of error messages. If there is an error, the status will be set to Locked and if not, the status will be set to Released. Example:

/mxp/vcha_cl_va_engine=>factory(
i_badi_implementation = me
i_explosion_date = ref #( explosion_date )
i_hierarchy = ref #( hierarchy )
i_characteristics = ref #( characteristics )
i_values = ref #( values )
i_bill_of_materials = ref #( bill_of_materials )
i_assign_by_value = ref #( assign_by_value )
i_assign_by_key = ref #( assign_by_key )
i_unassign = ref #( unassign )
)->process( new /mxp/vcha_cl_va_task_composite( value #( "task list, one after each other
( new zcl_your_task( ) ) "task implementation(s) to be replaced
( new /mxp/vcha_cl_va_log_to_status( ) ) "evaluates error messages and sets status
) ) ).

Composite Task

A composite task sequences multiple tasks—either simple or other composite tasks—executed one after another.
It allows complex behavior to be modularized and reused.

Example:

/mxp/vcha_cl_va_engine=>factory(
i_badi_implementation = me
i_explosion_date = ref #( explosion_date )
i_hierarchy = ref #( hierarchy )
i_characteristics = ref #( characteristics )
i_values = ref #( values )
i_bill_of_materials = ref #( bill_of_materials )
i_assign_by_value = ref #( assign_by_value )
i_assign_by_key = ref #( assign_by_key )
i_unassign = ref #( unassign )
)->process( new /mxp/vcha_cl_va_task_composite( value #( "task list, one after each other
( new zcl_initialize_some_things( ) ) "task implementation(s) to be replaced
( new /mxp/vcha_cl_va_task_composite( value #(
( new zcl_do_something( ) )
( new zcl_do_something2( ) )
) ) )
( new /mxp/vcha_cl_va_log_to_status( ) ) "evaluates error messages and sets status
) ) ).

While the above nesting may appear redundant, this pattern allows for flexibility—such as looping or conditional logic—especially useful in more advanced scenarios.

Settler Task

A settler task extends the composite task and repeats its execution until stability is reached—i.e., no further value changes occur.
This is useful when characteristics have mutual dependencies.

Example:

/mxp/vcha_cl_va_engine=>factory(
i_badi_implementation = me
i_explosion_date = ref #( explosion_date )
i_hierarchy = ref #( hierarchy )
i_characteristics = ref #( characteristics )
i_values = ref #( values )
i_bill_of_materials = ref #( bill_of_materials )
i_assign_by_value = ref #( assign_by_value )
i_assign_by_key = ref #( assign_by_key )
i_unassign = ref #( unassign )
)->process( new /mxp/vcha_cl_va_task_composite( value #( "task list, one after each other
( new zcl_initialize_some_things( ) ) "task implementation(s) to be replaced
( new /mxp/vcha_cl_va_task_settler( value #( "repeat until values reaches stability
( new zcl_calc_b_based_on_a( ) )
( new zcl_calc_a_based_on_b( ) )
) ) )
( new /mxp/vcha_cl_va_log_to_status( ) ) "evaluates error messages and sets status
) ) ).

When using CDS views to define characteristic dependencies, a settler task is often required to iterate until all interdependencies are resolved.