Use Proven Coding Techniques

Use these guidelines to help you create an order management extension.

Overview

payload that Uses Proven Coding Techniques

Note

  1. Use an IF. Avoid writing code that runs in every condition in your development environment. Instead, use an IF statement so your code runs only in your specific use case.

    Assume you write a statement that runs every time the extension point happens, without conditional logic, but the extension contains an error. The extension might cause every sales order in your development environment to fail in every situation, regardless of the condition you must test. This situation might negatively affect other developers, and also make it more difficult for you to manage each of your own extensions.

    For example, assume you write an extension that manipulates the shipInstructions attribute. You can add this statement as the first statement in your extension so your code runs only for your use case.

    if (shipInstructions != "ValidateCustomerPONumber" ) return;

    If the statement evaluates to true, then no more logic in your extension runs. Instead, the flow exits your extension.

    Remove the IF after you test your extension and are ready to deploy into production.

  2. Check for empty values. Avoid a null pointer exception. Use an IF statement that makes sure each attribute you reference contains a value. If it doesn't, then return flow out of the extension.

  3. Add comments. Add detailed comments that document each part of your code so you know exactly the logic that each statement implements. Comments help others to understand the intent of your code, and also help you to troubleshoot large complex code, or code that you haven't examined for a long period of time.

Notes
  • If your extension does an action only on a new sales order or only on a revision, then add a condition that determines whether the sales order you're modifying is new or is a revision right at the beginning of your extension. This way, if the condition evaluates to false, you can exit the extension immediately without having to evaluate the rest of the extension code.

    Consider all factors that impact the order line, such as configured items, kits, or ship sets.

  • Take advantage of Groovy constructs, such as simplified array usage and initializing maps.

Define Variable Type in Groovy

Groovy is a dynamic language and doesn't require you to define the type for each variable. For example, you can define soldToPartyName and Lines each as a variable without a type. As an option, specify a type, if necessary. For example, define soldToPartyName as type String.

Access each child entity as an attribute. For example:

header.getAttribute("Lines"), header.getAttribute("SalesCredits")

Use Implicit Variables

Use implicit variables with each extension. You don't need to define them.

Implicit Variable

Description

Header

Represents the order header object. Use the Header variable to access order header attributes and child entity rows.

Context

Context object that allows each extension to access context details, such as the name of the extension that's running, the event code, and so on. The context object also provides access to utility and helper methods, such as logging.

You use this format.

context extension name

For example:

context Update Order Submit Date

Reference Sales Order Entities

Use the implicit header variable to access each order entity. Order Management exposes each entity as a generic row object. Each extension can reference only get methods or set methods.

Action

Code

Read an attribute value.

getAttribute("attributeName")

Write to an attribute.

setAttribute("attributeName", attributeValue)

For example:

Code

Description

def soldToPartyName = header.getAttribute("BuyingPartyName");

Get the value of the BuyingPartyName attribute.

header.setAttribute("ShippingInstructions", "Use only next-day air.");

Set the value of the ShippingInstructions attribute to Use only next-day air.

def lines = header.getAttribute("Lines");

Return a set of lines. You can iterate over the iterator to access individual lines.

Loop Through Lines

You might need to update a number of attributes on all the order lines in a sales order.

Assume you need to update the Shipping Method, Packing Instructions, and Payment Terms on all 50 order lines in sales order 54638. It's possible to create 50 extensions to update each line separately, but we recommend that you create a single extension to update all of the attributes on all lines, and then loop through the lines to update the attributes.

This approach avoids having to create 50 instances of the extension, doing 50 different line loop checks, and that improves performance.

Navigate Row Sets

Order Management returns each child entity as a set of rows. For example, an order line is a child of a sales order. This example illustrates how you can use while next to loop through each row, an order line, from the set, which is the sales order.

code that loops through each row

Here's the same code with descriptions.

Code

Description

def lines = header.getAttribute("Lines");

Call the getAttribute method on the order header to access the row set iterator for the order lines.

while( lines.hasNext() ) {

Determine whether the lines row set includes a next row, and loop until the row set doesn't contain any more rows.

def line = lines.next();

Get the next order line row.

  • On the first loop through the while, move from line 1 to line 2.

  • On the second loop through the while, move from line 2 to line 3.

  • And so on.

line.SetAttribute("BillingTransactionTypeIdentifier, 12345L");

Set the value of the billing transaction type on the order line to 12345L.

For brevity, this example hard codes the value 12345L. In most situations, its more likely you would define a variable or some other logic rather than hard code the value.

Here's the same code without comments.


  while( lines.hasNext() ) {
  def line = lines.next();
  line.SetAttribute("BillingTransactionTypeIdentifier, 12345L");
}

Navigate Row Sets of Grandchild Entities

Access a grandchild entity.

Here's an example extension that:

  • Accesses the Charge Component row of an order line

  • Gets the order line

  • Accesses the order charge rows below the order line

  • Accesses the charge component rows from the order charge

Code

Description

def lines = header.getAttribute("Lines");

Use method getAttribute on the order header to access the row set iterator for the order lines.

while( lines.hasNext() ) {

Determine whether the lines row set includes a next row, and loop until the row set doesn't contain any more rows.

def line = lines.next();

Get the next row.

def charges = line.getAttribute("OrderCharges");

Get the row set for the order charges on the order line.

while( charges.hasNext() ) {

Loop through the order charge rows.

def charge = charges.next();

Get the next order charge from the row set.

def chargeComps = charge.getAttribute("ChargeComponents");

Get the row set for the charge components of the child entity.

while( chargeCompo.hasNext() ) {

Loop through the charge components for the current charge.

def chargeComp = chargeCompo.next();

Get the next charge component.

def currency = chargeComp.getAttribute("ChargeCurrencyCode");

Get the value of attribute ChargeCurrencyCode from the current charge component row.

Here's the same code without comments.

def lines = header.getAttribute("Lines"); //get the lines row set
while( lines.hasNext() ) {//determine whether more lines exist
  def line = lines.next();
  def charges = line.getAttribute("OrderCharges");
  while( charges.hasNext() ) {
    def charge = charges.next();
    def chargeComps = charge.getAttribute("ChargeComponents");
    while( chargeCompo.hasNext() ) {
      def chargeComp = chargeCompo.next();
      def currency = chargeComp.getAttribute("ChargeCurrencyCode");
    }
  }
}

Secure Your Extension

Write logic according to the job role. For example, write an extension that prevents an action or that sets default values on the sales order according to the job role that the Order Entry Specialist uses when signing into Order Management. This example references ORA_FOM_ORDER_ENTRY_SPECIALIST_JOB, which is the code for the Order Entry Specialist job role.

This topic uses predefined job roles. You must create your own job roles, depending on your security requirements.

For details about how to set up privileges, see Security Reference for Order Management.

how to define job role ORA_FOM_ORDER_ENTRY_SPECIALIST_JOB

Note

  1. Use the Security Console to get details about the job roles and role code that your extension must reference. For details, see Overview of Security Console in Oracle ERP Cloud, Securing ERP.

  2. Use the isUserInRole method.

  3. In the first parameter for isUserInRole, reference the role code that the security console defines.

Don't Use Extensions and Transformation Rules Together

Don't use an order management extension and a product transformation rule to add order lines to the same sales order because the rule might remove or modify the lines that the extension added.

For example, if you use an extension to add Line 1 to sales order 65748, and then use a rule to add line 2 to the same sales order, then the rule will remove line 1 and add line 2 when you save, submit, or revise the order.

For another example, if you use an extension to add the AS54888 item with a quantity of 2 to line 1 on sales order 65748, and then use a rule to add the AS29888 with a quantity of 10 on line 1, then the rule will remove the AS54888 and the quantity before it adds the AS29888 with a quantity of 10.