Script to update child line

SOLVED

I wrote a script sales order detail post write script that creates a child line that is a percentage of the parent line. If the updates the parent line quantity, unit price or extension the script updates the child line, BUT does not display the change in the grid until you go to another tab, then back to the lines. I have tried using the add line function, but still does not refresh the grid line.  

'Get Values from parent line

Set oUI = oSession.AsObject(oSession.UI)

retval = oHeaderObj.getvalue("ARDivisionNo$",ARDiv)
retval = oHeaderObj.getvalue("CustomerNo$",Customerno)
retval = oBusObj.getvalue("SalesOrderNo$",SalesOrderNo)
retval = obusObj.getvalue("LineKey$",ParentLineKey)
retval = obusObj.getvalue("QuantityOrdered",Quantity)
retval = oBusObj.getvalue("UDF_TARIFF_AMT",TariffAmt)
retval = obusObj.getvalue("UDF_TARIFFLINEKEY$",ChildLineKey)

if Quantity <> 0 then UnitPrice = TariffAmt / Quantity

'Locate child line

if ChildLineKey <> "" then


retVal = oBusObj.MoveFirst()

do until cBool(oBusObj.EOF)


retval = obusObj.getvalue("LineKey$",LineKey)


'Checks if the line is the child
if Linekey = ChildLineKey then


retVal = oBusObj.SetValue("QuantityOrdered",Quantity)
retVal = oBusObj.SetValue("UnitPrice",UnitPrice)
if retval <> 1 then oui.messagebox(oBusObj.LastErrorMsg)
retVal = oBusObj.Write()

'Refresh the grid
oScript.LinesAdded = -1
oScript.LoadGrid "GD_Lines"

End if

oBusObj.movenext
loop


End if

Any help would be greatly appreciated.

Justin 

  • 0

    I think i have a solution somewhere for this.

    Also, you should probably place you oBusObj.Write between a oScript.DeactivateProcedure and oScript.ActivateProcedure line so you don't end up recursively looping through the lines.

    Here are more details on the two methods from the scripting.docx.

    retVal = oScript.ActivateProcedure
    (proc_name as String)


    and


    retVal = oScript.DeactivateProcedure
    (proc_name as String)

    These are used to give the script author the ability to avoid recursive calls. For example, if the PostValidateQuantityShipped(col, val) procedure script was to invoke the oBusObj.SetValue(“QuantityShipped”, val), this would in turn cause the PostValidateQuantityShipped(col, val) procedure to be called again. To avoid this, call retVal = oScript.DeactivateProcedure(“PostValidateQuantityShipped”) prior to the SetValue() call, then use the retVal=oScript.ActivateProcedure(“PostValidateQuantityShipped”) to reactivate this procedure.

    Note: Use retVal = oScript.DeactivateProcedure(“*ALL*”) to deactivate/activate all procedures for the current business object.

    Note: Use retVal = oScript.Deactivate(“*”) to deactivate/activate the current procedure.

    EDIT: Removed code that wasn't working and removed redundant info that can be obtained from my latest answer.

  • 0 in reply to David Speck

    Hi David,

    I am trying to use the oBusObj.EditLine . The message box returns the key I want to update, but the error message is referencing a linekey that does not exists on the order. Below is the code with screenshots inserted. Any advise would be greatly appreciated.

    Script is on post write on the Sales Order Detail business object. 

    'Other code above

    retval = oBusObj.getvalue("SalesOrderNo$",SalesOrderNo)
    retval = obusObj.getvalue("UDF_TARIFFLINEKEY$",TariffLineKey)

    slinkey = SalesOrderNo & TariffLineKey

    oui.messagebox(slinkey)

     

    retval = oBusObj.EditLine(slinekey)

    'Retval = 2 

    if retval <> 1 then oui.messagebox(oBusObj.LastErrorMsg)

     

     

     

    Here is the record in DFDM

     

  • 0 in reply to justinaroberts

    EditLine MUST be passed the full kDisplay key. In this case, that is SalesOrderNo+LineSeqNo+LineKey.

    GetEditKey only works for detail records that have been committed to the physical file,this occurs when you click Accept in Sales Order Entry. 

    After using EditLine, instead of checking the return value, trying using a message box to display the value returned from the GetKey method. Sometimes LastErrorMsg doesn't clear between methods and events and you could go down a rabbit hole trying to resolve a false positive. If you absolutely must trap an error, before you call the method that is prone to errors, set the LastErrorMsg property to a blank string. The GetKey method will tell you which key you are on, it should be a combination of the SalesOrderNo+LineSeqNo+LineKey.

    EDIT: Corrected details on the EditLine method.

  • +1 in reply to David Speck
    verified answer

    So a little testing revealed EditLine expects the key defined by the KDisplay index, which is SalesOrderNo+LineSeqNo+LineKey. GetEditKey will return this if you pass it a LineKey but it will not work on new lines added to an order that have not been committed to the physical file yet.

    So this means either loop though the lines or, assuming no one ever reorders the lines, store the full KDisplay key in the UDF instead of just the LineKey, this will be a problem if someone does resequence a line because the LineSeqNo will change but if you don't script a way to update the full key value stored in the UDF, it will no longer match.

    Hopefully that all makes sense.

    You might just be better off looping through the lines after all.

  • 0 in reply to David Speck

    Hi David,

    I still am unable to have the grid refreshed. When I added the following code I receive the the error below.  

    If oScript.UIObj > 0 Then
           oSession.AsObject(oScript.UIObj).LoadGrid "GD_Lines"
          oSession.AsObject(oScript.UIObj).LinesAdded = -1
    End If

    Also what is the difference from the code above to :

    retVal = oScript.LinesAdded = -1
    retVal = oScript.LoadGrid("GD_Lines")

  • 0 in reply to David Speck

    For completeness, another way to do this would be to use the Browse Index and Browse Filter. You do want to be careful and check and save off any current values for the current key (use the GetKey method) CurrentBrowseIndex property and use GetValue on "cBrowseFilter". Save these into variables and then use the SetBrowseIndex method followed by the SetBrowseIndex method followed my the MoveFirst method, if the MoveFirst method returns 0, then no record was found matching the Browse Filter for the specified Browse Index. After locating the line, you can use GetKey to store its full key, then set the browse filter back to what it was previously using the variable you stored it into followed by setting the Browse Index to what it was previously followed by using EditLine on the correct key. Once done editing the line, use EditLine on the original key that you stored in a variable. Then refresh the grid.

  • 0 in reply to justinaroberts

    Think i messed up those two lines, the idea is to get the script object for the UI object, sometimes, you can only accomplish certain things from the UI object's context.

    Give me a few minutes and i'll dig up my solution for the grid refresh.

  • 0 in reply to David Speck

    Here is a verified method to refresh the grid from a table event script. I recommend placing this as close to the end of your script as possible and not in the middle of a loop on the lines.

    If oScript.UIObj > 0 Then
    	Set oSOUIObj = oSession.AsObject(oScript.UIObj)
    	GD_Lines = 0 : oSOUIObj.GetControlProperty "GD_Lines", "Ctl", GD_Lines 
    	If IsNumeric(GD_Lines) And GD_Lines > 0 Then
    		GD_Lines = CLng(GD_Lines)
    		oSOUIObj.ClearGrid GD_Lines
    		oSOUIObj.ClearTotals
    		oSOUIObj.LoadLines GD_Lines
    		oSOUIObj.SetStartingRow GD_Lines
    	End If
    	Set oSOUIObj = Nothing
    End If

  • +1
    verified answer

    Here is a complete solution with key notes.

    Make sure to set the correct value in the TargetLineKey variable since i hardcoded it in the example.

    Make sure to test it in your environment to confirm everything is working as expected.

    Read through the script so you can understand what is happening. 

    Depending on other script events you are using, you may or may not need to deactivate and re-activate them at various points in the script. Refer to my examples where i do this with the PostWrite event. If you find that you also have PostRead event scripts on the lines but don't need them to fire when handling the lines in this script, then deactivate and re-activate the PostRead event where the EditLine methods appear if applicable.

    CurrentBrowseIndex = "" : CurrentBrowseIndex = oBusObj.CurrentBrowseIndex : If CurrentBrowseIndex = "0" Then CurrentBrowseIndex = "" ' This gets the current browse index.
    oScript.DebugPrint "CurrentBrowseIndex: " & CurrentBrowseIndex
    cBrowseFilter = "" : oBusObj.GetValue "cBrowseFilter$", cBrowseFilter ' This gets the current brows filter.
    oScript.DebugPrint "cBrowseFilter: " & cBrowseFilter
    OriginalKey = "" : OriginalKey = oBusObj.GetKey() ' This gets the current key of the line that triggered this script via the post-write event.
    oScript.DebugPrint "OriginalKey: " & OriginalKey
    TargetKey = "" ' Set this to blank so we can evaluate whether or not the target line is found later.
    TargetLineKey = "000002" ' You would get this from your UDF, for testing purposes, i hardcoded it.
    HeaderKey = "" : HeaderKey = oHeaderObj.GetKey() ' This gets the header's primary key.
    oScript.DebugPrint "HeaderKey: " & HeaderKey
    oBusObj.SetBrowseIndex "kPrimary", oBusObj.CurrentIndex ' This sets the browse index to kPrimary and will fall back to the current index if the first argument fails.
    oBusObj.SetBrowseFilter HeaderKey & TargetLineKey ' This sets the browse filter. The way a browse filter works is you pass is a value that corresponds to the browse index, it uses a "Begins with" matching method.
    If oBusObj.MoveFirst() = 1 Then ' Check that a record exists that matches the browse filter. If no record exists, MoveFirst will return a 0.
    	TargetKey = oBusObj.GetKey() ' Get the full kDisplay key for the target line.
    End If
    oBusObj.SetBrowseIndex CurrentBrowseIndex, oBusObj.CurrentIndex ' Set the browse index back to what it was originally.
    oBusObj.SetBrowseFilter cBrowseFilter ' Set the browse filter back to what it was originally.
    oScript.DebugPrint "TargetKey: " & TargetKey
    If TargetKey <> "" Then
    	' Do logic in here now that you have found the target line.
    	oBusObj.EditLine TargetKey ' Put the target line in an edit state.
    	QuantityOrdered = 0 : oBusObj.GetValue "QuantityOrdered", QuantityOrdered ' Do various activities against the target line.
    	oBusObj.SetValue "QuantityOrdered", QuantityOrdered + 1 ' Do various activities against the target line.
    	' Make sure to deactivate any script procedures that would cause a infinite loop.
    	oScript.DeactivateProcedure "PostWrite"
    	oBusObj.Write ' Write changes to the target line if applicable. MAKE SURE TO DISABLE ANY SCRIPT EVENTS THAT WILL TRIGGER AN INFINITE LOOP.
    	oScript.ActivateProcedure "PostWrite"
    End If
    If oScript.UIObj > 0 Then ' Check if the UI Object is present.
    	GridKey = "" : oSession.AsObject(oScript.UIObj).GetControlProperty "GD_Lines", "Text$", GridKey ' Grids in sage 100 store the kDisplay key in the grids "Text$" property in a HEX string format. Get this value into a variable so in case the grid selection has changed, we can make sure we put the business object back on the right line record to keep the UI object and Business object in sync.
    	If GridKey <> "" Then
    		OriginalKey = oScript.Evaluate("ATH(""" & GridKey & """)") ' Convert the HEX string to a string.
    	End If
    End If
    oScript.DebugPrint "Key To Edit: " & OriginalKey
    oBusObj.EditLine OriginalKey ' Put the original or currently selected row in the grid's key in an edit state.
    
    If oScript.UIObj > 0 Then ' Check if the UI Object is present.
    	Set oSOUIObj = oSession.AsObject(oScript.UIObj) ' Set this to an object handle since we will be using it for more than a few lines.
    	GD_Lines = 0 : oSOUIObj.GetControlProperty "GD_Lines", "Ctl", GD_Lines ' Get the Control ID for the GD_Lines control.
    	If IsNumeric(GD_Lines) And GD_Lines > 0 Then ' Check that the grid's control ID is numeric and greater than 0.
    		GD_Lines = CLng(GD_Lines) ' Make sure the value returned from the GetControlProperty method is converted to the type that the following methods expect.
    		oSOUIObj.ClearGrid GD_Lines ' Clear the grid.
    		oSOUIObj.ClearTotals ' Clear the totals so we don't continually add the lines totals while loading to the total displayed in the bottom right.
    		oSOUIObj.LoadLines GD_Lines ' Load the lines.
    		oSOUIObj.SetStartingRow GD_Lines ' Go to the last row selected.
    	End If
    	Set oSOUIObj = Nothing
    End If