Forcing Cancellation Code when deleting Sales Orders into history through BOI

SOLVED

Good morning all,

So I figured this would have been a relatively easy script but I can't seem to find a way of accomplishing what I need.

I have a customer that would like to force a cancellation reason whenever you delete a Sales Order into history.  They currently have the "Retain Deleted Sales Order" setting to Prompt in SO Options, which first prompts the user if they would like to delete the order (standard), but THEN it asks "Do you want to save the deleted order in history?"  If you say yes, it's all good.  However, you can say No and it will delete the order and not save it (a BIG no no for the customer).  Furthermore, if you do click Yes to save to history, then it bring up this screen to enter the Cancellation Code:

Cancellation Code reason

While I have the Cancellation Code as a required field in Advanced Settings for UDF and Table Maintenance, it will not force an entry unless I validate the field with a list I create, which I would have to make it match the existing lookup on this field.  If I don't have validation, the user can simply click OK without a code and it will delete it.

So I was thinking my quick fix would be to set "Retain Deleted Sales Order" setting to Yes, then create a Table - Pre Delete script that would launch the Cancellation Code screen above BEFORE it asks to delete the order.  I figured that by doing this, the Cancellation Code would be written into the table and then the order would be deleted into history.
Unfortunately, I cannot seem to find the correct UI to bring that screen.  This is the code I had tried but it brings up Cancel and Reason Code Maintenance On The Fly.   

oSOCancel = 0

oSOCancel = oSession.GetObject("SO_CancelReasonCodeOTF_UI")
Set oSOCancel = oSession.AsObject(oSOCancel)
retVal = oSOCancel.Process()

I tried the SO_CancelReasonCode_UI object as well, but that brings up the standard Cancel and Reason Code Maintenance.  
Is there a way of bringing up that specific screen?  I had also tried using the InvokeButton to bring up "fldr.DCANCEL" (Cancellation Code screen in SO_SalesOrder.M4L library) but I had no luck.  Maybe I was using the wrong code?  Any ideas or suggestions would be highly appreciated.

Thanks in advance!
Javier

  • 0

    Instead of trying to launch the panel, you might be better off invoking the SO_CancelReason lookup instead. I'm not sure if this will actually work in a UDS as long as you have a handle to the UI object, such as oSession.AsObject(oScript.UIObj).InvokeLookup but if it does, you will want to make sure you are actually filtering for very specific details, such as the UI being present in the first place, can use oScript.UIObj <> 0, the start program, might want to make sure it is SO_SalesOrder_UI, make sure oSession.Updating = 0, etc.

    Another way to do this might be to use oSession.AsObject(oScript.UIObj).NomadsProcess "DCANCEL", "SO_SalesOrder.M4L" but you may need either a UI post exit script or a fake OK button to run a button script to capture the value entered in the field so you can set it into a storage variable using oSession.AsObject(oSession.ScriptObject).SetStorageVar. You would then use oSession.AsObject(oSession.ScriptObject).GetStorageVar in your original script to get the value that was entered. You could then loop if the value returned is blank in case the user just tried to click OK or Cancel. 

    I would try the InvokeLookup first though as it will be much cleaner and efficient. The first argument is the lookup name, i believe "SO_CancelReason" should give you what you want. The second argument is the variable you want the select value returned in. Make sure you initialize the variable as a blank string before you pass it to the method.

  • 0 in reply to David Speck

    Awesome, thanks for the great info as always .  I'm going to take it and run with it.  If I stumble (I'm sure I will), I'll post a reply.  

  • 0 in reply to Javier Guzman

    My concern would be that anything set in a script during the Pre-Delete event might not make it into SO History.

  • 0 in reply to Kevin M

    Good point, may actually have to move to a post delete and attempt to update the history record afterwards. I haven't messed with history and pre deletes much.

  • 0 in reply to David Speck

    I'd almost lean towards a custom button, invoking BT_ACCEPT first (prompting then setting the reason code value), then re-opening the SO to process the delete.

  • 0 in reply to Kevin M

    That's what I'm seeing.  I can bring up the lookup, select it, and it looks like it deletes ok.  However, it does not flow into SO_SalesOrderHistory as a pre-delete script.  I will try David's suggestion as a post-delete and write to history.

  • 0 in reply to Javier Guzman

    You could use a fake Delete button, hide the real one, have the fake delete button prompt with the same verbiage confirming they want to delete the order, if they answer No, do nothing, if they answer Yes, then proceed to invoke the lookup, get the value back, set it into the cancel reason field, either use oBusObj.Write or oUIObj.BT_Accept/oScript.InvokeButton "BT_Accept", then then call oBusObj.Delete and pass it the sales order number, may then need to follow up with oUIObj.BT_Cancel/oScript.InvokeButton "BT_Cancel".

    If you use the InvokeButton methods, you may also need the oUIObj.HandleScriptUI immediately after each InvokeButton. You can check the return value when doing the "accept" step to see if the order was saved successfully or if an error or warning occurred. The only reason the final step for BT_Cancel might be needed is if the panel doesn't reset to the default state where the fields are empty after you use the finish the "accept" step. If you use oUIObj.BT_Cancel, you may need to follow up after it immediately with oUIObj.RefreshScrn

  • 0 in reply to David Speck

    Hi David,
    Thank you again for your excellent advice.  I am currently working on the fake button method (slowly but surely, one step at a time since I'm still a newbie at this) and I was able to create a fake button, which once pressed gives me the two options.  When clicking Yes, I invoke the lookup and catch the value, which I then try to pass onto the order.  However, it is not writing it back to the order for some reason.  Is it because by invoking the lookup it loses the handle to the SO_SalesOrder_bus?  I thought so, so I made sure to call it back.  However, it still doesn't work.   Here is my code (a work in progress)

    r=oScript.DebugPrint("Deleting Sales Order with Custom Delete button")
    sMsg = "StartProgram = " & oSession.StartProgram & " Updating = " & CStr(oSession.Updating)
    r=oScript.DebugPrint(sMsg)
    oUIObj = 0
    response = ""
    oSOWrite = ""
    oSOCancel = ""

    If IsObject(oUIObj) = False Then
    oUIObj = oScript.UIObj
    Set oUIObj = oSession.AsObject(oUIObj)
    End if

    If oScript.UIObj <> 0 and oSession.Updating = 0 then

    SONo = ""
    retVal = oBusObj.GetValue("SalesOrderNo$",SONo)
    r=oScript.DebugPrint("SONo = " & SONo)
    sMsg = ("Do you want to delete Sales Order " & SONo)
    r=oScript.DebugPrint(sMsg)
    response = oSession.AsObject(oSession.UI).MessageBox("",sMsg,"style=YesNo,icon=?")

    If response = "YES" Then
    sMsg = ("Deleting SO " & SONo)
    r=oScript.DebugPrint(sMsg)

    retVal = oUIObj.InvokeLookup("SO_CancelReason",oSOCancel)
    sMsg = ("Cancel Code = " & oSOCancel)
    r=oScript.DebugPrint(sMsg)
    set oSOWrite = oSession.AsObject(oSession.GetObject("SO_SalesOrder_bus"))
    retVal = oSOWrite.SetKeyValue("SalesOrderNo$",SONo)
    retVal = oSOWrite.SetKey()
    retVal = oSOWrite.SetValue("CancelReasonCode$",oSOCancel)
    retVal = oSOWrite.Write()
    retVal = oSOWrite.Clear()

    oUIObj.BT_Accept

    Else
    sMsg = ("Not deleting SO " & SONo)
    r=oScript.DebugPrint("sMsg = " & sMsg)
    End If

    End If

  • 0 in reply to Javier Guzman

    I would do something more along the lines of this. 

    sMsg = "Deleting Sales Order with Custom Delete button"
    oScript.DebugPrint sMsg
    sMsg = "StartProgram = " & oSession.StartProgram & " Updating = " & CStr(oSession.Updating)
    oScript.DebugPrint sMsg
    
    If oScript.UIObj > 0 And oSession.Updating = 0 Then
    	If Not(IsObject(oUIObj)) Then Set oUIObj = oSession.AsObject(oScript.UIObj)
    	sSalesOrderNo = "" : oBusObj.GetValue "SalesOrderNo$", sSalesOrderNo
    	oScript.DebugPrint "sSalesOrderNo: " & sSalesOrderNo
    	sMsg = "Do you want to delete Sales Order " & sSalesOrderNo
    	oScript.DebugPrint sMsg
    	sResponse = "" : sResponse = oSession.AsObject(oSession.UI).MessageBox("", sMsg, "style=YesNo,icon=?")
    	If UCase(sResponse) = UCase("Yes") Then
    		sMsg = "Deleting SO " & sSalesOrderNo
    		oScript.DebugPrint sMsg
    		sCancelReasonCode = "" : oUIObj.InvokeLookup "SO_CancelReason", sCancelReasonCode
    		oBusObj.SetValue "CancelReasonCode$", sCancelReasonCode
    		If oUIObj.BT_Accept() <> 0 Then
    			oBusObj.Delete sSalesOrderNo
    			oUIObj.BT_Cancel
    			oUIObj.RefreshScrn
    		End If
    	Else
    		sMsg = "Not deleting SO " & sSalesOrderNo
    		oScript.DebugPrint sMsg
    	End If
    End If

    A button script can already access the oBusObj so there is no need to get another handle as you are currently doing, more than likely, your current SetKey is failing because the sales order is still in use by the current oBusObj. 

    I also initialize my variables on the same line they are used to be sure that they are initialized and not forgotten, which can happen if you always put them at the beginning. 

    VBScript has a weird nuance when using parenthesis with a method when you aren't returning the result into a variable, think this happens either when the method has only one argument or more than one argument, been a while since i've seen it because i stopped using the parenthesis when they weren't needed. I only use them if i'm returning the value into a variable or if i need to evaluate the returned value.

  • 0 in reply to David Speck

    Thanks so much for this, David.  Lots of good stuff here for me to learn.

    I tried the script and unfortunately it still does not write to the SO Header, which then does not write to history.  Also, I noticed it creates a blank records in SO_SalesOrderHistoryHeader table.  I tried adding oBusObj.Write() after the SetValue but that didn't do anything either :(