Read line items for a specific Invoice order without using a loop for every order.

 using (DispatchObject soObject = new DispatchObject(pvx.InvokeMethod("NewObject", "SO_Invoice_bus", oSS.GetObject())))              	 {
                    soObject.InvokeMethod("nSetKeyValue", new object[] { "InvoiceNo$", strRefNumber });
                    int rt = (int)soObject.InvokeMethod("nFind");
                    if (rt > 0)
                    {
                        var dta = new object[] { "InvoiceNo$", "lineitem$" };
                        int val = (int)soObject.InvokeMethodByRef("nGetRecord", dta);
                    }
                    var invoiceNo = soObject.GetDataObject("InvoiceNo$");
	  }

I was able to get the header details based on the order number. But how to read the line items for a specific order without using a loop to read all line items for every order?

  • Header objects like SO_Invoice_Bus have a property called Lines that you can access to loop through the line records belonging to the currently set header record but you have to use SetKey instead of Find on the header to prepare the Lines object.

  • Thanks for your reply David.

    But still I'm getting all orders line items instead of the required order number. Also when I use SetKey instead of Find, it returns 0. (Check1 returns 0)
    Please let me know if I did anything wrong.

                    using (DispatchObject poObject = new DispatchObject(pvx.InvokeMethod("NewObject", "SO_Invoice_bus", oSS.GetObject())))
                    {
                        poObject.InvokeMethod("nSetKeyValue", new object[] { "InvoiceNo$", strRefNumber });
                        int check = (int)poObject.InvokeMethod("nFind"); 
                        var data = new object[] { "InvoiceNo$", strRefNumber };
                        int value = (int)poObject.InvokeMethodByRef("nGetRecord", data);
                        using (DispatchObject so_line = new DispatchObject(poObject.GetProperty("oLines")))
                        {
                            so_line.InvokeMethod("nSetKeyValue", new object[] { "InvoiceNo$", strRefNumber });
                            int check1 = (int)so_line.InvokeMethod("nSetKey");
                            var data1= new object[] { "InvoiceNo$", strRefNumber };
                            int value1 = (int)so_line.InvokeMethodByRef("nGetRecord", data1);
                            so_line.InvokeMethod("nMoveFirst");
                            int EOF = (int)so_line.GetProperty("nEOF");
                            do
                            {
                                var InvoiceLineNumber = so_line.GetDataObject("InvoiceNo$");                            
    
                                so_line.InvokeMethod("nMoveNext");
                                EOF = (int)so_line.GetProperty("nEOF");
    
                            } while (EOF != 1);
                        }
                    }


  • If you want to access the lines, you can't use Find at all.  You need to replace the Find with SetKey, not do Find and then SetKey.  I'm not well versed in C# but something like this might work.  

                    using (DispatchObject poObject = new DispatchObject(pvx.InvokeMethod("NewObject", "SO_Invoice_bus", oSS.GetObject())))
                    {
                        poObject.InvokeMethod("nSetKeyValue", new object[] { "InvoiceNo$", strRefNumber });
                        int check = (int)poObject.InvokeMethod("nSetKey"); 
                        var data = new object[] { "InvoiceNo$", strRefNumber };
                        int value = (int)poObject.InvokeMethodByRef("nGetRecord", data);
                        using (DispatchObject so_line = new DispatchObject(poObject.GetProperty("oLines")))
                        {
                            so_line.InvokeMethod("nMoveFirst");
                            int EOF = (int)so_line.GetProperty("nEOF");
                            do
                            {
                                var InvoiceLineNumber = so_line.GetDataObject("InvoiceNo$");                            
    
                                so_line.InvokeMethod("nMoveNext");
                                EOF = (int)so_line.GetProperty("nEOF");
    
                            } while (EOF != 1);
                        }
                    }

    I also don't recognize the nGetRecord method you are trying to use in the manner that you are because nGetRecord expects two arguments.  If you are trying to get the value from a single field, you need to use nGetValue, the first argument to it is the field name (with a $ suffix for string fields and no suffix for numeric fields) and the second argument is the variable you want the value returned in.  

    Look at the online object reference for SY_Service to see more details on the GetValue and GetRecord methods.

    https://help-sage100.na.sage.com/2021/FLOR/index.htm#Object_Reference/BaseSystem/SY_Service.htm 

  • var SOrder = new clsInvoice();
    
                    using (DispatchObject poObject = new DispatchObject(pvx.InvokeMethod("NewObject", "SO_Invoice_bus", oSS.GetObject())))
                    {
                        poObject.InvokeMethod("nSetKeyValue", new object[] { "InvoiceNo$", strRefNumber });
                        int check = (int)poObject.InvokeMethod("nSetKey");
                        var data = new object[] { "InvoiceNo$", strRefNumber };
                        int value = (int)poObject.InvokeMethodByRef("nGetRecord", data);
    
                        SOrder.InvoiceNo = poObject.GetDataObject("InvoiceNo$");
                        SOrder.CustomerNo = poObject.GetDataObject("CustomerNo$");
                        SOrder.OrderDate = TextUtilities.ConvertDate(poObject.GetDataObject("InvoiceDate$")).ToShortDateString();
                        SOrder.SalesOrderNo = poObject.GetDataObject("SalesOrderNo$");
                        SOrder.CustomerPONo = poObject.GetDataObject("CustomerPONo$");
    
                        using (DispatchObject so_line = new DispatchObject(poObject.GetProperty("oLines")))
                        {
                            so_line.InvokeMethod("nMoveFirst");
                            int EOF = (int)so_line.GetProperty("nEOF");
                            do
                            {
                                SOrder.InvoiceNo = so_line.GetDataObject("InvoiceNo$");
                                SOrder.InvoiceLineItemCode = so_line.GetDataObject("ItemCode$");
                                SOrder.InvoiceLineDesc = so_line.GetDataObject("ItemCodeDesc$");
                                SOrder.InvoiceLineUnitOfMeasure = so_line.GetDataObject("UnitOfMeasure$");
                                SOrder.InvoiceLineQuantity = so_line.GetDataNumericObject("QuantityOrdered");
                                SOrder.InvoiceLineQuantityShipped = so_line.GetDataNumericObject("QuantityShipped");
                                SOrder.InvoiceLineUnitPrice = so_line.GetDataDecimalObject("UnitPrice");
                                alInvoices.Add(SOrder);
    
                                so_line.InvokeMethod("nMoveNext");
                                EOF = (int)so_line.GetProperty("nEOF");
    
                            } while (EOF != 1);
                        }
                    }

    I even replaced the SetKey, it still returned 0. But I'm able to get the header details of the specific order and not able to get the line items for this order number.
    The 'olines' property returns all line item values for all orders.
    But, I need to get line items for the specific order number. 
    How to set 'KeyValue' inside the line items property?

  • I don't know that language but this is how you'd do it in a VB script.

    Set oLines = oSession.AsObject(oBusObj.Lines)

    retVal = oLines.MoveFirst()

    Where oBusObj is the SO Invoice header object, with an active invoice (after SetKey).