Error: 0 in Method SETKEYVALUE

Hi Forum,

I am getting an error 0 in Method SETKEYVALUE trying to set the key for Sales Order Lines.

Below is the code i have.  I can read the key of the Sales Order Header but i cannot read the Lines.

'Get Sales Order Header

retVal = o.nSetKeyValue("SalesOrderNo$", strOrderNo)
retHdrKey = o.nFind(strOrderNo)

If retHdrKey = 0 Then
MsgBox(o.sLastErrorMsg & strOrderNo & vbCRLF & "SO Header")
End If

r = o.nGetValue("ARDivisionNo$", sDiv)
r = o.nGetValue("CustomerNo$", CustNo)
r = o.nGetValue("CustomerPONo$", strcustPO)

msgbox "SO #: " & strOrderNo & " Customer #: " & CustNo

'Get Sales Order Detail
retVal = 0
retVal = o.oLines.nSetKeyValue("SalesOrderNo$", strOrderNo) *** here is where i get the error.
retVal = o.oLines.nSetKeyValue("LineKey$", sLine_Key)
retKey = o.oLines.nFind()

If retKey = 0 Then
MsgBox(o.sLastErrorMsg & vbCRLF & "SO Detail")
Else
msgbox "Found SO : " & strOrderNo
End If

I cannot figure out what is wrong.  I copied this code from another script that is working.

What am I missing ?

Any suggestions ?

Regards,

Manuel

Parents
  • When you open oLines from an open SO it should already be filtered to the correct lines.  If you MoveFirst, does it load a line from the correct SO?

  • in reply to Kevin M

    I've tried,

    retVal = oLines.nMoveFirst()

    and

    retVal = o.oLines.nMoveFirst()

    Same error, now in method MOVEFIRST, below are the objects..

    ' Instantiate a Sales Order business object
    oSEC = oSS.nSetProgram(oSS.nLookupTask("SO_SalesOrder_ui"))
    Set o = oScript.NewObject("SO_SalesOrder_bus", oSS)
    Set oLines = oScript.NewObject("SO_SalesOrder_bus", oSS)
    'Set oLines = o.oLines

    Still nothing,

    Regards,

    Manuel

  • in reply to mroman

    We're telling you that creating two instances of SO_SalesOrder_bus isn't going to accomplish what you want.

    As for the object required, you can either use o.oLines or first set o.oLines into another variable.

    Something you are missing is that the header is not filtering the lines automatically for you when using the header's Find method (the filtering of the lines is done automatically if you use SetKey).  If you continue using Find, you need to follow it up with SetCurrentKey which requires the full header key to be passed to it.  You can use GetKeyPadded() to get the full key.  

    I did a little testing with the Lines' SetKeyValue and found that it return zero and the following message in the LastErrorMsg property when used on SalesOrderNo$ and ItemCode$.

    In order to EditLine, SetKey, or Find against a detail record, you need the fully padded key including the LineSeqNo, so for SO_SalesOrderDetail, it should be SalesOrderNo$ + LineSeqNo$ + LineKey$ which you can use the Lines' GetEditKey method for this in which you pass it the LineKey that you are after.  Its returned value can be used with EditLine, SetKey, or Find, however, GetEditKey only works for saved detail records which shouldn't be an issue in this case since this is an external script.

    Now I've attempted to change the index used by the detail object to the "KPRIMARY" index so i would just have to use the padded SalesOrderNo$ + LineKey$ with SetKey or Find but it still didn't like that.

    Short of looping through the lines use MoveFirst, MoveNext with EoF and checking the LineKey, the only other ways that I'm aware of is to use GetResultSets or set the browse filter using the kPrimary index and then set the browse filter to the header key fully padded plus the LineKey (you should be able to check the return value when calling SetBrowseFilter, if a 1, then a record met your filter) and then test the MoveFirst method, if it returns a 1, then it was able to navigate to a record matching your browse filter.

    EDIT: As Elliot pointed out, you cannot change the Lines object's index because it uses a *Memory* instead of the physical table.

  • in reply to David Speck

    What is the primary purpose of your script?  Are you trying to edit the line for which you have a LineKey value?  Are you looking to loop through all the lines for the order?

    The way the line entry paradigm was designed is as such.   Using the business object of the header, in our case SO_SalesOrder_bus.

    1. r = o.SetKey( { order number } ) - this will prepare the order for editting as well as load all the detail lines for the order from the physical detail table and put them into a memory table.  (Btw, David the memory table does not respect changing the indexes).  If you use Find() it will NOT filter the lines, Find is used for read-only functions on the primary table in this case SO_SalesOrderHeader and does not fire off the other components such as SetCurrentKey() that David mentioned.

    2. If you know the line key of the order you are looking for then use the method David mention above.  editKey = o.oLines.sGetEditKey( { line key } )  The reason we need to use this method is the memory table used above has one key and that is the kDISPLAY key, which is order + lineSeqNo + lineKey.  So we need the key in that format to edit it.

    2a. If you receive a value back then the key exists, if that's all you want to know then you're done.  If you want to edit that line, then use r = o.oLines.nEditLine(editKey) or r=o.oLInes.nSetKey(editKey).  The return value will be '1' if line exists and '2' if it does not exist (new line)

    3. To make changes to the values in that line, you use r = o.oLines.nSetValue( {field}, {value})

    4. To write change to the detail line r = o.oLines.nWrite() NOTE: this updates the values in the memory table, this does NOT update the physical table yet.

    5. To commit all change to the physical files, write the header, using  r = o.nWrite()

    If you are looping for some other reason, then use a movefirst(), movenext() approach looking for EOF.

    Hope this helps

    E

  • in reply to jepritch

    Thanks for the reminder about the index against the memory table, I now vaguely recall finding that out a while back while trying something else.

  • in reply to jepritch

    What i need to do is to read the Sales Order Header an Lines to compare the lines in a External shipping file to create invoices in Sage.

    I do not need to update/edit any columns i just want to read the SO tables.

    Regards,

    Manuel

  • in reply to David Speck

    Thanks David, i will give it a try.  Although i am sure i tried that becaus ei have the same code in another script.

    Anyways, I will try and see what happens.  

    Regards,

    Manuel

  • in reply to Kevin M

    I did, i have no oLines at all. in fact i stated with no oLines and was using o.oLines and that's when i got the first error message "Error: o in Method SETKEYVALUE", i changed the logic to MoveFirst() and i got the same error 0 but now in Method MoveFirst()

  • in reply to mroman

    The following is the code i am working with 

    ' Instantiate a Sales Order business object
    oSEC = oSS.nSetProgram(oSS.nLookupTask("SO_SalesOrder_ui"))
    Set o = oScript.NewObject("SO_SalesOrder_bus", oSS)

    'Get Sales Order Header

    retVal = o.nSetKeyValue("SalesOrderNo$", strOrderNo)
    retHdrKey = o.nSetKey()

    If retHdrKey = 0 Then
    MsgBox(o.sLastErrorMsg & strOrderNo & vbCRLF & "SO Header")
    End If

    r = o.nGetValue("ARDivisionNo$", sDiv)
    r = o.nGetValue("CustomerNo$", CustNo)
    r = o.nGetValue("CustomerPONo$", strcustPO)

    msgbox "SO #: " & strOrderNo & " Customer #: " & CustNo

    'Get Sales Order Detail

    retVal = o.oLines.nMoveFirst()  **** here is where i get the error message

    Gets the Sales Order Header fine, i get the following info from the header...

    Then i get the error on the MoveFirst() method

    AM I doing the o.oLines correctly ?.  This is how i have it on another script.

    This is a BOI script as you can see on the code.

    Regrards

    Manuel

  • in reply to mroman

    Does the install you are running that script on have any third party enhancements that affect sales order entry?

    If you do have any enhancements, with all users out of the system, can you try renaming the Links folder and try to run the script again?

    The following works for me in an external script on version 2018 and 2020.  This worked whether I used the SY_Session object's NewObject method or the ProvideX.Script object's NewObject method.  I also used SO_SalesOrder_UI when setting the program and SO_SalesOrder_bus when creating the new object.

    sSalesOrderNo = "0000174"
    nRetVal = 0 : nRetVal = o.nSetKey(sSalesOrderNo) 
    MsgBox o.oLines.nGetRecordCount("Main")
    nRetVal = 0 : sARDivisionNo = "" : nRetVal = o.nGetValue("ARDivisionNo$", sARDivisionNo) 
    nRetVal = 0 : sCustomerNo = "" : nRetVal = o.nGetValue("CustomerNo$", sCustomerNo) 
    nRetVal = 0 : o.oLines.sLastErrorMsg = "" : nRetVal = o.oLines.nMoveFirst() 
    MsgBox nRetVal & vbCrLf & o.oLines.sLastErrorMsg
    nRetVal = 0 : sItemCode = "" : nRetVal = o.oLines.nGetValue("ItemCode$", sItemCode) 
    MsgBox sSalesOrderNo & vbCrLf & sARDivisionNo & "-" & sCustomerNo & vbCrLf & o.oLines.nGetRecordCount("Main") & vbCrLf & sItemCode

  • in reply to David Speck

    Yes, they do have MAPADOC and an xKzero customization.

    Which leads me to ask another question.... but i think i'll open another case once this one gets resolved.

    I will rename the Links folder.

    I am testing the script on a test environment.

  • in reply to David Speck

    David,

    nRetVal = 0 : o.oLines.sLastErrorMsg = "" : nRetVal = o.oLines.nMoveFirst()

    MsgBox nRetVal & vbCrLf & o.oLines.sLastErrorMsg

    The message show the following...

    and yet 

    nRetVal = 0 : sOrder = "" : nRetVal = o.oLines.nGetValue("SalesOrderNo$", sOrder)
    nRetVal = 0 : sItemCode = "" : nRetVal = o.oLines.nGetValue("ItemCode$", sItemCode)
    MsgBox sSalesOrderNo & vbCrLf & sARDivisionNo & "-" & sCustomerNo & vbCrLf & o.oLines.nGetRecordCount("Main") & vbCrLf & "SO#: " & sOrder & " Item: " & sItemCode

    show the correct Customer, Sales Order and Item Number...

    Renaming the Links folder didn't help.

Reply
  • in reply to David Speck

    David,

    nRetVal = 0 : o.oLines.sLastErrorMsg = "" : nRetVal = o.oLines.nMoveFirst()

    MsgBox nRetVal & vbCrLf & o.oLines.sLastErrorMsg

    The message show the following...

    and yet 

    nRetVal = 0 : sOrder = "" : nRetVal = o.oLines.nGetValue("SalesOrderNo$", sOrder)
    nRetVal = 0 : sItemCode = "" : nRetVal = o.oLines.nGetValue("ItemCode$", sItemCode)
    MsgBox sSalesOrderNo & vbCrLf & sARDivisionNo & "-" & sCustomerNo & vbCrLf & o.oLines.nGetRecordCount("Main") & vbCrLf & "SO#: " & sOrder & " Item: " & sItemCode

    show the correct Customer, Sales Order and Item Number...

    Renaming the Links folder didn't help.

Children
  • in reply to mroman

    the LastErrorMsg is only pertinent if the value being returned in nRetVal <= 0.  Otherwise this value could be leftover from a previous read or some other area.  If nRetVal=1 then your MoveFirst() passed.  The other variable you need to reference when using the browsing functions is o.oLines.nEOF this will tell you whether you've reached an end-of-file condition (or beginning of file, depending on how you are browsing)

    Elliott

  • in reply to jepritch

    Got it, Thanks Elliott.

  • in reply to jepritch

    I can see the script is working with the code i got from David , same code i had?(maybe not).

    anyways, i am cleaning the script.  i'll try it again and let you know what happens.

    Thanks for the help!!! 

  • in reply to mroman

    mroman, one thing I'll add is that if you are trying to trap an error or warning that you expect could occur when calling a specific method, then you'll want to reset the LastErrorMsg the way I was by setting it to an blank string.  However, as Elliott said, you really only need to be concerned with its contents if your returned value is <= 0 because 0 is failure and -1 is a warning.  LastErrorMsg doesn't normally get reset, so when a method sets it, it just overrides whatever was in it previously, this is why checking just LastErrorMsg alone (when not resetting it) can be dangerous because you'll see false positives, like the " is not on file." one.  Another common one is "x is not numeric" which usually occurs when setting CustomerNo or other key fields that allow alphanumeric values.  Since the code I posted was for the sole purpose of trying to identify why your methods might have been failing, I was resetting nRetVal and LastErrorMsg before every method call and outputting the results step by step to help you pinpoint where the issue might be.  For production purposes, I usually only reset LastErrorMsg before methods like SetKey, Write, GetObject/NewObject, Update, ProcessReport, etc.  Keep in mind that LastErrorMsg is a property of each object, so your SY_Session object, SO_SalesOrder_bus object, its Lines object, SO_Invoice_bus object, its Lines object, etc all have their own LastErrorMsg property so you need to make sure you are resetting and checking the correct one based on the object whose method you are calling.

  • in reply to David Speck

    First let me thank you guys for all the help...Really appreciated!!

    Got it David.. i just made sure all LastErrorMsg are reset.

    The SalesOrder_Bus and lines works fine now..!!!.

    my next is the SO_Invoice_bus and lines.  I am able to set the iBatch Number, the novice number, division & CustomerNo fine, When i try to AddLine() i get an error.

    Here is my code...

    ' Instantiate a Sales Order business object
    oSEC = oSS.nSetProgram(oSS.nLookupTask("SO_SalesOrder_ui"))
    Set o = oScript.NewObject("SO_SalesOrder_bus", oSS)

    ' Instantiate a Sales Order Invoice business object
    oSEC = oSS.nSetProgram(oSS.nLookupTask("SO_Invoice_ui"))
    Set oInv = oScript.NewObject("SO_Invoice_bus", oSS)

    **** code to populate Invoice Header and Detail

    'r = o.nGetNextInvoiceNo(InvoiceNo)
    r = oInv.nSetKey(InvoiceNo)

    if r = 0 then
    MsgBox(oInv.sLastErrorMsg & sInvoiceNo & vbCRLF & "Inv Header")
    end if

    r = oInv.nSetValue("ARDivisionNo$", "00")
    r = oInv.nSetValue("CustomerNo$", CustNo)
    ''r = oInv.nSetValue("CustomerPONo$", strCustPO) **** I cannot set Customer PO

    msgbox "Invoice #: " & InvoiceNo

    End if

    'Write Inovice Lines

    r = oInv.oLines.nAddLine() *** Error: 0 Method ADDLINE()


    r = oInv.oLines.nSetValue("ItemCode$",trim(sItemCode))
    r = oInv.oLines.nSetValue("WareHouseCode$", sLineWhseWhse)
    r = oInv.oLines.nSetValue("QuantityOrdered", nQtyOrdered)
    r = oInv.oLines.nSetValue("QuantityShipped", nQtyOrdered)
    r = oInv.oLines.nSetValue("LineKey$", sOrderLine_Key)
    r = oInv.oLines.nSetValue("LineSeqNo$", sOrderLine_Key)
    r = oInv.oLines.nSetValue("ItemType$", sItemType)
    r = oInv.oLines.nSetValue("ItemCodeDesc$", sItemCodeDesc)
    r = oInv.oLines.nSetValue("SkipPrintCompLine$", "N")
    r = oInv.oLines.nSetValue("ExplodedKitItem$", "N")
    r = o.oLines.nSetValue("UnitPrice", strPrice)

    r = oInv.oLines.nWrite()

    My question is: it oInv.oLines.nSetValue correct?... 

    oInv is the header, i just added ".oLines" for the lines object.

    once again, i have this same thing on another script and works fine except that i am doing it for AP invoices.

    Regards,

    Manuel

  • in reply to mroman

    Just to add, when i set the customer in the Invoice Header i get the message..

    L018949 is the invoice number ...

    I guess i need to find out why is invalid for the rest of the lines to go thru.

    Regards,

  • in reply to mroman

    When posting code, use the code feature, also, it helps to indent your code to make readability easier.  Below is your code from your post. 

    There seems to be an "End If" on line 24 that isn't valid.

    With line 11 commented out (btw you are using the o object which is your handle to SO_SalesOrder_bus instead of oInv), where are you getting the invoice number used in the SetKey?

    Your handling of the returned value of the SetKey method is flawed, at the moment, regardless of the returned value, i.e. 0 (failure), your code is still proceeding to try to process the header fields and lines.

    Line 40 is also referencing the o object instead of oInv.

    ' Instantiate a Sales Order business object
    oSEC = oSS.nSetProgram(oSS.nLookupTask("SO_SalesOrder_ui"))
    Set o = oScript.NewObject("SO_SalesOrder_bus", oSS)
    
    ' Instantiate a Sales Order Invoice business object
    oSEC = oSS.nSetProgram(oSS.nLookupTask("SO_Invoice_ui"))
    Set oInv = oScript.NewObject("SO_Invoice_bus", oSS)
    
    ' **** code to populate Invoice Header and Detail
    
    'r = o.nGetNextInvoiceNo(InvoiceNo)
    r = oInv.nSetKey(InvoiceNo)
    
    if r = 0 then
    	MsgBox(oInv.sLastErrorMsg & sInvoiceNo & vbCRLF & "Inv Header")
    end if
    
    r = oInv.nSetValue("ARDivisionNo$", "00")
    r = oInv.nSetValue("CustomerNo$", CustNo)
    'r = oInv.nSetValue("CustomerPONo$", strCustPO) **** I cannot set Customer PO
     
    msgbox "Invoice #: " & InvoiceNo
    
    End if
    
    'Write Inovice Lines
    
    r = oInv.oLines.nAddLine() ' *** Error: 0 Method ADDLINE()
    
    r = oInv.oLines.nSetValue("ItemCode$",trim(sItemCode))
    r = oInv.oLines.nSetValue("WareHouseCode$", sLineWhseWhse)
    r = oInv.oLines.nSetValue("QuantityOrdered", nQtyOrdered)
    r = oInv.oLines.nSetValue("QuantityShipped", nQtyOrdered)
    r = oInv.oLines.nSetValue("LineKey$", sOrderLine_Key)
    r = oInv.oLines.nSetValue("LineSeqNo$", sOrderLine_Key)
    r = oInv.oLines.nSetValue("ItemType$", sItemType)
    r = oInv.oLines.nSetValue("ItemCodeDesc$", sItemCodeDesc)
    r = oInv.oLines.nSetValue("SkipPrintCompLine$", "N")
    r = oInv.oLines.nSetValue("ExplodedKitItem$", "N")
    r = o.oLines.nSetValue("UnitPrice", strPrice)
    
    r = oInv.oLines.nWrite()

  • in reply to David Speck

    End if on line 24 is part of an IF statement the i didn't include on the code.

    I am getting the Invoice number from a SQL table that i using to import the Invoices.

    Line 40 was commented, i just took it out, 

    Thanks, i am cleaning the trash of the script...

  • in reply to mroman

    Looks better now that i clean the script.

    I am able to set lines in the Sales Order Invoice Header and Detail and that brings me to a question.

    Is there an object that will allow me to set the Sales Order Number in the SO_Invoice_bus object to bring the Sales Order information into the Sales Order Invoice table like when we do manually in Invoice data entry?

    Regards,

    Manuel

  • in reply to mroman

    The invoice object's Lines object has a method called CopyLinesFromSalesOrder.  Refer to this post which has additional links and info.

    https://www.sagecity.com/support_communities/sage100_erp/f/sage-100-business-object-interface/173110/type-mismatch-copyfromorder-err-ret-2-0/441788#441788