Extend Order Revisions

Use an order management extension to extend your order revisions.

See If It's a Revision

An order management extension doesn't distinguish between a new order and an order revision, by default. You can inspect the ReferenceHeaderId attribute on the header entity and the ReferenceFulfillmentLineIdentifier attribute on the Line entity to determine whether the sales order is new or a revision.

This extension uses the On Save extension point.

/* 
   This extension compares some of the attribute of the revision line to the existing sales order.
    */
import oracle.apps.scm.doo.common.extensions.ValidationException;
import java.util.Date;

def postShippedStatuses = ["AWAIT_BILL","ASSET_COMPLETED","BILLED","SHIPPED","CLOSED"];
def startTime = context.getCurrentTime();
if (!"SNCHECKREV".equals(header.getAttribute("CustomerPONumber"))) return;

Integer changeVersionNumber = header.getAttribute("ChangeVersionNumber");
Long runningHeaderId = header.getAttribute("ReferenceHeaderId");

debug(changeVersionNumber.toString() + " ref " + runningHeaderId.toString());
//If this sales order isn't a revision, then don't run the extension.
if (changeVersionNumber == null || changeVersionNumber <= 1 || runningHeaderId == null) return;

try {

    // Create an array of order lines from the existing sales order.
    Map linesFromRunningOrder = getLinesFromRunningOrder(runningHeaderId);
    debug("Line from running order" + linesFromRunningOrder.size());

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

    while (lines.hasNext()) {

        def line = lines.next();
       
        //Skip order lines that are already cancelled or are being cancelled as part of this revision.
        if (line.isCanceled() || line.getAttribute("OrderedQuantity") == 0) continue;
      
        Long referenceFlineId = line.getAttribute("ReferenceFulfillmentLineIdentifier");
        if (referenceFlineId == null) {
            // Nothing to do here. This is a new order line in the current version of the order.
             debug("No Fline Ref");
             continue;
        }
        
        // Get the corrosponding order line from existing sales order.
        def runningLine = linesFromRunningOrder.get(referenceFlineId);

        if (runningLine == null) {
            // we have an error. The extension can't find a fulfillment line that has referenceFlineId. We should ideally never get here.
            throw new ValidationException("Something's not right. The extension can't find a fulfillment line that has referenceFlineId.");
        }

        Date priorRequestedShipDate = runningLine.getAttribute("FulfillLineRequestShipDate");
        Date priorRequestedArrivalDate = runningLine.getAttribute("FulfillLineRequestArrivalDate");
        def priorShippedQuantity = runningLine.getAttribute("FulfillLineShippedQty");
        def priorOrderedQty = runningLine.getAttribute("FulfillLineOrderedQty");
      
        def lineStatus = line.getAttribute("StatusCode");
        debug("StatusCode: " + lineStatus + priorRequestedShipDate + " " + priorRequestedArrivalDate);

        //Skip order lines that already shipped.
        if (postShippedStatuses.contains(lineStatus)) continue;

        // Skip order lines that already shipped.
        if (priorShippedQuantity != null && priorShippedQuantity > 0) continue;

        // Skip order lines that are already cancelled.
        if (priorOrderedQty != null && priorOrderedQty == 0) continue;

        Date lineRequestedShipDate = line.getAttribute("RequestedShipDate");
        Date lineRequestedArrivalDate = line.getAttribute("RequestedArrivalDate");

        def changeInRequestDateAttributes = (areDifferent(priorRequestedShipDate, lineRequestedShipDate)
                                            || areDifferent(priorRequestedArrivalDate, lineRequestedArrivalDate));

         /*
         If the requested ship date or the requested arrival date changed, then do something.
         */
        if (changeInRequestDateAttributes) {
            //Put your code here.
          debug("One of the dates is diff");
        } 
    }
} finally {
    def endTime = context.getCurrentTime();
    long diff = endTime.getTime() - startTime.getTime();
    debug("Time taken by extension " + context.getExtensionName() + ";" + diff.toString());
}


/*
 * Return a boolean value that indicates whether the two incoming dates are same or different.
 */
boolean areDifferent(def v1, def v2) {
    if (v1 == null || v2 == null) return v1 != v2;

    return v1.compareTo(v2) != 0;
}


/*
 * Use the fline id to return a map of the sales order's order lines. 
 */
Map getLinesFromRunningOrder(Long runningHeaderId) {

    //Create an Instance of the FulfillLinePVO public view object.
    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("FulfillLineHeaderId", runningHeaderId);
    vc.add(vcrow);

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

    Map linesMap = new HashMap();

    while (rowset.hasNext()) {
        def fline = rowset.next();

        Long fLineId = fline.getAttribute("FulfillLineId");
        linesMap.put(fLineId, fline);
    }

    return linesMap;
}

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

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