Use Extensions to Manage Messages

Uses messages in your extension to get and display data.

Manage Validation Exceptions

To display a validation error, Order Management creates a validation exception, stops running the extension that failed, then runs a subsequent extension for the 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 message and message parameters in your extension. Order Management will get the message from the Oracle 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 Set Up Messages in Order Management.

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

Use this code to create 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);

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;

If your billing application already authorized payment, then run this extension to prevent you from editing payment attributes when revising a sales order. Run it on the On End of Submission Request extension point.

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

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

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

String messageText = "The request to revise the sales order failed because the billing application already authorizedpayment for the order. ";

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

if (header.getAttribute("ChangeVersionNumber") == null || header.getAttribute("ChangeVersionNumber") <= 1) return;

def paymentRows = header.getAttribute("Payments");
def isPreAuth = false;

if (paymentRows.hasNext()) {
  def paymentRow = paymentRows.next();
  isPreAuth = ("Y".equals(paymentRow.getAttribute("AuthorizedInSourceFlag")));
}
if (isPreAuth) {
   //Check OrderTotal
   if(null != header.getAttribute("ReferenceHeaderId")) {
      def origTotal = getPayNowTotalByHeaderId(header.getAttribute("ReferenceHeaderId"));
      def newTotal = getPayNowTotalByHeaderRow(header);
      if(newTotal > origTotal ) {
         messages.add(new Message(Message.MessageType.ERROR, messageText + "The total for the sales total is greater than the original order. The original total is :" + origTotal));
         ValidationException ex = new ValidationException(messages);
         throw ex;
      }
   }
def lines = header.getAttribute("Lines");       
  while (lines.hasNext()) {
    def line = lines.next();
    def refFulfillLineId = line.getAttribute("ReferenceFulfillmentLineIdentifier");
     if (line.getAttribute("ModifiedFlag").equals("Y")) {
      //Line is modified - compare the bill to with that of the base row.
      def refLine = getRefLine(refFulfillLineId);      
     if (null != refLine && !refLine.getAttribute("FulfillLineBillToCustomerId").equals(line.getAttribute("BillToCustomerIdentifier")) || 
     !refLine.getAttribute("FulfillLineBillToSiteUseId").equals(line.getAttribute("BillToAccountSiteUseIdentifier"))) {
        messages.add(new Message(Message.MessageType.ERROR, "You can't modify billing details for source transaction SourceTransactionLineNumber " + line.getAttribute("SourceTransactionLineNumber")". Discard your revision, create a new one, don't modify any attributes on the Billing and Payment Details tab, don't modify bill-to details on the order line, then submit your sales order."));
        ValidationException ex = new ValidationException(messages);
        throw ex;
      } 
    }
  }
}


Object getRefLine(Long refFulfillLineId) {
  def fLinePVO = context.getViewObject("oracle.apps.scm.doo.publicView.analytics.FulfillLinePVO");
  def vc = fLinePVO.createViewCriteria();
  def vcrow = vc.createViewCriteriaRow();
  vcrow.setAttribute("FulfillLineId", refFulfillLineId);

  def rowset = fLinePVO.findByViewCriteria(vc, -1);
  def line = rowset.next();
  return line;
}

Object getPayNowTotalByHeaderId(Long headerId) {
def totalPVO = context.getViewObject("oracle.apps.scm.doo.publicView.analytics.OrderTotalPVO");
def vc = totalPVO.createViewCriteria();
def vcrow = vc.createViewCriteriaRow();
vcrow.setAttribute("OrderTotalHeaderId", headerId);
vcrow.setAttribute("OrderTotalTotalCode", "QP_TOTAL_PAY_NOW");

  def rowset = totalPVO.findByViewCriteria(vc, -1);
  def total = rowset.next();
  if(null != total)
   return total.getAttribute("OrderTotalTotalAmount");
  else
    return 0;
}

Object getPayNowTotalByHeaderRow(def headerRow) {
def totals = header.getAttribute("OrderTotals");       
  while (totals.hasNext()) {
   def total = totals.next();
   if(total.getAttribute("TotalCode").equals("QP_TOTAL_PAY_NOW"))
      return total.getAttribute("TotalAmount");
  }
  return 0;
}

Display 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);                                                           
}

Display a Warning

This example displays a warning when fulfillment can't meet the order date. It uses the server time to determine whether fulfillment can ship the item according to the order entry date. If it can't, then 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 that indicates whether the sales order is past the cut off time to false.
boolean orderAfterCutOffTime = false;

//Initialize calendar object. The calendar has the current system time, by default. In this example, we want to set up the calendar so it's 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 see whether the ship from organization contains Vision Operations on any of the order lines. This will save some CPU cycles.
//We'll 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);
           }
        }
    }
}

Get and Display Transactional Data

This example uses messages to get and display tax data for a 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;

Get and Display Document References

This example uses messages to get and display document references for a sales 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("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;

Test a Transaction Attribute

This example uses messages to 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 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;