10Extend

This chapter contains the following:

Extensions

Overview

Write your own Groovy script that modifies your Order Management deployment, implements your own functionality, and specifies the extension point that determines when to run this script.

An order management extension is a Groovy script you write that meets your specific business requirements. An extension point is an event that you specify to determine when to run the script.

You can use a flexfield to modify the data model, or Page Composer to modify the user interface, but you can't use them to programmatically modify logic or modify your order management deployment. Instead, you can create an order management extension.

Here is some Groovy script in an example extension named Update Order Submit Date. It uses attribute _H1AttributeDateTime so it can set the value of an extensible flexfield to the date and time when Order Management submitted the sales order.

Extension That Modifies Order Management

Business Requirements That Your Order Management Extension Can Meet

Example Requirement Description

Get data

Create an order management extension to get data from different sources.

  • Use the getAttr method to get data from Order Management.

  • Use a public view object (PVO) to get data from some other Oracle Fusion product. A public view object is a data object that Order Management gets from some other Oracle Fusion solution. For example, you can use a public view object to look up an item category in Product Information Management or a purchase order in Oracle Fusion Purchasing.

  • Use a web service to get data from a source that resides outside of Order Management Cloud.

Implement your own logic

Use Groovy to write your own logic when you code your extension. Your code can validate the sales order. If validation fails, then your code can stop the flow and create a message.

For details about Groovy, see website Groovy Programming Language at www.groovy-lang.org.

Raise error messages and warnings

Create an extension that raises an error message or warning.

Set the default value for sales order attributes or extensible flexfields

Use Groovy to write your own logic that sets default values before you save the sales order or submit it to order fulfillment.

Get values for return lines from the original sales order.

A return order doesn't include values from the original order on some order line attributes. For example, the return line doesn't include the original value for the sales credit or purchase order number. You can use an extension to get the value from the original line order.

Example Actions

Action Description

Submit a sales order

  • Reassign the warehouse for pick-to-order. Set up an item that determines whether the sales order references a pick-to-order or a hardware model.

  • Stop support lines that reference an incorrect accounting rule. Set up item entities and accounting rule entities.

  • Make sure only one contract is Active or Signed for a booking. Set up entities for the installed base, contracts, or order management.

  • Assign a sales representative. Set up sales compensation rules.

  • Update the accounting rule for a model for included items.

  • Update the quote status for each sales order from a store front that a third-party partner maintains.

  • Verify the purchase order number that the Order Entry Specialist enters on the sales order equals a purchase order in Oracle Fusion Procurement.

  • Assign the Salesperson according to a sales compensation rule that you create in some application outside of Oracle Fusion, then use a web service to call the application.

  • During order import, copy attachments from a purchase-to-order kit to each item that the kit contains.

  • Set the default value for order preferences in each sales order. Get these values from the customer master.

Save or validate a sales order

Write a validation on an imported source order that rejects the import or prevents the Order Entry Specialist from saving the order without fixing the problem.

Parts of an Order Management Extension

Part Description

Function

A Groovy function, similar to a Java function, such as getAttr. Use a function only in the extension where you set it up. You can't define a function in one extension, and then use it in another extension.

Attribute

The attribute of a sales order, such as ShippingInstructions.

Web Service

The name of a web service.

  • Your extension code can only call a web service that you set up on the Manage Web Service Definitions page.

  • You must manually create the request payload in your code.

  • Your code must parse and interpret the response payload.

  • You must write your code so it works only for a synchronous interaction. You can't write code for an asynchronous interaction.

Message

A message you send to Order Management and that can display in the Order Management work area.

  • An extension can log an error or warning message in the messaging framework.

  • Order Management logs each message in a log file as part of order import or when a web service rejects a sales order.

  • An error message stops the flow and rejects the save or submit action.

  • A warning allows the flow to continue. If you use a warning at the beginning of a submission request, then Order Management displays the warning message to the Order Entry Specialist, then continues to process the sales order in order fulfillment.

  • Use the Manage Messages page to define messages and tokens.

  • Use tokens to insert dynamic content into each message.

  • Modify the DOO_MSG_REQUEST_FUNCTION lookup to categorize the errors that Order Management displays to the Order Entry Specialist and improve search for these errors.

Points Where You Can Run Order Management Extensions

Run an order management extension at different extension points when creating a sales order or during order fulfillment.

Points Where You Can Run Order Management Extensions

Note.

  1. Something occurs that triggers the On Save extension point.

    • An Order Entry Specialist does an action in the Order Management work area that causes Order Management Cloud to automatically save the sales order. Here are some example actions.

      • Validate

      • Save

      • Save and Close

      • Reprice

      • Submit

      • Copy Order

      • Create Revision

      • Create Return

    • Order Management imports a source order from a source system, then processes it, such as creating a cross-reference, defaulting a value, and so on.

  2. You can create an extension that runs on the On Save extension point.

  3. You can create an extension that runs on the On Start of Submission Request extension point. If the extension results in failure, then Order Management sets the sales order status to Draft, with errors.

  4. Order Management processes the submission request, including running validations, doing credit check, communicating with Global Trade Management, order approvals, and so on.

  5. You can create an extension that runs on the On End of Submission Request extension point. If the extension results in. . .

    • Failure. Order Management sets the sales order status to Draft, with errors.

    • Warning. Order Management displays a warning message, successfully submits the sales order, and continues to process it through order fulfillment. The Order Entry Specialist can examine the warning messages on the submitted order.

  6. The fulfillment system fulfills the sales order, including shipping, invoicing, and so on. You can't run an extension after Order Management submits the sales order to order fulfillment and order orchestration.

Extension Point Behavior

On Save

If an order management extension that runs during On Save raises a validation failure, then Order Management stops running the extension and moves control to the next extension that you specify to run during On Save. If the validation failure includes at least one error message, and if Order Management has already run each of the On Save extensions, then it aborts the save for the sales order.

Order Management handles each message that the extension raises differently depending on how its saving the sales order.

  • An Order Entry Specialist is saving a sales order in the Order Management work area. Order Management displays the message in a dialog. This user must correct the validation error and attempt to save the sales order again.

  • A service is saving a source order during order import. Order Management returns the message in a response. The channel that's importing the source order must fix it, then import it again.

Order Management doesn't save the message in the messaging framework because it might not have saved the sales order and the change that caused the validation to fail.

On Start of Submission Request

  • Order Management calls the extension when the extension point occurs. Its the first operation that Order Management does when it validates the submit.

  • An extension can modify values on each writable order attribute, including header attributes and order line attributes, flexfield attributes, and attachment attributes.

  • Order Management runs the extension before it validates the submit or applies constraints.

  • If an extension raises a validation failure, then Order Management stops running the extension and moves control to the next extension that you specify to run during On Start of Submission Request.

  • If the validation failure includes at least one error message, then Order Management aborts the submit for the sales order, returns the order status to Draft, then logs the error and warning messages.

  • If the Order Entry Specialist is saving a sales order in the Order Management work area, and if the validation failure includes at least one error message, then Order Management displays a dialog that includes the message.

  • If all messages are warnings, then Order Management submits the sales order to order fulfillment and doesn't display a dialog in the Order Management work area. The user can view the warning message after Order Management submits the sales order to order fulfillment.

On End of Submission Request

  • Order Management calls the extension when the extension point occurs. It makes this call as the last step before it sends the sales order to order fulfillment.

  • The extension can modify values only on header flexfields and fulfillment line flexfields. If the extension attempts to modify any other attribute, then Order Management logs a runtime error and aborts all extensions that its running for this extension point.

Use guidelines to help you create an order management extension.

Determine Your Data Requirements

Determine the type of data you need and how you will access it.

Type of Data You Need How to Access Data Limitation

Data from a sales order in Order Management Cloud.

To read data, use methodgetAttribute.

To write data, use the setAttribute method.

Each method can read or write only to the sales order that the Order Entry Specialist is currently entering in work area Order Management. They don't read or write to some other version of the current sales order, or to some other sales order in Order Management.

Use a public view object to access data from a sales order that isn't the current sales order.

Each method can only read from or write to an attribute. They can't create an order line.

Data from an Oracle Fusion Application outside of Order Management, such as the customer master, the item master in Oracle Fusion Procurement or Oracle Fusion Receivables, and so on.

Data from a sales order in Order Management Cloud that isn't the current sales order.

Public View Object (PVO).

For details, see the Use Extensions to Access Data Outside of Order Management topic.

The Oracle Fusion Application must share their data through a public view object. The public view object you need might not be available, or it might not provide access to the attribute that you require. It might be necessary to submit a request to get access to the data you need.

Data from a system that resides outside of an Oracle Fusion Application

Web service.

You can use only a synchronous web service. You can't use an asynchronous web service.

You can only use a SOAP service. You can't use a REST service.

Consider the data you can access. For a complete list, see the Attributes You Can Use With Order Management Extensions topic.

Read Access Write Access

Do a read operation on this data at any of the extension points.

  • Order header, including extensible flexfield

  • Fulfillment lines, including extensible flexfield

  • Sales credit

  • Pricing entity, such as charge, charge component, manual price adjustment, total, price validation, tax detail, and so on

  • Lot or serial

  • Transaction item attribute

  • Payment

  • Billing plan

  • Attachment

  • Fulfillment line detail

  • Document reference

Do a write operation on this data during the On Save or the On Start of Submission Request extension points.

  • Order header, including extensible flexfield

  • Fulfillment line, including extensible flexfield

  • Attachment

  • Sales credit

  • Transaction item attribute

  • Document reference

You can't do a write operation on this data during the On End of Submission Request extension point because Order Management already performed a large set of predefined validations at this point.

Perform a write operation on data during the On End of Submission Request extension point.

  • Extensible flexfield on the order header

  • Extensible flexfield on the fulfillment line

  • Attachment

Consider Runtime Behavior

flow of the runtime behavior

Note.

  • Order Management runs each extension in sequential order, and it only extensions where the Active attribute contains a check mark run. Assume you create extensions x, y, and z. Extension x runs first, then extension y. If you make z active, then Order Management runs extension x, and then z, and then y.

    Sequence Extension Name Active

    1

    x

    Contains a check mark

    10

    y

    Contains a check mark

    5

    z

    Doesn't contain a check mark

  • Order Management runs each active extension until it finishes unless an error or warning occurs. If an error or warning occurs, then Order Management doesn't run any more extensions. For example, assume x, y, and z are active, x finishes, but z ends in error. Order Management won't run extension y.

  • Each variable is local to each extension. You can't share them across extensions. For example, assume you require variable A in extensions x and y. If you define variable A in x, then you can't use A in y. Instead, you must write logic in y that references A in x.

Call Web Services

Apply these guidelines when your extension calls a web service.

extension that calls a web service

Note.

  1. Use the invokeSoapService method in your extension to call the web service.

    You can call an Oracle Fusion web service or some other service that resides outside of Oracle Fusion. You can call only a SOAP service. You can't call a REST service.

  2. Set up the connector.

    Note: You must use the Manage Connector Details page to set up a connector for the web service that you reference in your extension.

    Set these values.

    Attribute Value

    Connector Name

    Use the exact same name that you use in the extension. For example.

    invokeSoapService("FundsCapturePaymentMethod") 

    For this example, set Connector Name to FundsCapturePaymentMethod.

    Connector URL

    Enter the URL that locates the web service address that you deploy on the external system.

    User Name

    Enter the user name you use to sign into the web service.

    Password

    Enter the password you use to sign into the web service.

    Invocation Mode

    You must use Synchronous Service.

    For details about how to set up a connector, see the Manage Connector Details Between Order Management and Your Fulfillment System topic.

Define the payload.

payload that calls a web service

Note.

  1. Define the payload. This example uses String payLoad to hard code the payload as a string. You can also use other techniques to meet your requirements, such as defining variables in the payload.

  2. Reference your payload definition in a parameter of the invokeSoapService method. This example references string payLoad.

  3. Use the getSoapBody method to handle the response that the web service sends in reply to your request. Your extension can receive the response, parse it, then extract the details it requires from the response.

  4. Define your payload so it includes only the main content. Don't include envelope or body details. invokeSoapService expects only the main content. It will add envelope and body details.

Extract Details from Web Service Response

The getSoapBody() call on the response object in a web service response is an instance of Java class javax.xml.soap.SOAPBody for a SOAP body (Simple Object Access Protocol). The Java documentation at https://docs.oracle.com/javaee/5/api/javax/xml/soap/SOAPBody.html describes that SOAPBody is an instance of org.w3c.dom.Element and org.w3c.dom.Node. Use the methods that are available on these interfaces to extract details from a web service response.

This example order management extension uses methods from these interfaces to extract data from the response.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

def poNumber = header.getAttribute("CustomerPONumber");

if( poNumber != "CreditCheck" ) return; 

// get attribute to populate in the payload
String customer = header.getAttribute("BillToCustomerName");
Long accountId = header.getAttribute("BillToCustomerIdentifier");
BigDecimal amount = new BigDecimal(1000);

// prepare the payload
String payLoad = "<ns1:creditChecking xmlns:ns1=\"http://xmlns.oracle.com/apps/financials/receivables/creditManagement/creditChecking/creditCheckingService/types/\">" +
 "<ns1:request xmlns:ns2=\"http://xmlns.oracle.com/apps/financials/receivables/creditManagement/creditChecking/creditCheckingService/\">" +
  "<ns2:CustomerName>" + customer + "</ns2:CustomerName>" +
  "<ns2:CustomerAccountNumber>" + accountId + "</ns2:CustomerAccountNumber>" + 
  "<ns2:RequestType>Authorization</ns2:RequestType>" + 
  "<ns2:PriceType>ONE_TIME</ns2:PriceType>" +
  "<ns2:RecurrencePeriod></ns2:RecurrencePeriod>" +
  "<ns2:RequestAuthorizationAmount currencyCode=\"USD\">" + amount + "</ns2:RequestAuthorizationAmount>" +
  "<ns2:RequestAuthorizationCurrency>USD</ns2:RequestAuthorizationCurrency>" +
  "<ns2:ExistingAuthorizationNumber></ns2:ExistingAuthorizationNumber>" +
  "<ns2:Requestor>ar_super_user</ns2:Requestor>" +
  "</ns1:request>" +
  "</ns1:creditChecking>";

// invoke the Check Check service using web service connector name 'CreditCheckService'. The connector is set up using task 'Manage External Interface Web Service Details'. Since this is an external service that is secured
// using message protection policy, we have registered the the https (external) URL of the service
def response = context.invokeSoapService("CreditCheckService", payLoad); 

// print a debug message. This appends the entire response to the shipping instuctions attribute. 
// Note: debug statements like these should be disabled in extensions on production instance as they can cause performance issues.
debug(response.getSoapBody().getTextContent());

// The response XML sent by the Credit Check service contains an element named 'Response'. A YES value indicates that credit check passed. Let us extract the contents of Response tag. The following XML API will return all nodes (tags)
// with name 'Response' in a NodeList element. We are expecting only one such element in our XML response
def nodeList = response.getSoapBody().getElementsByTagNameNS("*", "Response");

// print out the lenght of the node list
debug(nodeList.getLength());

// Get the first element with name 'Response' (we are expecting only one), and gets its text content
String ccResponse = nodeList.item(0).getTextContent();

debug(ccResponse);

// Check if credit check passed
if( ccResponse != 'YES' ) {
 // Credit check failed. Raise a warning validation exception here
 throw new ValidationException( new Message(Message.MessageType.WARNING, "Credit check failed.") );
}
else {
 // Credit check passed
 // Write the credit check response in an EFF attribute.
 def psiContext = header.getOrCreateContextRow("ComplianceDetails");
 psiContext.setAttribute("_ComplianceInfo", ccResponse);   
}

/**
* Appends passed in msg to the Shipping Instructions attribute. This method has been implemented only for debugging purposes.
*/
void debug(def msg) {
 String si = header.getAttribute("ShippingInstructions");
 header.setAttribute("ShippingInstructions", si + ", " + msg.toString());
}

Use Proven Coding Techniques

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 occurs, 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 attribute shipInstructions. 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.

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

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.

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

Navigate Row Sets of Grandchild Entities

Access a grandchild entity.

The following example extension.

  • 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");
    }
  }
}

Use Extensible Flexfields

For details, see topic Using Extensible Flexfields in Order Management: Guidelines.

Implement Security

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 role code for job role Order Entry Specialist.

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 topic Security Console: Overview.

  2. Use method isUserInRole.

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

Manipulate Attachments

Use an order management extension to create, read, update, or delete an attachment. Use a text or XML attachment file. Don't use a binary file.

code that uses text or XML attachment files

Note.

  1. Use get methods to get attachment details from an attachment that already exists, such as getText to get all the text that the attachment contains, use getPklValue to get the sales order or order line that references the attachment, getFileName to get the name of the attachment file name, and so on. Here's some of the methods you can use.

    • getText

    • getPklValue

    • getEntityName

    • getDataTypeCode

    • getTitle

    • getDescription

    • getFileName

    • getUrl

    • getCategoryName

  2. Use the createAttachment method to create an attachment, and use set methods to specify how to create it. You can specify a new attachment file of type File, Text, or URL. For example, use setFileName to specify the name of the attachment file. Here are some of the methods you can use.

    • setDataTypeCode

    • setTitle

    • setDescription

    • setFileName

    • setFileContentType

    • setFileContent

  3. Use the deleteAttachment method to delete an attachment. In this example, the code uses a for statement to iterate through all the attachments that a sales order contains and deletes all of them.

Define Messages

Use an extension to define a message.

code that Defines Messages

Note.

  1. messageType. Define the messageType as WARNING or ERROR. The Order Management work area uses a different icon for each type.

  2. Lookup. Use the Manage Order Lookups page in the Setup and Maintenance work area to categorize your messages, then reference them from your code.

    Use predefined lookups or create your own. Categorizing helps the Order Entry Specialist search for messages and view them in analytic charts.

    Use Error to improve search and display because errors display in work area Order Management in attribute Error Type.

    In this example, assume you define the Meaning as Customer Relationship Mismatch.

  3. Header or line. Indicate where the error occurs. Use one of these values.

    • header. Apply the message to an error that occurs on the order header.

    • line. Apply the message to an error that occurs on an order line.

      The example in the screen print uses line. This example includes code (not visible, for brevity) above throw new ValidationException that defines line as a variable, uses it to iterate through all the lines in the sales order, then saves the order line number where the error occurs, such as line 3. At run time, Order Management displays an icon on line 3 that the Order Entry Specialist can click to examine message details.

  4. Manage Messages. Use the Manage Messages page in the Setup and Maintenance work area.

    • Referencing a message provides advantages over hard coding the message.

    • Reference the message from different extensions, manage the message independently of the extension, and translate the message to some other language besides English.

    • Using the Manage Messages page can simplify message management because other developers and administrators can then use Manage Messages instead of modifying hard coded messages in your extension, which requires knowledge of writing in Groovy.

    • You can also define a message to help you troubleshoot your extension during development. You can include details in the message that display the state of various objects to help you pinpoint problem areas. Remove the message when you're ready to deploy your extension to your production environment.

  5. Use tokens as placeholders for variable content.

The Order Entry Specialist can view and search data in work area Order Management according to Error Type or Message Type. In this example, notice that Customer Relationship Mismatch displays as a label in the Draft Orders in Error diagram on the Overview page.

data in work area Order Management according to
Error Type or Message Type

The Order Entry Specialist can take action.

  • Click on the orange part of the circle to drill into to sales orders that are in error because of the mismatch.

  • Search attribute Error Type on page Manage Orders for Customer Relationship Mismatch.

For details, see the Define Error Messages When Using Order Management Extensions topic.

Accumulate Error Messages and Display Them

Accumulate messages, then display them in the Order Management work area all together at one time. For example, assume you write an extension that contains three lines that check for error conditions, x, y, and z. At run time, assume x, y and z all meet their error conditions, but the extension stops immediately after it encounters x and displays the message for error x. Instead, write your extension so it continues to run through y and z, saves each message to a temporary list, then displays messages for x, y and z together in a single dialog. This technique allows the Order Entry Specialist to examine all errors together, correct them, then resubmit the sales order instead of correcting x, submit, correct y, submit, correct z, and submit.

For example.

code that accumulates messages

If the revenue percentage is less than 30% for the sales credit, then the extension creates a message and stores it in a local list. The extension processes all sales credits. If the local list contains any messages after it finishes processing sales credits, then the extension displays them in a dialog in the Order Management work area.

Here is the code that this example uses to examine each sales credit.

Code Description

import oracle.apps.scm.doo.common.extensions.ValidationException;

Import the ValidationException method so your code can use it.

import oracle.apps.scm.doo.common.extensions.Message;

Import the Message method so your code can use it.

def salesCredits = header.getAttribute("SalesCredits");

Define a local variable named salesCredits, use the getAttribute method to get the value of the SalesCredits attribute from the order header, then set the value of this variable to the value that getAttribute returns.

getAttrbute("SalesCredits") returns an iterator you can use to access sales credits rows. For example, the code references salesCredits later in this topic to get SalesCreditTypeCode, Percent, and Salesperson.

List<Message> msgs = new ArrayList<Message>();

Use this code.

  • List<Message> msgs. Define a local variable named msgs as a list type. Use this technique to add more than one message into the list so ValidationException can raise all messages at one time.

    You typically use this technique in a longer extension that contains more than one condition. The extension code stops when it raises the first message, so you can use ValidationException to let all validations run, then display a dialog that includes all errors.

  • new ArrayList<Message>(). Define an array that uses list format. You will use this array to store messages that the while loop creates.

The while loop

Iterate through each sales credit until it finishes processing all of them.

Examine attributes SalesCreditTypeCode, Percent, and Salesperson for each sales credit.

def percent = salesCredit.getAttribute("Percent")

Define a local variable named percent, use method getAttribute to get the value of attribute Percent from local variable salesCredit, then set this variable to the value that getAttribute returns.

if ( percent < 30 )

If the condition is True, then create a message, and add it to the local msgs list. Messages accumulate in the msgs list until the extension finishes processing all sales credits.

def tokens

Define these tokens.

  • SALESPERSON. def tokens sets the value of this token to the value that method getAttribute gets for attribute Salesperson from local variable salesCredit.

  • PERCENT. def tokens sets the value of this token to the value of variable percent that the while loop defines.

Message msg = new Message

Define a local variable named msg and add it to local array Message. msg stores each message that the code adds to list object msgs.

(Message.MessageType.ERROR, "SALES_CREDIT_TOO_LOW_MSG", tokens);

Use this code.

  • Message.Use method Message to define a message.

  • MessageType.ERROR. Set the Message type to ERROR.

  • SALES_CREDIT_TOO_LOW_MSG. Get message text details from message SALES_CREDIT_TOO_LOW_MSG from page Manage Message, then add this text to local variable msg.

  • tokens. Get the value of local variable tokens, then add it to local variable msg immediately after message text SALES_CREDIT_TOO_LOW_MSG.

msgs.add(msg);

Add the contents of local variable msg, which contains a single message, to local list variable msgs, which is an array that includes all messages that the code creates in this scenario.

if( !msgs.isEmpty() ) {
throw new ValidationException(msgs);
}

If local list msgs isn't empty, then run method ValidationException. Display all the messages that local list msgs contains.

Perform this check after the while loop finishes processing all sales credits.

Here's the complete code without comments.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
def salesCredits = header.getAttribute("SalesCredits");
List<Message> msgs = new ArrayList<Message>();
while( salesCredits.hasNext() ) {
 def salesCredit = salesCredits.next();
  if( "1".equals(salesCredit.getAttribute("SalesCreditTypeCode")) ) {
   def percent = salesCredit.getAttribute("Percent");
    if ( percent < 30 ) {
def tokens = [SALESPERSON: salesCredit.getAttribute("Salesperson"), PERCENT: percent];
Message msg = new Message(Message.MessageType.ERROR, "SALES_CREDIT_TOO_LOW_MSG", tokens);
msgs.add(msg);
  }
 }
}
if( !msgs.isEmpty() ) {
 throw new ValidationException(msgs);
}

Consider Order Import Behavior

Import behavior it different depending on whether your extension creates a warning message or error message.

behavior differences depending on whether your
extension creates a warning message or error message

Note.

  • Sales orders entered in the Order Management work area. The Warning dialog in work area Order Management allows the Order Entry Specialist to examine the warning, then submit the sales order or cancel.

  • Source orders imported from a source system. Order processing stops only if an error occurs. If only warnings occur, then you can view the messages but the import submits the sales order to order fulfillment. It doesn't allow user intervention.

Use Public View Objects

Reference a public view object. For a list of the view objects you can use, see Public View Objects in Oracle Applications Cloud (Doc ID 2386411.1) on My Oracle Support at https://support.oracle.com/epmos/faces/ui/km/DocumentDisplay.jspx?_afrLoop=581155108280882&id=2386411.1.

extension that references a public view object

Note.

Code Description
Object getItem(Long itemId, Long orgId) {

Define a local object that your code can call. This object will contain data from the public view object.

  • Object getItem. Define an object named getItem.

  • Long itemId, Long orgId. Specify itemId and orgId as Long data type strings. These strings will contain data from the public view object.

def itemPVO = context.getViewObject("context")

Create an instance of the public view object for the item, then store it in the itemPVO variable. Use this format.

  • itemPVO. Variable that will contain the instance.

  • context.getViewObject. Use the getViewObject method to get the view object according to the context.

  • "context". Context to use when getting the view object.

For example, reference the ItemPVO public view object.

def itemPVO = context.getViewObject("oracle.apps.scm.productModel.items.publicView.ItemPVO")

where

  • oracle.apps.scm.productModel.items is the context. It specifies to get product model items from supply chain management.

def vc = itemPVO.createViewCriteria();

Define the variable that will store details for the public view object.

  • vc. Variable that stores details for the view criteria object.

    View criteria is a filter that determines the data that the public view object returns.

  • itemPVO. Name of the public view object that contains the data you must get and filter.

  • createViewCriteria. Method that creates the view criteria object. It defines vc as a list that contains one or more rows.

def vcrow = vc.createViewCriteriaRow();

Define a variable for the row.

  • vcrow. Variable that stores details for rows of the view criteria object.

  • vc.createViewCriteriaRow. Use the createViewCriteriaRow method to create a row in variable vc.

vcrow.setAttribute("InventoryItemId", itemId);

Populate variable vcrow with data from the public view object.

  • setAttribute. Method that sets the value for the attribute in the row.

  • InventoryItemId. Attribute in the public view object. This example gets the value that uniquely identifies the item in inventory.

  • itemId. Variable that the extension code defines. This code gets the value of attribute InventoryItemId on the order line from the public view object, then stores it in itemId.

vcrow.setAttribute("OrganizationId", orgId);

Populate variable vcrow with data from the public view object.

  • setAttribute. Method that sets the value for the attribute in the row.

  • OrganizationId. Attribute in the public view object. This example gets the value that uniquely identifies the organization that ordered the item.

  • orgId. Variable that the extension code defines. This code gets the value of the OrganizationId attribute on the order header from the public view object, then stores it in orgId.

def rowset = itemPVO.findByViewCriteria(vc, -1);

Get the iterator that contains the number of rows that meet the criteria and store it in local variable rowset.

  • rowset. Variable that stores the iterator.

  • findByViewCriteria. Method that searches the public view object according to criteria that you define.

  • vc. Contains the data that the public view object returns.

  • -1. Return all rows that match the view criteria.

    You can also use a positive integer to get a subset of rows. For example, use vc, 3 to get the first three rows that match the criteria. If only two rows match the criteria, then the method returns only these two rows.

def item = rowset.first()

Define a variable named item.

return item

The item variable can now access all attributes in ItemPVO. return returns variable item so you can reference item from your extension to get details from ItemPVO.

Here's the entire code without comments.

Object getItem(Long itemId, Long orgId) {
 def itemPVO = context.getViewObject(
  "oracle.apps.scm.productModel.items.publicView.ItemPVO");
 def vc = itemPVO.createViewCriteria();
 def vcrow = vc.createViewCriteriaRow();
 vcrow.setAttribute("InventoryItemId", itemId);
 vcrow.setAttribute("OrganizationId", orgId);
 def rowset = itemPVO.findByViewCriteria(vc, -1);
 def item = rowset.first();
 return item;
}

Get Descriptive Flexfields from a Public View Object

The customer master in Oracle Trading Community Architecture (TCA) might include descriptive flexfields. However, public view objects that contain customer account site details, such as PartyPVO, might not include these descriptive flexfields. Use this technique to get them.

code that Gets Descriptive Flexfields from a Public
View Object

Note.

  1. Go to the Manage Customer Account Site Descriptive Flexfields page, locate the descriptive flexfield that you must access, click Download Flexfield Archive, then examine the structure that it uses.

  2. Reference the publicFlex public view object to reference the descriptive flexfield. In this example, you reference publicFlex for custAccountSite.

    oracle.apps.cdm.foundation.parties.publicFlex.custAccountSite.view.CustAccountSiteInformationVO
  3. Use the structure you examined when you downloaded the archive to help determine how to specify the view criteria.

Here's the entire code.

def siteFlexPVO = context.getViewObject 
 ("oracle.apps.cdm.foundation.parties.publicFlex.
 custAccountSite.view.CustAccountSiteInformationVO"); 
def vc = siteFlexPVO.createViewCriteria(); 
def vcrow = vc.createViewCriteriaRow(); 
vc.add(vcrow); 
def rowset = siteFlexPVO.findByViewCriteriaWithBindVars 
 (vc, -1, new String [0], new String [0]); 
def custDFF = rowset.first(); 
String values = custDFF.getAttribute("Salesperson")

Get Data From Sales Orders That Aren't the Current Sales Order

You can use HeaderPVO to access order header data and FulfillLinePVO to access order line or fulfillment line data. For example, if the Order Entry Specialist sets the purchase order number on a sales order, then make sure some other sales order doesn't already use this purchase order number. Do this validation when the Order Entry Specialist submits the sales order.

code that uses HeaderPVO to access order header
data and FulfillLinePVO

Here are some more examples.

  • If a new sales order includes return lines, then get the order type from the original sales order and use it to set the order type on each return line.

  • If order revision 2 increases the total price of the sales order by 10% or more over the total price on order revision 1, then don't allow the revision. For example, version 1 of sales order x is a complete and separate sales order from version 2 of sales order x. Use a public view object to get data from a version that isn't the current version.

Test Your Work

Validate Your Code

Enter your code into the Definition area of the Edit Extensions page, then click Validate to validate your design-time code. Order Management will make sure you correctly formatted your code, such as correct usage of parentheses, semicolons, and so on.

If an error occurs at runtime, then Order Management handles the error in the same way it handles any other error. It displays the cause of failure, extension name, and event name. It displays these details in the Order Management work area and in the log files. It can handle these runtime errors.

  • Reference to an attribute or method that isn't valid

  • Incorrect reference between the message name and a token

  • Incorrect reference to a web service name

Use Logging to Test Your Code

Include debugging tests during development to test your code and verify that it runs as expected.

Using Logging to Test Your Code

Note.

  • After you finish testing and are ready to deploy your extension to production, modify your debugging logic to write to a log file instead of commenting your test code. Writing to the log file can be helpful for future possible troubleshooting. If you write data to the log file in a production environment, then you must contact Oracle Support or a customer administrator to get view access to the log files that include application diagnostic data.

  • Use the log files to evaluate performance. For example, if you write a lot of extension code, then examine and monitor performance to make sure your code doesn't impact performance in a negative way.

    For example, extension code typically performs a significant amount of validation immediately after the Order Entry Specialist clicks Submit. If Order Management requires a long amount of time to finish the submit, such as five minutes, then it might be necessary to look closely at your code to determine whether it contains some logic you can streamline.

Inspect Payloads When You Use Web Services or Public View Objects

It might be difficult to examine the response from a web service or from the view criteria of a public view object. Use the setAttribute method during development to get values for the attributes that your code references, display them in the Order Management work area, then examine these values to verify your code returns the values you expect.

using the setAttribute method during development

For example, assume your extension references shipping instructions. You can use this code to write the contents of ShippingInstructions into the response from the web service.

header.setAttribute("ShippingInstructions", response.getSoapBody().getTextContext());

You can write the same data into the response from a public view object.

Make sure you convert your test code to log files or comment it ( // ) before you deploy to production.

You can also write a message to achieve a similar result. However, a message stops or pauses processing. Use a payload so processing can continue without interruption, and so you can view attribute values in the context of how they display in the Order Management work area, such as the Shipping Instructions attribute on the order line.

Use the Debug Method

Use the Debug method at various points in your code during development to write variables and other values to an attribute that you can examine in work area Order Management. This example calls debug three times, then writes the contents of debug into the ShippingInstructions attribute.

Using the Debug method at various points in your
code

You can then write your code so it displays these contents in the Shipping Instructions attribute in the Order Management work area, then examine this display output to determine the values of various attributes and variables that exist at various points in your code.

When you're ready to deploy to production, modify void debug. For example, assume you use this code to write your debug contents.

void debug(def msg) 
 {String si = header.getAttribute("ShippingInstructions"); 
 header.setAttribute("ShippingInstructions", si + ", " + msg.toString());

Modify this code so it writes to the log. You replace header.setAttribute with logger.logFine. For example.

void debug(def msg) 
 {String si = header.getAttribute("ShippingInstructions"); 
 logger.logFine("ShippingInstructions", si + ", " + msg.toString());

Use this approach so you can change only a single line in your code, which is useful if you have 10s of lines that call debug. You can also comment each line that calls the debug method, but commenting runs the risk of missing lines that call debug, or accidentally commenting a line that doesn't call debug but that's critical to your code logic.

Here's the complete code for this example.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

def poNumber = header.getAttribute("CustomerPONumber");

if( poNumber != "CreditCheck" ) return; 

// get attribute to populate in the payload
String customer = header.getAttribute("BillToCustomerName");
Long accountId = header.getAttribute("BillToCustomerIdentifier");
BigDecimal amount = new BigDecimal(1000);

// prepare the payload
String payLoad = "<ns1:creditChecking xmlns:ns1=\"http://xmlns.oracle.com/apps/financials/receivables/creditManagement/creditChecking/creditCheckingService/types/\">" +
 "<ns1:request xmlns:ns2=\"http://xmlns.oracle.com/apps/financials/receivables/creditManagement/creditChecking/creditCheckingService/\">" +
  "<ns2:CustomerName>" + customer + "</ns2:CustomerName>" +
  "<ns2:CustomerAccountNumber>" + accountId + "</ns2:CustomerAccountNumber>" + 
  "<ns2:RequestType>Authorization</ns2:RequestType>" + 
  "<ns2:PriceType>ONE_TIME</ns2:PriceType>" +
  "<ns2:RecurrencePeriod></ns2:RecurrencePeriod>" +
  "<ns2:RequestAuthorizationAmount currencyCode=\"USD\">" + amount + "</ns2:RequestAuthorizationAmount>" +
  "<ns2:RequestAuthorizationCurrency>USD</ns2:RequestAuthorizationCurrency>" +
  "<ns2:ExistingAuthorizationNumber></ns2:ExistingAuthorizationNumber>" +
  "<ns2:Requestor>ar_super_user</ns2:Requestor>" +
  "</ns1:request>" +
  "</ns1:creditChecking>";

// invoke the Check Check service using web service connector name 'CreditCheckService'. The connector is set up using task 'Manage External Interface Web Service Details'. Since this is an external service that is secured
// using message protection policy, we have registered the the https (external) URL of the service
def response = context.invokeSoapService("CreditCheckService", payLoad); 

// print a debug message. This appends the entire response to the shipping instuctions attribute. 
// Note: debug statements like these should be disabled in extensions on production instance as they can cause performance issues.
debug(response.getSoapBody().getTextContent());

// The response XML sent by the Credit Check service contains an element named 'Response'. A YES value indicates that credit check passed. Let us extract the contents of Response tag. The following XML API will return all nodes (tags)
// with name 'Response' in a NodeList element. We are expecting only one such element in our XML response
def nodeList = response.getSoapBody().getElementsByTagNameNS("*", "Response");

// print out the lenght of the node list
debug(nodeList.getLength());

// Get the first element with name 'Response' (we are expecting only one), and gets its text content
String ccResponse = nodeList.item(0).getTextContent();

debug(ccResponse);

// Check if credit check passed
if( ccResponse != 'YES' ) {
 // Credit check failed. Raise a warning validation exception here
 throw new ValidationException( new Message(Message.MessageType.WARNING, "Credit check failed.") );
}
else {
 // Credit check passed
 // Write the credit check response in an EFF attribute.
 def psiContext = header.getOrCreateContextRow("ComplianceDetails");
 psiContext.setAttribute("_ComplianceInfo", ccResponse);   
}

/**
* Appends passed in msg to the Shipping Instructions attribute. This method has been implemented only for debugging purposes.
*/
void debug(def msg) {
 String si = header.getAttribute("ShippingInstructions");
 header.setAttribute("ShippingInstructions", si + ", " + msg.toString());
}

Filter Lines In Your Extensions, Rules, and Constraints

Make sure you filter out lines that you don't want to revise when you create an order management extension or business rule, and that you constrain the changes you allow on the fulfillment line.

For example.

  • Filter out order lines that are canceled, closed, on backorder, or that Order Management has sent to billing when you create a business rule that modifies a value on a fulfillment line that's still in progress.

  • Filter out order lines you already fulfilled. For example, filter out lines you already shipped for outbound lines or lines you already received and delivered for return lines.

  • Filter so you only process changes that you make to billing attributes, for example, on the Billing tab of the order line, and only if you haven't sent the order line to billing. For example, only modify Accounting Rule, Payment Terms, Receivable Transaction Type, and so on. Don't modify any other attributes.

  • Avoid the NullPointerException error. If your logic depends on using an attribute value as part of a calculation, then filter out lines that include an attribute that doesn't contain a value.

  • Filter according to line category code. For example, to process only order lines, not return lines, filter the categoryCode attribute on the fulfillment line according to ORDER. To process only returns, filter it according to the value RETURN.

  • If you use an order management extension, pretransformation rule, or posttransformation rule to set the default values for attributes, then filter out fulfillment lines that reference the original return when you populate the value for the Accounting Rule attribute and Invoicing Rule attribute.

Here are some more topics you might find useful.

  • Filter out lines that aren't shippable. Don't attempt to ship an item that isn't shippable, such as a warranty. For an example that filters out lines that aren't shippable, see topic Select Fulfillment Lines for Orchestration Process Steps.

  • Filter out lines that reference a coverage item, such as a service agreement. To reserve means you reserve an item in inventory. You don't store a service agreement in inventory because its not a physical item, so don't reserve it. For details, see topic Another Example of Using Extensible Flexfields In Line-Selection Rules.

  • Filter out return lines that you don't want to ship on an outbound sales order. See topic Prevent Orchestration Process from Shipping Return Lines.

  • Filter out lines that already passed trade compliance. If the line passed, then don't send a request to screen the line for trade compliance. For details, see topic Use Extensible Flexfields in Line-Selection Rules.

Create Filters In an Order Management Extension

Assume you're revising a line that Order Management is currently fulfilling, so you don't want to revise lines that are closed, canceled, shipped, or that Order Management has sent to accounts receivable. Write an extension that filters the lines.

//
//===========================================================
import oracle.apps.scm.doo.common.extensions.ValidationException;

def lines = header.getAttribute("Lines");
                               
while( lines.hasNext() ) {
  def line = lines.next();
  Long referenceFlineId = line.getAttribute("ReferenceFulfillmentLineIdentifier");

  // If the reference line is null then this isn't a revision.
  if(referenceFlineId != null) {
    // Get running line if this is a revision.
    def runningLine = getLinesFromRunningOrder(referenceFlineId);

    if( runningLine == null ) {
      // We have an error condition. No fline found with referenceFlineId.
      throw new ValidationException("Something's not right. Couldn't find line using reference fline id.");
    }
   
    if (runningLine.getAttribute("FulfillLineStatusCode") == "CLOSED" ||
        runningLine.getAttribute("FulfillLineCanceledFlag")  == "Y" ||  //Line is cancelled.
        runningLine.getAttribute("FulfillLineShippedQty") != null ||  //Line is shipped.
        runningLine.getAttribute("FulfillLineInvoiceInterfacedFlag") == "Y" ){  //Line is interfaced to invoicing.
        // This line isn't valid for setting default values.
        continue;
    }
  }
  else {
    // This sales order doesn't have a revision.
    //Its ok to set the default value for attributes.
  }
  //Put your defaulting logic here.
  //line.setAttribute(<attribute name>, <value>);
}

Object getLinesFromRunningOrder(Long runningLineId) {

  // Create an instance of the FulfillLinePVO public view object (PVO).
  def flinePVO = context.getViewObject("oracle.apps.scm.doo.publicView.analytics.FulfillLinePVO");
 
  // Create a view criteria object.
  def vc = flinePVO.createViewCriteria();

  // Create a view criteria row.
  def vcrow = vc.createViewCriteriaRow();

  // Set query conditions on the view criteria row.
  vcrow.setAttribute("FulfillLineId", runningLineId);
  vc.add(vcrow);

  def rowset = flinePVO.findByViewCriteriaWithBindVars(vc, -1, new String [0], new String [0]);
 
  if (rowset.hasNext()) {
      def fline = rowset.first();     
      return fline;
  }
} 

Create Filters in Business Rules

Write a business rule that filters fulfillment lines, such as in a pretransformation rule, posttransformation rule, line-selection criteria, or assignment rule.

Here's an example line-selection criteria.

Write business rules that filter fulfillment lines.

The line-selection criteria filters out lines that can't ship so Order Management only sends shippable lines to the fulfillment system that processes shippable lines, such as the shipping system or Global Order Promising.

Note.

  • Use the Manage Orchestration Process Definitions task in the Setup and Maintenance work area.

  • Use the line-selection criteria to add the rule.

  • Add the rule to each orchestration process step that shippable affects, as necessary. For example, if the item is a warranty, then it isn't shippable. To filter out the line that isn't shippable, you probably want to add the rule to each step that references a schedule, reserve, or ship task, such as the Schedule step, the Create Reservation step, Create Shipment Request step, and so on.

  • The entire If statement isn't visible in the screen capture. Here are the entire statements.

    • DooSeededOrchestrationRules.DOOFLine.categoryCode is "ORDER"

    • DooSeededOrchestrationRules.DOOFLine.shippableFlag is "Y"

  • You can't use Visual Information Builder to select fulfillment lines. You must edit the orchestration process and use Oracle Business Rules.

Example of a Pretransformation Rule

Write a pretransformation rule where you set the value for an attribute, but only after you filter lines. For example.

  • If the order line isn't closed, canceled, shipped, or already sent to billing, then set the default value for the requested ship date attribute.

For details about how to create a posttransformation rule, see the Transformation Rules topic.

Constrain Changes You Allow on Fulfillment Lines

Constrain the changes that you allow on the fulfillment
line.

Note.

  • Use the Manage Processing Constraints task in the Setup and Maintenance work area.

  • Set the Entity attribute to Order Fulfillment Line.

  • Use the Details area to add your filters.

    Assume you don't want your users to modify a fulfillment line value, such as Ship-to Site, if the line is closed or canceled, or if it already shipped or already invoiced.

    Attribute Name Validation Operation Value String

    Canceled

    Equal To

    Yes

    Invoiced

    Equal To

    Yes

    Shipped Quantity

    Is Not Null

    -

    Status

    Equal To

    Closed

You can also create a constraint that prevents the user from submitting a sales order that doesn't include payment terms for lines that meet a specific criteria. For example, the line isn't a return line, or the line is for an internal transfer. For details, see the Control Payment Terms section in topic Guidelines for Controlling Customer Details in Order Management.

External

Call Web Services from Order Management Extensions

Use an order management extension to get data from a source that resides outside of Order Management Cloud before you do default logic or validation logic.

Use ServiceInvoker in your extension code to call a web service and get the data. ServiceInvoker is available from the context object. You use the ExecutionContext method.

You will create an example extension that. . .

  • Allocates sales credits to a salesperson for order lines that include an item that satisfies a condition.

  • References the purchase order number and item number when it calls a web service so it can get the name of the salesperson and the percent sales credit to allocate.

  • Extracts the salesperson name and percent allocation from the web service response, then creates a new row in the sales credit row set that it gets from the order line.

Summary of the Steps

  1. Register the web service.

  2. Call the web service.

  3. Determine item of interest.

This topic includes example values. You might use different values, depending on your business requirements.

Register the Web Service

  1. Go to the Manage Connector Details page, then set the value.

    Attribute Value

    Invocation Mode

    Synchronous Service

    You must use Synchronous Service with an order management extension.

    For details, see the Manage Connector Details Between Order Management and Your Fulfillment System topic.

  2. Go to the Manage Order Management Extensions page and create a new extension.

  3. Set up the call.

    Code Description

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

    Get the row set for the order lines.

    while( lines.hasNext() )

    Determine whether more lines exist that we must process.

    def line = lines.next();

    def itemNumber = line.getAttribute("ProductNumber");

    Get the item number that the line specifies.

    if( itemOfInterest(itemNumber) )

    Determine whether the item number satisfies a condition.

    allocateSalesCredits(line);

    Call the method that allocates sales credits for this line.

Call the Web Service

Add code that calls the web service so it can get the sales credit allocation.

Code Description

void allocateSalesCredits(def line, String itemNumber) {

def serviceInvoker = context.getServiceInvoker();

Get the handle that you use to call the web service.

def poNumber = header.getAttribute("CustomerPONumber");

Get the value of attribute Purchase Order Number for the customer from the order header.

String payLoad = "<ns1:GetSalesCreditAllocation xmlns:ns1=\"http://www.your_company.com/SalesCreditWS/\">" +

"<ns1:poNumber>" + poNumber + "</ns1:poNumber>" +

"<ns1:itemNumber>" + itemNumber + "</ns1:itemNumber>" +

"</ns1:GetSalesCreditAllocation>";

Concatenate the strings so you can prepare the payload. As an option, you can also use an XML API to concatenate the string.

def responseBody = serviceInvoker.invokeSoapService("SalesCreditAllocationService", payLoad).getSoapBody();

Use the interface name of the web service and the request payload to call the web service.

You must specify the interface name in the Connector Name attribute on the Manage External Interface Web Service Details page. For this example, you specify SalesCreditAllocationService as the connector name.

def salesPerson = //;

Extract the salesperson name from the response payload.

def percent = //

Extract the percent allocation from the response payload.

def salesCredits = line.getAttribute("SalesCredits");

Get the row set for the sales credit from the current line.

def salesCredit = salesCredits.createRow();

Create a sales credit row.

sc.setAttribute("Salesperson", salesPerson);

Set the value for the salesperson attribute.

sc.setAttribute("Percent", new BigDecimal(percent));

Set the value for the percent allocation attribute.

sc.setAttribute("SalesCreditTypeCode", 1L);

Set the sales credit type. In this example, assume that 1 equals Revenue credits.

salesCredits.insertRow(salesCredit);

}

Insert the new row in the row set.

The code uses parameters.

  • param line. Line where we will allocate the sales credit.

  • param itemNumber. Number of the item that you specify on the line.

Determine Item of Interest

Add code that returns a boolean value to indicate whether we are interested in the item that the web service sent.

Code Description

boolean itemOfInterest(String itemNumber) {

For brevity, this example doesn't include details about how to implement this method. The logic you use is specific to your business requirement.

if condition

return true;

else

return false

}

condition is code you write. It decides whether the item number is of interest.

Complete Code

Here's the code for this example.

//get the lines row set. 
def lines = header.getAttribute("Lines");                                     

//if more lines exist.
while( lines.hasNext() ) {                                                     

  def line = lines.next();                                                     
                               
//then get the item number that the line specifies.
  def itemNumber = line.getAttribute("ProductNumber");                         
   
//determine whether the item number satisfies the condition.
  if( itemOfInterest(itemNumber) ) {                                           

//call method to allocate sales credits for this line.
    allocateSalesCredits(line);                                                                           
  } 
} 
   
/** 
 * Call a web service that gets sales credit allocation for the order line.
 * @param line identifies the line where you allocate sales credit.
 * @param itemNumber is the number of the item that the line specifies.
 */ 
void allocateSalesCredits(def line, String itemNumber) { 

//get a handle for the method that calls the web service.
  def serviceInvoker = context.getServiceInvoker();                           
   
//get the customer attribute for the purchase order number from the order header.
  def poNumber = header.getAttribute("CustomerPONumber");                     
   
String payLoad = "<ns1:GetSalesCreditAllocation 

//concatenate the strings to prepare the payload. 
xmlns:ns1=\"http://your.address/SalesCreditWS/\">" +        
//As an alternative, you can also use the following code. 
  "<ns1:poNumber>" + poNumber + "</ns1:poNumber>" +         
  //XML APIs 
  "<ns1:itemNumber>" + itemNumber + "</ns1:itemNumber>" + 
  "</ns1:GetSalesCreditAllocation>"; 
   
  def responseBody = 

//use the web service name and the constructed payload to call the service.
serviceInvoker.invokeSoapService("SalesCreditAllocationService", 
payLoad).getSoapBody(); 
   
//get the salesperson name from the web service response.
  def salesPerson = //;                                                       

//get the percent allocation from the service response.
  def percent = //                                                             
   
//get the row set for the sales credit for the current line.
  def salesCredits = line.getAttribute("SalesCredits");                       

//create a new row for the sales credit.
  def salesCredit = salesCredits.createRow();                                 

//set the salesperson attribute.
  sc.setAttribute("Salesperson", salesPerson);                                 

//set the percent allocation attribute.
  sc.setAttribute("Percent", new BigDecimal(percent));                         

//set the sales credit type. This code assumes your implementation uses the value 1 for revenue credits.
  sc.setAttribute("SalesCreditTypeCode", 1L);                                 

//set a unique identifier in case more than one SalesCredit exists. For example, 5768342869.         
  salesperson.setAttribute("SourceTransactionSalesCreditIdentifier',5768342869);                     

//insert the new row in the rowset.
  salesCredits.insertRow(salesCredit);       

} 
  
/** 
 *Return a boolean that indicates whether the item is of interest. 
 */ 
boolean itemOfInterest(String itemNumber) { 

//For brevity, and to keep focus on calling the web service, 
//this example does not include details about how to implement this method. 
//The logic you use is specific to your business process.
  
//Decide whether the item number is of interest. Pseudocode:
  // if (some condition) 
        return true; 
  // else 
  //    return false 
} 

Here's the same code without comments.

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

while( lines.hasNext() ) {                                                     
  def line = lines.next();                                              
  def itemNumber = line.getAttribute("ProductNumber");                         
   
  if( itemOfInterest(itemNumber) ) {                                           
    allocateSalesCredits(line);                                        
  } 
} 
void allocateSalesCredits(def line, String itemNumber) { 
  def serviceInvoker = context.getServiceInvoker();                           
  def poNumber = header.getAttribute("CustomerPONumber");                     
   
String payLoad = "<ns1:GetSalesCreditAllocation 

xmlns:ns1=\"http://your.address/SalesCreditWS/\">" +        

serviceInvoker.invokeSoapService("SalesCreditAllocationService", 
payLoad).getSoapBody(); 
  def salesPerson = //;                                                       
  def percent = //                                                             
  def salesCredits = line.getAttribute("SalesCredits");                       
  def salesCredit = salesCredits.createRow();                                 
  sc.setAttribute("Salesperson", salesPerson);                                 
  sc.setAttribute("Percent", new BigDecimal(percent));                         
  sc.setAttribute("SalesCreditTypeCode", 1L);                                 
  salesperson.setAttribute("SourceTransactionSalesCreditIdentifier',5768342869);
  salesCredits.insertRow(salesCredit);       

} 
boolean itemOfInterest(String itemNumber) { 

//implement this method.
  
//Decide whether the item number is of interest. Pseudocode:
  // if (some condition) 
       return true; 
  // else 
  //   return false 
} 

Use Extensions to Access Data Outside of Order Management

Write an order management extension that calls an API on the context object so it queries the table and accesses the public view objects that the table contains.

If you deploy into Oracle Fusion Cloud, then you can't programmatically access the Oracle database. You can't use PL, SQL, or JDBC to access data in other application tables. Write an extension instead.

Here's an example extension that accesses a public view object.

Code Description

def itemPVO = context.getViewObject("oracle.apps.scm.productModel.items.publicView.ItemPVO");

Create an instance of the public view object for the item. You must specify the entire name of the public view object.

This code uses each public view object as a row iterator, so the methods on the RowIterator interface are also available on each public view object. You can use the RowSetIterator method to access a method that gets the rows that the view object query returns, and to navigate the row set for the public view object. For details, see the ViewObject method in the Methods You Can Use with Order Management Extensions topic.

def item = itemPVO.first();

Access the first item.

Here's the public view objects you typically use.

Data View Object Name

Sales Order

HeaderPVO

FulfillLinePVO

Item

ItemPVO

ItemCategoryPVO

Customer

PartyPVO

PartySitePVO

LocationPVO

Customer Account

CustomerAccountPVO

CustomerAccountSitePVO

CustomerAccountSiteUsePVO

Receivable

TransactionTypePVO

To get a complete list of the public view objects you can use, the attributes they contain, and to help determine the view object you need, see Public View Objects in Oracle Applications Cloud (Document ID 2386411.1) on My Oracle Support.

Using View Criteria Objects to Filter Results

The example above is only for demonstration purposes. Its too simplistic for practical use because it gets arbitrary items from the items table. Its more likely that you must query for an item or a set of items that match a criterion. To support SQL, your extension must provide a WHERE clause that only selects rows that match a criterion. Use the ViewCriteria object for this purpose.

An order management extension can create a view criteria object that adds filtering logic to the public view object before it gets data from these objects. A view criteria object is a filter that you create and apply programmatically to a view object. Order Management converts each of these filters into a WHERE clause when your extension runs the query that you define in the public view object.

You use the view criteria row object to create a view criteria object. The view criteria object contains the attribute names and attribute values that become part of the WHERE clause.

You will create an extension that. . .

  • Creates a view criteria and uses it to query a public view object.

  • Queries the item master for an item according to the item Id and inventory organization Id.

  • Examines the HazardousMaterialFlag attribute on the item.

  • If the HazardousMaterialFlag attribute flags the item as hazardous, then the extension sets the Shipping Instruction flexfield context segment to indicate that the item needs hazardous handling.

This topic includes example values. You might use different values, depending on your business requirements.

Use view criteria objects to filter results.

  1. Get the item.

    Code Description

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

    Get the row set for the order lines.

    while( lines.hasNext() ) {

    Determine whether we must process more order lines.

    def line = lines.next();

    Get the next line and assign it to the variable line.

    def inventoryItemId = line.getAttribute("ProductIdentifier");

    Get the inventory item Id for the item from the order line that the Order Entry Specialist selected.

    def orgId = line.getAttribute("InventoryOrganizationIdentifier");

    Get the organization for the item from the order line that the Order Entry Specialist selected.

    def item = getItem(inventoryItemId, orgId);

    Get the item. Use the item Id and the organization Id to call the getItem method.

    String hazardous = item.getAttribute("HazardousMaterialFlag");

    Get the HazardousMaterialFlag attribute from the item.

    if( "Y".equals(hazardous) ) {

    Determine whether HazardousMaterialFlag flags the item as hazardous.

    def packShipInstruction = line. getOrCreateContextRow("PackShipInstruction");

    Get the row for the extensible flexfield context named PackShipInstruction.

    packShipInstruction.setAttribute("_ShippingInstruction", "Hazardous Handling Required.");

    Set the Shipping Instruction context segment.

  2. Define the public view object.

    Code Description

    Object getItem(Long itemId, Long orgId) {

    def itemPVO = context.getViewObject("oracle.apps.

    scm.productModel.items.publicView.ItemPVO");

    Create an instance of the public view object for the item.

    def vc = itemPVO.createViewCriteria();

    Create the view criteria object.

    def vcrow = vc.createViewCriteriaRow();

    Create the view criteria row.

    vcrow.setAttribute("InventoryItemId", itemId);

    Set the inventory item attribute so you can include it in the filter condition, and set the value that you will use to compare to this attribute.

    vcrow.setAttribute("OrganizationId", orgId);

    Set the organization attribute so you can include it in the filter condition, and set the value that you will use to compare to this attribute.

    def rowset = itemPVO.findByViewCriteria(vc, -1);

    Define the view criteria that filters the rows when you query the public view object.

    def item = rowset.first();

    Get the first item row that meets the condition.

    The code uses parameters.

    • param itemId. Inventory item Id that identifies the item.

    • param orgId. Inventory organization Id that identifies the organization that owns of the item.

Code Without Comments

Here's the entire code for this example with no comments.

def lines = header.getAttribute("Lines");                                                             
while( lines.hasNext() ) {                                                                            
  def line = lines.next();                                                                            
  def inventoryItemId = line.getAttribute("ProductIdentifier");                                       
  def orgId = line.getAttribute("InventoryOrganizationIdentifier");                                   
  def item = getItem(inventoryItemId, orgId);                                                         
  String hazardous = item.getAttribute("HazardousMaterialFlag");                                      
  if( "Y".equals(hazardous) ) {                                                                       
def packShipInstruction = line. getOrCreateContextRow("PackShipInstruction");                     
packShipInstruction.setAttribute("_ShippingInstruction", "Hazardous Handling Required.");         
  } 
}

Object getItem(Long itemId, Long orgId) {
def itemPVO = context.getViewObject("oracle.apps.scm.productModel.items.publicView.ItemPVO");        
  def vc = itemPVO.createViewCriteria();                                                               
  def vcrow = vc.createViewCriteriaRow();                                                              
  vcrow.setAttribute("InventoryItemId", itemId);                                                       
  vcrow.setAttribute("OrganizationId", orgId);                                                         
  def rowset = itemPVO.findByViewCriteria(vc, -1);                                                     
  def item = rowset.first();                                                                           
  return item;
}

Messages

Use Messages in Your Order Management Extensions

Create an order management extension to raise a validation error that indicates a sales order requires correction before Order Management Cloud submits it to order fulfillment.

  • To raise a validation error, Order Management creates a validation exception, stops running the extension that failed, then runs a subsequent extension for this extension point that you set up.

  • Order Management accumulates each message that it creates from validation exceptions for all the extensions that it runs during the extension point, then displays them together to the Order Entry Specialist or, if its a source order from a source system, returns them through a web service call in the response to the caller.

If Order Management creates a validation exception, then your extension code must send a message that describes the cause of the failure. You must do one of.

  • Add the message text to your extension. You must specify Distributed Order Orchestration as the application for the message. Order Management will display this text in the Order Management work area without modification.

  • Add the name of an Oracle Fusion message and message parameters in your extension. Order Management will get the message from the Oracle Fusion message repository, populate any message tokens that the message references, display the message in the Order Management work area, then add it to the message log. You can use the Manage Messages page to create a message. For details, see the Create Messages in Order Management topic.

This topic frequently mentions ValidationException. For details, see the ValidationException method in the Methods You Can Use with Order Management Extensions topic.

Here's the code that creates a validation exception.

Code Description

import oracle.apps.scm.doo.common.extensions.ValidationException;

Import the ValidationException class.

def salesCredits = header.getAttribute("SalesCredits");

Get the row set for the sales credits that the order header references.

while( salesCredits.hasNext() )

Determine whether more sales credit rows exist.

def salesCredit = salesCredits.next();

Get the next sales credit row.

if( "1".equals(salesCredit.getAttribute("SalesCreditTypeCode")) )

Determine whether the sales credit is a revenue percent.

def percent = salesCredit.getAttribute("Percent");

Get the percent allocation of the sales credit.

if( percent < 30 ) {

If percent is less than 30, then create a validation error.

def tokens = [SALESPERSON: salesCredit.getAttribute("Salesperson"), PERCENT: percent];

Specify the token values to send to ValidationException.

throw new ValidationException("SALES_CREDIT_TOO_LOW_MSG", tokens);

Create the exception, and then stop the execution.

Here's the same code without comments.

import oracle.apps.scm.doo.common.extensions.ValidationException;
def salesCredits = header.getAttribute("SalesCredits");                                          
while( salesCredits.hasNext() ) {                                                                
def salesCredit = salesCredits.next();                                                         
if( "1".equals(salesCredit.getAttribute("SalesCreditTypeCode")) ) {                            
  def percent = salesCredit.getAttribute("Percent");                                           
  if( percent < 30 ) {                                                                        
def tokens = [SALESPERSON: salesCredit.getAttribute("Salesperson"), PERCENT: percent];     
    throw new ValidationException("SALES_CREDIT_TOO_LOW_MSG", tokens);   
    }
  } 
}

Hard Coding the Message

Here's a variation that creates a validation exception that hard codes the message text. You replace def tokens and throw new with this code.

String messageText = "The " + percent  + "% sales credit for salesperson " + salesperson + " is less than the required minimum, which is 30%.";
throw new ValidationException(messageText);

For example, if percent equals 20, and if salesperson equals Diane Cho, then here's the text that displays at run time.

The 20% sales credit for salesperson Diane Cho is less than the required minimum, which is 30%.

Reference Request Functions

Here's a variation that creates a validation exception that references a request function that you define instead of the default function that comes predefined with Order Management. You replace def tokens and throw new with this code.

def tokens = [SALESPERSON: salesCredit.getAttribute("Salesperson"), PERCENT: percent];
throw new ValidationException("ORA_CUSTOM_REQ_FUNCTION", "SALES_CREDIT_TOO_LOW_MSG", tokens);
Raise More Than One Validation Message

In the example above, the extension stops running as soon as it finds one sales credit record that doesn't meet the requirement, then reports the error. This extension code doesn't create or use a Message object but instead works directly against the ValidationException class.

An extension can create one or more instances of a Message object before calling ValidationException. Use this capability to report all sales credit rows that fail the requirement, and to control how you code your extension.

Here's an example that uses the Message object and provides detailed error reporting. It reports all sales credit rows that fail validation.

Code Description

import oracle.apps.scm.doo.common.extensions.ValidationException;

Import the ValidationException class so you can construct a ValidationMessage object.

import oracle.apps.scm.doo.common.extensions.Message;

Import the Message class so you can construct a Message object.

def salesCredits = header.getAttribute("SalesCredits");

Get the row set for the sales credits that the order header references.

List<Message> msgs = new ArrayList<Message>();

while( salesCredits.hasNext() )

Determine whether more sales credit rows exist that we must process.

def salesCredit = salesCredits.next();

Get the next sales credit row.

if( "1".equals(salesCredit.getAttribute("SalesCreditTypeCode")) ) {

Determine whether the sales credit is a revenue percent.

def percent = salesCredit.getAttribute("Percent");

Get the percent allocation of the sales credit.

if( percent < 30 ) {

If percent is less than 30, then create a validation error.

def tokens = [SALESPERSON: salesCredit.getAttribute("Salesperson"), PERCENT: percent];

Specify the token values to send to ValidationException.

Message msg = new Message(Message.MessageType.ERROR, "SALES_CREDIT_TOO_LOW_MSG", tokens);

Create a new message.

msgs.add(msg);

Accumulate each message in a list.

if( !msgs.isEmpty() ) {

If the msgs list isn't empty, then at least one sales credit row is in error.

throw new ValidationException(msgs);

Create and throw ValidationException.

Here's the same code without comments.

import oracle.apps.scm.doo.common.extensions.ValidationException;                                
import oracle.apps.scm.doo.common.extensions.Message;                                            
def salesCredits = header.getAttribute("SalesCredits");                                          
List<Message> msgs = new ArrayList<Message>();
while( salesCredits.hasNext() ) {                                                                
  def salesCredit = salesCredits.next();                                                         
  if( "1".equals(salesCredit.getAttribute("SalesCreditTypeCode")) ) {                            
    def percent = salesCredit.getAttribute("Percent");                                           
    if( percent < 30 ) {                              
def tokens = [SALESPERSON: salesCredit.getAttribute("Salesperson"), PERCENT: percent]; 
Message msg = new Message(Message.MessageType.ERROR, "SALES_CREDIT_TOO_LOW_MSG", tokens);  
msgs.add(msg);                                                                             
    }
  } 
}
if( !msgs.isEmpty() ) {                                                                          
  throw new ValidationException(msgs);                                                           
}

Write Error Messages to Logs When Using Order Management Extensions

Create an order management extension that writes log messages to the same applications log file and uses the same application settings that an Oracle Fusion application uses.

Avoid degrading performance during logging.

  • Use the SEVERE logging level only for extremely important conditions, such as a read error condition. Logging all events as SEVERE will produce a large number of log messages and degrade performance.

  • Use the FINEST logging level to get detailed reporting. Use FINEST for entry and exit logging. The Logger Method can write logs at different levels.

  • Avoid concatenating strings. If your log statement must concatenate strings, then write your code so it makes sure logging for the targeted logging level is enabled before you concatenate.

    Use the Logger method to avoid code readability problems that sometimes occur when you write code that makes sure the logging level is enabled, and when you include this code for every log statement. The Logger Method provides an alternative way to log for each level. It can use a format string and parameters as input. It can substitute the parameters in the format string only if the logging is enabled at the targeted level before writing to the log. This approach postpones string manipulation until your code confirms that logging is enabled.

For details about how to set log levels, see java.util.logging.Level on the Java Platform, Standard Edition 7 API Specification website at https://docs.oracle.com/javase/7/docs/api/java/util/logging/Level.html.

This topic includes example values. You might use different values, depending on your business requirements.

Write error messages to logs when using order management extensions:

  1. Write to the log.

    Code Description

    def logger = context.getLogger();

    Get the logger object from the context. The first few lines have been left out of the example.

    def item = getItem(inventoryItemId, orgId);

    Get the item. Use item Id and organization Id when calling the getItem method.

    String hazardous = item.getAttribute("HazardousMaterialFlag");

    Get the HazardousMaterialFlag attribute from the item.

    if( "Y".equals(hazardous) ) {

    Determine whether the item is hazardous.

    logger.logFinest("Found line with hazardous item %s, %s", inventoryItemId, orgId);

    Log at the finest level. Note that the string format provides the first argument and the subsequent arguments provide the parameters.

    def packShipInstruction = line. getOrCreateContextRow("PackShipInstruction");

    Get the row for the extensible flexfield context named PackShipInstruction.

    packShipInstruction.setAttribute("_ShippingInstruction", "Hazardous Handling Required.");

    Set the context segment for Shipping Instruction.

  2. Define the public view object.

    Code Description

    Object getItem(Long itemId, Long orgId, def logger) {

    logger.logFiner("Entering method getItem");

    def itemPVO = context.getViewObject("oracle.apps.scm.productModel.items.publicView.ItemPVO");

    Create an instance of a public view object named Item. Specify to log at the FINER level.

    def vc = itemPVO.createViewCriteria();

    Create the view criteria object.

    def vcrow = vc.createViewCriteriaRow();

    Create the view criteria row.

    vcrow.setAttribute("InventoryItemId", itemId);

    Set the inventory item attribute to include in the filter condition and the value to use when comparing against this attribute.

    vcrow.setAttribute("OrganizationId", orgId);

    Set the organization attribute to include in the filter condition and the value to use when comparing against this attribute.

    def rowset = itemPVO.findByViewCriteria(vc, -1);

    Specify the view criteria to filter rows and query the view object.

    def item = rowset.first();

    Get the first item row that matches the condition.

    logger.logFiner("Exiting method getItem: itemNumber %s", item.getAttribute("ItemNumber"));

    Specify to log at the FINER level. Exit the log.

    The code uses parameters.

    • param itemId. Inventory item Id that identifies the item.

    • param orgId. Inventory organization Id that identifies the organization that owns the item.

Here's the same code with no comments.

def logger = context.getLogger();                                                                   
def item = getItem(inventoryItemId, orgId);                                                         
String hazardous = item.getAttribute("HazardousMaterialFlag");                                      
if( "Y".equals(hazardous) ) {                                                                       
	logger.logFinest("Found line with hazardous item %s, %s", inventoryItemId, orgId);                
	def packShipInstruction = line. getOrCreateContextRow("PackShipInstruction");                     
	packShipInstruction.setAttribute("_ShippingInstruction", "Hazardous Handling Required.");         
}
Object getItem(Long itemId, Long orgId, def logger) {
	logger.logFiner("Entering method getItem");
	def itemPVO = context.getViewObject("oracle.apps.scm.productModel.items.publicView.ItemPVO");
	def vc = itemPVO.createViewCriteria();                                                               
	def vcrow = vc.createViewCriteriaRow();                                                              
	vcrow.setAttribute("InventoryItemId", itemId);                                                       
	vcrow.setAttribute("OrganizationId", orgId);                                                         
	def rowset = itemPVO.findByViewCriteria(vc, -1);                                                     
	def item = rowset.first();                                                                           
	logger.logFiner("Exiting method getItem: itemNumber %s", item.getAttribute("ItemNumber"));           
	return item;
}

Examples

Use Extensions to Update the Order Submit Date

Create an extension that uses an extensible flexfield to update the order submit date.

This topic includes example values. You might use different values, depending on your business requirements.

  1. Create an extensible flexfield.

    Attribute Value

    Name

    H1AttributeDateTime1

    Category

    Additional Header Information

    Context

    HeaderContext1

    For details about how to create an extensible flexfield, see the Set Up Extensible Flexfields in Order Management topic.

  2. In the Setup and Maintenance work area, go to the task.

    • Offering: Order Management

    • Functional Area: Orders

    • Task: Manage Order Management Extensions

  3. On the Manage Order Management Extensions page, notice the elements.

    • Three tabs, one for each extension point.

    • A Sequence column. Order Management runs the extensions for each extension point sequentially according to the values in the Sequence column. For example, if the first row contains a value of 10, the second row a value of 30, and the third row a value of 20, then Order Management will run row one, row three, and then row two.

  4. On the Manage Order Management Extensions page, click Actions > Create New.

  5. In the Create Extension dialog, accept the default values, then click OK.

    The Use Existing option creates a reference to an extension that already exists. It doesn't create a copy. For example, assume an extension named My_Extension already exists on the On Save extension point. Assume you set Use Existing to My_Extension when you create an extension on the On Start of Submission Request extension point. If you modify My_Extension from On Start of Submission Request at any point in the future, then Order Management will automatically update My_Extension for On Save with your modification. If you modify My_Extension for On Save, then Order Management will update My_Extension for On Start of Submission Request.

  6. On the Create Extension page, on the On Start of Submission Request tab, enter values.

    Attribute Value

    Name

    Update Order Submit Date

    Description

    This extension sets the value of an extensible flexfield to the date and time when Order Management submitted the sales order.

  7. In the Definition area, add code.

    // Make sure the extension runs only for your test sales order. If multiple developers use your test environment, then this condition makes sure the code updates only your sales order. You must remove this condition in a production environment.
    def poNumber = header.getAttribute("CustomerPONumber");
    if( !"UpdateOrderSubmissionDate".equals(poNumber) ) return;
    
    // Get the current time, and then create an instance of java.sql.Date, and set it to the current time.
    long currentTime = new Date().getTime();
    def date = new java.sql.Date(currentTime);
    
    // Get the row for the flexfield context named HeaderContext1.
    def flexfieldContext = header.getOrCreateContextRow("HeaderContext1");
    
    // Set the date on the attribute named _H1AttributeDateTime1 to the current date. Use flexfieldContext to identify the flexfield context where _H1AttributeDateTime1 resides, which is HeaderContext1.
    flexfieldContext.setAttribute("_H1AttributeDateTime1", date);
  8. Click Validate > Save and Close.

Test Your Set Up

  1. Navigate to the Order Management work area, create a new sales order, then click Submit.

    Attribute Value

    Purchase Order

    UpdateOrderSubmitDate_run_extension

  2. Click Actions > View Additional Information.

  3. In the Additional Information dialog, click HeaderEFFDetails, then verify that the dialog displays the value.

    Attribute Value

    H1AttributeDateTime1

    The current date and time. For example:

    04/01/17 6:25 PM

Use Extensions to Validate Relationships Between Attributes

Create an order management extension that makes sure the sales order includes a relationship between the sold-to customer and the ship-to customer, and between the sold-to customer and bill-to customer.

If one of these relationships doesn't exist when the user attempts to submit the sales order, then the extension stops the sales order from proceeding and displays an error message.

This topic includes example values. You might use different values, depending on your business requirements.

  1. In the Setup and Maintenance work area, go to the task.

    • Offering: Order Management

    • Functional Area: Orders

    • Task: Manage Order Management Extensions

  2. On the Manage Order Management Extensions page, on the On Start of Submission Request tab, create a new extension.

    Attribute Value

    Name

    Validate Relationships Between Attributes

    Description

    Make sure a relationship exists between the sold-to customer and the ship-to customer, and between the sold-to customer and the bill-to customer. If one of these relationships doesn't exist, then create an error and stop the sales order from proceeding.

  3. In the Definition area, add code.

    //import classes for validation exceptions and messages from Oracle Trading Community Architecture.
    import oracle.apps.scm.doo.common.extensions.ValidationException;
    import oracle.apps.scom.doo.comm.extensions.Message;
    
    // Make sure the extension runs only for your test sales order. If multiple developers use your test environment, then this condition makes sure the code updates only your sales order. You must remove this condition in a production environment.
    def poNumber = header.getAttribute("CustomerPONumber" );
    if(poNumber == null) return;
    if( !poNumber.startsWith("MatchRelationship") ) return;
    boolean relationExists=false;
    
    //define the variables you will use to store the identifiers.
    def soldTo = header.getAttribute("BuyingPartyIdentifier")
    def billTo = header.getAttribute("BillToCustomerIdentifier")
    
    //if the relationship exists, then further validation is not necessary, so save the sales order, and then exit.
    if (header.getAttribute("BuyingPartyName")==header.getAttribute("BillToCustomerName"))
      relationExists=true;
    
    //determine what relationship currently exists between the bill-to customer and the sold-to customer.
    //reference the view object that stores the relationship. In this example, the CustomerAccountRelationship view object stores this relationship.
    def CustPVO = context.getViewObject("oracle.apps.cdm.foundation.parties.publicView.customerAccounts.CustomerAccountRelationshipPVO");
    
    //create the view criteria. 
    def vc = CustPVO.createViewCriteria();
    def vcrow = vc.createViewCriteriaRow();
    //RelatedCustAccountId is an attribute that stores the sold-to relationship, so you set vcrow to reference RelatedCustAccountId. You will examine it to determine whether the sold-to customer is related to the bill-to customer.
    vcrow.setAttribute("RelatedCustAccountId", soldTo);
    //Query the view object according to the criteria that you set in the previous line of code.
    def rowSet = CustPVO.findByViewCriteria(vc, -1);
    
    //Read through the row set. If a row exists that contains a relationship, then you have determined that a relationship exists between sold-to and bill-to, so save the sales order, and then exit.
    while (rowSet.hasNext()) {
      def row = rowSet.next();
      def billtorelation=row.getAttribute("CustAccountId")
      if (billtorelation == billTo)
      {
        relationExists=true;
      }
    }
    //Create an exception when a relationship does not exist and display an error message.
    //header.setAttribute("ShippingInstructions", header.getAttribute("ShippingInstructions") + ", " relationExists)
    
    if( !relationExists) {
    throw new ValidationException("The order submit failed because the bill-to customer is not related to the sold-to customer.");
    }
    

    This example is only for demonstration purposes in a development environment. It hard codes the message to display in the Order Management work area in the English language as The order submit failed because the bill-to customer is not related to the sold-to customer. To avoid problems with translation to other languages, don't code the message in a production environment.

    Instead, here's some code you can use to reference a message from the messaging framework.

    throw new ValidationException("lookup_code", "message name", token_values);

    where

    • lookup_code determines where and how to display the message in the Order Management work area. For example, you can reference more than one lookup code to display messages in different pie slices on the infolets in the Order Management work area, according to lookup code.

    • message name identifies the name of the message that exists in the messaging framework.

    • token_values specifies a list of the values to use in the tokens that the message contains. If the message doesn't contain any tokens, then use null.

    For example, here's some code that displays the contents of the FOM_CMN_INV_BILL_TO message.

    throw new ValidationException("ORA_MANAGE_EXTENSIONS", "FOM_CMN_INV_BILL_TO", null);

    For details about using lookup_code, see the ValidationException method in the Methods You Can Use with Order Management Extensions topic.

Test Your Set Up

  1. Navigate to the Order Management work area, create a new sales order, then click Submit.

    Attribute Value

    Customer

    Computer Service and Rentals

    Bill-to Customer

    Business World Inc.

    Purchase Order

    ValidateRelationshipsBetweenAttributes _run_extension

  2. Verify that the error dialog displays the message you coded.

    Computer Service and Rentals is the sold-to customer, Business World Inc is the bill-to customer, they don't match, so Order Management displays an error.

  3. Set the value, then click Submit.

    Attribute Value

    Bill-to Customer

    Computer Service and Rentals

  4. Verify that Order Management submits the sales order and sets the status to Processing.

    Computer Service and Rentals is the sold-to customer and the bill-to customer, they match, so Order Management processes the sales order.

Use Extensions to Verify Data That Users Enter

Create an order management extension that determines whether a purchase order exists for the purchase order number that the Order Entry Specialist enters in the Purchase Order attribute.

It calls a public view object to get data from Oracle Fusion Procurement.

For demonstration purposes, this example hard codes some values, such as HW INTERNAL. Your environment will likely require different variable values.

This topic includes example values. You might use different values, depending on your business requirements.

  1. In the Setup and Maintenance work area, go to the task.

    • Offering: Order Management

    • Functional Area: Orders

    • Task: Manage Order Management Extensions

  2. On the Manage Order Management Extensions page, on the On Start of Submission Request tab, create a new extension.

    Attribute Value

    Name

    Verify That the Purchase Order Exists

    Description

    Determine whether a purchase order exists for the purchase order number that the Order Entry Specialist enters in the Purchase Order attribute.

  3. In the Definition area, add code.

    //Import classes for validation exceptions and messages from Oracle Trading Community Architecture.
    import oracle.apps.scm.doo.common.extensions.ValidationException;
    
    def orderType = header.getAttribute("TransactionTypeCode");
    
    //Determine whether the sales order is internal.
    if(orderType != null && orderType.contains("HW INTERNAL")) {
    
      //Determine whether the purchase order exists.
      String poNumber = header.getAttribute("CustomerPONumber");
    
      boolean poExists = false;
      if( poNumber != null ) {
    
    //Get the PVO you need to access purchase orders.
    def poPVO = context.getViewObject("oracle.apps.prc.po.publicView.PurchasingDocumentHeaderPVO");
          
    //Create the view criteria. Use where clause predicates.
    def vc = poPVO.createViewCriteria();
    def vcrow = vc.createViewCriteriaRow();
    vcrow.setAttribute("Segment1", poNumber);
         
    //Query the view object to find a matching row.
    def rowset = poPVO.findByViewCriteriaWithBindVars(vc, 1, new String [0], new String [0]);
          
    //Determine whether a matching row exists.
    poExists = rowset.hasNext();
    }
    
    //If a matching row does not exist, then the purchase order that the user entered does not exist. Create a validation error and stop the sales order submit.
      if( !poExists ) {
    throw new ValidationException("ORA_MANAGE_EXTENSIONS",   "DOO_EXT_HW_INTERNAL_PO_REQD", null);
      }    
    }
    

Use Extensions to Cancel Order Lines

Create an extension that uses an extensible flexfield to cancel order lines in a sales order.

Assume your customer places a sales order for items you can't fulfill because the items have become obsolete and your supplier no longer supplies the item. You can use an order management extension to cancel lines that contain a value, such as Obsolete, in an extensible flexfield.

This topic includes example values. You might use different values, depending on your business requirements.

  1. Create the extensible flexfield.

    • Add it to the Fulfillment Line Information flexfield. Use these values.

      Attribute Value

      Name

      CancelLine

      Category

      Additional Fulfillment Line Information

      Context

      ProductObsoleteContext

    • Set values on the Create Segment page.

      Attribute Value

      Name

      CancelLine

      Code

      CancelLine

      API Name

      cancelline

      Enabled

      Contains a check mark.

      Data type

      Character

      Table Column

      ATTRIBUTE_CHAR2

      Value Set

      10 Characters

      Prompt

      Cancel Line

      Display Type

      Text Box

    • Publish and deploy your flexfield.

    For details about how to create an extensible flexfield, see the Set Up Extensible Flexfields in Order Management topic.

  2. Create your extension.

    • In the Setup and Maintenance work area, go to the task.

      • Offering: Order Management

      • Functional Area: Orders

      • Task: Manage Order Management Extensions

    • On the Create Extension page, on the On Start of Submission Request tab, enter values.

      Attribute Value

      Name

      Cancel Order Quantity

      Description

      This extension examines the value of an extensible flexfield on an order line to determine whether to cancel the line.

    • In the Definition area, add code.

      import oracle.apps.scm.doo.common.extensions.ValidationException;
       
      def poNumber = header.getAttribute("CustomerPONumber");
      if( !"CancelOrderQuantity".equals(poNumber) ) 
      return;
      
      def lines = header.getAttribute("Lines");
      
      if(lines == null)
      return;
      
      while(lines.hasNext()){
      
         def line = lines.next();
         
         //Get the row for the flexfield context named ProductObsoleteContext.
         //Use the code value for the context as the argument to get the context row.
         
         def context = line.getOrCreateContextRow("ProductObsoleteContext");
      
         if(context == null)
         throw new ValidationException("Context ProductObsoleteContext was null");
         
         def cancelLineEffVal = context.getAttribute("cancelline");
         
         if("Y".equals(cancelLineEffVal)){
           line.setAttribute("OrderedQuantity",0);
         } 
      
      }
    • Click Validate > Save and Close.

Test Your Setup

Create a test sales order for customer Computer Service and Rentals.

  1. Create the sales order.

    • Go to the Order Management work area and create a new sales order.

      Set attributes on the order header.

      Attribute Value

      Customer

      Computer Service and Rentals

      Order Type

      Standard Orders

    • Add an order line that contains an item that isn't configured.

    • Click Submit.

  2. Wait for the order line status to change to Awaiting Shipping. Click Refresh to update the status.

  3. Revise your sales order.

    • On the Manage Orders page, click Actions > Create Revision

    • On the Create Revision page, set the attribute on the order header.

      Attribute Value

      Purchase Order

      CancelOrderQuantity

    • Click an order line, then click Update Lines.

    • On the Update Lines page, move the Additional Information attribute to the Selected window, then click Next.

    • In the Specify values area, click Update Additional Information.

    • In the dialog that opens, click CancelLine.

    • In the ProductObsoleteContext area, in the window next to CancelLine, enter "Y".

      You must include the double quotation marks.

    • Click Ok, then click Update.

  4. Verify that Order Management changed the quantity on the order line to 0, and canceled the line.

Use Extensions to Get Values for Return Orders

A return order doesn't include values from the original order on some order line attributes. For example, the return line doesn't include the original value for the sales credit or purchase order number. You can use an extension to get the value from the original order line.

Here are some examples you can use to get values from the original order when you use a return material authorization (RMA).

Get Order Type from Original Sales Order

Get the order type from the original sales order and use it to set the value of the order type of a return order.

// Extension : DefaultOrderTypeFromOrigOrder
//
//===========================================================
import oracle.apps.scm.doo.common.extensions.ValidationException;

// Go through all the order lines. We're interested in return lines. As soon as we find a return line, we will use the document
// reference on the line to try to locate the original order.
def lines=header.getAttribute(""Lines"");

while (lines.hasNext()) {

    def line=lines.next();

    // Get the line type specified on the line. A line type code of ORA_RETURN means its a return line.
    String lineTypeCode=line.getAttribute(""TransactionLineTypeCode"");

    if (""ORA_RETURN""==lineTypeCode) {
        // We have a return line. Now let's find the original order.
        // We will go through the document references on this line to locate the document reference
        // that identifies the original order.
        def docRefs=line.getAttribute(""DocumentReferences"");

        while (docRefs.hasNext()) {
            def docRef=docRefs.next();
            String docRefType=docRef.getAttribute(""DocumentReferenceType"");

            if (""ORIGINAL_ORCHESTRATION_ORDER""==docRefType) {
                // We found the document reference that points to the original order.
                // The DocumentIdentifier attribute is the header id of the original order.
                Long headerId=new Long(docRef.getAttribute(""DocumentIdentifier""));
                // Call the getOrderType method to get the order type of the original order using a PVO
                String orderTypeCode=getOrderType(headerId);

                debug(""Original Order Order Type: ""+ orderTypeCode);

                // If order type isn't null, set it on the current order, else raise a validation exception.
                if (orderTypeCode !=null) {
                    header.setAttribute(""TransactionTypeCode"", orderTypeCode);
                    break;
                }

                else {
                    throw new ValidationException(""Order type isn't specified on the original order."");
                }
            }
        }
    }
}

/**
* Returns the order type of the indicated order.
*/
String getOrderType(Long headerId) {
    debug(""finding order by headerId: ""+ headerId);

    def vo=context.getViewObject(""oracle.apps.scm.doo.publicView.analytics.HeaderPVO"");

    Object[] rows=vo.findByKey(headerId, 1);
    def originalHeader=rows[0];

    return originalHeader.getAttribute(""OrderTypeCode"");
}

Get Purchase Order from Original Sales Order

Get purchase order details from the order header and order line of the original order, then copy them to the return order and return order line.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
import java.util.logging.Level;
Long lineId = 0;
Long headerId = 0;
def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
  def line = lines.next();
  String categoryCode = line.getAttribute("TransactionCategoryCode");

  if ("RETURN" != categoryCode) continue;
    def docRefs = line.getAttribute("DocumentReferences");
    lineId = 0;
    while (docRefs.hasNext() & lineId == 0) {
      def docRef = docRefs.next();
      String docRefType = docRef.getAttribute("DocumentReferenceType");

      if ("ORIGINAL_ORCHESTRATION_ORDER" == docRefType) {
        // We found the document reference that points to the original order.
        // The DocumentSubLineIdentifier attribute is the fulfillline id of the original order fulfillment line.
        lineId = new Long(docRef.getAttribute("DocumentSubLineIdentifier"));

        if (headerId == 0) {
          // The DocumentIdentifier attribute is the header id of the original order header.
          headerId = new Long(docRef.getAttribute("DocumentIdentifier"));
        }
      }
  }
  if (lineId != 0) {
    // throw new ValidationException(lineId.toString());
    def oLine = getLine(lineId);

    if (oLine == null) continue;
      def oLinePO = oLine.getAttribute("FulfillLineCustomerPoNumber");
      def oHeaderPO = oLine.getAttribute("HeaderCustomerPoNumber");
      line.setAttribute("CustomerPONumber", oLinePO);
      header.setAttribute("CustomerPONumber", oHeaderPO);
    } else {
        throw new ValidationException("Value not found");
  }
}
  def Object getLine(Long lineId) {
  def vo = context.getViewObject("oracle.apps.scm.doo.publicView.analytics.FulfillLinePVO");
  Object[] rows = vo.findByKey(lineId, 1);
  def originalFLine = rows[0];
  return originalFLine;
}
Get Extensible Flexfields from Original Sales Order

Get extensible flexfields from the order line of the original order, then copy it to a return order line.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
import java.util.logging.Level;
Long lineId = 0;
Long headerId = 0;
def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
    def line = lines.next();

    String categoryCode = line.getAttribute("TransactionCategoryCode");

    if ("RETURN" != categoryCode) continue;
    def docRefs = line.getAttribute("DocumentReferences");
    lineId = 0;
    while (docRefs.hasNext() & lineId == 0) {
        def docRef = docRefs.next();
        String docRefType = docRef.getAttribute("DocumentReferenceType");
        if ("ORIGINAL_ORCHESTRATION_ORDER" == docRefType) {
            // We found the document reference that references the original order.
            // The DocumentSubLineIdentifier attribute identifies the fulfillment line in the original order.

            lineId = new Long(docRef.getAttribute("DocumentSubLineIdentifier"));
            if (headerId == 0) {
                // The DocumentIdentifier attribute identifies the header in the original order.
                headerId = new Long(docRef.getAttribute("DocumentIdentifier"));
            }
        }
    }
    if (lineId != 0) {
        // throw new ValidationException(lineId.toString());
        def oLine = getLine(lineId);
        if (oLine == null) continue;

        def Ocontext = oLine.getAttribute("FulfillLineBIEffEFFBIFlattened");
        def oContextRow = Ocontext.first();
        def oattr1 = oContextRow.getAttribute("DOO_FULFILL_LINES_ADD_INFO_FulfillLineContext1_EffLineId");
        def oattr = oContextRow.getAttribute("DOO_FULFILL_LINES_ADD_INFO_FulfillLineContext1__FL1AttributeNum1");

        def context = line.getOrCreateContextRow("FulfillLineContext1");
        context.setAttribute("_FL1AttributeNum1", oattr);
    } else {
        throw new ValidationException("Value not found");

    }
}
def Object getLine(Long lineId) {

    def vo = context.getViewObject("oracle.apps.scm.doo.publicView.analytics.FulfillLinePVO");
    Object[] rows = vo.findByKey(lineId, 1);
    def originalFLine = rows[0];

    return originalFLine;
}

Code Examples and Snippets

Use these code examples to help you create order management extensions that manipulate data on the sales order header.

  • Set the Billing Transaction Type According to Order Type

  • Add Attachment to Order Header

  • Delete Attachment from Order Header

  • Set Extensible Flexfield On Order Header

  • Set the Pricing Freeze Attributes on the Order Header

  • Set Extensible Flexfield Values for Hazardous Items

  • Set Payment Term on Order Header

  • Validate That Ship-to Site Belongs to Business Unit on Order Header

  • Prevent Duplicate Purchase Order Numbers on Order Header

Many of these examples test a value for the purchase order number on the order header. This test isolates the extension and prevents it from affecting other developers who might also be running test code. For details about this technique, see the Guidelines for Creating Extensions That Modify Order Management topic.

Set the Billing Transaction Type According to Order Type

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

String orderTypeCode = header.getAttribute("TransactionTypeCode");
def billingTxnTypeId = null;

//Message msg = new Message(Message.MessageType.WARNING, "Order Type: " + orderTypeCode);
//throw new ValidationException(msg);


//Case statement which tests order type and calls function to get billing transaction type

switch (orderTypeCode) {
    case ["AUTO RETURN - SHIP", "AUTO RETURN - SHIP", "AUTO RETURN - MXT SHIP", "Mosoi_test"]:
        billingTxnTypeId = getBillingTxnTypeId("MOTO_INVOICE");
        //msg = new Message(Message.MessageType.WARNING, "First Case " + billingTxnTypeId );
        break;
    case ["UnreferencedRMA"]:
        billingTxnTypeId = getBillingTxnTypeId("Invoice");
        //msg = new Message(Message.MessageType.WARNING, "Second Case " + billingTxnTypeId );
        break;
    default:
        billingTxnTypeId = null;
        //msg = new Message(Message.MessageType.WARNING, "Default " + billingTxnTypeId );
        break;
}

//throw new ValidationException(msg);

//update all order lines with the Billing Transaction Type

def lines = header.getAttribute("Lines"); //get the lines row set
while (lines.hasNext()) { //if there are more order lines
    def line = lines.next();
    line.setAttribute("BillingTransactionTypeIdentifier", billingTxnTypeId);
}


//Function to get Billing Transaction Type

Long getBillingTxnTypeId(String billingTxnTypeName) {

    def txnTypePVO = context.getViewObject("oracle.apps.financials.receivables.publicView.TransactionTypePVO");

    //Create view criteria (where clause predicates)
    def vc = txnTypePVO.createViewCriteria();
    def vcrow = vc.createViewCriteriaRow();

    //Only return Billing Transaction Type for the - Common Set - to be changed as required

    vcrow.setAttribute("Name", billingTxnTypeName);
    vcrow.setAttribute("SetName", "Common Set");

    //Execute the view object query to find a matching row
    def rowset = txnTypePVO.findByViewCriteriaWithBindVars(vc, 1, new String[0], new Object[0]);

    //check if we have a matching row
    def row = rowset.first();

    Long txnTypeId = (Long) row.getAttribute("CustTrxTypeSeqId");

    return txnTypeId;
}

Add Attachment to Order Header

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
import oracle.apps.scm.doo.common.extensions.Attachment;
import oracle.jbo.domain.BlobDomain;
String poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null) return;
if (!poNumber.startsWith("WriteAttachmentsHeaderOnEndSubmit_run_extension")) return;

List < Message > messages = new ArrayList < Message > ();
//messages.add(new Message( Message.MessageType.ERROR, "HeaderId: " + header.getAttribute("HeaderId")));

/////////////////create header attachments
//Create TEXT attachment
Attachment newAttachment1 = new Attachment();
newAttachment1.setDatatypeCode("TEXT");
newAttachment1.setTitle("This is a text type title on submit");
newAttachment1.setText("this is some text");
newAttachment1.setDescription("this is some description");
header.createAttachment(newAttachment1);

//Create URL attachment
Attachment newAttachment2 = new Attachment();
newAttachment2.setDatatypeCode("WEB_PAGE");
newAttachment2.setTitle("This URL points to google server on submit");
newAttachment2.setUrl("http://www.google.com/");
newAttachment2.setDescription("Used for searching stuffs");
header.createAttachment(newAttachment2);

//Create a file attachment
Attachment newAttachment3 = new Attachment();
newAttachment3.setDatatypeCode("FILE");
newAttachment3.setTitle("file type title");
newAttachment3.setDescription("this file contains some random data on submit");
newAttachment3.setFileName("APITextFile.txt");
//newAttachment3.setFileContentType("application/text");
newAttachment3.setFileContentType("text/plain");
//newAttachment3.setFileContent(new BlobDomain("This is a test creation using Bytes".getBytes()));
newAttachment3.setFileContent("This is a test for creation file from api using bytes".getBytes());
header.createAttachment(newAttachment3);

/*delete all header attachments
//messages.add(new Message( Message.MessageType.ERROR, "Delete all header attachments"));
def attachments1 = header.getAttachments();
for (int i; i< attachments1.size(); ++i) {
def attachment1 = attachments1[i];
//header.deleteAttachment(attachment1);
}*/

ValidationException ex = new ValidationException(messages);
throw ex;

Delete Attachment from Order Header

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
import oracle.apps.scm.doo.common.extensions.Attachment;
import oracle.jbo.domain.BlobDomain;

String poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null) return;
if (!poNumber.startsWith("DeleteAttachmentsHeaderOnSubmit_run_extension")) return;

//delete all header attachments
//messages.add(new Message( Message.MessageType.ERROR, "Delete all header attachments"));
def attachments1 = header.getAttachments();

for (int i; i < attachments1.size(); ++i) {
    //throw new ValidationException("An order with the Purchase Order  ddddd  Number " +  attachments1 + " already exists.");
    def attachment1 = attachments1[i];
    header.deleteAttachment(attachment1);
}

Set Extensible Flexfield On Order Header

Set an attribute to the current date and time. Use an extensible flexfield on the order header.

import oracle.apps.scm.doo.common.extensions.ValidationException;
def poNumber = header.getAttribute("CustomerPONumber");
//throw new ValidationException("An order with the Purchase Order Number " + poNumber + " already exists.");

if (poNumber == null || !poNumber.startsWith("SetDateEffAttributeOnSubmit")) return;

Date now = new Date();

//throw new ValidationException("An order with the Purchase Order Number " + now + " already exists.");
def complianceDetails = header.getOrCreateContextRow("ComplianceDetails");

complianceDetails.setAttribute("compliancedatetime", now);

Set the Pricing Freeze Attributes on the Order Header

String poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null) return;
if (!poNumber.startsWith("WriteFreezeFlags_run_extension")) return;
header.setAttribute("FreezePriceFlag", "N");
header.setAttribute("FreezeShippingChargeFlag", "N");
header.setAttribute("FreezeTaxFlag", "N");

Set Extensible Flexfield Values for Hazardous Items

If the HazardousMaterialFlag attribute equals Y, then set value for attributes that use extensible flexfields on the order header and order lines.

import oracle.apps.scm.doo.common.extensions.ValidationException;
def poNumber = header.getAttribute("CustomerPONumber");

if (poNumber == null) return;

if (!poNumber.startsWith("SetEFFAttributeOnSave")) return;

def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
    def line = lines.next();
    def inventoryItemId = line.getAttribute("ProductIdentifier");
    def orgId = line.getAttribute("InventoryOrganizationIdentifier");
    def item = getItem(inventoryItemId, orgId);

    String hazardous = item.getAttribute("HazardousMaterialFlag");

    //throw new ValidationException("Item Hazardous Material Flag is    "  + hazardous);

    if ("Y".equals(hazardous)) {
        //get tow for fulfill line context PackShipInstruction
        def packShipInstruction = line.getOrCreateContextRow("PackShipInstruction");
        packShipInstruction.setAttribute("shippinginstruction", "Hazardous Handling Required.");
    }
}


Date now = new Date();

def complianceDetails = header.getOrCreateContextRow("ComplianceDetails");
complianceDetails.setAttribute("compliancedatetime", now);
complianceDetails.setAttribute("compliancereason", "This is a compliance reason.");

Object getItem(Long itemId, Long orgId) {
    def itemPVO = context.getViewObject("oracle.apps.scm.productModel.items.publicView.ItemPVO");
    def vc = itemPVO.createViewCriteria();
    def vcrow = vc.createViewCriteriaRow();
    vcrow.setAttribute("InventoryItemId", itemId);
    vcrow.setAttribute("OrganizationId", orgId);
    vc.add(vcrow);

    def rowset = itemPVO.findByViewCriteriaWithBindVars(vc, -1, new String[0], new String[0]);
    def item = rowset.first();

    return item;

}

Set Payment Term on Order Header

Set the default value to use for the payment term on the order header.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

List < Message > messages = new ArrayList < Message > ();
def logger = context.getLogger();
def HeaderPayTerm = header.getAttribute("PaymentTerm");
def PName = header.getAttribute("BillToCustomerName");
def AId = header.getAttribute("BillToCustomerIdentifier");


def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
    def line = lines.next();
    def linePayTerm = line.getAttribute("PaymentTerm");
    def linetransactioncode = line.getAttribute("TransactionCategoryCode")
    def partyId = getBillToPartyId(PName);
    def termId = gettermID(AId, partyId);
    def termName = gettermName(termId);

    if (HeaderPayTerm == null && linePayTerm == null && linetransactioncode != 'RETURN') {
        if (termName != null)
            header.setAttribute("PaymentTerm", termName.getAttribute("Name"));
    }
}

Object getBillToPartyId(String partyName) {
    def partyId;
    def logger = context.getLogger();
    def custPVO =
        context.getViewObject("oracle.apps.scm.doo.workbench.publicViewEcsf.view.CustomerPVO");
    def vc = custPVO.createViewCriteria();
    def vcrow = vc.createViewCriteriaRow();
    vcrow.setAttribute("PartyName", partyName);
    def rowset = custPVO.findByViewCriteria(vc, -1);
    def partyIdRowSet = rowset.first();
    if (partyIdRowSet != null)
        partyId = partyIdRowSet.getAttribute("PartyId");
    logger.logSevere("party id for Bill To customer", partyId);
    return partyId;
}


Object gettermID(Long AId, Long partyId) {
    def termId;
    def logger = context.getLogger();
    def custProfilePVO =
        context.getViewObject("oracle.apps.financials.receivables.publicView.analytics.CustomerProfilePVO");
    def vc1 = custProfilePVO.createViewCriteria();
    def vcrow1 = vc1.createViewCriteriaRow();
    vcrow1.setAttribute("CustAcctProfileCustAccountId", AId);
    vcrow1.setAttribute("CustFinProfileSiteUseId", null);
    vcrow1.setAttribute("CustAcctProfilePartyId", partyId);
    def rowset1 = custProfilePVO.findByViewCriteria(vc1, -1);
    def profile = rowset1.first();
    if (profile != null)
        termId = profile.getAttribute("CustProfileStandardTerms");
    logger.logSevere("Term Id from customer profile VO", termId);
    return termId;
}

Object gettermName(Long termID) {
    def raTermPVO =
        ontext.getViewObject("oracle.apps.financials.receivables.publicView.TrxPaymentTermPVO");
    def vc2 = raTermPVO.createViewCriteria();
    def vcrow2 = vc2.createViewCriteriaRow();
    vcrow2.setAttribute("TermId", termID);
    def rowset2 = raTermPVO.findByViewCriteria(vc2, -1);
    def termName = rowset2.first();
    return termName;
}

Validate That Ship-to Site Belongs to Business Unit on Order Header

import oracle.apps.scm.doo.common.extensions.ValidationException;

def VARShipToPartySiteIdentifier = header.getAttribute("ShipToPartySiteIdentifier");
def VARBusinessUnitIdentifier = header.getAttribute("BusinessUnitIdentifier");
def ShipToPartySite = getShipTo(VARShipToPartySiteIdentifier);
def RETShipToSetId = ShipToPartySite.getAttribute("SetId")
def VARBusinesseUnitSetId = 0

//A test should be created for each Business Unit SET ID Assignment Set combination using the following SQL:
//SELECT haotl.NAME ,
//haotl.organization_id,
//fsa.SET_ID
//FROM fusion.FND_SETID_ASSIGNMENTS fsa,
//fusion.HR_ORGANIZATION_UNITS_F_TL haotl
//WHERE reference_group_name LIKE 'HZ_CUSTOMER_ACCOUNT_SITE'
//AND determinant_value = haotl.organization_id
//AND haotl.NAME LIKE '&Business_Unit_Name%'
//AND haotl.LANGUAGE = USERENV('LANG')

//

if (300000017871360. equals(VARBusinessUnitIdentifier)) {
    VARBusinesseUnitSetId = 300000000002582;
}

if ((VARBusinesseUnitSetId).equals(RETShipToSetId)) {} else {
    //The validation error below can be amended to match your business requirements. The example provided shows information on the SET IDs returned
    Throw new ValidationException("BU Set Id does not match Customer Ship to SET ID - BU Set ID is " + VARBusinesseUnitSetId + " Ship to Set ID is :" + RETShipToSetId)
}

Object getShipTo(Long ShipToSiteId) {
    def ShipToPVO = context.getViewObject("oracle.apps.hed.campusCommunity.shared.shoppingCart.publicModel.view.AccountSitePVO");
    def vc = ShipToPVO.createViewCriteria();
    def vcrow = vc.createViewCriteriaRow();
    vcrow.setAttribute("PartySiteId", ShipToSiteId);
    def rowset = ShipToPVO.findByViewCriteria(vc, -1);
    def ShipTo = rowset.first();
    return ShipTo;
}

Prevent Duplicate Purchase Order Numbers on Order Header

Prevent Order Management from creating a duplicate of the purchase order number on the order header.

import oracle.apps.scm.doo.common.extensions.ValidationException;
//get the Customer PO Number, order number and the buying party id from the order header of the order being saved
String customerPONumber = header.getAttribute("CustomerPONumber");
String buyingPartyIdentifier = header.getAttribute("BuyingPartyIdentifier");
String OrderNumber = header.getAttribute("OrderNumber");

//If the PO number is null, then there's nothing to validate
if (customerPONumber == null) return;

//Convert User Entered PO Number to upper case
customerPONumber = customerPONumber.toUpperCase()
//We will use the HeaderPVO to run a query with a predicate based on customer PO Number and  Sold To Party Id. The where clause predicate will be set using
//a view criteria
def vo = context.getViewObject("oracle.apps.scm.doo.publicView.analytics.HeaderPVO");
def vc = vo.createViewCriteria();
def vcrow = vc.createViewCriteriaRow();
vcrow.setAttribute("CustomerPoNumber", customerPONumber);
vcrow.setAttribute("SoldToPartyId", buyingPartyIdentifier);
vc.add(vcrow);

//Find one row using the specified view criteria. Even if we find one row, we know that we already have an order with the same PO Number and Bill to Site ID
def rowset = vo.findByViewCriteria(vc, 1);

if (rowset.hasNext()) {
    //An Order has been found for the Bill to Site and the order number entered
    //Now test to check if the order currently worked on has been previously save or if this is a revision
    def vcSameOrder = vo.createViewCriteria();
    def vcSameOrderrow = vc.createViewCriteriaRow();
    vcSameOrderrow.setAttribute("CustomerPoNumber", customerPONumber);
    vcSameOrderrow.setAttribute("SoldToPartyId", buyingPartyIdentifier);
    vcSameOrderrow.setAttribute("OrderNumber", OrderNumber);
    vcSameOrder.add(vcSameOrderrow);
    def rowsetSameOrder = vo.findByViewCriteria(vcSameOrder, 1);
    if (rowsetSameOrder.hasNext()) {
    //An Order has been found. this has the same order number and PO number as the order being worked on. this is a valid case. The order found is a revision or a previously saved order.
        header.setAttribute("CustomerPONumber", customerPONumber);
    } else
    //The order found is for a different order number
    //Set the customerPO number to the upper case value
    {
        throw new ValidationException("An order with the Purchase Order Number for this Customer already exists " + customerPONumber + " already Exists");
    }
} else
//No Order found for the bill to site id an po Number - the order can be saved
//Set the customerPO number to the upper case value
{
    header.setAttribute("CustomerPONumber", customerPONumber);
}

Use these code examples to help you create order management extensions that manipulate order lines.

  1. Set the Fulfillment Organization and Shipping Instructions on the Order Line

  2. Add Packing Instruction for Hazardous Item

  3. Add Attachment to Order Line

  4. Delete Attachment from Order Line

Many of these examples test a value for the purchase order number on the order header. This test isolates the extension and prevents it from affecting other developers who might also be running test code. For details about this technique, see the Guidelines for Creating Extensions That Modify Order Management topic.

1. Set the Fulfillment Organization and Shipping Instructions on the Order Line

If the item is shippable, then set the fulfillment organization for the order line and shipping instructions on the line to the default shipping organization that the item references.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

def poNumber = header.getAttribute("CustomerPONumber");

if (poNumber == null) return;

if (!poNumber.startsWith("DefaultShippingOrg")) return;

def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
    def line = lines.next();
    def inventoryItemId = line.getAttribute("ProductIdentifier");
    def orgId = line.getAttribute("InventoryOrganizationIdentifier");
    def item = getItem(inventoryItemId, orgId);

    String shippable = item.getAttribute("ShippableItemFlag");

    if ("Y".equals(shippable)) {
        Long defaultOrgId = item.getAttribute("DefaultShippingOrg");

        //msg =   new Message(Message.MessageType.WARNING, "default: " + inventoryItemId + " - " + orgId + " - " + shippable+ " - " +  defaultOrgId);
        //throw new ValidationException(msg);

        line.setAttribute("FulfillmentOrganizationIdentifier", defaultOrgId);
        line.setAttribute("FulfillmentOrganizationIdentifier", 1234);
        line.setAttribute("ShippingInstructions", "Ship From Org :" + 999);
    }
}

Object getItem(Long itemId, Long orgId) {
    def itemPVO = context.getViewObject("oracle.apps.scm.productModel.items.publicView.ItemPVO");
    def vc = itemPVO.createViewCriteria();
    def vcrow = vc.createViewCriteriaRow();
    vcrow.setAttribute("InventoryItemId", itemId);
    vcrow.setAttribute("OrganizationId", orgId);
    vc.add(vcrow);

    def rowset = itemPVO.findByViewCriteriaWithBindVars(vc, -1, new String[0], new String[0]);
    def item = rowset.first();

    return item;

}

2. Add Packing Instruction for Hazardous Item

If the item is hazardous, then set the packing instructions on the order line.

def poNumber = header.getAttribute("CustomerPONumber");

if (poNumber == null) return;

if (!poNumber.startsWith("HazardousMaterial")) return;

def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
    def line = lines.next();
    def inventoryItemId = line.getAttribute("ProductIdentifier");
    def orgId = line.getAttribute("InventoryOrganizationIdentifier");
    def item = getItem(inventoryItemId, orgId);

    String hazardous = item.getAttribute("HazardousMaterialFlag");

    if ("Y".equals(hazardous)) {
        //get row for fulfill line context PackShipInstruction
        line.setAttribute("PackingInstructions", "Hazardous Handling Required.");
    }
}

Object getItem(Long itemId, Long orgId) {
    def itemPVO = context.getViewObject("oracle.apps.scm.productModel.items.publicView.ItemPVO");
    def vc = itemPVO.createViewCriteria();
    def vcrow = vc.createViewCriteriaRow();
    vcrow.setAttribute("InventoryItemId", itemId);
    vcrow.setAttribute("OrganizationId", orgId);
    vc.add(vcrow);

    def rowset = itemPVO.findByViewCriteriaWithBindVars(vc, -1, new String[0], new String[0]);
    def item = rowset.first();

    return item;

}

3. Add Attachment to Order Line

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
import oracle.apps.scm.doo.common.extensions.Attachment;
import oracle.jbo.domain.BlobDomain;

String poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null) return;
if (!poNumber.startsWith("WriteAttachmentsLineOnEndSubmitOnly_run_extension")) return;

List < Message > messages = new ArrayList < Message > ();
//messages.add(new Message( Message.MessageType.ERROR, "HeaderId: " + header.getAttribute("HeaderId")));
def lines = header.getAttribute("Lines");

while (lines.hasNext()) {

    def line = lines.next();

    /////////////////create header attachments
    //Create TEXT attachment
    Attachment newAttachment1 = new Attachment();
    newAttachment1.setDatatypeCode("TEXT");
    newAttachment1.setTitle("This is a text type title");
    newAttachment1.setText("this is some text");
    newAttachment1.setDescription("this is some description");

    line.createAttachment(newAttachment1);

    //Create URL attachment
    Attachment newAttachment2 = new Attachment();
    newAttachment2.setDatatypeCode("WEB_PAGE");
    newAttachment2.setTitle("This URL points to google server");
    newAttachment2.setUrl("http://www.google.com/");
    newAttachment2.setDescription("Used for searching stuffs");
    line.createAttachment(newAttachment2);

    //Create a file attachment
    Attachment newAttachment3 = new Attachment();
    newAttachment3.setDatatypeCode("FILE");
    newAttachment3.setTitle("file type title");
    newAttachment3.setDescription("this file contains some random data");
    newAttachment3.setFileName("APITextFile.txt");
    //newAttachment3.setFileContentType("application/text");
    newAttachment3.setFileContentType("text/plain");
    //newAttachment3.setFileContent(new BlobDomain("This is a test creation using Bytes".getBytes()));
    newAttachment3.setFileContent("This is a test for creation file from api using bytes".getBytes());
    line.createAttachment(newAttachment3);

}
/*delete all header attachments
//messages.add(new Message( Message.MessageType.ERROR, "Delete all header attachments"));
def attachments1 = header.getAttachments();
for (int i; i< attachments1.size(); ++i) {
  def attachment1 = attachments1[i];
  //header.deleteAttachment(attachment1);
}*/

ValidationException ex = new ValidationException(messages);
throw ex;

4. Delete Attachment from Order Line

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
import oracle.apps.scm.doo.common.extensions.Attachment;
import oracle.jbo.domain.BlobDomain;
String poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null) return;
if (!poNumber.startsWith("DeleteAttachmentsLineOnSubmitOnly_run_extension")) return;

List < Message > messages = new ArrayList < Message > ();
//messages.add(new Message( Message.MessageType.ERROR, "HeaderId: " + header.getAttribute("HeaderId")));
def lines = header.getAttribute("Lines");

while (lines.hasNext()) {

    def line = lines.next();

    //delete all header attachments
    //messages.add(new Message( Message.MessageType.ERROR, "Delete all header attachments"));
    def attachments1 = line.getAttachments();
    for (int i; i < attachments1.size(); ++i) {
        def attachment1 = attachments1[i];
        line.deleteAttachment(attachment1);
    }

}

Use these code examples to help you create order management extensions in your implementation.

  1. Display Warning When Fulfillment Can't Meet the Order Date

  2. Copy Extensible Flexfield from Original Order to an RMA

  3. Get Document References

  4. Test a Transaction Attribute

  5. Get Tax Details for Sales Order

  6. Handle an Unexpected Exception

Many of these examples test a value for the purchase order number on the order header. This test isolates the extension and prevents it from affecting other developers who might also be running test code. For details about this technique, see the Guidelines for Creating Extensions That Modify Order Management topic.

1. Display Warning When Fulfillment Can't Meet the Order Date

Use the server time to determine whether fulfillment can ship the item according to the order entry date. If it doesn't, display a warning.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

//Get the sold-to customer
String customer = header.getAttribute("BuyingPartyName");

//If cusomer is not PMC  - Snow Enterprise then we do not want to check for the order date
if( customer != "PMC  - Snow Enterprise" ) return;

//Initialize the variable indicating that the order is past cut off time to false
boolean orderAfterCutOffTime = false;

//Initialize calendar object. By default calendar has the current system time. We want to setup the calendar to be in Eastern Stardard Time
Calendar now = new GregorianCalendar(TimeZone.getTimeZone("EST"));

//The following commented out code line is just for debugging purposes. It prints out the customer, and hour of day values in the shipping instructions attribute which is visible in the UI.
//This is an easy way to inspect variable values and debug code
 header.setAttribute("ShippingInstructions", customer + ", " + now.get(Calendar.HOUR_OF_DAY) + ", " + now.get(Calendar.MINUTE));

CutOffHour = 10
CurrentHour = now.get(Calendar.HOUR_OF_DAY)

if( CurrentHour > CutOffHour  ) {
    orderAfterCutOffTime = true;
}

//We will iterate through the lines in the order to check if any of the lines has ship from organization set to "Vision Operations". In order to save CPU cycles, we run this code
//to iterate through lines only if the order is past the cut-off time
if( orderAfterCutOffTime ) {
  //get the lines iterator
  count = 0
 
  def lines = header.getAttribute("Lines");//get the lines row set
  while( lines.hasNext() ) {//if there are more order lines
       def line = lines.next();  
       count = count +1;  
       String shipFromOrgName = line.getAttribute("FulfillmentOrganizationName");
 
       if( shipFromOrgName != null) {    
           if( shipFromOrgName != "Vision Operations" ){
               msg = new Message(Message.MessageType.WARNING, "This order has been entered after the cut off time " + CutOffHour + " and will not be shipped tomorrow, current hour is : " + CurrentHour + " !!!!!");
               throw new ValidationException(msg);
           }
        }
    }
}

2. Copy Extensible Flexfield from Original Order to an RMA

Copy extensible flexfield data from the original order to a return order that includes a return material authorization.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
import java.util.logging.Level;

//Following lines are for applying this extension only to specific cases
String poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null) return;
if (poNumber != "PMC TEST") return;


Long lineId = 0;
Long headerId = 0;

def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
    def line = lines.next();

    //get the category code specified on the line. A category code of RETURN means it is a return line
    String categoryCode = line.getAttribute("TransactionCategoryCode");

    if ("RETURN" != categoryCode) continue;

    //we have a return line. Now let's find the original line
    //we will go through the document references on this line to locate the document reference
    //that identifies the original order line.

    def docRefs = line.getAttribute("DocumentReferences");
    lineId = 0;
    while (docRefs.hasNext() & lineId == 0) {

        def docRef = docRefs.next();
        String docRefType = docRef.getAttribute("DocumentReferenceType");
        if ("ORIGINAL_ORCHESTRATION_ORDER" == docRefType) {
            //We found the document reference that points to the original order.
            //The DocumentSubLineIdentifier attribute is the fulfillline id of the original order fulfillment line

            lineId = new Long(docRef.getAttribute("DocumentSubLineIdentifier"));

            if (headerId == 0) {
                //The DocumentIdentifier attribute is the header id of the original order header
                headerId = new Long(docRef.getAttribute("DocumentIdentifier"));
            }
        }
    }
    /*
     if (lineId != 0) {
       
         //call method getline to get the original line a PVO
         def oLine = getLine(lineId);
         if (oLine == null) continue;
         //Define the context variable that you want to copy value to
         def context1 = line.getOrCreateContextRow("FulfillLineContext1");
         //Define the next context variable that you want to copy value to
         def packShipContext = line.getOrCreateContextRow("PackShipInstruction");
         //Define the next context variable that you want to copy value to
         def itemMaterialContext = line.getOrCreateContextRow("Item Material");
         //get Context form the oldline
         def Ocontext = oLine.getAttribute("FulfillLineBIEffEFFBIFlattened");
         //get to the first row of the context for the original order fulfillment line
         def oContextRow = Ocontext.first();
         //Attribute name will be like DOO_FULFILL_LINES_ADD_INFO_<contextname>_<segmentname>
         //You can download the Flexfield archives and navigate to oracle\apps\scm\doo\processOrder\flex\fulfillLineCategories\view\
         //and look for j_ExtendedDeclarativeprivateVO.xml.  This is where you will find all the flex attribute names in above fashion
         def attr1 = oContextRow.getAttribute("DOO_FULFILL_LINES_ADD_INFO_FulfillLineContext1__FL1AttributeNum1");
         context1.setAttribute("_FL1AttributeNum1", attr1);
         context1.setAttribute("_FL1AttributeChar1",oContextRow.getAttribute("DOO_FULFILL_LINES_ADD_INFO_FulfillLineContext1__FL1AttributeChar1"));
         context1.setAttribute("_FL1AttributeDate1",oContextRow.getAttribute("DOO_FULFILL_LINES_ADD_INFO_FulfillLineContext1__FL1AttributeDate1"));
         itemMaterialContext.setAttribute("lineMaterialSgmt",oContextRow.getAttribute("DOO_FULFILL_LINES_ADD_INFO_Item__Material_lineMaterialSgmt"));
         itemMaterialContext.setAttribute("lineMaterialText",oContextRow.getAttribute("DOO_FULFILL_LINES_ADD_INFO_Item__Material_lineMaterialText"));
         packShipContext.setAttribute("_PackingInstruction",oContextRow.getAttribute("DOO_FULFILL_LINES_ADD_INFO_PackShipInstruction__PackingInstruction"));
     }
    }
    */

    if (headerId != 0) {

        def oHeader = getHeader(headerId)

        if (oHeader == null) continue;
        //get Context from the original header
        def context = oHeader.getAttribute("HeaderBIEffEFFBIFlattened");

        //get to the first row of the context for the original header
        def contextRow = context.first();

        //Attribute name will be like DOO_HEADERS_ADD_INFO_<contextname>_<segmentname>
        //You can download the Flexfield archives and navigate to oracle\apps\scm\doo\processOrder\flex\headerCategories\view\
        //and look for j_ExtendedDeclarativeprivateVO.xml.  This is where you will find all the flex attribute names in above fashion
        def complInfo = contextRow.getAttribute("DOO_HEADERS_ADD_INFO_PMC__Pricing_partyid");

        //Define the context variable that you want to copy value to - header is the header of the return oorder which is currently being worked on
        def complianceDetails = header.getOrCreateContextRow("PMC Pricing");
        complianceDetails.setAttribute("partyid", complInfo);

        /* The following SQL will be useful in identifying the correct values to set

select
fdsb.context_code
,fdsb.segment_code
,fdsb.SEGMENT_IDENTIFIER
from
fnd_df_segments_tl fdst,
fnd_df_segments_b fdsb
where
fdst.APPLICATION_ID = fdsb.APPLICATION_ID and
fdst.ENTERPRISE_ID = fdsb.ENTERPRISE_ID and
fdst.DESCRIPTIVE_FLEXFIELD_CODE = fdsb.DESCRIPTIVE_FLEXFIELD_CODE and
fdst.CONTEXT_CODE = fdsb.CONTEXT_CODE and
fdst.SEGMENT_CODE = fdsb.SEGMENT_CODE and
fdst.language = 'US' and
fdst.descriptive_flexfield_code = 'DOO_HEADERS_ADD_INFO'
order by
fdst.CONTEXT_CODE,
fdsb.SEQUENCE_NUMBER

In this instance the Sql returned

CONTEXT_CODE SEGMENT_CODE SEGMENT_IDENTIFIER

PMC Pricing PartyID     partyid

The value DOO_HEADERS_ADD_INFO_PMC__Pricing_partyid - is derived from :

Context_code = PMC Pricing , note the space is replaced by __
Segment_identifier = partyid

*/


    }
}

def Object getLine(Long lineId) {

    def vo = context.getViewObject("oracle.apps.scm.doo.publicView.analytics.FulfillLinePVO");

    Object[] rows = vo.findByKey(lineId, 1);
    def originalFLine = rows[0];

    return originalFLine;
}

def Object getHeader(Long headerId) {
    def vo = context.getViewObject("oracle.apps.scm.doo.publicView.analytics.HeaderPVO");

    Object[] rows = vo.findByKey(headerId, 1);
    def originalHeader = rows[0];
    return originalHeader;
}

void debug(String msg) {
    header.setAttribute("ShippingInstructions", header.getAttribute("ShippingInstructions") + ", " + msg);
}

3. Get Document References

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

String poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null) return;
if (!poNumber.startsWith("DocReferences")) return;

List < Message > messages = new ArrayList < Message > ();
messages.add(new Message(Message.MessageType.ERROR, "HeaderId: " + header.getAttribute("HeaderId")));
messages.add(new Message(Message.MessageType.ERROR, "Pre-submit"));

def docReferences = header.getAttribute("DocumentReferences");
while (docReferences.hasNext()) {
    def docRef = docReferences.next();
    messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalNumber: " + docRef.getAttribute("DocumentAdditionalNumber")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionaldentifier: " + docRef.getAttribute("DocumentAdditionaldentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentIdentifier: " + docRef.getAttribute("DocumentIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalLineNumber: " + docRef.getAttribute("DocumentAdditionalLineNumber")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalLineIdentifier" + docRef.getAttribute("DocumentAdditionalLineIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentLineIdentifier: " + docRef.getAttribute("DocumentLineIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentLineNumber: " + docRef.getAttribute("DocumentLineNumber")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentReferenceType: " + docRef.getAttribute("DocumentReferenceType")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalSubLineNumber: " + docRef.getAttribute("DocumentAdditionalSubLineNumber")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalSubLineIdentifier: " + docRef.getAttribute("DocumentAdditionalSubLineIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentSubLineIdentifier: " + docRef.getAttribute("DocumentSubLineIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentSubLineNumbe: " + docRef.getAttribute("DocumentSubLineNumber")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentNumber: " + docRef.getAttribute("DocumentNumber")));
    messages.add(new Message(Message.MessageType.ERROR, "FulfillLineIdentifier: " + docRef.getAttribute("FulfillLineIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "LineIdentifier: " + docRef.getAttribute("LineIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "OwnerTableId: " + docRef.getAttribute("OwnerTableId")));
    messages.add(new Message(Message.MessageType.ERROR, "OwnerTableName: " + docRef.getAttribute("OwnerTableName")));
    messages.add(new Message(Message.MessageType.ERROR, "TaskType: " + docRef.getAttribute("TaskType")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentSystemReferenceIdentifier: " + docRef.getAttribute("DocumentSystemReferenceIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "HeaderId: " + docRef.getAttribute("HeaderId")));
}

def lines = header.getAttribute("Lines");
messages.add(new Message(Message.MessageType.ERROR, "get lines"));
while (lines.hasNext()) {
    messages.add(new Message(Message.MessageType.ERROR, "A line"));
    def line = lines.next();
    def lineDocReferences = line.getAttribute("DocumentReferences");
    while (lineDocReferences.hasNext()) {
        messages.add(new Message(Message.MessageType.ERROR, "has doc references"));
        def lineDocRef = lineDocReferences.next();
        messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalNumber: " + lineDocRef.getAttribute("DocumentAdditionalNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionaldentifier: " + lineDocRef.getAttribute("DocumentAdditionaldentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentIdentifier: " + lineDocRef.getAttribute("DocumentIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalLineNumber: " + lineDocRef.getAttribute("DocumentAdditionalLineNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalLineIdentifier" + lineDocRef.getAttribute("DocumentAdditionalLineIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentLineIdentifier: " + lineDocRef.getAttribute("DocumentLineIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentLineNumber: " + lineDocRef.getAttribute("DocumentLineNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentReferenceType: " + lineDocRef.getAttribute("DocumentReferenceType")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalSubLineNumber: " + lineDocRef.getAttribute("DocumentAdditionalSubLineNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalSubLineIdentifier: " + lineDocRef.getAttribute("DocumentAdditionalSubLineIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentSubLineIdentifier: " + lineDocRef.getAttribute("DocumentSubLineIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentSubLineNumbe: " + lineDocRef.getAttribute("DocumentSubLineNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentNumber: " + lineDocRef.getAttribute("DocumentNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "FulfillLineIdentifier: " + lineDocRef.getAttribute("FulfillLineIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "LineIdentifier: " + lineDocRef.getAttribute("LineIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "OwnerTableId: " + lineDocRef.getAttribute("OwnerTableId")));
        messages.add(new Message(Message.MessageType.ERROR, "OwnerTableName: " + lineDocRef.getAttribute("OwnerTableName")));
        messages.add(new Message(Message.MessageType.ERROR, "TaskType: " + lineDocRef.getAttribute("TaskType")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentSystemReferenceIdentifier: " + lineDocRef.getAttribute("DocumentSystemReferenceIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "HeaderId: " + lineDocRef.getAttribute("HeaderId")));
    }
}

ValidationException ex = new ValidationException(messages);
throw ex;

4. Test a Transaction Attribute

Test a transaction attribute during the On Save extension point.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

if (!"TestTIAOnSave_run_extension".equals(header.getAttribute("CustomerPONumber"))) return;

String poNumber = header.getAttribute("CustomerPONumber");
//Long headerId = header.getAttribute("HeaderId");

List < Message > messages = new ArrayList < Message > ();
/*messages.add(new Message( Message.MessageType.ERROR, "Enter TIA On Save"));
messages.add(new Message( Message.MessageType.ERROR, "CustomerPONumber: " + poNumber));
messages.add(new Message( Message.MessageType.ERROR, "HeaderId: " + headerId));*/

def lines = header.getAttribute("Lines");
def i = 0;
while (lines.hasNext()) {
    def line = lines.next();
    def tias = line.getAttribute("TransactionAttributes");
    while (tias.hasNext()) {
        messages.add(new Message(Message.MessageType.ERROR, "FulfillLineId: " + line.getAttribute("FulfillmentLineIdentifier")));
        def tia = tias.next();
        messages.add(new Message(Message.MessageType.ERROR, "TransactionAttributeIdentifier: " + tia.getAttribute("TransactionAttributeIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "TransactionAttributeCode: " + tia.getAttribute("TransactionAttributeCode")));
        messages.add(new Message(Message.MessageType.ERROR, "TransactionAttributeName: " + tia.getAttribute("TransactionAttributeName")));
        messages.add(new Message(Message.MessageType.ERROR, "CharacterValue: " + tia.getAttribute("CharacterValue")));
        messages.add(new Message(Message.MessageType.ERROR, "NumberValue: " + tia.getAttribute("NumberValue")));
        messages.add(new Message(Message.MessageType.ERROR, "DateValue: " + tia.getAttribute("DateValue")));
        messages.add(new Message(Message.MessageType.ERROR, "TimestampValue: " + tia.getAttribute("TimestampValue")));
        /*
          //tia.setAttribute("TransactionAttributeCode", "Color");  //TransactionAttributeIdentifier will be 300100061374755
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeCode to Color, TransactionAttributeCode:  " + tia.getAttribute("TransactionAttributeCode")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeCode to Color, TransactionAttributeName:  " + tia.getAttribute("TransactionAttributeName")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeCode to Color, TransactionAttributeIdentifier:  " + tia.getAttribute("TransactionAttributeIdentifier")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeCode to Color, CharacterValue: " + tia.getAttribute("CharacterValue")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeCode to Color, NumberValue: " + tia.getAttribute("NumberValue")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeCode to Color, DateValue: " + tia.getAttribute("DateValue")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeCode to Color, TimestampValue: " + tia.getAttribute("TimestampValue")));
        
          //tia.setAttribute("CharacterValue", "Purple");
          //messages.add(new Message( Message.MessageType.ERROR, "After setting CharacterValue to Purple, CharacterValue:  " + tia.getAttribute("CharacterValue")));
          
          //tia.setAttribute("TransactionAttributeName", "zcz colors 2");   //TransactionAttributeIdentifier will be 300100033383860, code: zcz_colors_2
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeName to zcz colors 2, TransactionAttributeCode:  " + tia.getAttribute("TransactionAttributeCode")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeName to zcz colors 2, TransactionAttributeName:  " + tia.getAttribute("TransactionAttributeName")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeName to zcz colors 2, TransactionAttributeIdentifier:  " + tia.getAttribute("TransactionAttributeIdentifier")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeName to zcz colors 2, CharacterValue: " + tia.getAttribute("CharacterValue")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeName to zcz colors 2, NumberValue: " + tia.getAttribute("NumberValue")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeName to zcz colors 2, DateValue: " + tia.getAttribute("DateValue")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeName to zcz colors 2, TimestampValue: " + tia.getAttribute("TimestampValue")));
          
          //tia.setAttribute("TransactionAttributeIdentifier", "300100039021944"); //mapping to internal name: zCZ_FRAME_COLOR, display name: Frame Color
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeIdentifier to 300100039021944, TransactionAttributeCode:  " + tia.getAttribute("TransactionAttributeCode")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeIdentifier to 300100039021944, TransactionAttributeName:  " + tia.getAttribute("TransactionAttributeName")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeIdentifier to 300100039021944, TransactionAttributeIdentifier:  " + tia.getAttribute("TransactionAttributeIdentifier")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeIdentifier to 300100039021944, CharacterValue: " + tia.getAttribute("CharacterValue")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeIdentifier to 300100039021944, NumberValue: " + tia.getAttribute("NumberValue")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeIdentifier to 300100039021944, DateValue: " + tia.getAttribute("DateValue")));
          //messages.add(new Message( Message.MessageType.ERROR, "After setting TransactionAttributeIdentifier to 300100039021944, TimestampValue: " + tia.getAttribute("TimestampValue")));

          tia.setAttribute("TransactionAttributeIdentifier", "300100005319663"); //set back to the original TransactionAttributeIdentifier 
          tia.setAttribute("CharacterValue", "BLUE");
          messages.add(new Message( Message.MessageType.ERROR, "After resetting TransactionAttributeIdentifier to 300100005319663, TransactionAttributeCode:  " + tia.getAttribute("TransactionAttributeCode")));
          messages.add(new Message( Message.MessageType.ERROR, "After resetting TransactionAttributeIdentifier to 300100005319663, TransactionAttributeName:  " + tia.getAttribute("TransactionAttributeName")));
          messages.add(new Message( Message.MessageType.ERROR, "After resetting TransactionAttributeIdentifier to 300100005319663, TransactionAttributeIdentifier:  " + tia.getAttribute("TransactionAttributeIdentifier")));
          messages.add(new Message( Message.MessageType.ERROR, "After resetting TransactionAttributeIdentifier to 300100005319663, CharacterValue: " + tia.getAttribute("CharacterValue")));
          messages.add(new Message( Message.MessageType.ERROR, "After resetting TransactionAttributeIdentifier to 300100005319663, NumberValue: " + tia.getAttribute("NumberValue")));
          messages.add(new Message( Message.MessageType.ERROR, "After resetting TransactionAttributeIdentifier to 300100005319663, DateValue: " + tia.getAttribute("DateValue")));
          messages.add(new Message( Message.MessageType.ERROR, "After resetting TransactionAttributeIdentifier to 300100005319663, TimestampValue: " + tia.getAttribute("TimestampValue")));*/
    }
}

ValidationException ex = new ValidationException(messages);
throw ex;

5. Get Tax Details for Sales Order

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

if (!"OrderTaxDetails_run_extension".equals(header.getAttribute("CustomerPONumber"))) return;

List < Message > messages = new ArrayList < Message > ();

messages.add(new Message(Message.MessageType.ERROR, "Status Code is " + header.getAttribute("StatusCode")));

def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
    def line = lines.next();
    def charges = line.getAttribute("OrderCharges");
    while (charges.hasNext()) {
        def charge = charges.next();
        def chargeComponents = charge.getAttribute("OrderChargeComponents");
        while (chargeComponents.hasNext()) {
            def chargeComponent = chargeComponents.next();
            def taxDetails = chargeComponent.getAttribute("OrderTaxDetails");
            while (taxDetails.hasNext()) {
                def taxDetail = taxDetails.next();
                messages.add(new Message(Message.MessageType.ERROR, "OrderChargeComponentId is " + taxDetail.getAttribute("OrderChargeComponentId")));
                messages.add(new Message(Message.MessageType.ERROR, "TaxRate is " + taxDetail.getAttribute("TaxRate")));
                messages.add(new Message(Message.MessageType.ERROR, "TaxIncludedFlag is " + taxDetail.getAttribute("TaxIncludedFlag")));
                messages.add(new Message(Message.MessageType.ERROR, "HeaderCurrencyTaxUnitAmount is " + taxDetail.getAttribute("HeaderCurrencyTaxUnitAmount"))); //Not HdrCurrTaxUnitAmt
                messages.add(new Message(Message.MessageType.ERROR, "HeaderCurrencyTaxableUnitAmount is " + taxDetail.getAttribute("HeaderCurrencyTaxableUnitAmount"))); //Not HdrCurrTaxableUnitAmt
                messages.add(new Message(Message.MessageType.ERROR, "TaxRateIdentifier is " + taxDetail.getAttribute("TaxRateIdentifier"))); //Not TaxRateId
                messages.add(new Message(Message.MessageType.ERROR, "OrderTaxDetailId is " + taxDetail.getAttribute("OrderTaxDetailId")));
                messages.add(new Message(Message.MessageType.ERROR, "TaxExemptReasonCode is " + taxDetail.getAttribute("TaxExemptReasonCode")));
                messages.add(new Message(Message.MessageType.ERROR, "TaxExemptionCertificateNumber is " + taxDetail.getAttribute("TaxExemptionCertificateNumber"))); //Not TaxExemptCertificateNumber
            }
        }
    }

}

ValidationException ex = new ValidationException(messages);
throw ex;

6. Handle an Unexpected Exception

Handle an unexpected exception during the On Save extension point.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
import oracle.apps.scm.doo.common.extensions.Person;

String poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null) return;
if (!poNumber.startsWith("UnexpectedExceptionOnSave_run_extension")) return;

List < Message > messages = new ArrayList < Message > ();

//Test DOO:::DOO_CX_EXECUTION_ERROR for NoDataFoundException when setAttribute on header
//An error occurred when running extension **, during event **: JBO-25002: Definition ** of type Attribute is not found..
//header.setAttribute("NonExistAttribute", "anyvalue");  //An error occurred when running extension UnexpectedExceptionOnSave, during event On Save: JBO-25058: Definition NonExistAttribute of type Attribute is not found in Header..
//header.getAttribute("HeaderAddresses");  //HeaderEffCategories

//Test DOO:::DOO_CX_ATTRIB_NO_DATA
//Expected message: A value could not be assigned to attribute {ATTRIBUTE}, while running extension {EXTENSION}, during event {EVENT}, because no data was found.
//Acutally got: An error occurred when running extension UnexpectedExceptionOnSave, during event On Save: oracle.jbo.JboException: JBO-29000: Unexpected exception caught: oracle.apps.scm.doo.common.extensions.NoDataFoundException, msg=No data was found using the provided parameters.
def person = new Person("First Name", "Last Name");
header.setBillToAccount(person);

//header.setAttribute("FreezePriceFlag", "1231");   //Error message: Value 100 for field FreezePriceFlag exceeds the maximum length allowed.

//def lines = header.getAttribute("Lines");
//if (lines.hasNext()) {
//def line = lines.next();
//Test DOO:::DOO_CX_ATTRIB_NO_DATA for NoDataFoundException when setAttribute on line 
//line.setAttribute("NonExistAttribute", "anyvalue");

//Test DOO:::DOO_CX_CONN_NOT_FOUND for ServiceDetailNotFound when invokeSoapService
//def itemNumber = line.getAttribute("ProductNumber");
//String payLoad = "<ns1:GetSalesCreditAllocation xmlns:ns1=\"http://www.yourCompany.com/SalesCreditWS/\">" +
//"<ns1:poNumber>" + poNumber + "</ns1:poNumber>" + 
//"<ns1:itemNumber>" + itemNumber + "</ns1:itemNumber>" +
//"</ns1:GetSalesCreditAllocation>";
//Correct integration name is SalesCreditAllocationService
//def responseBody = (context.invokeSoapService("SalesCreditAllocationService", payLoad)).getSoapBody(); 
////def serviceInvoker = context.getServiceInvoker();
////def responseBody = (serviceInvoker.invokeSoapService("SalesCreditAllocationService", payLoad)).getSoapBody(); 
//messages.add(responseBody);


//}

//ValidationException ex = new ValidationException(messages);
//throw ex;

Use these code snippets to help you create order management extensions in your implementation.

  • Order Headers

  • Order Lines

  • Revisions and Returns

  • Shipping

  • Billing and Payment

  • Extensible Flexfields

  • Other Areas

Many of these examples test a value for the purchase order number on the order header. This test isolates the extension and prevents it from affecting other developers who might also be running test code. For details about this technique, see the Guidelines for Creating Extensions That Modify Order Management topic.

Each snippet describes how to do a function or how to access data.

Order Headers

Use an order management extension to manage order headers.

  • Get Pricing Details for Order Header

  • Get Attachments from Order Headers

  • Prevent Order Management from Deleting the Order Header

  • Validate Sales Credits for Salesperson from Order Header

Get Pricing Details for Order Header

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

if (!"PMC TEST".equals(header.getAttribute("CustomerPONumber"))) return;

List < Message > messages = new ArrayList < Message > ();

def payments = header.getAttribute("OrderTotals");
while (payments.hasNext()) {
    def payment = payments.next();
    messages.add(new Message(Message.MessageType.ERROR, "TotalAmount is " + payment.getAttribute("TotalAmount")));
    messages.add(new Message(Message.MessageType.ERROR, "OrderTotalId is " + payment.getAttribute("OrderTotalId")));
    messages.add(new Message(Message.MessageType.ERROR, "TotalCode is " + payment.getAttribute("TotalCode")));
    messages.add(new Message(Message.MessageType.ERROR, "CurrencyCode is " + payment.getAttribute("CurrencyCode")));
    messages.add(new Message(Message.MessageType.ERROR, "DisplayName is " + payment.getAttribute("DisplayName")));
    messages.add(new Message(Message.MessageType.ERROR, "TotalGroup is " + payment.getAttribute("TotalGroup")));
    messages.add(new Message(Message.MessageType.ERROR, "PrimaryFlag is " + payment.getAttribute("PrimaryFlag")));

    messages.add(new Message(Message.MessageType.ERROR, "EstimatedFlag is " + payment.getAttribute("EstimatedFlag")));
    messages.add(new Message(Message.MessageType.ERROR, "CreatedBy is " + payment.getAttribute("CreatedBy")));


    messages.add(new Message(Message.MessageType.ERROR, "HeaderId is " + payment.getAttribute("HeaderId")));
    messages.add(new Message(Message.MessageType.ERROR, "ObjectVersionNumber is " + payment.getAttribute("ObjectVersionNumber")));


}

ValidationException ex = new ValidationException(messages);
throw ex;

Get Attachments from Order Headers

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
import oracle.apps.scm.doo.common.extensions.Attachment;
import oracle.jbo.domain.BlobDomain;

String poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null) return;
if (!poNumber.startsWith("PMC TEST")) return;

List < Message > messages = new ArrayList < Message > ();
//messages.add(new Message( Message.MessageType.ERROR, "HeaderId: " + header.getAttribute("HeaderId")));


/////////////////Read header attachments
def attachments = header.getAttachments();
for (int i = 0; i < attachments.size(); ++i) {
    def attachment = attachments[i];
    messages.add(new Message(Message.MessageType.ERROR, "Pk1value:" + attachment.getPk1Value()));
    messages.add(new Message(Message.MessageType.ERROR, "Entityname:" + attachment.getEntityName()));
    messages.add(new Message(Message.MessageType.ERROR, "DatatypeCode:" + attachment.getDatatypeCode()));
    messages.add(new Message(Message.MessageType.ERROR, "Title:" + attachment.getTitle()));
    messages.add(new Message(Message.MessageType.ERROR, "Description:" + attachment.getDescription()));
    messages.add(new Message(Message.MessageType.ERROR, "FileName:" + attachment.getFileName()));
    messages.add(new Message(Message.MessageType.ERROR, "File Content Type:" + attachment.getFileContentType()));
    def blobDomainData = attachment.getFileContent();
    messages.add(new Message(Message.MessageType.ERROR, "File Content:" + blobDomainData.toString()));
    messages.add(new Message(Message.MessageType.ERROR, "Url:" + attachment.getUrl()));
    messages.add(new Message(Message.MessageType.ERROR, "Text:" + attachment.getText()));
}

ValidationException ex = new ValidationException(messages);
throw ex;

Prevent Order Management from Deleting the Order Header

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
def reference = header.getAttribute("ReferenceHeaderId");
if (reference == null)
return;
def lines = header.getAttribute("Lines");

Validate Sales Credits for Salesperson from Order Header

Get the sales credit percent, then validate that Order Management allocates a percent greater than x to each salesperson.

import oracle.apps.scm.doo.common.extensions.ValidationException;


def poNumber = header.getAttribute("CustomerPONumber");

if (poNumber != null && poNumber.startsWith("PMC TEST")) {
    //def tokens = [EVENT_CODE: "Jason Carrier", EVENT_CRITERIA: "20"];
    //throw new ValidationException("ORA_MANAGE_EXTENSIONS", "DOO_CMN_ETP_INVALID_EVENT_DTLS", tokens);
}


def salesCredits = header.getAttribute("SalesCredits"); //Get the row set for sales credits that are specified on the order header.

while (salesCredits.hasNext()) {
    def salesCredit = salesCredits.next();
    if ("1".equals(salesCredit.getAttribute("SalesCreditTypeCode"))) {
        //we are dealing with revenue percent
        def percent = salesCredit.getAttribute("Percent");

        if (percent < 30) {
            def tokens = [EVENT_CODE: salesCredit.getAttribute("Salesperson"), EVENT_CRITERIA: percent];
            throw new ValidationException("ORA_MANAGE_EXTENSION", "DOO_CMN_ETP_INVALID_EVENT_DTLS", tokens);
        }
    }
}
Order Lines

Use an order management extension to manage order lines.

  • Get Manual Price Adjustments from Order Lines

  • Get Fulfillment Line Attributes

  • Get Attachments from Order Lines

  • Prevent Updates on Order Lines

  • Prevent Updates on Order Lines That Are on Backorder

  • Skip Order Lines That Are Fulfilled, Closed, or Canceled

  • Update the ModifiedFlag Attribute for Closed Order Lines

  • Manipulate Dates on Order Lines

  • Remove the System Date from the Contract Start Date on the Order Line

  • Set the Default Value for the Unit of Measure on the Order Line

  • Get the Rate for a Unit of Measure

Get Manual Price Adjustments from Order Lines

Iimport oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

if (!"PMC TEST".equals(header.getAttribute("CustomerPONumber"))) return;

List < Message > messages = new ArrayList < Message > ();

def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
    def line = lines.next();
    def MPAS = line.getAttribute("ManualPriceAdjustments");

    while (MPAS.hasNext()) {
        def mpa = MPAS.next();
        messages.add(new Message(Message.MessageType.ERROR, "AdjustmentElementBasis is " + mpa.getAttribute("AdjustmentElementBasis")));
        messages.add(new Message(Message.MessageType.ERROR, "AdjustmentTypeCode is " + mpa.getAttribute("AdjustmentTypeCode")));
        messages.add(new Message(Message.MessageType.ERROR, "ChargeDefinitionCode is " + mpa.getAttribute("ChargeDefinitionCode")));
        messages.add(new Message(Message.MessageType.ERROR, "ChargeRollupFlag is " + mpa.getAttribute("ChargeRollupFlag")));


        messages.add(new Message(Message.MessageType.ERROR, "Comments is " + mpa.getAttribute("Comments")));
        messages.add(new Message(Message.MessageType.ERROR, "ManualPriceAdjustmentId is " + mpa.getAttribute("ManualPriceAdjustmentId")));

        messages.add(new Message(Message.MessageType.ERROR, "ParentEntityCode is " + mpa.getAttribute("ParentEntityCode")));

        messages.add(new Message(Message.MessageType.ERROR, "ParentEntityId is " + mpa.getAttribute("ParentEntityId")));


        messages.add(new Message(Message.MessageType.ERROR, "PricePeriodicityCode is " + mpa.getAttribute("PricePeriodicityCode")));
        messages.add(new Message(Message.MessageType.ERROR, "ReasonCode is " + mpa.getAttribute("ReasonCode")));
        messages.add(new Message(Message.MessageType.ERROR, "SequenceNumber is " + mpa.getAttribute("SequenceNumber")));

        messages.add(new Message(Message.MessageType.ERROR, "SourceManualPriceAdjustmentIdentifier is " + mpa.getAttribute("SourceManualPriceAdjustmentIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "ValidationStatusCode is " + mpa.getAttribute("ValidationStatusCode")));

        messages.add(new Message(Message.MessageType.ERROR, "ChargeDefinition is " + mpa.getAttribute("ChargeDefinition")));
        messages.add(new Message(Message.MessageType.ERROR, "AdjustmentType is " + mpa.getAttribute("AdjustmentType")));
        messages.add(new Message(Message.MessageType.ERROR, "AdjustmentElementBasisCode is " + mpa.getAttribute("AdjustmentElementBasisCode")));

    }
}

ValidationException ex = new ValidationException(messages);
throw ex;

Get Fulfillment Line Attributes

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

if (!"PMC TEST".equals(header.getAttribute("CustomerPONumber"))) return;

List < Message > messages = new ArrayList < Message > ();

def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
    def line = lines.next();
    def flinedetails = line.getAttribute("FulfillLineDetails");
    while (flinedetails.hasNext()) {
        def flinedetail = flinedetails.next();
        messages.add(new Message(Message.MessageType.ERROR, "ActualDeliveryDate is " + flinedetail.getAttribute("ActualDeliveryDate")));


        messages.add(new Message(Message.MessageType.ERROR, "AvailabilityShipDate is " + flinedetail.getAttribute("AvailabilityShipDate")));
        messages.add(new Message(Message.MessageType.ERROR, "BillOfLadingNumber is " + flinedetail.getAttribute("BillOfLadingNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "BillingTransactionNumber is " + flinedetail.getAttribute("BillingTransactionNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "DeliveryName is " + flinedetail.getAttribute("DeliveryName")));
        messages.add(new Message(Message.MessageType.ERROR, "ExceptionFlag is " + flinedetail.getAttribute("ExceptionFlag")));

        messages.add(new Message(Message.MessageType.ERROR, "Category is " + flinedetail.getAttribute("Category")));
        messages.add(new Message(Message.MessageType.ERROR, "CreatedBy is " + flinedetail.getAttribute("CreatedBy")));
        messages.add(new Message(Message.MessageType.ERROR, "CreationDate is " + flinedetail.getAttribute("CreationDate")));
        messages.add(new Message(Message.MessageType.ERROR, "CustomerTrxLineId is " + flinedetail.getAttribute("CustomerTrxLineId")));



        messages.add(new Message(Message.MessageType.ERROR, "FulfillLineDetailId is " + flinedetail.getAttribute("FulfillLineDetailId")));
        messages.add(new Message(Message.MessageType.ERROR, "FulfillLineId is " + flinedetail.getAttribute("FulfillLineId")));
        messages.add(new Message(Message.MessageType.ERROR, "LastUpdateDate is " + flinedetail.getAttribute("LastUpdateDate")));
        messages.add(new Message(Message.MessageType.ERROR, "LastUpdateLogin is " + flinedetail.getAttribute("LastUpdateLogin")));
        messages.add(new Message(Message.MessageType.ERROR, "LastUpdatedBy is " + flinedetail.getAttribute("LastUpdatedBy")));


        messages.add(new Message(Message.MessageType.ERROR, "ObjectVersionNumber is " + flinedetail.getAttribute("ObjectVersionNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "Quantity is " + flinedetail.getAttribute("Quantity")));
        messages.add(new Message(Message.MessageType.ERROR, "RmaReceiptDate is " + flinedetail.getAttribute("RmaReceiptDate")));
        messages.add(new Message(Message.MessageType.ERROR, "RmaReceiptLineNumber is " + flinedetail.getAttribute("RmaReceiptLineNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "RmaReceiptNumber is " + flinedetail.getAttribute("RmaReceiptNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "RmaReceiptTransactionId is " + flinedetail.getAttribute("RmaReceiptTransactionId")));
        messages.add(new Message(Message.MessageType.ERROR, "Status is " + flinedetail.getAttribute("Status")));
        messages.add(new Message(Message.MessageType.ERROR, "StatusAsofDate is " + flinedetail.getAttribute("StatusAsofDate")));


        messages.add(new Message(Message.MessageType.ERROR, "TaskType is " + flinedetail.getAttribute("TaskType")));
        messages.add(new Message(Message.MessageType.ERROR, "TrackingNumber is " + flinedetail.getAttribute("TrackingNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "TradeComplianceCode is " + flinedetail.getAttribute("TradeComplianceCode")));
        messages.add(new Message(Message.MessageType.ERROR, "TradeComplianceExplanation is " + flinedetail.getAttribute("TradeComplianceExplanation")));
        messages.add(new Message(Message.MessageType.ERROR, "TradeComplianceResultCode is " + flinedetail.getAttribute("TradeComplianceResultCode")));
        messages.add(new Message(Message.MessageType.ERROR, "TradeComplianceTypeCode is " + flinedetail.getAttribute("TradeComplianceTypeCode")));

        messages.add(new Message(Message.MessageType.ERROR, "WaybillNumber is " + flinedetail.getAttribute("WaybillNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "TradeComplianceName is " + flinedetail.getAttribute("TradeComplianceName")));
        messages.add(new Message(Message.MessageType.ERROR, "TradeComplianceCode is " + flinedetail.getAttribute("TradeComplianceCode")));
        messages.add(new Message(Message.MessageType.ERROR, "TradeComplianceResultName is " + flinedetail.getAttribute("TradeComplianceResultName")));
        messages.add(new Message(Message.MessageType.ERROR, "TradeComplianceTypeName is " + flinedetail.getAttribute("TradeComplianceTypeName")));


    }

}

ValidationException ex = new ValidationException(messages);
throw ex;

Get Attachments from Order Lines

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

String poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null) return;
if (!poNumber.startsWith("PMC TEST")) return;

List < Message > messages = new ArrayList < Message > ();
//messages.add(new Message( Message.MessageType.ERROR, "Enter Attachment On Save"));
//messages.add(new Message( Message.MessageType.ERROR, "CustomerPONumber: " + poNumber));
Long headerId = header.getAttribute("HeaderId");
messages.add(new Message(Message.MessageType.ERROR, "HeaderId: " + headerId));

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

while (lines.hasNext()) {

    def line = lines.next();
    def attachments = line.getAttachments();

    for (int i = 0; i < attachments.size(); ++i) {
        def attachment = attachments[i];
        messages.add(new Message(Message.MessageType.ERROR, "Pk1value:" + attachment.getPk1Value()));
        messages.add(new Message(Message.MessageType.ERROR, "Entityname:" + attachment.getEntityName()));
        messages.add(new Message(Message.MessageType.ERROR, "DatatypeCode:" + attachment.getDatatypeCode()));
        messages.add(new Message(Message.MessageType.ERROR, "Text:" + attachment.getText()));
        messages.add(new Message(Message.MessageType.ERROR, "Title:" + attachment.getTitle()));
        messages.add(new Message(Message.MessageType.ERROR, "Description:" + attachment.getDescription()));
        messages.add(new Message(Message.MessageType.ERROR, "FileName:" + attachment.getFileName()));
        messages.add(new Message(Message.MessageType.ERROR, "Url:" + attachment.getUrl()));
        messages.add(new Message(Message.MessageType.ERROR, "Url:" + attachment.getCategoryName()));
    }
}
ValidationException ex = new ValidationException(messages);
throw ex;

Prevent Updates on Order Lines

Prevent Order Management from updating order lines that it has fulfilled, canceled, closed, backordered, or split. This extension doesn't prevent updates to lines that Order Management has canceled.

import oracle.apps.scm.doo.common.extensions.ValidationException;  
import oracle.apps.scm.doo.common.extensions.Message;
 
/*
def poNumber = header.getAttribute("OrderNumber");
if (poNumber == null || !poNumber.equals("520956"))
return;
*/
def reference = header.getAttribute("ReferenceHeaderId");
 
if(reference != null){
  def lines = header.getAttribute("Lines");
 
  if (!lines.hasNext()){
      throw new ValidationException("We need more time to process the order.");
  }
 
  Set<Long> splitFlinesSet = null;
  def vo = context.getViewObject("oracle.apps.scm.doo.processOrder.publicModel.partyMerge.view.FulfillLinePVO");
  def vc1 = vo.createViewCriteria();
  def vcrow1 = vc1.createViewCriteriaRow();
  vcrow1.setAttribute("HeaderId", header.getAttribute("HeaderId"));
  vcrow1.setAttribute("FulfillLineNumber", " > 1 ");
  vcrow1.setAttribute("FulfillmentSplitRefId", " is not null ");
  vcrow1.setAttribute("FulfilledQty", " is null ");
  rowset1 = vo.findByViewCriteria(vc1, -1);
 
  rowset1.reset();
  while (rowset1.hasNext()) {
    if (splitFlinesSet == null) {
      splitFlinesSet = new TreeSet<Long>();
    }
    def line1 = rowset1.next();
    splitFlinesSet.add(line1.getAttribute("FulfillLineId"));
  }
 
  if (splitFlinesSet == null) {
    return;
  }
 
  while (lines.hasNext()) {
    def line = lines.next();
    Long fLineId = line.getAttribute("FulfillmentLineIdentifier");
    if (!(splitFlinesSet.contains(fLineId))) {
      continue;
    }
    if('Y'.equals(line.getAttribute("ModifiedFlag")) && line.getAttribute("ReferenceFulfillmentLineIdentifier") != null && !(0 == line.getAttribute("OrderedQuantity")) ){
      throw new ValidationException("Backordered Split line can't be updated. DisplayLineNumber: " + line.getAttribute("DisplayLineNumber"));
    }
  }
}

Prevent Updates on Order Lines That Are on Backorder

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
 
String orderType = header.getAttribute("TransactionTypeCode");
def excludeStatuses = ["CANCELED", "CLOSED", "PARTIAL_CLOSE"] as Set;
def forOrderTypes = ["DOMESTIC", "EXPORT", "DOMESTICPPD", "CONSIGN", "EXPORTC", "EXPORTD", "EXPORTF", "HWIPARTNER", "HWIPARTNERC", "HWIPARTNERD", "HWIPARTNERF", "RETURN", "VAS"] as Set;
 
if (orderType == null) return;
if (!forOrderTypes.contains(orderType)) return;
 
def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
 def line = lines.next();
  
 Long lineId = line.getAttribute("LineId");
 boolean backUpdateFlag = readFlineStatus(lineId);
 
 if (backUpdateFlag) //if not back order line
 {
  if (!excludeStatuses.contains(line.getAttribute("StatusCode"))) {
 
   def BillingTransactionTypeId_Current = line.getAttribute("BillingTransactionTypeIdentifier");
   def BillingTransactionTypeId_New = line.getAttribute("BillingTransactionTypeIdentifier");
 
   if (orderType.equals("DOMESTIC")) {
    BillingTransactionTypeId_New = 300000034980382;
   }
   if (orderType.equals("EXPORT")) {
    BillingTransactionTypeId_New = 300000034980386;
   }
   if (orderType.equals("DOMESTICPPD")) {
    BillingTransactionTypeId_New = 300000039619347;
   }
   if (orderType.equals("CONSIGN")) {
    BillingTransactionTypeId_New = 300000034980380;
   }
   if (orderType.equals("EXPORTC")) {
    BillingTransactionTypeId_New = 300000034988180;
   }
   if (orderType.equals("EXPORTD")) {
    BillingTransactionTypeId_New = 300000034988182;
   }
   if (orderType.equals("EXPORTF")) {
    BillingTransactionTypeId_New = 300000034989759;
   }
   if (orderType.equals("HWIPARTNER")) {
    BillingTransactionTypeId_New = 300000084209774;
   }
   if (orderType.equals("HWIPARTNERC")) {
    BillingTransactionTypeId_New = 300000036925861;
   }
   if (orderType.equals("HWIPARTNERD")) {
    BillingTransactionTypeId_New = 300000036925863;
   }
   if (orderType.equals("HWIPARTNERF")) {
    BillingTransactionTypeId_New = 300000036925870;
   }
   if (orderType.equals("RETURN")) {
    BillingTransactionTypeId_New = 300000034980378;
   }
   if (orderType.equals("VAS")) {
    BillingTransactionTypeId_New = 300000034980370;
   }
 
   if (BillingTransactionTypeId_Current != BillingTransactionTypeId_New) {
    line.setAttribute("BillingTransactionTypeIdentifier", BillingTransactionTypeId_New);
   }
  }//Condition skipping lines of particular status codes
 }//Back order line check condition
}
 
/*Method that determines whether the line is shipped or backordered. If the line shipped, the method returns true. If the line is backordered, the method returns false.

*/
def readFlineStatus(Long lineId) {
 
 def lines = header.getAttribute("Lines");
 
 if (!lines.hasNext()) {
  throw new ValidationException("In readFlineStatus failing to read lines");
 }
 
 while (lines.hasNext()) {
 
  def line = lines.next();
  def eachLineId = line.getAttribute("LineId");
  def quantity = line.getAttribute("OrderedQuantity");
 
  if (lineId.equals(eachLineId)) {
 
   def flineDetails = line.getAttribute("FulfillLineDetails");
   if (!flineDetails.hasNext()) {
    continue;
   }
 
   while (flineDetails.hasNext()) {
    def eachFlineDetails = flineDetails.next();
    def status = eachFlineDetails.getAttribute("Status");
    if ("BACKORDERED".equals(status) || "SHIPPED".equals(status)) {
     return false;
    }
 
   }
  }
 }
 return true;
}

Skip Order Lines That Are Fulfilled, Closed, or Canceled

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
/* Exclude orchestration processes that you have set up where the statuses are equivalent to SHIPPED or FULFILLED.*/
Set excludeStatusesSet = ["CANCELED", "CLOSED", "SHIPPED", "BACKORDERED", "AWAIT_BILLING", "BILLED" ];
/*
def poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null || !poNumber.equals("CSR_2720"))
return;
*/
def requestedDate = header.getAttribute("RequestShipDate");
def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
def line = lines.next();
def statusCode = line.getAttribute("StatusCode");
if (statusCode != null && excludeStatusesSet.contains(statusCode)) {
continue;
}
/*
def comments = line.getAttribute("Comments");
if (comments == null)
comments = "TEST:";
line.setAttribute("Comments", comments + header.getAttribute("ChangeVersionNumber"));
*/
line.setAttribute("RequestedShipDate",requestedDate);
line.setAttribute("ScheduleShipDate",requestedDate);
}

Update the ModifiedFlag Attribute for Closed Order Lines

if(!header.getAttribute("OrderNumber").equals("100002054")) {
  return;
}
 
def lines = header.getAttribute("Lines");
while(lines.hasNext()) {
  def line = lines.next();
 
  if(line.getAttribute("ModifiedFlag").equals("Y") && line.getAttribute("StatusCode").equals("CLOSED")) {
    line.setAttribute("ModifiedFlag", "N");
  }
}

Manipulate Dates on Order Lines

import oracle.apps.scm.doo.common.extensions.ValidationException;  
import oracle.apps.scm.doo.common.extensions.Message;
import java.sql.Date;
import java.sql.Timestamp;
 
 
List<Message> messages = new ArrayList<Message>();
 def poNumber = header.getAttribute("CustomerPONumber");
  
if(poNumber != null && poNumber.equals("RAD") ){
 def lines=header.getAttribute("Lines");
    //Iterate through all lines on the sales order.
    while( lines.hasNext() ) {
        def line=lines.next();
         def reqShipDate=line.getAttribute("RequestedShipDate");
 
      long reqShipDateTime = reqShipDate.getTime();
      //No of days difference
      long oneDayMillSec  = toMilliSeconds(2);
       
      //Caleculate the final date to set.
      long diffDate = reqShipDateTime - oneDayMillSec;
       
    def date = new java.sql.Date(diffDate);
       
    //line.setAttribute("RequestedArrivalDate",date);
      line.setAttribute("ScheduleShipDate",date);
           
        }
}
 
public static long toMilliSeconds(long day)
{
    return day * 24 * 60 * 60 * 1000;
}

Remove the System Date from the Contract Start Date on the Order Line

Order Management sets the Contract Start Date attribute to the system date when you copy a sales order. Use this extension to remove the system date from the Contract Start Date.

def lines = header.getAttribute("Lines");
 
while( lines.hasNext() ) {
   def line = lines.next();
   def VARTotalContractAmount = line.getAttribute("TotalContractAmount");
   def refFlineId=line.getAttribute("ReferenceFulfillmentLineIdentifier");
   if( VARTotalContractAmount == null && refFlineId==null) {
      line.setAttribute("ContractStartDate1",null);
   }
 
}

Set the Default Value for the Unit of Measure on the Order Line

import oracle.apps.scm.doo.common.extensions.ValidationException;
 
def poNumber = header.getAttribute("CustomerPONumber");;
def reference = header.getAttribute("ReferenceHeaderId");
def headerId = header.getAttribute("HeaderId");
def sourceOrderId = header.getAttribute("SourceTransactionIdentifier");
 
//If you use the Order Management work area to create the sales order, then don't run this extension.
if (headerId == sourceOrderId)
    return;
//If its an order revision, then don't run this extension. Remove this condition to run the extension for revisions.
if (reference != null)
    return;
 
def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
    def line = lines.next();
    def inventoryItemId = line.getAttribute("ProductIdentifier");
    def orgId = line.getAttribute("InventoryOrganizationIdentifier");
    def parentFLineId = line.getAttribute("RootParentLineReference");
    if (parentFLineId != null) {
        def item = getItem(inventoryItemId, orgId);
        def uomCode = item.getAttribute("PrimaryUomCode");
        if (uomCode != null) {
            line.setAttribute("OrderedUOMCode", uomCode);
        }
    }
 
}
 
Object getItem(Long itemId, Long orgId) {
    def itemPVO = context.getViewObject("oracle.apps.scm.productModel.items.publicView.ItemPVO");
    def vc = itemPVO.createViewCriteria();
    def vcrow = vc.createViewCriteriaRow();
    vcrow.setAttribute("InventoryItemId", itemId);
    vcrow.setAttribute("OrganizationId", orgId);
    def rowset = itemPVO.findByViewCriteria(vc, -1);
    def item = rowset.first();
    return item;
}

Get the Rate for a Unit of Measure

import oracle.apps.scm.doo.common.extensions.ValidationException;
 
def serviceInvoker = context.getServiceInvoker();                                                      
 
String payLoad =  "<ns1:invUomConvert xmlns:ns1=\"http://xmlns.oracle.com/apps/scm/inventory/uom/uomPublicService/types/\">"+
            "<ns1:pInventoryItemId>141</ns1:pInventoryItemId>"+
            "<ns1:pFromQuantity>1</ns1:pFromQuantity>"+
            "<ns1:pFromUomCode>Ea</ns1:pFromUomCode>"+
            "<ns1:pToUomCode>Ea</ns1:pToUomCode>"+
            "<ns1:pFromUnitOfMeasure/>"+
            "<ns1:pToUnitOfMeasure/>"+
        "</ns1:invUomConvert>";
         
def responseBody = serviceInvoker.invokeSoapService("UOM_RATE", payLoad).getSoapBody().getTextContent();
//throw new ValidationException("response final_Uom_Rate : "+responseBody);

Revisions and Returns

Use an order management extension to manage revisions and returns.

  • Run Extension Only for Order Revisions

  • Validate Revision on Drop Ship Order

  • Copy an Attribute from a Previous Revision

  • Make Sure the Business Unit on the Return Order Matches the Business Unit on the Original Order

Run Extension Only for Order Revisions

import oracle.apps.scm.doo.common.extensions.ValidationException;   
import oracle.apps.scm.doo.common.extensions.Message;
def reference = header.getAttribute("ReferenceHeaderId");
List<Message> messages = new ArrayList<Message>();
 if(reference!=null){//firing for revisions
 //Include logic here that you want to run only for an order revision.
 }

Validate Revision on Drop Ship Order

Make sure the purchase order isn't on hold when you revise a sales order in a drop ship flow.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

def poNumber = header.getAttribute("CustomerPONumber");

if (poNumber == null) return;

if (!poNumber.startsWith("PMC TEST")) return;

List < Message > messages = new ArrayList < Message > ();

messages.add(new Message(Message.MessageType.ERROR, "In Code"));

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

def headerPVO = context.getViewObject("oracle.apps.scm.doo.processOrder.publicModel.partyMerge.view.HeaderPVO");

def vc = headerPVO.createViewCriteria();
def vcrow = vc.createViewCriteriaRow();
vcrow.setAttribute("SourceOrderNumber", header.getAttribute("SourceTransactionNumber"));
vcrow.setAttribute("SourceOrderSystem", header.getAttribute("SourceTransactionSystem"));
vcrow.setAttribute("StatusCode", "OPEN");

def rowset = headerPVO.findByViewCriteria(vc, -1);
def headerPRow = rowset.first();
def headerId = null;

if (headerPRow != null)
    headerId = headerPRow.getAttribute("HeaderId");
else {
    //ValidationException ex = new ValidationException(messages);
    //throw ex;
    return;
}

while (lines.hasNext()) {
    def line = lines.next();

    def linePVO = context.getViewObject("oracle.apps.scm.doo.processOrder.publicModel.partyMerge.view.FulfillLinePVO");

    def vcLine = linePVO.createViewCriteria();
    def vcrowLine = vcLine.createViewCriteriaRow();
    vcrowLine.setAttribute("HeaderId", headerId);
    vcrowLine.setAttribute("SourceLineId", line.getAttribute("SourceTransactionLineIdentifier"));

    def rowsetLine = linePVO.findByViewCriteria(vcLine, -1);
    def linePRow = rowsetLine.first();
    def flineId = null;

    if (linePRow != null)
        flineId = linePRow.getAttribute("FulfillLineId");
    else
        continue;

    def docRefPVO = context.getViewObject("oracle.apps.scm.doo.common.pricing.integration.publicView.DocumentReferencePVO");

    def vcDr = docRefPVO.createViewCriteria();
    def vcrowDr = vcDr.createViewCriteriaRow();
    vcrowDr.setAttribute("HeaderId", headerId);
    vcrowDr.setAttribute("FulfillLineId", flineId);
    vcrowDr.setAttribute("DocRefType", "DROPSHIP_PO_REFERENCE");

    def rowsetDr = docRefPVO.findByViewCriteria(vcDr, -1);
    def drPRow = rowsetDr.first();
    def poHeaderId = null;

    if (drPRow != null)
        poHeaderId = drPRow.getAttribute("DocId");
    else
        continue;


    def poPVO = context.getViewObject("oracle.apps.prc.po.publicView.PurchasingDocumentHeaderPVO");

    def vcPo = poPVO.createViewCriteria();
    def vcrowPo = vcPo.createViewCriteriaRow();
    vcrowPo.setAttribute("PoHeaderId", poHeaderId);

    def rowsetPo = poPVO.findByViewCriteria(vcPo, -1);
    def poPRow = rowsetPo.first();

    if (poPRow != null) {
        if ("Y".equals(poPRow.getAttribute("FrozenFlag")) || "ON HOLD".equals(poPRow.getAttribute("DocumentStatus")))
            throw new ValidationException("PO is frozen. OM Change cannot be submitted");

        def pvPVO = context.getViewObject("oracle.apps.prc.po.publicView.PurchasingDocumentVersionPVO");

        def vcPv = pvPVO.createViewCriteria();
        def vcrowPv = vcPv.createViewCriteriaRow();
        vcrowPv.setAttribute("PoHeaderId", poHeaderId);
        vcrowPv.setAttribute("ChangeOrderStatus", "INCOMPLETE");

        def rowsetPv = pvPVO.findByViewCriteria(vcPv, -1);
        def pvPRow = rowsetPv.first();

        if (pvPRow != null)
            messages.add(new Message(Message.MessageType.ERROR, "PO Change is in progress. OM Change cannot be submitted"));

    } else
        continue;
}

ValidationException ex = new ValidationException(messages);
throw ex;

Copy an Attribute from a Previous Revision

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
 
def po = header.getAttribute("CustomerPONumber");
def reference = header.getAttribute("ReferenceHeaderId");
 
previousLinesMap = [:];
if (reference == null)
return;
 
def lines = header.getAttribute("Lines");
populateReferenceLines(reference);
    while (lines.hasNext()) {
        def line = lines.next();
        def sourceLineId=line.getAttribute("SourceTransactionLineIdentifier");
        def originalLine=previousLinesMap.get(sourceLineId);
        def currentTaxCode=line.getAttribute("TaxClassificationCode");
        if(originalLine!=null && currentTaxCode==null){
            def orginalTaxCode=originalLine.getAttribute("FulfillLineTaxClassificationCode");
            line.setAttribute("TaxClassificationCode",orginalTaxCode);
        }
}
 
void populateReferenceLines(Long headerId) {
    def vo =context.getViewObject("oracle.apps.scm.doo.publicView.analytics.FulfillLinePVO");
    def vc1 = vo.createViewCriteria();
    def vcrow1 = vc1.createViewCriteriaRow();
    vcrow1.setAttribute("FulfillLineHeaderId", headerId);
    rowset1 = vo.findByViewCriteria(vc1, -1);
 
    while (rowset1.hasNext()) {
        def originalFLine=rowset1.next();
 
        previousLinesMap.put(originalFLine.getAttribute("FulfillLineSourceLineId"),originalFLine);
    }
}

Make Sure the Business Unit on the Return Order Matches the Business Unit on the Original Order

import oracle.apps.scm.doo.common.extensions.ValidationException;
 
/*
def poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null || !("VS_BU_TEST".equals(poNumber))) {
  return;
}
*/
 
Set<Long> referencedReturnLinesHeaderIds = null;
 
def lines = header.getAttribute("Lines");
while( lines.hasNext() ) {
 
  def line = lines.next();
 
  def categoryCode = line.getAttribute("TransactionCategoryCode");
  if (categoryCode == null || !(categoryCode.equals("RETURN"))) {
    continue;
  }
 
  def docRefs = line.getAttribute("DocumentReferences");
  Long headerId = null;
  while(docRefs.hasNext()) {
 
    def docRef = docRefs.next();
    String docRefType = docRef.getAttribute("DocumentReferenceType");
    if( "ORIGINAL_ORCHESTRATION_ORDER".equals(docRefType) ) {
      if (referencedReturnLinesHeaderIds == null) {
        referencedReturnLinesHeaderIds = new HashSet<Long>();
      }
      headerId = new Long(docRef.getAttribute("DocumentIdentifier"));
      if (!(referencedReturnLinesHeaderIds.contains(headerId))) {
        referencedReturnLinesHeaderIds.add(headerId);
      }
      break;
    }
  }
}
 
if (referencedReturnLinesHeaderIds != null && referencedReturnLinesHeaderIds.size()>0) {
 
  def buId = header.getAttribute("BusinessUnitIdentifier");
 
  def vo = context.getViewObject("oracle.apps.scm.doo.publicView.analytics.HeaderPVO");
  def vc = vo.createViewCriteria();                                                             
 
  def vcrow = vc.createViewCriteriaRow();
  Object inQuery = " in " + referencedReturnLinesHeaderIds;
  inQuery = inQuery.replace('[', '(');
  inQuery = inQuery.replace(']', ')');
  vcrow.setAttribute("HeaderId", inQuery);
 
  def rowset = vo.findByViewCriteria(vc, -1);
  def row = null;
  if(rowset.hasNext()){
    row = rowset.next();
    def returnBuId = row.getAttribute("BUBusinessUnitId");
    if (returnBuId != buId) {
      throw new ValidationException("The request failed. Make sure the business unit of this return order matches the business unit on the original order, then resubmit your sales order. ");
    }
  }
}

Shipping

Use an order management extension to manage shipping.

  • Validate Ship-to, Bill-to, and Sold-to Attributes

  • Set the Default Value for Ship-To Address According to Business Unit

  • Cascade the Shipping Method from the Order Header to Order Lines

  • Populate Shipping Instructions on Order Lines

Validate Ship-to, Bill-to, and Sold-to Attributes

Get values for the Ship-to, Bill-to, and Sold-to attributes from the order header. Compare them to the customer account details and validate that they're all for the same customer.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

def poNumber = header.getAttribute("CustomerPONumber");

if (poNumber == null) return;

if (!poNumber.startsWith("PMC TEST")) return;

List < Message > messages = new ArrayList < Message > ();

boolean relationExists = false;

def soldTo = header.getAttribute("BuyingPartyIdentifier");
def shipTo = header.getAttribute("ShipToPartyIdentifier");
def billTo = header.getAttribute("BillToCustomerIdentifier");

messages.add(new Message(Message.MessageType.ERROR, "Sold to is " + soldTo));
messages.add(new Message(Message.MessageType.ERROR, "Ship to is " + shipTo));
messages.add(new Message(Message.MessageType.ERROR, "Bill to is " + billTo));

if (header.getAttribute("BuyingPartyName") == header.getAttribute("BillToCustomerName"))
    relationExists = true;

messages.add(new Message(Message.MessageType.ERROR, "Buying Party Name is  " + (header.getAttribute("BuyingPartyName"))));
messages.add(new Message(Message.MessageType.ERROR, "Bill to Customer Name is  " + header.getAttribute("BillToCustomerName")));


def CustPVO = context.getViewObject("oracle.apps.cdm.foundation.parties.publicView.customerAccounts.CustomerAccountRelationshipPVO");
def vc = CustPVO.createViewCriteria();
def vcrow = vc.createViewCriteriaRow();
vcrow.setAttribute("RelatedCustAccountId", soldTo);
def rowSet = CustPVO.findByViewCriteria(vc, -1);

messages.add(new Message(Message.MessageType.ERROR, "Found a row: " + rowSet.hasNext()));

while (rowSet.hasNext()) {
    def row = rowSet.next();
    def billtorelation = row.getAttribute("CustAccountId");
    if (billtorelation == billTo) {
        relationExists = true;
    }
}

//header.setAttribute("ShippingInstructions", header.getAttribute("ShippingInstructions") + ", " + relationExists);

/*
if( !relationExists) {
 
  messages.add(new Message( "Bill To Customer is not related with Sold To"));
}  
*/
ValidationException ex = new ValidationException(messages);
throw ex;

Set the Default Value for Ship-To Address According to Business Unit

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
 
List<Message> messages = new ArrayList<Message>();
 
def buNumber = header.getAttribute("BusinessUnitIdentifier");
 
def lines = header.getAttribute("Lines");                                                            
if(!lines.hasNext()){
 messages.add(new Message( Message.MessageType.ERROR,"No lines available"));
}
while( lines.hasNext() ) {                                                                           
  def line = lines.next();
//Add more business units according to your requirements. 
  if(buNumber==204){
    setShipToPartySiteId(line,messages,1220);//Have to pass the ShipToPartySiteId
    }
  if(buNumber==500){
    setShipToPartySiteId(line,messages,1222);
    }
}//end of while
 
if(!messages.isEmpty()) {                          
        ValidationException ex = new ValidationException(messages);
        throw ex;
   }
 
 
def setShipToPartySiteId(def line,List<Message> messages, def partySiteId){
  def partySiteUsgFlag = getPartySiteUssage(partySiteId);
  if(!partySiteUsgFlag){
      messages.add(new Message( Message.MessageType.ERROR,"The Ship-to Address isn't valid. Examine your setup."));
      return null;
  }//shipBeginDate  null check
  else{
    header.setAttribute("ShipToPartySiteIdentifier",partySiteId);
    line.setAttribute("ShipToPartySiteIdentifier",partySiteId);
  }
   return null;
}
 
def getPartySiteUssage(Long partySiteId) {
def PartySiteUsePVO = context.getViewObject("oracle.apps.cdm.foundation.parties.publicView.analytics.PartySiteUsePVO");       
  def vc = PartySiteUsePVO.createViewCriteria();                                                              
  def vcrow = vc.createViewCriteriaRow();
   
  vcrow.setAttribute("PartySiteId", partySiteId); 
  vcrow.setAttribute("SiteUseType", "SHIP_TO");
  def rowset = PartySiteUsePVO.findByViewCriteria(vc, -1);
    if(rowset.hasNext()){
    def row = rowset.next();
  return true;
  }
  else
    return null;
}

Cascade the Shipping Method from the Order Header to Order Lines

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
def poNumber = header.getAttribute("CustomerPONumber");
List<Message> messages = new ArrayList<Message>();
 
if(poNumber != "shipmethod") return;
def ServiceCode=header.getAttribute("ShipClassOfServiceCode");
def Carrier=header.getAttribute("CarrierId");
def ShipModeOfTransport=header.getAttribute("ShipModeOfTransportCode");
 
def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
            def line = lines.next();
            line.setAttribute("ShippingInstructions","ship_method_test");
            line.setAttribute("ShippingCarrierCode",Carrier);
            line.setAttribute("ShippingServiceLevelCode",ServiceCode);
            line.setAttribute("ShippingModeCode",ShipModeOfTransport);
}

Populate Shipping Instructions on Order Lines

Run this extension when the original order doesn't contain shipping instructions and you're revising the order.

import oracle.apps.scm.doo.common.extensions.ValidationException;
def poNumber = header.getAttribute("CustomerPONumber");
def orderNumber = header.getAttribute("SourceTransactionNumber");
 
if(orderNumber != "BMIQ-05022018-248408") return;
if(changeVN < 2) return;
 
def lines = header.getAttribute("Lines");
    while (lines.hasNext()) {
            def line = lines.next();
            def lineStatus = line.getAttribute("StatusCode");
            def shipInst = line.getAttribute("ShippingInstructions");
                if("CLOSED".equals(lineStatus) && shipInst != null){
                def refFlineId = line.getAttribute("ReferenceFulfillmentLineIdentifier");
                if(refFlineId == null){
                  continue;
                }
                def orginalFlinePRow = getFLineForRefFLine(refFlineId);
                if(orginalFlinePRow!=null) {
                   def lineStatus1 = orginalFlinePRow.getAttribute("FulfillLineStatusCode");
                   def shipInst1 = orginalFlinePRow.getAttribute("FulfillLineShippingInstructions");
                   if("CLOSED".equals(lineStatus1) && shipInst1 == null){
                      line.setAttribute("ShippingInstructions", null);
                   }
     }
    }      
}
 
def Object getFLineForRefFLine(Long refFlineId) {
def vo = context.getViewObject("oracle.apps.scm.doo.publicView.analytics.FulfillLinePVO");
   Object[] rows = vo.findByKey(refFlineId, 1);
   def originalFLine = rows[0];
   
   return originalFLine;
}

Make Sure Site Usage is Ship To

import oracle.apps.scm.doo.common.extensions.ValidationException;
def poNumber = header.getAttribute("CustomerPONumber");
 
if(poNumber != null && poNumber.equals("ship")) {
 
def lines = header.getAttribute("Lines");                                                            
while( lines.hasNext() ) {                                                                           
  def line = lines.next();                                                                           
  def partySiteId = line.getAttribute("ShipToPartySiteIdentifier"); 
 //throw new ValidationException("partySiteUseId :"+partySiteUseId);
  
  if(!(getPartySiteUssage(partySiteId)))                                                        
   throw new ValidationException("siteUssage is not shipto");
  }
 
}
 
Boolean getPartySiteUssage(Long partySiteId) {
def PartySiteUsePVO = context.getViewObject("oracle.apps.cdm.foundation.parties.publicView.analytics.PartySiteUsePVO");       
  def vc = PartySiteUsePVO.createViewCriteria();                                                              
  def vcrow = vc.createViewCriteriaRow();
   
  vcrow.setAttribute("PartySiteId", partySiteId); 
  vcrow.setAttribute("SiteUseType", "SHIP_TO");
  def rowset = PartySiteUsePVO.findByViewCriteria(vc, -1);
   
  if(rowset.hasNext())
  return true;
  else
    return false;
 
}

Billing and Payment

Use an order management extension to manage billing and payment.

  • Get Details for Billing Plans from Order Lines

  • Get Details for Payment Methods from Order Lines

  • Set the Billing Transaction ID

  • Prevent Updates on the Billing Transaction Type

  • Set the Default Value for the Payment Term

  • Set the Default Value for the Payment Term Before You Submit the Sales Order

Set the Default Value of the Payment Term According to CustAccountId and Date Range

Get Details for Billing Plans from Order Lines

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

def poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null) return;
if (!poNumber.startsWith("PMC TEST")) return;

List < Message > messages = new ArrayList < Message > ();

def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
    def line = lines.next();
    def billingPlans = line.getAttribute("BillingPlans");
    while (billingPlans.hasNext()) {
        def billingPlan = billingPlans.next();
        messages.add(new Message(Message.MessageType.ERROR, "BillingPlanTypeCode is " + billingPlan.getAttribute("BillingPlanTypeCode")));
        messages.add(new Message(Message.MessageType.ERROR, "BillingPlanId is " + billingPlan.getAttribute("BillingPlanId")));
        messages.add(new Message(Message.MessageType.ERROR, "ObjectVersionNumber is " + billingPlan.getAttribute("ObjectVersionNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "BillingTrxDate is " + billingPlan.getAttribute("BillingTrxDate")));
        messages.add(new Message(Message.MessageType.ERROR, "CancellationEffectiveDate is " + billingPlan.getAttribute("CancellationEffectiveDate")));
        messages.add(new Message(Message.MessageType.ERROR, "FulfillLineId is " + billingPlan.getAttribute("FulfillLineId")));

        messages.add(new Message(Message.MessageType.ERROR, "OverridePeriod is " + billingPlan.getAttribute("OverridePeriod")));
        messages.add(new Message(Message.MessageType.ERROR, "OverridePeriodAmount is " + billingPlan.getAttribute("OverridePeriodAmount")));
        messages.add(new Message(Message.MessageType.ERROR, "PeriodicityCode is " + billingPlan.getAttribute("PeriodicityCode")));
        messages.add(new Message(Message.MessageType.ERROR, "PeriodicityName is " + billingPlan.getAttribute("PeriodicityName")));
    }
}

ValidationException ex = new ValidationException(messages);
throw ex;.

Get Details for Payment Methods from Order Lines

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

if (!"PMC TEST".equals(header.getAttribute("CustomerPONumber"))) return;

List < Message > messages = new ArrayList < Message > ();

def lines = header.getAttribute("Lines");
while (lines.hasNext()) {
    def line = lines.next();

    def payments = line.getAttribute("Payments");

    messages.add(new Message(Message.MessageType.ERROR, "PaymentMethodCode is " + payments.hasNext()));

    while (payments.hasNext()) {
        def payment = payments.next();


        messages.add(new Message(Message.MessageType.ERROR, "PaymentMethodCode is " + payment.getAttribute("PaymentMethodCode")));
        messages.add(new Message(Message.MessageType.ERROR, "PaymentTransactionIdentifier is " + payment.getAttribute("PaymentTransactionIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "PaymentSetIdentifier is " + payment.getAttribute("PaymentSetIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "SourceTransactionPaymentIdentifier is " + payment.getAttribute("SourceTransactionPaymentIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "ReceiptMethodId is " + payment.getAttribute("ReceiptMethodId")));
        messages.add(new Message(Message.MessageType.ERROR, "PaymentMethod is " + payment.getAttribute("PaymentMethod")));
        messages.add(new Message(Message.MessageType.ERROR, "PaymentTypeCode is " + payment.getAttribute("PaymentTypeCode")));
        messages.add(new Message(Message.MessageType.ERROR, "PaymentType is " + payment.getAttribute("PaymentType")));
        messages.add(new Message(Message.MessageType.ERROR, "FulfillLineId is " + payment.getAttribute("FulfillLineId")));
        messages.add(new Message(Message.MessageType.ERROR, "HeaderId is " + payment.getAttribute("HeaderId")));
        messages.add(new Message(Message.MessageType.ERROR, "ObjectVersionNumber is " + payment.getAttribute("ObjectVersionNumber")));

        messages.add(new Message(Message.MessageType.ERROR, "AuthorizationStatus is " + payment.getAttribute("AuthorizationStatus")));
        messages.add(new Message(Message.MessageType.ERROR, "InstrumentAssignmentIdentifier is " + payment.getAttribute("InstrumentAssignmentIdentifier")));
    }

}

ValidationException ex = new ValidationException(messages);
throw ex;

Set the Billing Transaction ID

String orderTypeCode = header.getAttribute("TransactionTypeCode");
 
def billingTxnTypeId = null;
 
if( orderTypeCode.equals("STD") ) { // Get the order type.       
   billingTxnTypeId = getBillingTxnTypeId("Credit Memo"); 
}
else if ( orderTypeCode.equals("MIX") ){
   billingTxnTypeId = getBillingTxnTypeId("Invoice");          
}
 
def lines = header.getAttribute("Lines");// Get the lines for the row set.
 
while( lines.hasNext() ) {// If more order lines exist...
    def line = lines.next(); 
    line.setAttribute("BillingTransactionTypeIdentifier", billingTxnTypeId);
}
 
Long getBillingTxnTypeId(String billingTxnTypeName) {
  
  def txnTypePVO = context.getViewObject("oracle.apps.financials.receivables.publicView.TransactionTypePVO");
     
  // Create view criteria (where clause predicates)
  def vc = txnTypePVO.createViewCriteria();
  def vcrow = vc.createViewCriteriaRow();
  vcrow.setAttribute("Name", billingTxnTypeName); 
   
   
  // Execute the view object query to find a matching row
  def rowset = txnTypePVO.findByViewCriteriaWithBindVars(vc, 1, new String[0], new Object[0]);
     
  // check if we have a matching row
  def row = rowset.first();
   
  Long txnTypeId = (Long) row.getAttribute("CustTrxTypeSeqId");
  //header.setAttribute("ShippingInstructions", txnTypeId);  // debug statement
   
  return txnTypeId;
}

Prevent Updates on the Billing Transaction Type

If Order Management already sent the order line to accounts receivable, then don't allow Order Management to update the billing transaction type on the order line.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
 
def po = header.getAttribute("CustomerPONumber");
if (po == null || !"VS_TEST".equals(po))
    return;
 
def reference = header.getAttribute("ReferenceHeaderId");
if (reference == null) return;
 
previousLinesMap = [:];
IsBillingTrxTypeIdUpdateable(reference);
 
if(previousLinesMap.size() == 0) {
  return;
}
 
 
def billTrxTypeId = null;
def origBillTrxTypeId = null;
def refFlineId = null;
 
def lines = header.getAttribute("Lines");
def line = null;
while (lines.hasNext()) {
 
    line = lines.next();
 
    refFlineId = line.getAttribute("ReferenceFulfillmentLineIdentifier");
 
    if (refFlineId != null && previousLinesMap.containsKey(refFlineId)) {
        billTrxTypeId = line.getAttribute("BillingTransactionTypeIdentifier");
        origBillTrxTypeId = previousLinesMap.get(refFlineId);
        if( (billTrxTypeId == null && origBillTrxTypeId == null) || (billTrxTypeId != null && origBillTrxTypeId != null && billTrxTypeId == origBillTrxTypeId)) {
            continue;
        }
        throw new ValidationException("Billing Transaction Type (aka Receivable Transaction Type) can't be updated :: Line#" + line.getAttribute("DisplayLineNumber") + " [ NEW:" + billTrxTypeId + " - OLD:" + origBillTrxTypeId + " ]");
    }
}
     
void IsBillingTrxTypeIdUpdateable(def referenceHeaderId) {
 
    def statusesSet = ["AWAIT_BILLING", "BILLED", "CANCELED", "CLOSED"] as Set;
 
    def vo = context.getViewObject("oracle.apps.scm.doo.publicView.analytics.FulfillLinePVO");
    def vc = vo.createViewCriteria();
    def vcrow = vc.createViewCriteriaRow();
    vcrow.setAttribute("FulfillLineHeaderId", referenceHeaderId);
    rowset = vo.findByViewCriteria(vc, -1);
     
    def line = null;
    def fldItr = null;
    def fld = null;
    while (rowset.hasNext()) {
 
      line = rowset.next();
 
        if (statusesSet.contains(line.getAttribute("FulfillLineStatusCode"))) {
            previousLinesMap.put(line.getAttribute("FulfillLineId"), line.getAttribute("FulfillLineBillingTrxTypeId"));
            continue;
        }
 
        fldItr = line.getAttribute("FulfillLineDetail");
        while(fldItr.hasNext()) {
            fld = fldItr.next();
            if("Invoice".equals(fld.getAttribute("FulfillLineDetailTaskType"))) {
                previousLinesMap.put(line.getAttribute("FulfillLineId"), line.getAttribute("FulfillLineBillingTrxTypeId"));
                break;
            }
        }
    }
}

Set the Default Value for the Payment Term

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
 
List < Message > messages = new ArrayList < Message > ();
def logger = context.getLogger();
 
//def PName = header.getAttribute("BillToCustomerName");
//def custActId = header.getAttribute("BillToCustomerIdentifier");
//def siteUseId = header.getAttribute("BillToAccountSiteUseIdentifier");
 
def HeaderPayTerm = header.getAttribute("PaymentTermCode");
def lines = header.getAttribute("Lines");
if (!lines.hasNext()){
    throw new ValidationException("More time is needed to process the order");
}
 
while (lines.hasNext()) {
 
    def line = lines.next();
    def custActId = line.getAttribute("BillToCustomerIdentifier");
    def siteUseId = line.getAttribute("BillToAccountSiteUseIdentifier");
    def linePayTerm = line.getAttribute("PaymentTermCode");
    def linetransactioncode = line.getAttribute("TransactionCategoryCode");
 
    //def termId = getBillToPartyIdTermId(PName);
    def termId = getTermID(custActId, siteUseId);
    def termName = gettermName(termId);
    logger.logSevere("Term Name TrxPaymentTermPVO : ", termName);
    if (HeaderPayTerm == null && linePayTerm == null && linetransactioncode != 'RETURN') {
        if (termId != null){
            header.setAttribute("PaymentTerm", termName);
            line.setAttribute("PaymentTerm", termName);
        }
    }
}
 
Object getTermID(Long custActId, Long siteUseId) {
    def termId;
    def logger = context.getLogger();
    def custProfilePVO =
        context.getViewObject("oracle.apps.financials.receivables.publicView.analytics.CustomerFinancialProfilePVO");
    def vc1 = custProfilePVO.createViewCriteria();
    def vcrow1 = vc1.createViewCriteriaRow();
    vcrow1.setAttribute("CustProfileCustAccountId", custActId);
    vcrow1.setAttribute("CustProfileSiteUseId", siteUseId);
    vcrow1.setAttribute("CustProfileStandardTerms", "> -1");
 
    def rowset1 = custProfilePVO.findByViewCriteria(vc1, -1);
    def profile = rowset1.first();
    if (profile != null) {
 
        termId = profile.getAttribute("CustProfileStandardTerms");
        header.setAttribute("ShippingInstructions", "TERM=" + termId);
        logger.logSevere("Term Id from CustomerFinancialProfilesPVO : ", termId);
    }
    else {
        vc1 = custProfilePVO.createViewCriteria();
        vcrow1 = vc1.createViewCriteriaRow();
        vcrow1.setAttribute("CustProfileCustAccountId", custActId);
        vcrow1.setAttribute("CustProfileSiteUseId", "is null");
        vcrow1.setAttribute("CustProfileStandardTerms", "> -1");
         
        rowset1 = custProfilePVO.findByViewCriteria(vc1, -1);
        profile = rowset1.first();
        if (profile != null) {
 
            termId = profile.getAttribute("CustProfileStandardTerms");
            header.setAttribute("ShippingInstructions", "TERM=" + termId);
            logger.logSevere("Term Id from CustomerFinancialProfilesPVO : ", termId);
        }
        else {
            header.setAttribute("ShippingInstructions", termId);
            throw new ValidationException("No Payment Term found for the BillToCustomer 2 :: "+siteUseId);
        }
    }
    return termId;
}
 
Object gettermName(Long termID) {
    def raTermPVO =
        context.getViewObject("oracle.apps.financials.receivables.publicView.TrxPaymentTermPVO");
    def vc2 = raTermPVO.createViewCriteria();
    def vcrow2 = vc2.createViewCriteriaRow();
    vcrow2.setAttribute("TermId", termID);
    def rowset2 = raTermPVO.findByViewCriteria(vc2, -1);
    def termName = rowset2.first();
    def paymentName = termName.getAttribute("Name");
    header.setAttribute("PackingInstructions", paymentName);
    return paymentName;
}

Set the Default Value for the Payment Term Before You Submit the Sales Order

//preSubmit_PAYMENT_TERM_DEFAULTING//
import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
 
 
//Return if not a test order based on PO number if
(!"TERMS".equals(header.getAttribute("CustomerPONumber")))
return;
List < Message > messages = new ArrayList <
Message > (); def logger = context.getLogger();
//def PName =
header.getAttribute("BillToCustomerName");
//def custActId = header.getAttribute("BillToCustomerIdentifier");
//def siteUseId =
header.getAttribute("BillToAccountSiteUseIdentifier");
def HeaderPayTerm =
header.getAttribute("PaymentTermCode");
 
def lines = header.getAttribute("Lines"); if
(!lines.hasNext()){ throw new ValidationException("More time is needed to
process the order"); } while (lines.hasNext()) {
def line = lines.next();
 
 
def custActId =
line.getAttribute("BillToCustomerIdentifier");
 
def siteUseId =
line.getAttribute("BillToAccountSiteUseIdentifier");
 
def linePayTerm =
line.getAttribute("PaymentTermCode");
 
def linetransactioncode =
line.getAttribute("TransactionCategoryCode");
 
 
//def termId = getBillToPartyIdTermId(PName);
def termId = getTermID(custActId, siteUseId);
def termName = gettermName(termId);
logger.logSevere("Term Name TrxPaymentTermPVO : ", termName);
if(HeaderPayTerm == null && linePayTerm == null && linetransactioncode !='RETURN') {
 
        if (termId != null){
            header.setAttribute("PaymentTerm", termName);
            line.setAttribute("PaymentTerm", termName);
        }
    }
}
 
Object getTermID(Long custActId, Long siteUseId) { def
termId; def logger = context.getLogger(); def custProfilePVO =
context.getViewObject("oracle.apps.financials.receivables.publicView.analytics.CustomerFinancialProfilesPVO");
 
def vc1 = custProfilePVO.createViewCriteria();
 
def vcrow1 = vc1.createViewCriteriaRow();
vcrow1.setAttribute("CustProfileCustAccountId", custActId);
//vcrow1.setAttribute("CustProfileSiteUseId", siteUseId);
vcrow1.setAttribute("CustProfileStandardTerms", "> -1");
 
//vcrow1.setAttribute("PartyId", partyId); def
rowset1 = custProfilePVO.findByViewCriteria(vc1, -1);
def profile =rowset1.first();
    if (profile != null) {
        termId =profile.getAttribute("CustProfileStandardTerms");
        logger.logSevere("Term Id from CustomerFinancialProfilesPVO: ", termId);
   }
   else throw new ValidationException("No Payment Term found for the BillToCustomer :: "+custActId); return termId; }
 
Object gettermName(Long termID) {
def raTermPVO = context.getViewObject("oracle.apps.financials.receivables.publicView.TrxPaymentTermPVO");
def vc2 = raTermPVO.createViewCriteria(); def vcrow2 =
vc2.createViewCriteriaRow(); vcrow2.setAttribute("TermId", termID);
def rowset2 = raTermPVO.findByViewCriteria(vc2, -1); def termName =
rowset2.first(); def paymentName = termName.getAttribute("Name")
return paymentName;
}

Set the Default Value of the Payment Term According to CustAccountId and Date Range

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
 
List < Message > messages = new ArrayList < Message > ();
def logger = context.getLogger();
 
//def PName = header.getAttribute("BillToCustomerName");
//def custActId = header.getAttribute("BillToCustomerIdentifier");
//def siteUseId = header.getAttribute("BillToAccountSiteUseIdentifier");
 
def HeaderPayTerm = header.getAttribute("PaymentTermCode");
def lines = header.getAttribute("Lines");
if (!lines.hasNext()) {
 throw new ValidationException("More time is needed to process the order");
 //header.setAttribute("ShippingInstructions","More time is needed to process the order");
}
 
 
while (lines.hasNext()) {
 
 def line = lines.next();
 def custActId = line.getAttribute("BillToCustomerIdentifier");
 def siteUseId = line.getAttribute("BillToAccountSiteUseIdentifier");
 def linePayTerm = line.getAttribute("PaymentTermCode");
 def linetransactioncode = line.getAttribute("TransactionCategoryCode");
 
 //def termId = getBillToPartyIdTermId(PName);
 def termId = getTermID(custActId, siteUseId);
 def termName = gettermName(termId);
 logger.logSevere("Term Name TrxPaymentTermPVO : ", termName);
 if (HeaderPayTerm == null && linePayTerm == null && linetransactioncode != 'RETURN') {
  if (termId != null) {
   header.setAttribute("PaymentTerm", termName);
   line.setAttribute("PaymentTerm", termName);
  }
 }
}
 
 
Object getTermID(Long custActId, Long siteUseId) {
 def termId;
 def logger = context.getLogger();
 def custProfilePVO =
  context.getViewObject("oracle.apps.financials.receivables.publicView.analytics.CustomerPrfilePVO");
  
 java.sql.Date sqlDate = new java.sql.Date((new Date()).getTime());
  
 def vc1 = custProfilePVO.createViewCriteria();
 def vcrow1 = vc1.createViewCriteriaRow();
 vcrow1.setAttribute("CustomerProfileCustAccountId", custActId);
 vcrow1.setAttribute("CustomerProfileSiteUseId", siteUseId);
 vcrow1.setAttribute("CustomerProfileStandardTerms", "> -1");
 vcrow1.setAttribute("CustomerProfileEffectiveEndDate", ">= "+sqlDate);
 vcrow1.setAttribute("CustomerProfileEffectiveStartDate", " <= "+sqlDate);
  
 def rowset1 = custProfilePVO.findByViewCriteria(vc1, -1);
 def profile = rowset1.first();
 if (profile != null) {
 
  termId = profile.getAttribute("CustomerProfileStandardTerms");
  //header.setAttribute("ShippingInstructions", "TERM=" + termId);
  logger.logSevere("Term Id from CustomerFinancialProfilesPVO : ", termId);
 } else {
  vc1 = custProfilePVO.createViewCriteria();
  vcrow1 = vc1.createViewCriteriaRow();
  vcrow1.setAttribute("CustomerProfileCustAccountId", custActId);
  vcrow1.setAttribute("CustomerProfileSiteUseId", "is null");
  vcrow1.setAttribute("CustomerProfileStandardTerms", "> -1");
  vcrow1.setAttribute("CustomerProfileEffectiveEndDate", ">= "+sqlDate);
  vcrow1.setAttribute("CustomerProfileEffectiveStartDate", " <= "+sqlDate); 
 
  rowset1 = custProfilePVO.findByViewCriteria(vc1, -1);
  profile = rowset1.first();
  if (profile != null) {
 
   termId = profile.getAttribute("CustomerProfileStandardTerms");
   //header.setAttribute("ShippingInstructions", "TERM=" + termId);
   logger.logSevere("Term Id from CustomerFinancialProfilesPVO : ", termId);
  } else {
   //header.setAttribute("ShippingInstructions", termId);
   throw new ValidationException("No Payment Term found for the BillToCustomer 2 :: " + siteUseId);
  }
 }
 return termId;
}
 
Object gettermName(Long termID) {
 def raTermPVO =
  context.getViewObject("oracle.apps.financials.receivables.publicView.TrxPaymentTermPVO");
 def vc2 = raTermPVO.createViewCriteria();
 def vcrow2 = vc2.createViewCriteriaRow();
 vcrow2.setAttribute("TermId", termID);
 def rowset2 = raTermPVO.findByViewCriteria(vc2, -1);
 def termName = rowset2.first();
 def paymentName = termName.getAttribute("Name");
 header.setAttribute("PackingInstructions", paymentName);
 return paymentName;
}

Extensible Flexfields

Use an order management extension to manage extensible flexfields.

  • Take Action According to the Value of an Extensible Flexfield

  • Copy Extensible Flexfield Values to Data Values

  • Copy Extensible Flexfield Values from the Original Fulfillment Line During a Return Order

  • Use an Extensible Flexfield to Update Ship-To Addresses

Take Action According to the Value of an Extensible Flexfield

import oracle.apps.scm.doo.common.extensions.ValidationException;
 
def poNumber = header.getAttribute("CustomerPONumber");
 
if(poNumber != null && poNumber.equals("test") ){
def lines = header.getAttribute("Lines");
while( lines.hasNext() ) {
def line = lines.next();
def context = line.getOrCreateContextRow("VS_Context");
    def effVal = context.getAttribute("eligibleforprime");
     
// throw new ValidationException("Eff value effVal:: "+effVal);
    if(effVal.equals("Y")){
      line.setAttribute("OrderedQuantity",0);   
    }
 
}
}

Copy Extensible Flexfield Values to Data Values

import oracle.apps.scm.doo.common.extensions.ValidationException;
def poNumber = header.getAttribute("CustomerPONumber");
 
if(poNumber != null && poNumber.equals("TEST_CO2") ){
def docRefs = header.getAttribute("DocumentReferences");
  if (!docRefs.hasNext()){
 throw new ValidationException("We need more time to get the document reference.");
}
while(docRefs.hasNext()) { 
def docRef = docRefs.next();
String docRefType = docRef.getAttribute("DocumentReferenceType");
if(!'COPY_REF_ORDER'.equals(docRefType))continue;
def cntxRow = header.getOrCreateContextRow("HeaderContext1");
cntxRow.setAttribute("_H1AttributeChar2",docRef.getAttribute("DocumentNumber"));                 
}
}

Copy Extensible Flexfield Values from the Original Fulfillment Line During a Return Order

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
import java.util.logging.Level;
  
Long lineId = 0;
Long headerId = 0;
def lines = header.getAttribute("Lines");
  
while( lines.hasNext() ) {
 def line = lines.next();
    
  String categoryCode = line.getAttribute("TransactionCategoryCode");
    
  if ("RETURN" != categoryCode) continue;
  def docRefs = line.getAttribute("DocumentReferences");
  lineId = 0;
 while(docRefs.hasNext() & lineId == 0) {
  
   def docRef = docRefs.next();
   String docRefType = docRef.getAttribute("DocumentReferenceType");
   if( "ORIGINAL_ORCHESTRATION_ORDER" == docRefType ) {
     // We found the document reference that references the original order.
     // The DocumentSubLineIdentifier attribute identifies the fulfillment line on the original order.
       
     lineId = new Long(docRef.getAttribute("DocumentSubLineIdentifier"));
  
     if(headerId == 0) {
         // The DocumentIdentifier attribute identifies the header of the original order.
         headerId = new Long(docRef.getAttribute("DocumentIdentifier"));
       if (headerId !=0){
           def voRow = getContextHeaderRow(headerId, "HeaderBIEffBComplianceDetailsBIVO");
           def complianceInfo = voRow.getAttribute("_ComplianceInfo");
        
           def context = header.getOrCreateContextRow("ComplianceDetails");
           context.setAttribute("_ComplianceInfo",complianceInfo);
        }
     }
   }
 }
  if ( lineId != 0) {
   // throw new ValidationException(lineId.toString());
    /*
    def oLine = getLine(lineId);
    if (oLine == null) continue;
      
   def Ocontext = oLine.getAttribute("FulfillLineBIEffEFFBIFlattened");
    def oContextRow = Ocontext.first();
        def oattr1 = oContextRow.getAttribute("DOO_FULFILL_LINES_ADD_INFO_FulfillLineContext1_EffLineId");
    def oattr = oContextRow.getAttribute("DOO_FULFILL_LINES_ADD_INFO_FulfillLineContext1__FL1AttributeNum1");
     */
     
      def voRow = getContextVORow(lineId, "FulfillLineBIEffBPackShipInstructionBIVO");
  def contNum1 = voRow.getAttribute("_PackingInstruction");
 
    def context = line.getOrCreateContextRow("PackShipInstruction");
    context.setAttribute("_PackingInstruction",contNum1);
      //  context.setAttribute("_FL1AttributeNum1",23323);
  
     
      
  }
  else{
  throw new ValidationException("We couldn't find a value.");
    
  }
    
// def effValues = line.getOrCreateContextRow("SODetails");
// effValues.setAttribute("cogs",12);
  
}
  
def Object getLine(Long lineId) {
   
def vo = context.getViewObject("oracle.apps.scm.doo.publicView.analytics.FulfillLinePVO");
  
 Object[] rows = vo.findByKey(lineId, 1);
 def originalFLine = rows[0];
   
 return originalFLine;
}
 
/**
 * Returns a row for the context on the order header.
 * @param contextVOName identifies the name of the context for the virtual object. To get this value, use the context code or look it up in the extensible flexfield archive.
 * under oracle/apps/publicFlex/scm/doo/headerContextsB/analytics/view
 */
Object getContextVORow(Long headerId, String contextVOName) {    
     def contextVO = context.getViewObject("oracle.apps.publicFlex.scm.doo.fulfillLineContextsB.analytics.view." + contextVOName);
     def vc = contextVO.createViewCriteria();
     def vcrow = vc.createViewCriteriaRow();
     vcrow.setAttribute("FulfillLineId", headerId);
     def rowset = contextVO.findByViewCriteria(vc, -1);
     def effRow = rowset.first();
     return effRow;
}
 
Object getContextHeaderRow(Long headerId, String contextVOName) {    
     def contextVO = context.getViewObject("oracle.apps.publicFlex.scm.doo.headerContextsB.analytics.view." + contextVOName);
     def vc = contextVO.createViewCriteria();
     def vcrow = vc.createViewCriteriaRow();
     vcrow.setAttribute("HeaderId", headerId);
     def rowset = contextVO.findByViewCriteria(vc, -1);
     def effRow = rowset.first();
     return effRow;
}

Use an Extensible Flexfield to Update Ship-To Addresses

If the customer relationship type is Single, then set the value of the Ship-To Address according to the value of an extensible flexfield.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;
 
List < Message > messages = new ArrayList < Message > ();
def po = header.getAttribute("CustomerPONumber");
//Condition that specifies when to call the extension. You can can also use an extensible flexfield on the order header.
if (!"TEST_MDF".equals(po))
    return;
     
def line2AddrMap = [: ];
def lines = header.getAttribute("Lines");
 
if (!lines.hasNext()) {
    throw new ValidationException("Order Management hasn't saved the order line details. Save the sales order, then try again.");
}
while (lines.hasNext()) {
    def line = lines.next();
    def lineNo = line.getAttribute("DisplayLineNumber");
    line2AddrMap.put(lineNo, line.getAttribute("ShipToPartySiteIdentifier"));
}
 
lines.reset();
 
while (lines.hasNext()) {
    def line = lines.next();
    def context = line.getOrCreateContextRow("FulfillLineContext1"); //Add your own extensible flexfield context that identifies the address for the ship-to line that you must copy.
    def copyFromLineNo = context.getAttribute("_FL1AttributeChar1"); //Update this value with the display line number of the source line.
    if (copyFromLineNo != null && !copyFromLineNo.isEmpty()) {
        line.setAttribute("ShipToPartySiteIdentifier", line2AddrMap.get(copyFromLineNo));
    }
}
 
if (!messages.isEmpty()) {
    ValidationException ex = new ValidationException(messages);
    throw ex;
}

Other Areas

Use an order management extension to manage other areas.

  • Get Details for Related Sales Orders

  • Call the Web Service That Does Credit Check

  • Pseudocode That Cascades an Attribute Value from the Top Parent of a Configuration Model to All Child Lines

Get Details for Related Sales Orders

Get details about the relationship between the sales order and other related sales orders, such as the original order of a copied order or a return order.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

String poNumber = header.getAttribute("CustomerPONumber");
if (poNumber == null) return;
if (!poNumber.startsWith("PMC TEST")) return;

List < Message > messages = new ArrayList < Message > ();
messages.add(new Message(Message.MessageType.ERROR, "HeaderId: " + header.getAttribute("HeaderId")));

def docReferences = header.getAttribute("DocumentReferences");

messages.add(new Message(Message.MessageType.ERROR, "Header Doc"));
while (docReferences.hasNext()) {

    def docRef = docReferences.next();
    messages.add(new Message(Message.MessageType.ERROR, "Header Doc Refs"));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalNumber: " + docRef.getAttribute("DocumentAdditionalNumber")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionaldentifier: " + docRef.getAttribute("DocumentAdditionaldentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentIdentifier: " + docRef.getAttribute("DocumentIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalLineNumber: " + docRef.getAttribute("DocumentAdditionalLineNumber")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalLineIdentifier" + docRef.getAttribute("DocumentAdditionalLineIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentLineIdentifier: " + docRef.getAttribute("DocumentLineIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentLineNumber: " + docRef.getAttribute("DocumentLineNumber")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentReferenceType: " + docRef.getAttribute("DocumentReferenceType")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalSubLineNumber: " + docRef.getAttribute("DocumentAdditionalSubLineNumber")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalSubLineIdentifier: " + docRef.getAttribute("DocumentAdditionalSubLineIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentSubLineIdentifier: " + docRef.getAttribute("DocumentSubLineIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentSubLineNumbe: " + docRef.getAttribute("DocumentSubLineNumber")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentNumber: " + docRef.getAttribute("DocumentNumber")));
    messages.add(new Message(Message.MessageType.ERROR, "FulfillLineIdentifier: " + docRef.getAttribute("FulfillLineIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "LineIdentifier: " + docRef.getAttribute("LineIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "OwnerTableId: " + docRef.getAttribute("OwnerTableId")));
    messages.add(new Message(Message.MessageType.ERROR, "OwnerTableName: " + docRef.getAttribute("OwnerTableName")));
    messages.add(new Message(Message.MessageType.ERROR, "TaskType: " + docRef.getAttribute("TaskType")));
    messages.add(new Message(Message.MessageType.ERROR, "DocumentSystemReferenceIdentifier: " + docRef.getAttribute("DocumentSystemReferenceIdentifier")));
    messages.add(new Message(Message.MessageType.ERROR, "HeaderId: " + docRef.getAttribute("HeaderId")));
}

def lines = header.getAttribute("Lines");
messages.add(new Message(Message.MessageType.ERROR, "get lines"));
while (lines.hasNext()) {
    messages.add(new Message(Message.MessageType.ERROR, "A line"));
    def line = lines.next();
    def lineDocReferences = line.getAttribute("DocumentReferences");
    while (lineDocReferences.hasNext()) {
        messages.add(new Message(Message.MessageType.ERROR, "has doc references"));
        def lineDocRef = lineDocReferences.next();
        messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalNumber: " + lineDocRef.getAttribute("DocumentAdditionalNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionaldentifier: " + lineDocRef.getAttribute("DocumentAdditionaldentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentIdentifier: " + lineDocRef.getAttribute("DocumentIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalLineNumber: " + lineDocRef.getAttribute("DocumentAdditionalLineNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalLineIdentifier" + lineDocRef.getAttribute("DocumentAdditionalLineIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentLineIdentifier: " + lineDocRef.getAttribute("DocumentLineIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentLineNumber: " + lineDocRef.getAttribute("DocumentLineNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentReferenceType: " + lineDocRef.getAttribute("DocumentReferenceType")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalSubLineNumber: " + lineDocRef.getAttribute("DocumentAdditionalSubLineNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentAdditionalSubLineIdentifier: " + lineDocRef.getAttribute("DocumentAdditionalSubLineIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentSubLineIdentifier: " + lineDocRef.getAttribute("DocumentSubLineIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentSubLineNumbe: " + lineDocRef.getAttribute("DocumentSubLineNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentNumber: " + lineDocRef.getAttribute("DocumentNumber")));
        messages.add(new Message(Message.MessageType.ERROR, "FulfillLineIdentifier: " + lineDocRef.getAttribute("FulfillLineIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "LineIdentifier: " + lineDocRef.getAttribute("LineIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "OwnerTableId: " + lineDocRef.getAttribute("OwnerTableId")));
        messages.add(new Message(Message.MessageType.ERROR, "OwnerTableName: " + lineDocRef.getAttribute("OwnerTableName")));
        messages.add(new Message(Message.MessageType.ERROR, "TaskType: " + lineDocRef.getAttribute("TaskType")));
        messages.add(new Message(Message.MessageType.ERROR, "DocumentSystemReferenceIdentifier: " + lineDocRef.getAttribute("DocumentSystemReferenceIdentifier")));
        messages.add(new Message(Message.MessageType.ERROR, "HeaderId: " + lineDocRef.getAttribute("HeaderId")));
    }
}

ValidationException ex = new ValidationException(messages);
throw ex;

Call the Web Service That Does Credit Check

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

def poNumber = header.getAttribute("CustomerPONumber");

if (poNumber != "PMC TEST") return;

//get attribute to populate in the payload
String customer = header.getAttribute("BillToCustomerName");
Long accountId = header.getAttribute("BillToCustomerIdentifier");
BigDecimal amount = new BigDecimal(1000);

//prepare the payload
String payLoad = "<ns1:creditChecking xmlns:ns1=\"http://xmlns.oracle.com/apps/financials/receivables/creditManagement/creditChecking/creditCheckingService/types/\">" +
    "<ns1:request xmlns:ns2=\"http://xmlns.oracle.com/apps/financials/receivables/creditManagement/creditChecking/creditCheckingService/\">" +
    "<ns2:CustomerName>" + customer + "</ns2:CustomerName>" +
    "<ns2:CustomerAccountNumber>" + accountId + "</ns2:CustomerAccountNumber>" +
    "<ns2:RequestType>Authorization</ns2:RequestType>" +
    "<ns2:PriceType>ONE_TIME</ns2:PriceType>" +
    "<ns2:RecurrencePeriod></ns2:RecurrencePeriod>" +
    "<ns2:RequestAuthorizationAmount currencyCode=\"USD\">" + amount + "</ns2:RequestAuthorizationAmount>" +
    "<ns2:RequestAuthorizationCurrency>USD</ns2:RequestAuthorizationCurrency>" +
    "<ns2:ExistingAuthorizationNumber></ns2:ExistingAuthorizationNumber>" +
    "<ns2:Requestor>ar_super_user</ns2:Requestor>" +
    "</ns1:request>" +
    "</ns1:creditChecking>";

//Use the CreditCheckService web service connector to call the Check Credit service. Use the Manage External Interface Web Service Details task to set up the connector. This is a secured external service,
//so we're using a message protection policy. We use the external https URL of the service to register it.
def response = context.invokeSoapService("CreditCheckService", payLoad);

//Print a debug message. Append the entire response to the shipping instructions attribute.
//Make sure you disable debug statements like this one in your production instance because they can cause performance problems.
debug(response.getSoapBody().getTextContent());

//The response XML that the Credit Check service sends contains an element named Response. A YES value in the response means credit check passed. So, we extract the contents of the Response tag. The following XML API returns all tags
//that include the name Response in a NodeList element. We are expecting only one element in our XML response.
def nodeList = response.getSoapBody().getElementsByTagNameNS("*", "Response");

//Print out the lenght of the node list.
debug(nodeList.getLength());

//Get the first element that contains the name Response. We are expecting only one response. Then get its text content
String ccResponse = nodeList.item(0).getTextContent();

debug(ccResponse);

//Determine whether credit check passed.
if (ccResponse != 'YES') {
    //Credit check failed, so we a warning validation exception.
    throw new ValidationException(new Message(Message.MessageType.WARNING, "Credit check failed."));
} else {
    //Credit check passed.
    //Write the credit check response in an extensible flexfield.
    def psiContext = header.getOrCreateContextRow("ComplianceDetails");
    psiContext.setAttribute("_ComplianceInfo", ccResponse);
}

/**
 * Append the message that we received into the Shipping Instructions attribute. Use this method only for debugging purposes.
 */
void debug(def msg) {
    String si = header.getAttribute("ShippingInstructions");
    header.setAttribute("ShippingInstructions", si + ", " + msg.toString());
}

Pseudocode That Cascades an Attribute Value from the Top Parent of a Configuration Model to All Child Lines

import oracle.apps.scm.doo.common.extensions.ValidationException;
 
def poNumber = header.getAttribute("CustomerPONumber");;
 
//Condition that specifies to call the extension.
if(poNumber != null && poNumber.equals("CASCADE_CONTRACT_SDATE")){
    def lines=header.getAttribute("Lines");
    long currentTime = new Date().getTime();
    def date = new java.sql.Date(currentTime);
 
    //Iteration all lines of the order
    while( lines.hasNext() ) {
        def line=lines.next();
 
        def inventoryItemId = line.getAttribute("ProductIdentifier");
        def orgId = line.getAttribute("InventoryOrganizationIdentifier");
        def parentLineReference=line.getAttribute("ParentLineReference");
        def rootParentLineReference=line.getAttribute("RootParentLineReference");
        def item = getItem(inventoryItemId, orgId); // Getting item details for the line
        def itemTypeCode=item.getAttribute("BomItemType");
        def pickComponentsFlag=item.getAttribute("PickComponentsFlag");
        def parentstartdate=line.getAttribute("ContractStartDate1");
        def flineId=line.getAttribute("FulfillmentLineIdentifier");
        //Passing root line for PTO ,Hybrid and ATO Items
        if(1==itemTypeCode  && flineId==rootParentLineReference && rootParentLineReference== parentLineReference && parentstartdate!=null){
            updateChildLines(line);
        }
        //Passing root line For KIT Items
        else if(4==itemTypeCode  && "Y".equals(pickComponentsFlag) && parentstartdate!=null){
            updateChildLines(line);
        }
    }
}
 
Object getItem(Long itemId, Long orgId) {
    def itemPVO = context.getViewObject("oracle.apps.scm.productModel.items.publicView.ItemPVO");
    def vc = itemPVO.createViewCriteria();
    def vcrow = vc.createViewCriteriaRow();
    vcrow.setAttribute("InventoryItemId", itemId); 
    vcrow.setAttribute("OrganizationId", orgId);
    def rowset = itemPVO.findByViewCriteria(vc, -1);
    def item = rowset.first();
    return item;
}
 
//Iterate through all lines. Set the child lines's contract start date and end date to the parent's contract start date and end date.
void updateChildLines(def rootfline){
    def lines=header.getAttribute("Lines");
    def flineId=rootfline.getAttribute("FulfillmentLineIdentifier");
    def parentstartdate=rootfline.getAttribute("ContractStartDate1");
    def parentenddate=rootfline.getAttribute("ContractEndDate1");
    while( lines.hasNext() ) {
        def line=lines.next();
        def rootFlineId=line.getAttribute("RootParentLineReference");
        if(flineId==rootFlineId){
            line.setAttribute("ContractStartDate1",parentstartdate);
            line.setAttribute("ContractEndDate1",parentenddate);
        }
    } 
}

Reference

Methods You Can Use with Order Management Extensions

Get details about the methods you can use with your order management extension.

Execution Context Method

The ExecutionContext method calls a SOAP web service.

Use this format.

SoapServiceResponse invokeSoapService(String integrationName, String xmlStr)

where

  • integrationName. Identifies the name of the integration.

  • xmlStr. XML representation of the SOAP body in String format.

ExecutionContext returns details.

Parameter Description

public String getExtensionName()

String. Name of the order management extension that's currently running.

public String getEventCode()

String. Abbreviation that identifies the event that triggered the extension.

public Logger getLogger()

Logger. Logger where the extension can write logs.

public ServiceInvoker getServiceInvoker()

Returns a service that you can use to call a web service from the code in your order management extension.

public String getUserName()

Returns the name of the user currently signed in.

public boolean isUserInRole(String roleName)

Returns one of.

  • True. The user currently signed in is using the role that roleName specifies.

  • False. The user isn't using this role.

where

  • roleName. A string that identifies the role name.

public String getLanguage()

Returns an abbreviation that identifies the language that the user is using in the current session.

public Date getCurrentDate()

Returns the current system date in an instance of java.sql.Date.

public Timestamp getCurrentTime()

Returns the current system time in a java.sql.Timestamp object.

Logger Method

The Logger method returns the message log.

Use this format.

Format Description

public boolean isEnabled(Level level)

Returns one of.

  • True. Logging is enabled at the level that Level specifies.

  • False. Logging isn't enabled at this level.

where

  • level. Sets the logging level according to a constant from java.util.logging.Level.

public void logFine(String message)

Saves message to the log at the fine level.

where

  • message. A text string that the command saves to the log.

public void logFine(String messageFormat, Object... arguments)

Saves the message at the fine level.

where

  • messageFormat. Format of the message. The command uses this format to create the message string. It passes the format and argumentsto String.format().

  • arguments. Arguments that replace the tokens in the format string.

public void logFiner(String message)

Saves message to the log at the finer level.

where

  • message. A text string that the command saves to the log.

public void logFiner(String messageFormat, Object... arguments)

Saves the message at the finer level.

where

  • messageFormat. Format of the message. The command uses this format to create the message string. It passes the format and argumentsto String.format().

  • arguments. Arguments that replace the tokens in the format string.

public void logFinest(String message)

Saves message to the log at the finest level.

where

  • message. A text string that the command saves to the log.

public void logFinest(String message)

Saves message to the log at the finest level.

where

  • message. A text string that the command saves to the log.

public void logSevere(String messageFormat, Object... arguments)

Saves the message at the severe level.

where

  • messageFormat. Format of the message. The command uses this format to create the message string. It passes the format and argumentsto String.format().

  • arguments. Arguments that replace the tokens in the format string.

public void logSevere(String messageFormat, Object... arguments)

Saves the message at the severe level.

where

  • messageFormat. Format of the message. The command uses this format to create the message string. It passes the format and argumentsto String.format().

  • arguments. Arguments that replace the tokens in the format string.

Message Method

The Message method uses a message type and message text to create a message for the sales order. It uses the ORA_MANAGE_EXTENSIONS request function to log messages, by default.

Here's the format to use to display a literal message that uses the default message category and no tokens.

Message(MessageType type, String text)

where

  • type. Type of message. You can use ERROR or WARNING.

  • text. Text of the message to display, enclosed with one set of double quotation marks ( " " ).

Here's an example warning message that includes a literal string.

Message(MessageType Message.MessageType.WARNING, String "This is the warning message.")

Here's an error message that includes a literal string.

Message(MessageType Message.MessageType.ERROR, String "This is the error message.")

Specify Message Name and Tokens

Here's the format to use to specify the message name and message token parameters.

Message(MessageType type, String name, Map<String, Object> parameters)

where

  • type. Type of message. You can use ERROR or WARNING.

  • name. Name of a message from the Manage Messages page.

    Here's the values that attributes for this message must use on the Manage Messages page.

    Attribute Value

    Application

    Distributed Order Orchestration

    Module

    Distributed Order Orchestration

    For details, see the Creating Messages in Order Management topic.

  • parameters. A map that contains message tokens and token values. The Message method uses this map to populate tokens with values. These tokens are part of the message.

Here's some example code that displays the contents of a message named DOO_CUST_RELATIONSHIP_WARNING.

Message(MessageType Message.MessageType.WARNING, String "DOO_CUST_RELATIONSHIP_WARNING", Map<String, Object> messageParams)

Create Messages for Sales Orders and Sales Order Lines

You can use the Request function, message name, and message token parameters to create a message for the sales order or the order line. The Message method will log the message with the request function that you specify.

Here's the format to use for the sales order.

Message(MessageType type, String requestFunction, String name, Map string, object msgParams)

Here's the format to use for the order line.

Message(MessageType type, String requestFunction, Object line, String name, Map string, object msgParams)

where

  • Object line. Identifies the order line to reference when logging the message.

For details about the other parameters, see the Map Tokens for the Message Repository section in this topic.

Here's some example code that uses a request function.

Message(MessageType Message.MessageType.WARNING, String "DEMO_REQFUNC", String "DOO_CUST_RELATIONSHIP_WARNING", Map string, object msgParams)

where

  • DEMO_REQFUNC is a value in lookup DOO_MSG_REQUEST_FUNCTION.

Row Set Iterator Method

The RowSetIterator method manages rows in the iterator.

Use this format.

Row first()

RowSetIterator returns details.

Parameter Description

Row first()

Returns the first row in the iterator.

hasNext()

Returns a Boolean value that indicates whether another row exists after the current row.

Row next()

Returns the next row in the iterator.

If no more rows exist after the current row, then this parameter returns a null value.

Row last()

Returns the last row in the iterator.

hasPrevious()

Returns a Boolean value that indicates whether another row exists before the current row.

Row previous()

Returns the previous row in the iterator.

If no more rows exist before the current row, then this parameter returns a null value.

createRow()

Creates a new row. If the entity doesn't support creating a new row, then this parameter returns an error message when your extension calls this method.

insertRow(Row row)

Inserts the row into the current iterator, where row specifies the row number to insert.

Use this method to add a new row to the iterator after you create the iterator.

Service Invoker Method

The ServiceInvoker method calls a service.

Validation Exception Method

The ValidationException method uses the error text that you specify to create a validation exception. It displays the message text that you specify.

Use this format.

ValidationException(String messageText)

Display Messages from the Message Repository

ValidationException can get the error message text from the Oracle Fusion message repository, populate token values, and then display the message in the Order Management work area.

Use this format.

ValidationException(String name, Map string, object parameters)

where

  • name. Name of the message that you specify on the Manage Messages page.

  • parameters. A map that contains message tokens and token values. ValidationException uses this map to populate tokens with values in the message.

Map Tokens for the Message Repository

Here's the format to use with ValidationException to create the map that parameters specifies.

ValidationException(java.lang.String requestFunction, java.lang.String name, java.util.Map<java.lang.String,java.lang.Object> parameters)

where

  • requestFunction. Lookup code of the request function to log the message against. You use the Order Management lookup named Request Function to define a request function. If this parameter passes an empty value, then ValidationException defaults the request function to ORA_MANAGE_EXTENSIONS.

  • name. Name of the message that you specify on the Manage Messages page. You must specify Distributed Order Orchestration as the application for this message when you use the Manage Messages page.

  • parameters. A map that contains message tokens and token values. ValidationException uses this map to populate tokens with values in the message.

Display Message Objects from the Message Repository

ValidationException can use a list of message objects to create a validation exception. It can accommodate a validation error that includes more than one message.

Use this format.

ValidationException(List message messages)

where

  • messages. A list of message objects. For details about how to create a message object, see the Message Method section in this topic.

Use Reference Lookup Codes

Here's the format you use to reference a lookup code.

throw new ValidationException("lookup_code")

The lookup type named DOO_MSG_REQUEST_FUNCTION contains lookup codes.

Lookup Code Description

ASSIGN_PROC

Process assignment.

MANAGE_TASK

Fulfillment task.

MANAGE_HOLD

Hold.

MANAGE_PROC

Fulfillment process.

PLAN_PROC

Fulfillment planning.

PROC_CHANGE

Change order.

XFORM_ORDER

Order transformation. Location that Order Management uses to store an incoming source order before it transforms it to a sales order.

VALD_CONSTRAINT

Processing constraint.

VALD_PROC_DEFN

Process definition.

VALD_ACTION_ELGB

Action eligibility.

ORA_VALD_ORDER_DATA

Order validation.

ORA_VALD_CONFIG

Configuration.

ORA_VALD_PRICING

Pricing.

ORA_NOTIFY_EVENT

Event notification.

ORA_VALD_PAYMENT

Payment.

ORA_VERIFY_TRADE_COMPLIANCE

Verify that fulfillment lines meet trade compliance policies.

ORA_CREDIT_CHECK

Verify credit check failure.

ORA_ORDER_APPROVALS

Message function classification for Order Approval messages.

ORA_MANAGE_EXTENSIONS

Default type for messages that the extensions framework logs.

You can specify one of these lookup codes or add new ones to the lookup.

View Object Method

The ViewObject method finds and returns a view criterion.

Use this format.

ViewCriteria getViewCriteria(name)

where

  • name. Name of the view criterion.

A view criterion is a list of row criterion for the WHERE clause in a view object. Each row criterion is an array that contains criterion for each attribute.

Create View Criterion

Use this format.

ViewCriteria createViewCriteria()

ViewObject returns the new view criterion object.

Finding Rows According to View Criterion

Here's the format to use to find rows according to the view criterion that you provide and return them in an iterator.

RowIterator findByViewCriteria(ViewCriteria viewCriteria, int numberOfRows)

where

  • viewCriteria. Name of the view criteria to use to find rows.

  • numberOfRows. Number of rows to return. Use one of.

    • -1. Get all rows that match the view criteria.

    • Positive integer. Get a subset of rows. For example, use 3 to get the first three rows that match the criteria. If only two rows match the criteria, then the method returns only these two rows.

For example, here's some code that gets all rows and stores them in a local variable named vc.

def rowset = itemPVO.findByViewCriteria(vc, -1);

Here's the format to include an array of variable names and values.

RowIterator findByViewCriteriaWithBindVars(ViewCriteria viewCriteria, int maxNumOfRows, String[] variableNames, Object[] variableValues)

where

  • variableNames. Array of variable names to use with the view criteria.

  • variableValues. Array of variable values to use with the view criteria.

Here's the format to use to find rows according to the name of the view criteria.

RowIterator findByViewCriteriaWithBindVars(String viewCriteriaName, int maxNumOfRows, String[] variableNames, Object[] variableValues)

where

  • viewCriteriaName. Name of the view criteria to use to find the rows.

Get details about entities and attributes you can use with your order management extensions.

  • An extension can read from or write to the identifier attributes of a sales order, such as BillToCustomerIdentifier.

    The text Identifier, Id, or ID typically identifies an identifier attribute.

  • Your extension code can use the attribute name of the public view object.

  • Order Management converts values to identifiers when it saves your code.

  • Some identifier values use identifier Oracle Mobile Supply Chain.

  • You can use a public view object, but it might be necessary for you to use the identifier attributes.

  • If you set a default value for the ShipSetName attribute, then you must also set attribute PartialShipAllowedFlag to N.

  • Use the Line entity to get the value of the ItemSubTypeCode attribute.

  • Use the public view object for the item to get the ShippableFlag attribute.

  • You can't use the public view object for an order line that the user adds in the Order Management work area before the user clicks Submit because Order Management hasn't yet saved it to the database.

Sales Order Entities

Each extension can read data from or write data to sales order entities. Use method getAttribute() to access them.

Entity Value to Use in Code Parent Read During All Events Write During Save or Start of Submission Request Write During End of Submission Request

Order header

Header

Not applicable

Yes

Yes

No

Order line

Lines

Header

Yes

Yes

No

Fulfillment line detail

FulfillLineDetails

Lines

Yes

No

No

Sales credit

SalesCredits

Header, Lines

Yes

Yes

No

Order total

OrderTotals

Header

Yes

No

No

Manual price adjustment

ManualPriceAdjustments

Lines

Yes

No

No

Order charge

OrderCharges

Lines

Yes

No

No

Order charge component

OrderChargeComponents

OrderCharges

Yes

No

No

Lot serial

LotSerial

Lines

Yes

No

No

Transactional item attribute

TransactionAttributes

Lines

Yes

Yes

No

Payment

Payments

Headers, Lines

Yes

No

No

Billing plan

BillingPlans

Lines

Yes

No

No

Order tax detail

OrderTaxDetails

OrderChargeComponents

Yes

No

No

Document reference

DocumentReferences

Header, Lines

No

No

No

Project

Projects

Lines

Yes

Yes

No

Use method getAttachments() to get these attributes.

Entity Value to Use in Code Parent Read During All Events Write During Save or Start of Submission Request Write During End of Submission Request

Header attachment

Not applicable

Header

Yes

Yes

Yes

Fulfillment line attachment

Not applicable

Lines

Yes

Yes

No

Use methods getOrCreateContextRow("context code") and getAttribute("API name") with these attributes, where context code is the name of the context code of the extensible flexfield and API name is the name of the API (application programming interface) you use to call the method.

Entity Value to Use in Code Parent Read During All Events Write During Save or Start of Submission Request Write During End of Submission Request

Extensible flexfield on order header

Not applicable

Header

Yes

Yes

Yes

Extensible flexfield on fulfillment line

Not applicable

Lines

Yes

Yes

Yes

List of Attributes

Here's the list of attributes you can use in an order management extension. To get them in an Excel file, click Download Files at this end of this topic.

Order Header Attributes

Attribute Updatable

AgreementHeaderId

Yes

AgreementNumber

Yes

AllowCurrencyOverrideFlag

No

AppliedCurrencyCode

No

AppliedCurrencyName

No

BillToAccountContactIdentifier

Yes

BillToAccountContactName

Yes

BillToAccountContactNumber

Yes

BillToAccountDescription

No

BillToAccountPersonFirstName

No

BillToAccountPersonLastName

No

BillToAccountPersonMiddleName

No

BillToAccountPersonNameSuffix

No

BillToAccountPersonTitle

No

BillToAddress1

No

BillToAddress2

No

BillToAddress3

No

BillToAddress4

No

BillToCity

No

BillToContactFirstName

No

BillToContactLastName

No

BillToContactMiddleName

No

BillToContactNameSuffix

No

BillToContactTitle

No

BillToCountry

No

BillToCounty

No

BillToCustomerIdentifier

Yes

BillToCustomerName

Yes

BillToCustomerNumber

Yes

BillToCustomerSiteIdentifier

Yes

BillToPartyType

Yes

BillToPostalCode

No

BillToProvince

No

BillToState

No

BusinessUnitIdentifier

Yes

BusinessUnitName

Yes

BuyingPartyContactFirstName

No

BuyingPartyContactId

Yes

BuyingPartyContactLastName

No

BuyingPartyContactMiddleName

No

BuyingPartyContactName

Yes

BuyingPartyContactNameSuffix

No

BuyingPartyContactNumber

Yes

BuyingPartyContactTitle

No

BuyingPartyIdentifier

Yes

BuyingPartyName

Yes

BuyingPartyNumber

Yes

BuyingPartyPersonFirstName

No

BuyingPartyPersonLastName

No

BuyingPartyPersonMiddleName

No

BuyingPartyPersonNameSuffix

No

BuyingPartyPersonTitle

No

BuyingPartyType

Yes

CancelReason

Yes

CancelReasonCode

Yes

CarrierId

Yes

CarrierName

Yes

ChangeVersionNumber

No

Comments

Yes

CurrencyConversionDate

Yes

CurrencyConversionRate

Yes

CurrencyConversionTypeCode

Yes

CustomerPONumber

Yes

DemandClass

Yes

DemandClassCode

Yes

EarliestAcceptableShipDate

Yes

EarliestAcceptArrivalDate

Yes

EarliestAcceptArrivalDateTransient

Yes

FOBPoint

Yes

FOBPointCode

Yes

FreezePriceFlag

Yes

FreezeShippingChargeFlag

Yes

FreezeTaxFlag

Yes

FreightTerms

Yes

FreightTermsCode

Yes

FulfillmentOrganizationCode

Yes

FulfillmentOrganizationIdentifier

Yes

FulfillmentOrganizationName

Yes

HeaderId

No

LatestAcceptableShipDate

Yes

LatestAcceptArrivalDate

Yes

OrderNumber

No

OrigSysDocumentRef

Yes

PackingInstructions

Yes

PartialShipAllowedFlag

Yes

PaymentTerm

Yes

PaymentTermCode

Yes

PreCreditCheckedFlag

Yes

PreferredBillToContactPointIdentifier

Yes

PreferredShipToContactPointIdentifier

Yes

PreferredSoldToContactPointIdentifier

Yes

PricedOn

No

PricingSegmentCode

No

PricingSegmentExplanation

No

PricingStrategy

No

PricingStrategyExplanation

No

PricingStrategyIdentifier

No

ReferenceHeaderId

No

RequestArrivalDate

Yes

RequestCancelDate

Yes

RequestingBusinessUnit

No

RequestingBusinessUnitIdentifier

Yes

RequestingLegalUnit

Yes

RequestingLegalUnitIdentifier

Yes

RequestShipDate

Yes

RevisionSourceOrderSystem

Yes

SalesChannel

Yes

SalesChannelCode

Yes

Salesperson

Yes

SalespersonIdentifier

Yes

SegmentExplanationMessage

No

SegmentExplanationMsgName

No

ShipClassOfService

Yes

ShipClassOfServiceCode

Yes

ShipmentPriority

Yes

ShipmentPriorityCode

Yes

ShipModeOfTransport

Yes

ShipModeOfTransportCode

Yes

ShippingInstructions

Yes

ShipsetFlag

Yes

ShipToAddress1

No

ShipToAddress2

No

ShipToAddress3

No

ShipToAddress4

No

ShipToCity

No

ShipToContactFirstName

No

ShipToContactLastName

No

ShipToContactMiddleName

No

ShipToContactNameSuffix

No

ShipToContactTitle

No

ShipToCountry

No

ShipToCounty

No

ShipToPartyContactIdentifier

Yes

ShipToPartyContactName

Yes

ShipToPartyContactNumber

No

ShipToPartyIdentifier

Yes

ShipToPartyName

Yes

ShipToPartyNumber

Yes

ShipToPartyPersonFirstName

No

ShipToPartyPersonLastName

No

ShipToPartyPersonMiddleName

No

ShipToPartyPersonNameSuffix

No

ShipToPartyPersonTitle

No

ShipToPartySiteIdentifier

Yes

ShipToPartyType

Yes

ShipToPostalCode

No

ShipToProvince

No

ShipToState

No

SoldToPartyContactPointId

Yes

SourceTransactionIdentifier

No

SourceTransactionNumber

No

SourceTransactionRevisionNumber

No

SourceTransactionSystem

No

StatusCode

No

StrategyExplanationMessage

No

StrategyExplanationMsgName

No

SubmittedBy

Yes

SubmittedDate

Yes

SubmittedFlag

No

SubstituteAllowedFlag

Yes

SupplierAddressCity

No

SupplierAddressCountry

No

SupplierAddressCounty

No

SupplierAddressLine1

No

SupplierAddressLine2

No

SupplierAddressLine3

No

SupplierAddressLine4

No

SupplierAddressPostalCode

No

SupplierAddressProvince

No

SupplierAddressState

No

SupplierCode

Yes

SupplierName

Yes

SupplierNumber

Yes

SupplierSiteIdentifier

Yes

TradeComplianceResult

Yes

TradeComplianceResultCode

No

TransactionalCurrencyCode

Yes

TransactionalCurrencyName

Yes

TransactionDocumentTypeCode

Yes

TransactionOn

Yes

TransactionType

No

TransactionTypeCode

Yes

Lines

No

SalesCredits

No

OrderTotals

No

Payments

No

DocumentReferences

No

Order Line Attributes

Attribute Updatable

AccountingRule

Yes

AccountingRuleCode

Yes

ActionType

Yes

ActionTypeCode

Yes

AssessableValue

Yes

AssetGroupNumber

Yes

AssetTrackedFlag

Yes

BillingTransactionTypeIdentifier

Yes

BillToAccountContactIdentifier

Yes

BillToAccountContactName

Yes

BillToAccountContactNumber

Yes

BillToAccountPersonFirstName

No

BillToAccountPersonLastName

No

BillToAccountPersonMiddleName

No

BillToAccountPersonNameSuffix

No

BillToAccountPersonTitle

No

BillToAccountSiteUseIdentifier

Yes

BillToAddress1

No

BillToAddress2

No

BillToAddress3

No

BillToAddress4

No

BillToCity

No

BillToContactFirstName

No

BillToContactLastName

No

BillToContactMiddleName

No

BillToContactNameSuffix

No

BillToContactTitle

No

BillToCounty

No

BillToCustomerIdentifier

Yes

BillToCustomerName

Yes

BillToCustomerNumber

Yes

BillToPartyType

Yes

BillToPostalCode

No

BillToProvince

No

BillToState

No

BillingTransactionTypeIdentifier

Yes

BusinessUnitIdentifier

Yes

BusinessUnitName

Yes

CancelReason

Yes

CancelReasonCode

Yes

Comments

Yes

ComponentIdPath

Yes

ConfigHeaderId

Yes

ConfigRevisionNumber

Yes

ConfiguratorPath

Yes

ContractEndDate

Yes

ContractStartDate

Yes

ContractEndDate1

Yes

ContractStartDate1

Yes

CreditCheckAuthorizationCode

Yes

CreditCheckAuthorizationExpiryDate

Yes

CustomerPOLineNumber

Yes

CustomerPONumber

Yes

CustomerPOScheduleNumber

Yes

CustomerProductDescription

Yes

CustomerProductIdentifier

Yes

CustomerProductNumber

Yes

DefaultTaxationCountry

Yes

DefaultTaxationCountryShortName

Yes

DemandClass

Yes

DemandClassCode

Yes

DestinationShippingAddressCity

No

DestinationShippingAddressCountry

No

DestinationShippingAddressCounty

No

DestinationShippingAddressLine1

No

DestinationShippingAddressLine2

No

DestinationShippingAddressLine3

No

DestinationShippingAddressLine4

No

DestinationShippingAddressPostalCode

No

DestinationShippingAddressProvince

No

DestinationShippingAddressState

No

DestinationShippingLocationIdentifier

Yes

DestinationShippingOrganizationCode

Yes

DestinationShippingOrganizationIdentifier

Yes

DestinationShippingOrganizationName

Yes

DisplayLineNumber

No

DocumentSubType

Yes

DocumentSubTypeName

Yes

EarliestAcceptableShipDate

Yes

ExtendedAmount

Yes

FinalDischargeLocationAddressCity

No

FinalDischargeLocationAddressCountry

No

FinalDischargeLocationAddressCounty

No

FinalDischargeLocationAddressLine1

No

FinalDischargeLocationAddressLine2

No

FinalDischargeLocationAddressLine3

No

FinalDischargeLocationAddressLine4

No

FinalDischargeLocationAddressPostalCode

No

FinalDischargeLocationAddressProvince

No

FinalDischargeLocationAddressState

No

FinalDischargeLocationIdentifier

Yes

FirstPartyTaxRegistration

Yes

FirstPartyTaxRegistrationNumber

Yes

FOBPoint

Yes

FOBPointCode

Yes

FreightTerms

Yes

FreightTermsCode

Yes

FulfillInstanceId

Yes

FulfillmentLineIdentifier

No

FulfillmentOrganizationCode

Yes

FulfillmentOrganizationIdentifier

Yes

FulfillmentOrganizationName

Yes

HeaderId

No

IntendedUseClassificationIdentifier

Yes

IntendedUseClassificationName

Yes

InventoryOrganization

No

InventoryOrganizationIdentifier

No

InvoicingRule

Yes

InvoicingRuleCode

Yes

IsValidConfiguration

Yes

ItemSubTypeCode

No

LatestAcceptableArrivalDate

Yes

LatestAcceptableShipDate

Yes

LineAgreementNumber

Yes

LineId

No

LineNumber

No

LineType

No

ModifiedFlag

Yes

OrderedQuantity

Yes

OrderedUOM

Yes

OrderedUOMCode

Yes

OriginalProductDescription

Yes

OriginalProductIdentifier

Yes

OriginalProductNumber

Yes

PackingInstructions

Yes

ParentLineReference

Yes

PartialShipAllowedFlag

Yes

PaymentTerm

Yes

PaymentTermCode

Yes

PreferredBillToContactPointIdentifier

Yes

PreferredShipToContactPointIdentifier

Yes

ProductCategory

Yes

ProductCategoryName

Yes

ProductDescription

Yes

ProductFiscalCategoryIdentifier

Yes

ProductFiscalCategoryName

Yes

ProductIdentifier

Yes

ProductNumber

Yes

ProductType

Yes

ProductTypeName

Yes

ProjectRecordIndicator

Yes

PromiseArrivalDate

Yes

PromiseShipDate

Yes

QuantityPerModel

Yes

ReferenceFulfillmentLineIdentifier

No

RequestCancelDate

Yes

RequestedArrivalDate

Yes

RequestedShipDate

Yes

RequestingBusinessUnitIdentifier

Yes

RequestingBusinessUnitName

Yes

RequiredFulfillmentDate

Yes

ReturnReason

Yes

ReturnReasonCode

Yes

RootParentLineReference

Yes

Salesperson

Yes

SalespersonIdentifier

Yes

SalesProductType

Yes

SalesProductTypeCode

Yes

ScheduleArrivalDate

Yes

ScheduleShipDate

Yes

ServiceCancelDate

Yes

ServiceDuration

Yes

ServiceDurationPeriod

Yes

ServiceDurationPeriodCode

Yes

ShipmentPriority

Yes

ShipmentPriorityCode

Yes

ShippableFlag

Yes

ShippingCarrier

Yes

ShippingCarrierCode

Yes

ShippingInstructions

Yes

ShippingMode

Yes

ShippingModeCode

Yes

ShippingServiceLevel

Yes

ShippingServiceLevelCode

Yes

ShipSetName

Yes

ShipToAddress1

No

ShipToAddress2

No

ShipToAddress3

No

ShipToAddress4

No

ShipToCity

No

ShipToContactFirstName

No

ShipToContactId

Yes

ShipToContactLastName

No

ShipToContactMiddleName

No

ShipToContactNameSuffix

No

ShipToContactTitle

No

ShipToCounty

No

ShipToPartyContactIdentifier

Yes

ShipToPartyContactName

Yes

ShipToPartyContactNumber

Yes

ShipToPartyIdentifier

Yes

ShipToPartyName

Yes

ShipToPartyNumber

Yes

ShipToPartyPersonFirstName

No

ShipToPartyPersonLastName

No

ShipToPartyPersonMiddleName

No

ShipToPartyPersonNameSuffix

No

ShipToPartyPersonTitle

No

ShipToPartySiteIdentifier

Yes

ShipToPartyType

Yes

ShipToPostalCode

No

ShipToProvince

No

ShipToRequestRegion

Yes

ShipToState

Yes

SourceTransactionIdentifier

No

SourceTransactionLineIdentifier

No

SourceTransactionLineNumber

No

SourceTransactionNumber

No

SourceTransactionRevisionNumber

No

SourceTransactionScheduleIdentifier

No

SourceTransactionScheduleNumber

No

SourceTransactionSystem

No

StatusCode

No

SubInventoryCode

Yes

SubInventoryIdentifier

Yes

SubstitutionAllowedFlag

Yes

SubstitutionReason

Yes

SubstitutionReasonCode

Yes

SupplierAddressCity

No

SupplierAddressCountry

No

SupplierAddressCounty

No

SupplierAddressLine1

No

SupplierAddressLine2

No

SupplierAddressLine3

No

SupplierAddressLine4

No

SupplierAddressPostalCode

No

SupplierAddressProvince

No

SupplierAddressState

No

SupplierCode

Yes

SupplierName

Yes

SupplierNumber

Yes

SupplierSiteIdentifier

Yes

SupplyStatusCode

Yes

TaxClassification

Yes

TaxClassificationCode

Yes

TaxExemptFlag

Yes

TaxExemptionCertificateNumber

Yes

TaxExemptReason

Yes

TaxExemptReasonCode

Yes

TaxInvoiceNumber

Yes

ThirdPartyTaxRegistration

Yes

ThirdPartyTaxRegistrationNumber

Yes

TotalContractAmount

Yes

TotalContractQuantity

Yes

TransactionBusinessCategory

Yes

TransactionBusinessCategoryName

Yes

TransactionCategoryCode

Yes

TransactionLineType

Yes

TransactionLineTypeCode

Yes

UnitListPrice

Yes

UnitQuantity

Yes

UnitSellingPrice

Yes

UnreferencedReturnFlag

No

UserDefinedFiscClass

Yes

UserDefinedFiscClassName

Yes

TransactionAttributes

No

SalesCredits

No

OrderCharges

No

ManualPriceAdjustments

No

Payments

No

DocumentReferences

No

BillingPlans

No

FulfillLineDetails

No

LotSerial

No

Projects

No

Order Charge Attributes

Attribute Updatable

ApplyTo

No

AverageUnitSellingPrice

No

CanAdjustFlag

No

ChargeCurrencyCode

No

ChargeCurrencyName

No

ChargeDefinition

No

ChargeDefinitionCode

No

ChargeSubtype

No

ChargeSubtypeCode

No

ChargeType

No

ChargeTypeCode

No

GSAUnitPrice

No

OrderChargeId

No

ParentEntityId

No

PricedQuantity

No

PricedQuantityUOM

No

PricedQuantityUomCode

No

PricePeriodicityCode

No

PriceType

No

PriceTypeCode

No

PrimaryFlag

No

RollupFlag

No

SequenceNumber

No

SourceChargeIdentifier

No

OrderChargeComponents

No

Charge Component Attributes

Attribute Updatable

ChargeCurrencyCode

No

ChargeCurrencyDurationExtendedAmount

No

ChargeCurrencyExtendedAmount

No

ChargeCurrencyName

No

ChargeCurrencyUnitPrice

No

Explanation

No

HeaderCurrencyCode

No

HeaderCurrencyDurationExtendedAmount

No

HeaderCurrencyExtendedAmount

No

HeaderCurrencyName

No

HeaderCurrencyUnitPrice

No

OrderChargeComponentId

No

OrderChargeId

No

PercentOfComparisonElement

No

PriceElement

No

PriceElementCode

No

PriceElementUsage

No

PriceElementUsageCode

No

RollupFlag

No

SequenceNumber

No

SourceChargeComponentId

No

SourceChargeId

No

SourceMpaId

No

SourceParentChargeComponentId

No

TaxIncludedFlag

No

OrderTaxDetails

No

Order Total Attributes

Attribute Updatable

CurrencyCode

No

DisplayName

No

EstimatedFlag

No

OrderTotalId

No

PrimaryFlag

No

TotalAmount

No

TotalCode

No

TotalGroup

No

Order Tax Detail Attributes

Attribute Updatable

HeaderCurrencyTaxableUnitAmount

No

HeaderCurrencyTaxUnitAmount

No

OrderChargeComponentId

No

OrderTaxDetailId

No

TaxExemptionCertificateNumber

No

TaxExemptReason

No

TaxExemptReasonCode

No

TaxIncludedFlag

No

TaxRate

No

TaxRateIdentifier

No

Billing Plan Attributes

Attribute Updatable

BillingNumberOfPeriods

No

BillingPeriodEndDate

No

BillingPeriodNumber

No

BillingPeriodStartDate

No

BillingPlanId

No

BillingPlanTypeCode

No

BillingTrxDate

No

CancellationEffectiveDate

No

NetBillingAmountPERPeriod

No

OverridePeriod

No

OverridePeriodAmount

No

OverridePeriodQuantity

No

PeriodicityCode

No

PeriodicityName

No

SourceBillingPlanId

No

Sales Credit Attributes

Attribute Updatable

Percent

Yes

SalesCreditIdentifier

No

SalesCreditType

Yes

SalesCreditTypeCode

Yes

Salesperson

Yes

SalespersonIdentifier

Yes

SourceTransactionSalesCreditIdentifier

Yes

Transaction Item Attributes

Attribute Updatable

CharacterValue

Yes

DateValue

Yes

NumberValue

Yes

SourceTransactionLineAttributeIdentifier

Yes

TimestampValue

Yes

TransactionAttributeCode

Yes

TransactionAttributeIdentifier

Yes

TransactionAttributeName

Yes

TransactionAttrId

No

Lot Serial Attributes

Attribute Updatable

ItemRevisionNumber

No

LocatorIdentifier

No

LotNumber

No

LotSerialId

No

SerialNumberFrom

No

SerialNumberTo

No

SourceTransactionLotIdentifier

No

Payment Attributes

Attribute Updatable

AuthorizationStatus

No

InstrumentAssignmentIdentifier

No

PaymentMethod

No

PaymentMethodCode

No

PaymentSetIdentifier

No

PaymentTransactionIdentifier

No

PaymentType

No

PaymentTypeCode

No

SourceTransactionPaymentIdentifier

No

Document Reference Attributes

Attribute Updatable

DocumentAdditionaldentifier

Yes

DocumentAdditionalLineIdentifier

Yes

DocumentAdditionalLineNumber

Yes

DocumentAdditionalNumber

Yes

DocumentAdditionalSubLineIdentifier

Yes

DocumentAdditionalSubLineNumber

Yes

DocumentIdentifier

Yes

DocumentLineIdentifier

Yes

DocumentLineNumber

Yes

DocumentNumber

Yes

DocumentReferenceType

Yes

DocumentSubLineIdentifier

Yes

DocumentSubLineNumber

Yes

DocumentSystemReferenceIdentifier

No

OwnerTableId

Yes

OwnerTableName

Yes

TaskType

Yes

Attributes for Manual Price Adjustments

Attribute Updatable

AdjustmentAmount

No

AdjustmentElementBasis

No

AdjustmentElementBasisCode

No

AdjustmentType

No

AdjustmentTypeCode

No

ChargeDefinition

No

ChargeDefinitionCode

No

ChargeRollupFlag

No

Comments

No

ManualPriceAdjustmentId

No

ParentEntityCode

No

ParentEntityId

No

PricePeriodicityCode

No

Reason

No

ReasonCode

No

SequenceNumber

No

SourceManualPriceAdjustmentIdentifier

No

ValidationStatusCode

No

Fulfillment Line Attributes

Attribute Updatable

ActualDeliveryDate

No

AvailabilityShipDate

No

BillingTransactionAmount

No

BillingTransactionDate

No

BillingTransactionNumber

No

BillOfLadingNumber

No

CustomerTrxLineIdentifier

No

DeliveryName

No

ExceptionFlag

No

FulfillLineDetailId

No

FulfillLineId

No

Quantity

No

RMAReceiptDate

No

RMAReceiptLineNumber

No

RMAReceiptNumber

No

RMAReceiptTransactionIdentifier

No

Status

No

StatusAsOfDate

No

TaskType

No

TrackingNumber

No

TradeComplianceCode

No

TradeComplianceExplanation

No

TradeComplianceName

No

TradeComplianceResultCode

No

TradeComplianceResultName

No

TradeComplianceTypeCode

No

TradeComplianceTypeName

No

WaybillNumber

No

Project Attributes

Attribute Updatable

ContractId

Yes

ContractNumber

Yes

DooOrderPrjId

No

ExpenditureItemDate

Yes

ExpenditureOrganization

Yes

ExpenditureType

Yes

ExpenditureTypeId

Yes

FundingSource

Yes

OrganizationId

Yes

ParentEntityCode

No

ParentEntityId

No

ProjectId

Yes

ProjectNumber

Yes

ReferenceProjectId

No

ReservedAttribute1

Yes

TaskId

Yes

TaskNumber

Yes

Flexfields

Overview

Overview of Using Extensible Flexfields in Order Management

Set up an extensible flexfield so you can add your own attribute to Order Management Cloud.

An extensible flexfield is a field you can use to capture details in a sales order that are unique to your business requirements. Each sales order in Order Management comes predefined with a lot of attributes, but you might need one that's specific to your needs.

You can use the details in an extensible flexfield to determine process automation, send and receive details when communicating with systems outside of Order Management, or provide the criteria to use in a complex business rule. For example.

  • Capture consumer details in an extensible flexfield, then use them to add free samples to a shipment.

  • Capture customer loyalty details in an extensible flexfield, then determine whether to call the customer or upgrade shipping priority.

  • Receive a sales order request that includes unique build specifications from your customer, store them in an extensible flexfield, and then route the sales order to different manufacturing facilities according to the specifications.

  • Select and ship a bottle of wine according to your customer dining preferences. Store these preferences in an extensible flexfield.

  • Store the user ID of the order entry clerk who submitted a source order from a source system.

  • Track source orders that include warning messages from a source system.

  • Store the original schedule date and the new schedule date on the order line so you can track and report scheduling throughout the fulfillment lifecycle.

Note.

  • An extensible flexfield supports a one-to-many relationship between one entity and one or more attributes. You can use it to add more than one context sensitive segment.

  • You can set up an extensible flexfield for a fulfillment line, or on some other object that supports an extensible flexfield.

  • If you add an extensible flexfield to a fulfillment line, and if you use the Update or Close Sales Orders scheduled process to close the order line that the fulfillment line references at run time, then the Order Entry Specialist.

    • Can't update the value in the extensible flexfield on the fulfillment line.

    • Can revise the sales order and update the value in the extensible flexfield on the fulfillment line, but Order Management won't use the revised value when it processes the revision.

    • Can update an extensible flexfield on the order header regardless of the status of the sales order or order line.

For background details, see the Overview of Flexfields topic.

Examples of Using Extensible Flexfields

Example Description

Get details from a source system.

Get source order details from one or more source systems. A source order is an order that you import into Order Management from a source system, such as from an upstream channel.

A source order contains a set of attributes. If you need details or attributes that the source order doesn't contain, then you can use an extensible flexfield to get them, then use these details during order fulfillment.

You can use the same extensible flexfield attributes to receive details from each source system, or use different extensible flexfield attributes according to the unique requirements of each source system.

Send details to a fulfillment system.

Order Management sends a fulfillment request that includes a predefined set of attributes to a fulfillment system. You can use an extensible flexfield to send details that these attributes don't include, but that the fulfillment system needs to finish the fulfillment request.

Integrate with systems outside of Order Management.

For details, see the Overview of Using Flexfields to Integrate Order Management with Other Oracle Applications topic.

Receive details from a fulfillment system.

A fulfillment system might send attributes that provide a business value, and that the Order Entry Specialist must view in Order Management or in the source system. In some situations, Order Management might also use these details in the next set of tasks that it runs in an orchestration process. You can use an extensible flexfield to receive these attributes.

Write a business rule.

Use an extensible flexfield attribute with a business rule.

  • Transformation rule. Write a rule that references an extensible flexfield to add order details, delete unnecessary details, or modify details. Use an extensible flexfield to determine the transformations to do.

  • External interface routing rule.

  • Assignment rule.

For details, see the Overview of Using Business Rules With Order Management topic.

Manage change.

Use an extensible flexfield as an order attribute to store details about a change that occurred. For example, use an extensible flexfield as input to calculate the cost of change and to select a compensation pattern when Order management receives a change order.

Display attributes in the Order Management work area.

Allow the Order Entry Specialist to search for sales orders in the Order Management work area according to the value of an extensible flexfield.

Note that the Order Entry Specialist can read but not edit an extensible flexfield attribute.

Examples of Using Extensible Flexfields with Orchestration Processes

Example Description

Assign an orchestration process.

Use the value of an extensible flexfield in an assignment rule to automatically assign an orchestration process during order fulfillment to fulfill each sales order and each order line.

Use an extensible flexfield as part of the selection criteria during assignment.

Set up an orchestration process.

Create a business rule that uses an extensible flexfield to determine branching and the tasks to run in an orchestration process.

Select the fulfillment lines to process.

Use an extensible flexfield to determine whether a task in an orchestration process will process the fulfillment line or ignore it during order fulfillment.

Calculate the lead time that an orchestration process step requires.

Use an extensible flexfield to calculate lead time according to your data. For example, create an extensible flexfield named Engraving that includes a Yes or No value, then set up conditions.

  • If the item is a silver cup, and if engraving is yes, then set lead time to 3 days.

  • If the item is a silver cup, and if engraving is no, then set lead time to 1 day.

For details, see the Set Up Jeopardy and Lead Time to Manage Delay topic.

Entities You Can Use With Extensible Flexfields

Here are the entities you can use with an extensible flexfield on a sales order.

  • Header

  • Order line

  • Fulfillment line

  • Fulfillment line detail

  • Price adjustment

  • Sales credit

  • Payment

  • Lot serial

  • Activity

Web Services You Can Use to Map Extensible Flexfields

You can use these web services with all task types.

Web Service Description

Receive Fulfill Order Orchestration Task Response Service

For data that flows into Order Management. It uses this composite.

  • DooTaskFulfillOrderResponseInterfaceComposite

Request Fulfill Order Orchestration Task Service

For data that flows out of Order Management. It uses this composite.

  • DooTaskFulfillOrderRequestInterfaceComposite

Overview of Setting Up Extensible Flexfields in Order Management

Use a hierarchy to determine how to display an extensible flexfield in the Order Management work area.

Here's the hierarchy.

hierarchy of an extensible flexfield

Note.

  1. Order Management Entity. The top-level object in the hierarchy. You can specify an entity.

    • Header Information. Store details about the order header.

    • Fulfillment Line Information. Store details about the order line while order fulfillment processes the order line.

    • Fulfillment Line Detail Information. Store details that the fulfillment system provides that you don't typically store on the fulfillment line.

  2. Extensible Flexfield. Each extensible flexfield includes categories, contexts, and segments.

  3. Extensible Flexfield Category. Organize your data into a category according to attributes that contain similar business data. Specify where to display the extensible flexfield in the Order Management work area, such as on the order header or order line. You can use only one category for each entity.

  4. Extensible Flexfield Context. Specify how to display the attribute. For example.

    • Define criteria that determines the attribute to display.

    • Type of interface element that will display the attribute, such as text box or list of values.

    • Whether the Order Entry Specialist can view or edit the attribute.

    • Validation to do on the attribute.

    • Help text to display for the attribute.

    • Data type of the attribute.

    • Table column that stores the attribute.

    You can define one or more contexts in each category.

  5. Extensible Flexfield Segment. Specify the attributes. An extensible flexfield segment is equivalent to a sales order attribute. Each context includes one or more segments that you can use to specify sales order attributes that store your data. You can define one or more segments in each context.

Consider an example.

An extensible flexfield segment

Note.

  • Context1 stores details about trade compliance.

  • SegmentA references an attribute that stores the compliance description.

  • SegmentB references an attribute that stores the compliance date.

  • Context2 stores details about the call center representative who manages details about trade compliance.

  • SegmentF references an attribute that stores the representative name.

  • SegmentG references an attribute that stores the name of the person who manages the representative.

Here's an example that displays an extensible flexfield in the Order Management work area.

example that displays an extensible flexfield in
the Order Management work area.

Note.

  1. Additional Information. A dialog that displays when you click Actions > Edit Additional Information on the sales order header in the Order Management work area.

  2. Manage Order Extensible Flexfields. The setup page you use in the Setup and Maintenance work area to define an extensible flexfield.

  3. Additional Header Information. Specifies the data to display and how to display it in Additional Information.

  4. Pages tab. You use the Pages tab to define each area where your extensible flexfield displays. In this example, the Pages tab defines one area named Compliance Info and another area named HeaderEFFDetails. The example displays HeaderEFFDetails in the dialog. You can define one or more area, and you can define one more contexts in each area.

    In this example, the Pages tab defines HeaderContext1 and HeaderContext2. However, for brevity, the screen capture displays only HeaderContext1. The Sequence specifies the sequence to use when displaying these contexts in the area, with 1 displaying at the top, 2 below 1, 3 below 2, and so on.

  5. Sequence and Display Name for page. Defines the name for each category that displays in the dialog. Sequence specifies the sequence to display the pages in the dialog. In the example, the Sequence is 10 for Compliance Info and 20 for HeaderEFFDetails, so the dialog displays Compliance Info first, then HeaderEFFDetails.

  6. Sequence and Display Name for context. Defines the name for each context that displays in the dialog. For example, HeaderContext1 organizes similar business data into a concise area of the dialog.

  7. Context Sensitive Segment. Specifies one ore more segments that display details for each attribute. The Sequence specifies the sequence to use when displaying these segments in the area. You can define the following segments in each context.

    • 20 character segments. You can use up to 150 characters for each character segment.

    • 10 number segments.

    • Five date segments.

    • Five date and time segments.

Flexfield Categories Determine Where to Display Extensible Flexfields

You can display an extensible flexfield in different areas of the Order Management work area according to flexfield categories.

Flexfield Category Area in the Order Management Work Area

DOO_HEADERS_ADD_INFO

Order header

DOO_FULFILL_LINES_ADD_INFO

Order line and fulfillment line

DOO_FULFILL_LINE_DTLS_ADD_INFO

General tab on the fulfillment line

View Extensible Flexfields in a Sales Order According to Flexfield Category

  1. In the Navigator, click Order Management.

  2. In the Order Management work area, on the Overview page, click Tasks > Create Order.

  3. On the Create Order page, click Actions > Edit Additional Information.

    The Additional Information dialog displays each extensible flexfield you create that references the DOO_HEADERS_ADD_INFO flexfield category. For example, HeaderEFFDetails is an extensible flexfield.

    dialog Additional Information that will display
each extensible flexfield
  4. Click Cancel.

  5. In the Order Lines area, search for an item, then click Add.

  6. On the order line, click the down arrow, then click Edit Additional Information.

  7. Click Submit, then copy the sales order number, such as 57025.

  8. On the Overview page, click Tasks > Manage Fulfillment Lines.

  9. On the Manage Fulfillment Lines page, search for your sales order.

  10. In the Search Results, scroll to the far right, then click Additional Information.

    The Additional Information dialog displays the extensible flexfield you create that references the DOO_FULFILL_LINE_DTLS_ADD_INFO flexfield category. For example, Pack Ship Instruction is an extensible flexfield.

    dialog Additional Information that will display
any extensible flexfield you create that references flexfield category
DOO_FULFILL_LINE_DTLS_ADD_INFO
  11. In the Fulfillment Line Details area, in the Attributes area, click General, scroll down, click Additional Information, then notice the dialog that displays.

    example of dialog Additional Information that will display
any extensible flexfield you create that references flexfield category
DOO_FULFILL_LINE_DTLS_ADD_INFO
Another Example

Here's an Additional Information dialog that displays each extensible flexfield that references the DOO_FULFILL_LINES_ADD_INFO flexfield category. For example, FulfillLineEFFInfo is an extensible flexfield.

Additional Information dialog that will display each
extensible flexfield you create that references flexfield category
DOO_FULFILL_LINES_ADD_INFO

Order Management displays each extensible flexfield in an Additional Information dialog. Here's an example that displays the View Additional Information menu item on each order line on the Order Lines tab.

example dialog that displays a View Additional Information
menu item

In this example, View Additional Information allows the Order Entry Specialist to access the Source Line Info extensible flexfield.

View Additional Information dialog that allows the Order
Entry Specialist to access extensible flexfield
Overview of Your Setup

flow to set up and deploy an extensible flexfield
in Order Management

You do some or all of this set up, depending on your business requirements. It might be necessary to also do some of this flow when you update your extensible flexfield definition.

  1. Manage Extensible Flexfields. Use the Manage Extensible Flexfields page in the Setup and Maintenance work area to define your extensible flexfield. Click Deploy Flexfield to make it available throughout the architecture and to other set up pages.

  2. Order Management Work Area. Test your extensible flexfield. Depending on your setup, you create a new sales order, search for a sales order, use a fulfillment view, and so on. For example, use the Additional Information dialog when you create a new sales order to make sure your extensible flexfield displays and works as expected.

  3. Manage Order Management Extensions. Use the Manage Order Management Extensions page in the Setup and Maintenance work area to add your extensible flexfield to an order management extension.

  4. Schedule New Process. Use the Publish Extensible Flexfield Attributes scheduled process to make your extensible flexfield available to various parts of Order Management, other set ups in Oracle Fusion Applications, and integrations. This scheduled process updates the rule dictionaries in business rules, constraints, business events, Integration Cloud Service, and the service mappings that you use for an internal integration.

  5. Various Set Ups. Here's where you can use your extensible flexfield.

    Set Up Description

    Business Rule

    Use your extensible flexfield in a business rule.

    • Pretransformation

    • Transformation

    • Posttransformation

    • Routing

    • Assignment

    • Line Selection Criteria

    • Branching Expression

    • Lead Time Expression

    • Compensation Pattern

    • Cost of Change

    You can't use an extensible flexfield in an approval rule.

    Business Event

    Use an extensible flexfield to help determine when to raise a business event, and the actions to take when you raise it.

    Constraint

    Use an extensible flexfield to constraint a sales order attribute. Use a constraint to constrain an extensible flexfield.

    Integration Cloud Service

    Use an extensible flexfield with Integration Cloud Service to help achieve and manage an integration between Order Management and a technology or application.

    • Order Import

    • Order Information Service

    • Transportation Management

    • Global Trade Management

    Integration with an Oracle Fusion Application

    Use a service mapping to integrate with an Oracle Fusion Application.

    • Shipping

    • Accounts Receivables

    • Purchasing

    • Receiving

  6. Web Service. If you use one of these web services, then manually update your extensible flexfield definition in the web service payload.

    • CreateOrder

    • FulfillOrderService

    • FulfillmentResponseService

  7. Schedule New Process. Use scheduled process Import Oracle Fusion Data Extensions for Transactional Business Intelligence to make your extensible flexfield is available in area Subject Areas of Oracle Transactional Business Intelligence.

Guidelines for Setting Up Extensible Flexfields in Order Management

Apply guidelines when you set up an extensible flexfield in Order Management Cloud.

  • Unlike a descriptive flexfield, you can add as many segments as you need.

  • Use context to organize your business data into a concise area of the user interface element, such as a dialog.

  • Organize your attributes into logical groups according to your display and usage requirements.

  • Consider where an extensible flexfield might be useful in the order capture and order fulfillment lifecycle.

  • An extensible flexfield that you add on the sales order header is independent of an extensible flexfield that you add on a fulfillment line. Order Management doesn't communicate or transfer values between them, even if you use the same name for each extensible flexfield. If you require dependence between them, then create an order management extension, then define dependence logic in the extension.

Create Segments and Contexts

guidelines when you define each segment

Note.

  • New segments you create. To simplify setup and maintenance, use the same value for the Code attribute and the API Name attribute. You use API Name throughout the setup, such as during integration setup, with web services, business rules, business intelligence, and so on. You can't modify Code or API Name after you create the segment.

  • Segments that already exist. Don't modify API Name. Extensible flexfield logic examines API Name. If its empty, then the logic uses the value in Code, so it isn't necessary to define API Name. If you do modify API Name, then your flexfield might fail with unexpected results at run time.

  • Enter a unique code, name, and description for each segment. The Order Management work area doesn't display these values, so use whatever nomenclature is most helpful to you during setup and maintenance.

  • Don't include spaces in the Code attribute. Spaces will cause a run time error.

Make sure the name for each segment or context you create uses the correct nomenclature.

  • Begin the name with a letter of the alphabet, A through Z.

  • Don't include more than one consecutive space character.

  • Make sure the name contains only letters or numbers.

  • You can also use these characters.

    Character Description

    .

    Period

    -

    Hyphen

    Don't use an em dash or en dash.

    _

    Underscore

    ,

    Comma

    :

    Colon

    "

    Double quotation mark

    /

    Forward slash

If you encounter an invalid alias error when you run the Publish Extensible Flexfield Attributes scheduled process, then make sure your contexts and segments use the correct nomenclature.

Create Order Management Extensions

guidelines when you use an extensible flexfield
in an order management extension

Note.

  • Include an If statement that makes sure each context and segment that your extension references exists and contains a value. If you don't check for missing objects and empty values, then your extension might fail with unpredictable results.

  • Use the getOrCreateContextRow method to create or update a value in an extensible flexfield. If the object doesn't exist, then this method creates it, so it isn't necessary to determine whether the object exists before you use this method to do an update.

  • Use Context Code when you reference an extensible flexfield context.

  • Use API Name when you reference an extensible flexfield segment. If you don't specify API Name when you set up the extensible flexfield, then use Segment Code but with underscores ( _ ) instead of spaces ( ).

  • Your Groovy code must traverse the context and the segment to get all data from the extensible flexfield.

    Here's an example that uses a while statement to traverse all data.

    def complianceDetails = header.getOrCreateContextRow("ComplianceDetails");
    complianceDetails.setAttribute("_ComplianceReason", "This has been set by pre submit extension.");
    
    def lines = header.getAttribute("Lines");
    while( lines.hasNext() ) {
      def line = lines.next();
      def inventoryItemId = line.getAttribute("ProductIdentifier");
      def orgId = line.getAttribute("InventoryOrganizationIdentifier");
      def item = getItem(inventoryItemId, orgId);
      
      String hazardous = item.getAttribute("HazardousMaterialFlag");
      def packShipInstruction = line.getOrCreateContextRow("PackShipInstruction");
      
      if( "Y".equals(hazardous) ) {
          // get details for fulfill line context PackShipInstruction
          
          packShipInstruction.setAttribute("_ShippingInstruction", "Hazardous Handling Required.");
      } 
      
    }
Create Business Rules

If your fulfillment system needs data that the predefined attributes in a sales order don't provide, then use a value from an extensible flexfield as the criteria for setting the default value in some other sales order attribute.

Assume you set up an extensible flexfield named Sample Requested. Here's the values it can contain.

  • Complimentary

  • Charge

  • No Sample

You can create a transformation rule.

  • If the value is Complimentary or Charge, then add a fulfillment line for the sample item.

You can then set up a rule that populates price details for the sample lines according to whether the value is Complimentary or Charge.

Make sure you run the defaulting rule during one of these types of transformations when you process the transformation rule. You can't default an attribute value into an extensible flexfield.

Type of Transformation Description

Pretransformation

Use an extensible flexfield when some other transformation logic requires the default attribute value.

For example, if you must use the defaulted attribute value to determine whether to add a free sample item during transformation, then define a pretransformation rule that sets the default value.

Posttransformation

Use Posttransformation when transformation must occur before you run your defaulting rule.

For example, if you plan to add an item during transformation, and you also plan to use an extensible flexfield attribute on the order header to determine the defaulted value to set for the new fulfillment line.

For guidelines that describe how to use an extensible flexfield in a business rule, see the Guidelines for Creating Business Rules topic.

Process Change Orders

guidelines when you use an extensible flexfield
while processing a change order

Note.

  • Identify your requirements for change management. For example, determine whether the orchestration process must compensate when an extensible flexfield value changes, and the action to take during compensation, such as scheduling, calling Accounts Receivables, and so on.

  • Compensate when a value that the orchestration process references changes.

    • Any extensible flexfield. Enable the Use Flexfield Attributes option on the header of the orchestration process definition.

    • A specific extensible flexfield. Enable the Use Flexfield Attributes option in the Change Management area of the orchestration process definition. Add it to the orchestration process step that references the extensible flexfield. Also define a compensation pattern on this step.

      Use the compensation pattern to specify the action to perform, such as Cancel, Create, Update, and so on, depending on the value that changes. You can configure your set up to send an update when a single value changes and to skip sending an update when other values change. This approach provides more detailed control regarding the compensation you do.

      Here's an example compensation pattern.

      pseudocode: 
      If segment3 changes, then cancel task x, and then recreate task x. 
      If segment4 changes, then do nothing.
      If segment5 changes, then call an update service. 

      For a detailed code example, see the Compensate Sales Orders That Change topic.

    • To ignore changes to all extensible flexfield values, make sure Use Flexfield Attributes for each step in the Change Management area isn't enabled.

Change management ignores each change that the Order Entry Specialist makes to an extensible flexfield value that you set up on the sales order header.

Import and Integrate

Import Source Orders

Apply guidelines when you use the order import template to import data for an extensible flexfield.

  • Assign the Table Column attribute of each segment so it references the correct column in the order import template.

  • Add a comment in Excel to document your set up.

  • Use the DOO_ORDER_HDRS_ALL_EFF_B_INT worksheet to capture extensible flexfield details for order headers.

  • Use the DOO_ORDER_LINES_ALL_EFF_B_INT worksheet to capture extensible flexfield details for fulfillment lines.

  • Use columns, such as ATTRIBUTE_CHAR1, to capture details for each attribute.

  • Don't modify worksheet names or column names. Instead, add a comment.

You can't add an extensible flexfield on an order line entity. You can add one only on the order header entity or the fulfillment line entity. The template uses the phrase DOO_ORDER_LINES, but it uses details that you add on the DOO_ORDER_LINES_ALL_EFF_B_INT worksheet to interact with extensible flexfields on the fulfillment line, not on the order line.

For details, see the Import Orders into Order Management topic.

This example illustrates how to set up the Compliance Info segment that references the ATTRIBUTE_CHAR1 column.

set up segment Compliance Info that references
column ATTRIBUTE_CHAR1

Integrate with Web Services During Order Import

Add extensible flexfield details to the payload that Order Management uses to communicate with the web service.

  • Get an example payload from the Example Web Service Payloads That Integrate Order Management topic. A range of examples are available, such returns, coverage, configurations, and so on. These payloads include most of the sales order data that you require.

  • If you create your own payload, then create it according to the WSDL definition that the payload requires. For details, see the Use Your Own Payload to Import Extensible Flexfields topic.

  • Run the Publish Extensible Flexfield Attributes scheduled process.

  • Copy extensible flexfield data from the log file that the scheduled process creates into the XSD file that contains your payload. Copy this data onto each object that requires extensible flexfield data. This approach helps to keep your channel system synchronized with the set up in Order Management.

  • Use the ADF import service. Don't use the SOA import service.

Here's an example payload that copies one section of code from the log file into the XSD file.

payload to copy one section of code from the log
file into the XSD file

For details, see the Overview of Using Web Services to Integrate Order Management topic.

Integrate with Other Oracle Fusion Applications

Use an extensible flexfield when you integrate with some other Oracle Fusion Application, such as Pricing, Receivables, Shipping, Receiving, or Purchasing. You set up a service mapping that's similar to a service mapping that you set up for Oracle Fusion Pricing. You use an extensible flexfield to store values that the service mapping requires.

extensible flexfield to store values that the service
mapping requires

Note.

  • Copy the name of the view object from the log file. The service mapping uses the view object to get data from your extensible flexfield. Use the log file that the Publish Extensible Flexfield Attributes scheduled process creates.

  • Use the _Custom suffix when you define each new entity.

  • Use an integration algorithm to implement complex logic. For example, assume you must concatenate an item with the coverage that covers the item, add quantity, then store the results in a descriptive flexfield for Accounts Receivable. You would use an integration algorithm to implement this requirement.

Use Reports and Analytics

Modify Reports

guidelines when you use an extensible flexfield
in a report.

Note.

  • The Order Entry Specialist can use the Sales Order report when creating or viewing a sales order.

  • Add extensible flexfield data to the report.

    • Install Oracle BI Publisher Desktop,

    • Use the Edit Sales Order Report action in BI Publisher. This action displays Sales Order Report in rich text format so you can modify it.

    • Right-click a field, then click Copy.

    • Use BI Publisher Properties to specify the source that the report uses to display data for the field.

      Use this format.

      <?context/segment?>

      where

    • context. Name of the extensible flexfield context.

    • / (forward slash). You must use the forward slash between context and segment.

    • segment. Name of the extensible flexfield segment.

    • You must use a set of question marks ( ?? ) to enclose context/segment.

    • You must use a set of angle brackets ( < > ) to enclose the question marks.

    For example, assume you set up an extensible flexfield that uses Context1 to store details about trade compliance, and SegmentA to store the compliance description. Here's the code you use.

    <?Context1/SegmentA?>

Modify Analytics

Oracle Transaction Business Intelligence (OTBI) provides analytic reporting. You can display extensible flexfield data in OTBI.

guidelines when you display extensible flexfield
data in OTBI

Note.

  • Enable the BI Enabled option when you set up your extensible flexfield.

  • Run scheduled process Import Oracle Fusion Data Extensions for Transactional Business Intelligence. This process updates OTBI so it displays your extensible flexfields in area Subject Areas in OTBI.

  • Add your extensible flexfields from Subject Areas into a report in OTBI.

  • Here's the format that OTBI uses.

    Category_Context

    For example.

    Additional Fulfillment Line Information_Additional Details1

    where

    • Additional Fulfillment Line Information is the category

    • Additional Details1 is the context

Set Up

Set up an extensible flexfield in Order Management Cloud.

In this example, set up an extensible flexfield so the Order Entry Specialist can view sales order status from the source order.

extensible flexfield Order Entry Specialist can use
to view sales order status from the source order

Summary of the Steps

  1. Create the context.

  2. Associate the context with the category.

  3. Add the page to the category.

  4. Deploy the flexfield.

  5. Publish the extensible flexfield.

  6. Test your set up.

For background details, see the Overview of Flexfields topic.

This topic includes example values. You might use different values, depending on your business requirements.

Create the Context

  1. In the Navigator, click Setup and Maintenance.

  2. In the Setup and Maintenance work area, go to the task.

    • Offering: Order Management

    • Functional Area: Orders

    • Task: Manage Order Extensible Flexfields

  3. On the Manage Order Extensible Flexfields page, enter the value, then click Search.

    Attribute Value

    Name

    Fulfillment Line Information

  4. On the Manage Extensible Flexfields page, click Actions > Edit.

  5. On the Edit Extensible Flexfield page, click Manage Contexts.

  6. On the Manage Contexts page, click Search.

    Notice that the search results displays a list of predefined contexts. For this example, you will add a new context.

  7. Click Actions > Create.

  8. On the Create Context page, set values.

    Attribute Value

    Display Name

    SourceLineInfo

    Code

    SourceLineInfo

    API Name

    Sourcelineinfo

    Behavior

    Single Row

    You must use Single Row for any extensible flexfield that you use in Order Management.

    Values for some attributes, such as Code, automatically populate. In general, don't modify the predefined values.

  9. On the Context Usages tab, click Actions > Create, set the value, then click Save.

    Attribute Value

    Name

    Additional Fulfillment Line Information

  10. In area Context Sensitive Segments, click Actions > Create.

  11. On the Create Segment page, set values. For details about these attributes, see the Flexfield Segment Properties topic.

    Attribute Value

    Name

    Status

    Code

    Status

    API Name

    status

    The Create Segment page automatically sets the value for API Name. In this example, it sets the value to status, and uses lower case for the first letter. You must use the same value for API Name that the XML uses when it creates the sales order.

    Enabled

    Contains a check mark.

    Data Type

    Character

    Table Column

    ATTRIBUTE_CHAR1

    You can use choose any column. Choose a column you aren't already using to store some other value.

    To view the values that are available, click the down arrow, then click Search. In the Search and Select dialog, remove any values that display in the Name attribute, then click Search.

    Value Set

    10 Characters

    Use any value.

    Prompt

    Status

    Display Type

    Text Box

  12. Click Save and Close.

  13. On the Edit Context page, set the Sequence, if necessary, then click Save and Close.

Associate the Context with the Category

  1. On the Edit Extensible Flexfield page, in the Category area, in the Display Name column, click the text Additional Fulfillment Line Information.

    Notice that the Category Details area populates the list in the Associated Contexts tab.

  2. In the Associated Contexts tab, click Actions > Select and Add.

  3. In the Select and Add dialog, in the Name attribute, enter SourceLineInfo, which is the context you created earlier in this topic, then click Search.

  4. In the search results, immediately above OK, click the row, then click Apply > OK.

  5. On the Edit Extensible Flexfield page, click Save.

  6. In the Category Details area, click Pages.

  7. On the Pages tab, click Actions > Create.

Add the Page to the Category

To determine where the extensible flexfield displays in the Order Management work area, you use the Pages tab to assign each context to a page. The sequence number determines the sequence that Order Management uses when it displays the extensible flexfield.

  1. In the Create Page dialog, set values, then click OK.

    Attribute Value

    Display Name

    Source Line Info

    Code

    SourceLineInfo

    Don't include spaces.

    Usage

    Additional Fulfillment Line Information

  2. On the Edit Extensible Flexfield page, click Save.

  3. In the Category Details area, in the Sequence attribute, enter a number.

  4. In the Source Line Info area, click Actions > Select and Add.

  5. In the Select and Add dialog, search for the value.

    Attribute Value

    Name

    SourceLineInfo

  6. In the search results, click the row that contains SourceLineInfo in the Name column, then click Apply > OK.

  7. On the Edit Extensible Flexfield page, click Save and Close.

Deploy the Flexfield

  1. On the Manage Order Extensible Flexfields page, in the search results, click the row that includes the value.

    Column Value

    Name

    Fulfillment Line Information

  2. Click Deploy Flexfield.

  3. In the Confirmation dialog, wait for the deployment to finish, then click OK.

  4. On the Manage Order Extensible Flexfields page, verify that Deployment Status contains a check mark, then click Done.

Publish the Extensible Flexfield

You must publish each time you change the set up for your extensible flexfield. If you're using an extensible flexfield in a business rule or processing constraint, then you must publish so you can reference the flexfield from a rule fact or constraint.

  1. In the Navigator, click Scheduled Processes.

  2. On the Scheduled Processes page, click Actions > Schedule New Process.

  3. In the Schedule New Process dialog, search for Publish Extensible Flexfield Attributes, then click OK.

  4. In the Process Details dialog, click Submit.

  5. In the Confirmation dialog, copy the Process ID to the clipboard, such as 68721, then click OK.

  6. On the Scheduled Processes page, click Actions > Refresh, then notice the status of your process.

  7. The status is likely Running. Wait a few minutes, then click Refresh again until Status is Succeeded.

Example Payload That Includes Extensible Flexfields

extensible_flexfield_example_payload.xml includes code that's part of the payload that Order Management creates for the sales order when it submits a sales order that includes an extensible flexfield. It includes the XML that defines the namespace. Click the Download Files link in the Related Topics section at the end of this topic to access this file.

  • Context Code determines SourceLineInfo.

  • Segment API Name determines ns22:status.

  • The status value is FRAUD_HOLD. You will confirm this value later when you create a sales order.

  • For details about how to determine attribute names in the namespace for an extensible flexfield, see Document ID 2195245.1 (How to Include EFF Attributes in the Order Creation Payload - Invoking Web Service) on My Oracle Support.

Test Your Set Up

Verify that the extensible flexfield displays correctly in the Order Management work area.

  1. In the Navigator, click Order Management.

  2. Create a new sales order, then add an order line.

  3. At the far right of the order line, click the down arrow, then click Edit Additional Information.

  4. In the Edit Additional Information dialog, verify that the Source Line Info displays, and that it includes status value FRAUD_HOLD that you noticed earlier in this topic when you examined the payload.

  5. As an option, use SQL (Structured Query Language) to query extensible_flexfield_example_sql.xml. Verify the values you defined in this topic. Click the Download Files link in the Related Topics section at the end of this topic to access this file.

    Her's the values that your SQL should return.

    Attribute Value

    SOURCE_ORDER_NUMBER

    PMC-170113-001

    ORDER_NUMBER

    48030

    FULFILL_LINE_NUMBER

    1

    CONTEXT_CODE

    SourceLineInfo

    ATTRIBUTE_CHAR1

    FRAUD_HOLD

Set Up Extensible Flexfields When Using Oracle BI Publisher

If you use Oracle BI Publisher, then make sure you do these steps when you set up your extensible flexfield. For assistance, contact Oracle support.

  1. Run the Publish Extensible Flexfield Attributes scheduled process.

  2. On the Manage Extensible Flexfield page, click Actions > Refresh and Deploy Offline.

  3. Deploy your extensible flexfield. For details, see the Deploy Extensible Flexfields in Order Management topic.

  4. Download the flexfield archive.

    • On the Manage Extensible Flexfield page, click Actions > Download Flexfield Archive.

    • Wait for the dialog to display 100%, then click Download.

    • In the Opening dialog, click OK.

    • Save the file to a folder of your choice.

    • Unzip the file.

  5. Reset the Financial Analytics container.

Deploy Extensible Flexfields

Publish and deploy an extensible flexfield in Order Management.

Summary of the Steps

  1. Publish extensible flexfield attributes.

  2. Deploy extensible flexfield attributes.

Publish Extensible Flexfield Attributes

Publish extensible flexfield attributes into the business rules and processing constraints that Order Management uses. You publish so you can reference these attributes from rules and constraints.

  1. Sign in with a user that includes job role DOO_ORDER_ADMINISTRATOR.

    The scheduled process you run requires this role.

  2. In the Navigator, click Scheduled Processes.

  3. On the Scheduled Processes page, click Schedule New Process, then run the Publish Extensible Flexfield Attributes scheduled process.

  4. Click Actions > Refresh, then verify the value. It might be necessary to wait a few minutes and refresh.

    Attribute Value

    Status

    Succeeded

  5. In the Navigator, click Setup and Maintenance.

  6. On the Setup page, click Order Management.

  7. In the Setup and Maintenance work area, go to the task.

    • Offering: Order Management

    • Functional Area: Orders

    • Task: Manage Order Extensible Flexfields

  8. On the Manage Order Extensible Flexfields page, click Search, then verify that the search results contains a list of extensible flexfields.

Deploy Extensible Flexfield Attributes

  1. In the Search Results, choose the extensible flexfield you must deploy, then click Actions > Edit.

  2. On the Edit Extensible Flexfield page, define contexts.

  3. The context determines the attributes that display according to criteria you specify. A context is part of a hierarchy of attributes.

    • Entity and entity category represent the top level of the hierarchy.

    • Contexts represent the middle levels.

    • Attributes represent the lowest level.

  4. Use the Pages tab in the Categories Details area to define pages and to associate contexts to Order Management pages.

  5. Use the Manage Order Extensible Flexfields page to deploy each of your extensible flexfields.

  6. Sign out of Order Management, then sign back in to Order Management.

    If you create a new segment, create a new context, change the default on a segment, and so on, then you must do this step so Order Management can update your changes throughout the Order Management work area.

Extensible Flexfields You Can Publish

You can publish only the extensible flexfield attributes that come predefined with Order Management and that are part of the predefined extensible categories.

Entity Predefined Category

Headers

DOO_HEADERS_ADD_INFO

Lines

DOO_LINES_ADD_INFO

FulfillLines

DOO_FULFILL_LINES_ADD_INFO

Payments

DOO_PAYMENTS_ADD_INFO

PriceAdjustments

DOO_PRICE_ADJUSTMENTS_ADD_INFO

SalesCredits

DOO_SALES_CREDITS_ADD_INFO

OrchestrationTaskActivity

DOO_ACTIVITIES_ADD_INFO

FulfillLineDetails

DOO_FULFILL_LINE_DTLS_ADD_INFO

LotSerialNumber

DOO_LOT_SERIAL_NUM_ADD_INFO

The Category Hierarchy and Preconfigured Context Values aren't available for these extensible flexfields.

You typically modify a predefined, example payload that imports an extensible flexfield. But you can also create your own payload that meets your specific requirements.

  • You will create an example payload that uses the ReceiveOrderRequestService web service to import a test extensible flexfield.

  • This topic describes the minimum details you must include.

  • To modify an example predefined payload instead, see the Example Web Service Payloads That Integrate Order Management topic.

Summary of the Steps

  1. Create and import the payload.

  2. Verify you imported the context code.

  3. Verify you imported the flexfield segment.

Create and Import the Payload

  1. Create the payload.

    • Add header details.

      <ns2:AdditionalHeaderInformationCategories xsi:type="ns12:j_HeaderEffDooHeadersAddInfoprivate"
      xmlns:ns3=http://xmlns.oracle.com/apps/scm/doo/processOrder/service/
      xmlns:ns12=http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/headerCategories/
      xmlns:ns22=http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/headerContextsB/
      xmlns:ns8="http://xmlns.oracle.com/apps/scm/doo/processOrder/model/">
        <ns8:Category>DOO_HEADERS_ADD_INFO</ns8:Category>
        <ns8:SourceTransactionLineIdentifier>1</ns8:SourceTransactionLineIdentifier>
        <ns8:SourceTransactionScheduleIdentifier>1</ns8:SourceTransactionScheduleIdentifier>
        <ns12:HeaderEffBPREVIOUS_5FSO_5FREFprivateVO>
        <ns8:ContextCode>PREVIOUS_SO_REF</ns8:ContextCode>
        <ns22:locationname>West Coast</ns22:locationname>
        </ns12:HeaderEffBPREVIOUS_5FSO_5FREFprivateVO>
        </ns2:AdditionalHeaderInformationCategories>
    • Add fulfillment line details.

      <ns2:AdditionalFulfillmentLineInformationCategories
      xsi:type="ns12:j_FulfillLineEffDooFulfillLinesAddInfoprivate"
      xmlns:ns12="http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/fulfillLineCategories/"xmlns:ns22=http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/fulfillLineContextsB/
      xmlns:ns8="http://xmlns.oracle.com/apps/scm/doo/processOrder/model/">
        <ns8:Category>DOO_FULFILL_LINES_ADD_INFO</ns8:Category>
        <ns8:SourceTransactionLineIdentifier>1</ns8:SourceTransactionLineIdentifier>
        <ns8:SourceTransactionScheduleIdentifier>1</ns8:SourceTransactionScheduleIdentifier>
        <ns12:FulfillLineEffBADD_CONTEXT_HEREprivateVO>
            <ns8:ContextCode>ADD_CONTEXT_HERE</ns8:ContextCode>
            <ns22:ADD_SEGMENT_HERE>Working</ADD_SEGMENT_HERE>
          </ns12:FulfillLineEffBADD_CONTEXT_HEREprivateVO>
        </ns2:AdditionalFulfillmentLineInformationCategories>
      </ns2:OrchestrationOrderRequestLine>
      

      where

      • You change ADD_CONTEXT_HERE to the context code.

      • You change ADD_SEGMENT_HERE to the segment.

      • You add extensible flexfields details as the last line of the order line details, immediately before </ns2:OrchestrationOrderRequestLine>.

    For example.

    <ns2:AdditionalFulfillmentLineInformationCategories
    xsi:type="ns12:j_FulfillLineEffDooFulfillLinesAddInfoprivate"
    xmlns:ns12=http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/fulfillLineCategories/
    xmlns:ns22=http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/fulfillLineContextsB/ xmlns:ns8="http://xmlns.oracle.com/apps/scm/doo/processOrder/model/">
      <ns8:Category>DOO_FULFILL_LINES_ADD_INFO</ns8:Category>
            <ns8:SourceTransactionLineIdentifier>1</ns8:SourceTransactionLineIdentifier>
            <ns8:SourceTransactionScheduleIdentifier>1</ns8:SourceTransactionScheduleIdentifier>
            <ns12:FulfillLineEffBPCTESTAUGprivateVO>
                <ns8:ContextCode>PCTESTAUG</ns8:ContextCode>
                <ns22:pctestaugseg1>Working</pctestaugseg1>
            </ns12:FulfillLineEffBPCTESTAUGprivateVO>
        </ns2:AdditionalFulfillmentLineInformationCategories>
    </ns2:OrchestrationOrderRequestLine>
    

    where

    • PCTESTAUG is the context.

    • pctestaugseg1 is the segment. PCTESTAUG includes only one segment.

    Notice the value for the FulfillLineEffBPCTESTAUGprivateVO virtual object. You will verify it later.

  2. Use ReceiveOrderRequestService to import the payload. For details, see the Overview of Using Web Services to Integrate Order Management topic.

Verify You Imported the Context Code

  1. Open SoapUI, then create a project.

    Attribute Value

    Project Name

    Create Order with EFF Test

    Initial WSDL

    http://host:port/ soa-infra/services/default/DooDecompReceiveOrderExternalComposite/ReceiveOrderRequestServiceWSDL

    Replace host:port with your server address.

    Create Requests

    Enabled.

  2. Verify the virtual object.

    • In the Projects area, double click ReceiveOrderRequestServiceBinding.

    • On the Overview tab, in the Definition Parts area, click the link next to J_FulfillLineEFFDooFulfillLinesAdd.

      Overview tab, Definition Parts area, link next
to J_FulfillLineEFFDooFulfillLinesAdd

      Your browser displays the XSD.

      <?xml version='1.0' encoding='UTF-8'?>
      <xsd:schema xmlns:ns0="http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/fulfillLineContextsB/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sdoXML="commonj.sdo/xml" xmlns:sdo="commonj.sdo" xmlns="http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/fulfillLineCategories/" targetNamespace="http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/fulfillLineCategories/" elementFormDefault="qualified">
          <xsd:import schemaLocation="../fulfillLineContextsB/Lineprcoverride.xsd" namespace="http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/fulfillLineContextsB/"></xsd:import>
          <xsd:import schemaLocation="../fulfillLineContextsB/Pctestaug.xsd" namespace="http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/fulfillLineContextsB/"></xsd:import>
          <xsd:import schemaLocation="https://eczc-test.scm.em2.oraclecloud.com:443/soa-infra/services/default/DooDecompReceiveOrderExternalComposite/soa-cp/xml/sdoXML.xsd" namespace="commonj.sdo/xml"></xsd:import>
          <xsd:import schemaLocation="https://eczc-test.scm.em2.oraclecloud.com:443/soa-infra/services/default/DooDecompReceiveOrderExternalComposite/soa-cp/xml/sdoModel.xsd" namespace="commonj.sdo"></xsd:import>
          <xsd:include schemaLocation="j_FulfillLineEffCategories.xsd"></xsd:include>
          <xsd:complexType name="j_FulfillLineEffDooFulfillLinesAddInfoprivate">
              <xsd:annotation>
                  <xsd:appinfo source="http://xmlns.oracle.com/adf/svc/metadata/">
                      <key xmlns="http://xmlns.oracle.com/adf/svc/metadata/">
                          <attribute>FulfillLineId</attribute>
                      </key>
                  </xsd:appinfo>
              </xsd:annotation>
              <xsd:complexContent>
                  <xsd:extension base="j_FulfillLineEffCategories">
                      <xsd:sequence>
                          <xsd:element name="FulfillLineEffBLinePrcOverrideprivateVO" type="ns0:Lineprcoverride" minOccurs="0" sdoXML:dataType="sdo:DataObject"></xsd:element>
                          <xsd:element name="FulfillLineEffBPCTESTAUGprivateVO" type="ns0:Pctestaug" minOccurs="0" sdoXML:dataType="sdo:DataObject"></xsd:element>
                      </xsd:sequence>
                  </xsd:extension>
              </xsd:complexContent>
          </xsd:complexType>
          <xsd:element name="j_FulfillLineEffDooFulfillLinesAddInfoprivate" type="j_FulfillLineEffDooFulfillLinesAddInfoprivate"></xsd:element>
      </xsd:schema>
    • In dataType="sdo:DataObject", verify that xsd:element name= contains FulfillLineEffBPCTESTAUGprivateVO.

      This value must match the value you included earlier in your import payload. For example, <ns12:FulfillLineEffBPCTESTAUGprivateVO>.

  3. Verify the context code.

    • Sign into Order Management Cloud.

    • In the Setup and Maintenance work area, go to the task.

      • Offering: Order Management

      • Functional Area: Orders

      • Task: Manage Order Extensible Flexfields

    • On the Manage Extensible Flexfields page, search for the value.

      Attribute Value

      Flexfield Code

      DOO_FULFILL_LINES_ADD_INFO

    • In the search results, click Actions > Edit.

    • On the Edit Extensible Flexfield page, click Manage Contexts.

    • On the Manage Contexts page, search for the value.

      Attribute Value

      Code

      PCTESTAUG

    • Verify the search results display your context, then click Actions > Edit.

    • On the Edit Context page, verify the context contains the values you imported.

      On the header.

      Attribute Value

      Code

      PCTESTAUG

      API Name

      Pctestaug

      Note this value. You will use it later when you verify the segment.

      In the Context Sensitive Segments area.

      Attribute Value

      Name

      PCTESTAUGSEG1

      Code

      PCTESTAUGSEG1

      On the Context usages tab, make sure a row exists that contains this value.

      Attribute Value

      Name

      Additional Fulfillment Line Information

      For example.

      Edit Context page, verifying the context contains
the values you imported

    If you prefer not to use the Manage Order Extensible Flexfields page, then as an alternative, run a SQL query against the Oracle database.

    select
      fdct.application_ID,
      fdct.descriptive_flexfield_code,
      fdct.context_code,
      fdcb.context_identifier,
      fdcb.enabled_flag,
      fdct.description
    from
      fnd_df_contexts_TL fdct,
      fnd_df_contexts_B fdcb
    where
      fdct.context_code = fdcb.context_code and
      fdct.application_id = fdcb.application_id and
      fdct.language = 'US' and
      fdct.descriptive_flexfield_code = 'DOO_FULFILL_LINES_ADD_INFO';
    

    Here's an example of data the query might return.

    APPLICATION_ID DESCRIPTIVE_FLEXFIELD_CODE CONTEXT_CODE CONTEXT_IDENTIFIER ENABLED_FLAG

    10008

    DOO_FULFILL_LINES_ADD_INFO

    LinePrcOverride

    Lineprcoverride

    Y

    10008

    DOO_FULFILL_LINES_ADD_INFO

    Accounting_Rule

    AccountingRule

    N

    10008

    DOO_FULFILL_LINES_ADD_INFO

    PCTESTAUG

    Pctestaug

    Y

    PCTESTAUG is the CONTEXT_CODE for this example.

Verify You Imported the Flexfield Segment

  1. In SoapUI, in the Projects area, double click ReceiveOrderRequestServiceBinding.

  2. On the Overview tab, in the Definition Parts area, click the link next to Pctestaug.xsd.

    Pctestaug is the value of attribute API Name you noted earlier on the Edit Context page.

    the Overview tab, in the Definition Parts area,
the link next to the link

    Your browser displays the XSD.

    <?xml version='1.0' encoding='UTF-8'?>
    <xsd:schema xmlns:ns0="http://xmlns.oracle.com/apps/scm/doo/processOrder/model/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/fulfillLineContextsB/" targetNamespace="http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/fulfillLineContextsB/" elementFormDefault="qualified"><xsd:include xmlns:id="Pctestaug-xsd" schemaLocation="Pctestaug.xsd"></xsd:include>
        <xsd:import schemaLocation="../../model/FulfillLineEff.xsd" namespace="http://xmlns.oracle.com/apps/scm/doo/processOrder/model/"></xsd:import>
        <xsd:complexType name="Pctestaug">
            <xsd:annotation>
                <xsd:appinfo source="http://xmlns.oracle.com/adf/svc/metadata/">
                    <key xmlns="http://xmlns.oracle.com/adf/svc/metadata/">
                        <attribute>EffLineId</attribute>
                    </key>
                </xsd:appinfo>
            </xsd:annotation>
            <xsd:complexContent>
                <xsd:extension base="ns0:FulfillLineEff">
                    <xsd:sequence>
                        <xsd:element name="pctestaugseg1" type="xsd:string" minOccurs="0" nillable="true"></xsd:element>
                    </xsd:sequence>
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
        <xsd:element name="pctestaug" type="Pctestaug"></xsd:element>
    </xsd:schema>
  3. In xsd:extension base="ns0:FulfillLineEff", verify that xsd:element name= contains pctestaugseg1.

    This value must match the value you included earlier in your import payload.

    If you prefer not to use SoapUI to verify the flexfield segment, then as an alternative, run a SQL query against the Oracle database.

    select
      fdst.DESCRIPTIVE_FLEXFIELD_CODE,
      fdst.CONTEXT_CODE,
      fdst.SEGMENT_CODE,
      fdst.NAME,
      fdsb.SEGMENT_IDENTIFIER,
      fdsb.COLUMN_NAME,
      fdsb.SEQUENCE_NUMBER
    from
      fnd_df_segments_tl fdst,
      fnd_df_segments_b fdsb
    where
      fdst.APPLICATION_ID = fdsb.APPLICATION_ID and
      fdst.ENTERPRISE_ID = fdsb.ENTERPRISE_ID and
      fdst.DESCRIPTIVE_FLEXFIELD_CODE = fdsb.DESCRIPTIVE_FLEXFIELD_CODE and
      fdst.CONTEXT_CODE = fdsb.CONTEXT_CODE and
      fdst.SEGMENT_CODE = fdst.SEGMENT_CODE and
      fdst.language = 'US' and
      fdst.descriptive_flexfield_code = 'DOO_FULFILL_LINES_ADD_INFO'
    order by
      fdst.CONTEXT_CODE,
      fdsb.SEQUENCE_NUMBER;

    Here's an example of data the query might return.

    DESCRIPTIVE_FLEXFIELD_CODE CONTEXT_CODE SEGMENT_CODE NAME SEGMENT_IDENTIFIER COLUMN_NAME

    DOO_FULFILL_LINES_ADD_INFO

    Accounting_Rule

    PC 1

    pc1

    PC 1

    ATTRIBUTE_CHAR1

    DOO_FULFILL_LINES_ADD_INFO

    LinePrcOverride

    SalePrcOverrideVal

    SalePrcOverrideVal

    saleprcoverrideval

    ATTRIBUTE_NUMBER1

    DOO_FULFILL_LINES_ADD_INFO

    PCTESTAUG

    PCTESTAUGSEG1

    PCTESTAUGSEG1

    pctestaugseg1

    ATTRIBUTE_CHAR7

    The pctestaugseg1 value in the SEGMENT_IDENTIFIER column must match the value in <ns22:pctestaugseg1> from your import payload.

Update Extensible Flexfields During Fulfillment

Call the FulfillmentResponse web service to update an extensible flexfield on a sales order after your user already submitted the sales order to fulfillment.

Make the call only when the orchestration process is on a wait step.

Here's an example payload.

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
     <soap:Body>
         <ns1:FulfillmentRequest
xmlns:ns1="http://xmlns.oracle.com/apps/scm/doo/taskLayer/fulfillOrder/DooTaskFulfillOrderResponseInterfaceComposite">
             <ns1:FLine
xmlns:ns2="http://xmlns.oracle.com/apps/scm/doo/common/process/model/">
                 <!-- Mandatory attributes 3 below, make sure you provide the correct value--> <ns2:FulfillLineId>300100095720462</ns2:FulfillLineId>
<ns2:SourceOrderSystem>LEG</ns2:SourceOrderSystem>
<ns2:TaskType>FulfillOrder</ns2:TaskType>
                 <!-- Optional attributes -->
                 <ns2:OrderedQuantity unitCode="">11</ns2:OrderedQuantity>
                 <ns2:RecordNumber>1</ns2:RecordNumber>
                 <!-- Mandatory attributes assuming you want to update EFFs -->
                 <ns2:AdditionalFulfillLineInformationCategories
xsi:type="ns12:j_FulfillLineEffDooFulfillLinesAddInfoprivate" 
xmlns:ns12="http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/fulfillLineCategories/" 
xmlns:ns22="http://xmlns.oracle.com/apps/scm/doo/processOrder/flex/fulfillLineContextsB/" 
xmlns:ns8="http://xmlns.oracle.com/apps/scm/doo/processOrder/model/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns8:Category>DOO_FULFILL_LINES_ADD_INFO</ns8:Category>
                     <!-- Nodes below repeats for each of the context that you want to update -->
                     <!-- The node itself contains the name of the virtual object for the context-->
                     <!-- To get these details, run the Publish Extensible Flexfields scheduled process-->
                     <!-- This example assumes  you are updating two contexts --> <ns12:FulfillLineEffBPackShipInstructionprivateVO>
<ns8:ContextCode>PackShipInstruction</ns8:ContextCode>
<ns22:_PackingInstruction>NKResponsePack</ns22:_PackingInstruction>
<ns22:_ShippingInstruction>NKResponseShip</ns22:_ShippingInstruction>
<ns22:_ShippingCost>31</ns22:_ShippingCost>
<ns22:_NeedbyDate>2016-04-21</ns22:_NeedbyDate>
<ns22:_PickDate>2016-04-21T12:12:12</ns22:_PickDate>
</ns12:FulfillLineEffBPackShipInstructionprivateVO>
<ns12:FulfillLineEffBFulfillLineContext1privateVO>
<ns8:ContextCode>FulfillLineContext1</ns8:ContextCode>
<ns22:_FL1AttributeChar1>FLC1-Resp</ns22:_FL1AttributeChar1>
<ns22:_FL1AttributeChar2>FLC2-Resp</ns22:_FL1AttributeChar2>
<ns22:_FL1AttributeNum1>620</ns22:_FL1AttributeNum1>
<ns22:_FL1AttributeDate1>2016-03-13</ns22:_FL1AttributeDate1>
<ns22:_FL1AttributeDateTime1>2016-03-13T12:12:12</ns22:_FL1AttributeDateTime1>
</ns12:FulfillLineEffBFulfillLineContext1privateVO>
</ns2:AdditionalFulfillLineInformationCategories>
             </ns1:FLine>
         </ns1:FulfillmentRequest>
     </soap:Body>
</soap:Envelope>

where

  • FulfillLineId identifies your fulfillment line, such as 300100095720462.

  • SourceOrderSystem identifies your source system, such as LEG.

  • Replace values for other attributes, as necessary, such as PackingInstruction, dates, times, and so on.

Use Rich Text Files to Print Extensible Flexfield Data in Order Headers

Use an RTF file (Rich Text File) to print extensible flexfield data in the order header.

  1. Download, then install the BI Publisher for Microsoft Word plugin so you can edit the RTF layout. Select a version that's compatible with your version of Microsoft, such as Oracle BI Publisher Desktop 11.1.1.9.0 for 32 bit Office on Windows.

  2. Notice the BI Publisher option in the menu bar.

    BI Publisher option in the menu bar
  3. Set the BI Publisher related properties in the RTF template. See the BI Publisher documentation for details.

    BI Publisher related properties in the RTF template
  4. Access the line extensible flexfield.

    the line extensible flexfield

    To view an example rtf file, click Download Files in the Related Links section at the end of this topic, then open sales_order_report_with_extensible_flexfield.rtf.

  5. Examine the example XML payload that represents a sales order that you send to BIP to create the report.

    example of an XML payload that represents a sales order
that you send to BIP to create the report
  6. Create a new template.

  7. Edit the Sales Order Report.

  8. Upload the new template to Sales Order Report.

  9. Notice that the new template is now available in the Template menu on the view document dialog.

    Set the new template as the default template in BI Publisher.

    new template that's available in the Template menu new template that's available in the Template menu new template that's available in the Template menu

Business Rules

Use Extensible Flexfields in Transformation Rules

Use a transformation rule to add or change data in a fulfillment line. The rule determines information to add or change according to details that already exist in the fulfillment order.

You will create a rule.

  • If Preferred customer places a sales order that includes AS54888 Desktop Computer on or before 01/01/2019 12:00 AM, then set Shipment Priority to High Priority, and add a free printer to the shipment.

Create a rule that references an extensible flexfield that stores loyalty details.

flow of rule that references an extensible flexfield
that stores loyalty details

Summary of the Steps

  1. Create pretransformation rule.

  2. Create product transformation rule.

  3. Create posttransformation rule.

Assume you already created extensible flexfield Loyalty Status.

For details about how to create a business rule, see the Overview of Using Business Rules With Order Management topic.

This topic includes example values. You might use different values, depending on your business requirements.

Create Pretransformation Rule

Here's the rule you will create.

the Pretransformation Rule

Do it.

  1. Create the rule.

    • In the Navigator, click Setup and Maintenance.

    • In the Setup and Maintenance work area, go to the task.

      • Offering: Order Management

      • Functional Area: Orders

      • Task: Manage Pretransformation Rules for Sales Orders

    • On the Manage Pretransformation Defaulting Rules page, click Create New Rule.

    • Set values.

      Attribute Value

      Name

      Expedite Shipping for Loyal Customer

      Description

      If loyal customer places a sales order that includes AS54888 Desktop Computer on or before promotion date, then add a free printer to the sales order.

  2. Create the If statement.

    • Click in the IF area to expand it.

    • On the Attributes tab, expand Order Header > Header EFF Categories > Additional Header Information > Header Loyalty Status.

    • Click Loyalty Status, drag it, then drop it into the IF area.

      dragging and dropping status
    • In the Create Condition dialog, set the operator to Is Equal To.

    • Enter Preferred, then click OK.

  3. Add the And condition for the computer.

    • Click And.

    • In the Create Condition dialog, enter item, wait a moment, then click Item (Item Definition).

    • Set the operator to =.

    • Click Search.

    • In the Search dialog, search for AS54888, then click OK.

  4. Add the And condition for the date.

    • Click And.

    • In the Create Condition dialog, enter ordered, wait a moment, then click Ordered Date (Order Header).

    • Set the operator to is before.

    • Click Select Date and Time, set it to 01/01/2019 12:00 AM, then click OK > OK.

  5. Create the Do statement.

    • Click Then > Do > New Action > Set a Value, then click .

    • In the Create Action dialog, enter ship, wait a moment, then click Shipment Priority (Order Header).

    • Click Search.

    • In the Search dialog, click Advanced > Search, then notice the dialog displays values you can set for this attribute.

      This functionality helps make sure you specify a value that Order Management can use and understand for the attribute. For example, Shipment Priority can contain only alphabetic data.

    • In the Meaning list, click High Priority > OK > OK > Save and Close.

  6. Activate and publish your rule.

Create Product Transformation Rule

Use the value in the Loyalty Status extensible flexfield as criteria to make other fulfillment changes, such as add a fulfillment line for the free printer.

Use attributes to define the object hierarchy of the sales order.

Attribute Usage Hierarchy

Determine whether customer is preferred according to the value of the Loyalty Status extensible flexfield on the order header.

Header
  Header EFF Category
    Header EFF Context

Use the InventoryItemId attribute on the fulfillment line to identify the computer.

Header
  Line
    Fulfillment Line

Use the OrderedDate attribute on the order header to identify the date.

Header

Add a new fulfillment line to the sales order for the printer.

Header
  Fulfillment Line

Create the Rule

  1. In the Setup and Maintenance work area, go to the task.

    • Offering: Order Management

    • Functional Area: Orders

    • Task: Manage Product Transformation Rules

  2. On the Manage Product Transformation Rules page, in the View list, click TransformationDT.

    page Manage Product Transformation Rules
  3. To the right of View TransformationDT, click down arrow > Expand > Add Rule > Show Advanced Settings, then set values.

    Attribute Value