C# PO Write Fails BOI

SOLVED

First, thanks in advance for taking a look at this.  I'm looking at doing PO creation from C# and have been able to connect, get the next PO number etc., but everytime I try to finalize the PO, such as call the "nWrite" command, it always fails.  Any insight into what could be happening?  Below is my code.

using (DispatchObject poObject = new DispatchObject(pvx.InvokeMethod("NewObject", "PO_PurchaseOrder_bus", oSS.GetObject())))
{
try
{
string poNumber = "";
//int test1 = (int)poObject.InvokeMethod("nGetNextPurchaseOrderNo");
object[] poPass = new object[] {poNumber};
successCheck((int)poObject.InvokeMethodByRef("nGetNextPurchaseOrderNo", poPass), "GetNextPurchaseOrder");

//this was just to see what the PO number was coming back.
poNumber = poPass[0].ToString();

//we continue
successCheck((int) poObject.InvokeMethodByRef("nSetKey", poPass), "SetKey");
object[] divisionNoObject = new object[] {"APDivisionNo$", "00"};
successCheck((int) poObject.InvokeMethodByRef("nSetValue", divisionNoObject), "SetDivisionNo");
object[] vendorObject = new object[] { "VendorNo$", "0006630" };
successCheck((int)poObject.InvokeMethodByRef("nSetValue", vendorObject), "SetVendorNo");
object[] taxObject = new object[] { "TaxSchedule$", "NONTAX" };
successCheck((int)poObject.InvokeMethodByRef("nSetValue", taxObject), "SetTaxSchedule");

DispatchObject poLines = new DispatchObject(poObject.GetProperty("oLines"));
successCheck((int)poLines.InvokeMethod("nAddLine"), "AddLine");
object[] firstLine = new object[] { "ItemCode$", "/1." };
successCheck((int)poLines.InvokeMethodByRef("nSetValue", firstLine), "PoLineItemCode");
firstLine[0] = "QuantityOrdered";
firstLine[1] = "1";
successCheck((int)poLines.InvokeMethodByRef("nSetValue", firstLine), "PoLineQuantityOrdered");
successCheck((int)poLines.InvokeMethod("nWrite"), "PoLinesWrite");
successCheck((int) poObject.InvokeMethod("nWrite"), "Write");

MessageBox.Show("SUCCESS! " + poNumber.ToString());

}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}

}

And below is my successCheck method to see what fails.

public void successCheck(int checkValue, string call)
{
if (checkValue == 0)
{
MessageBox.Show("Error! " + call);

}

}

  • 0
    I don't know C# so I may be misunderstanding the syntax, but are you setting the value of the ItemCode to be "/1."? Do you have a misc code 1.? Also, are you assigning the Quantity Ordered to "1"? I believe it should be a numeric 1 instead.
  • 0 in reply to BadgerJerry
    The item code is set to "/1." because of the way we work. We simply type in an item, not pull from an item code. This allows us to type in anything we want in the item field. Also, the syntax for the DispatchObject, which essentially is what allows for using C# in BOI, reads the "1" as a numeric 1 I believe. Just in case, I tested it by setting firstLine[1] = 1 and it ended up still failing at the same point. Good catches though. :)
  • 0
    I would call sLastErrorMsg after the method that is failing on poObject. If it is falling into your catch before you can get the last error from poObject, then I would check the sLastErrorMsg on your oSS object. I just created an integration that was falling into an exception on nWrite, so I couldn't grab the last error. It turned out that the error was actually happening on my session object.
  • 0 in reply to willHyland

    Checking the sLastErrorMsg property is always a good idea!

    Luckily, if you are using the DispatchObject object wrapper that Sage provided, it includes a property indexer that makes it easy to do:
    var lastError = poObject["sLastErrorMsg"];

    That said, I got your code to work in my test project pretty much as is...
    I fixed the nSetKey line to pass the string poNumber, vs. the object array named poPass.
    The other thing I changed was the usage of InvokeMethodByRef to InvokeMethod, in a few places, where parameters are passed by value, not by ref.
    Not sure if this caused any problem, but ByRef is more overhead so I only use it when needed.
    Also I changed the vendor to 01-AIRWAY and the item code to "6655" to work with my ABX company, but everything else should fly.

    Thanks!
    Bret.

    string poNumber = "";
    //int test1 = (int)poObject.InvokeMethod("nGetNextPurchaseOrderNo");
    object[] poPass = new object[] { poNumber };
    successCheck((int)poObject.InvokeMethodByRef("nGetNextPurchaseOrderNo", poPass), "GetNextPurchaseOrder");

    //this was just to see what the PO number was coming back.
    poNumber = poPass[0].ToString();

    //we continue
    successCheck((int)poObject.InvokeMethod("nSetKey", poNumber), "SetKey");
    object[] divisionNoObject = new object[] { "APDivisionNo$", "01" };
    successCheck((int)poObject.InvokeMethod("nSetValue", divisionNoObject), "SetDivisionNo");
    object[] vendorObject = new object[] { "VendorNo$", "AIRWAY" };
    successCheck((int)poObject.InvokeMethod("nSetValue", vendorObject), "SetVendorNo");
    object[] taxObject = new object[] { "TaxSchedule$", "NONTAX" };
    successCheck((int)poObject.InvokeMethod("nSetValue", taxObject), "SetTaxSchedule");

    DispatchObject poLines = new DispatchObject(poObject.GetProperty("oLines"));
    successCheck((int)poLines.InvokeMethod("nAddLine"), "AddLine");
    //object[] firstLine = new object[] { "ItemCode$", "/1." };
    object[] firstLine = new object[] { "ItemCode$", "6655" };
    successCheck((int)poLines.InvokeMethod("nSetValue", firstLine), "PoLineItemCode");
    firstLine[0] = "QuantityOrdered";
    firstLine[1] = "1";
    successCheck((int)poLines.InvokeMethod("nSetValue", firstLine), "PoLineQuantityOrdered");
    successCheck((int)poLines.InvokeMethod("nWrite"), "PoLinesWrite");
    successCheck((int)poObject.InvokeMethod("nWrite"), "Write");

    Console.WriteLine("SUCCESS! " + poNumber.ToString());

  • 0 in reply to Bret
    Thank you very much for taking a look at this. With a little more tinkering, and some input from my accounting folks I was able to get everything to work. It turns out I was not passing the P.O. line enough information. I had to pass a unit cost, and an account number for the lines to write, then once I had at least one line, the po itself would write. I found this out by invoking the sLastErrorMsg function as described above. Thanks all for your help! Below is what I ended up with for future reference:

    using (DispatchObject poObject = new DispatchObject(pvx.InvokeMethod("NewObject", "PO_PurchaseOrder_bus", oSS.GetObject())))
    {
    try
    {
    string poNumber = "";
    //int test1 = (int)poObject.InvokeMethod("nGetNextPurchaseOrderNo");
    object[] poPass = new object[] {poNumber};
    successCheck((int)poObject.InvokeMethodByRef("nGetNextPurchaseOrderNo", poPass), "GetNextPurchaseOrder");
    poNumber = poPass[0].ToString();

    successCheck((int) poObject.InvokeMethodByRef("nSetKey", poPass), "SetKey");
    object[] divisionNoObject = new object[] {"APDivisionNo$", "00"};
    successCheck((int) poObject.InvokeMethodByRef("nSetValue", divisionNoObject), "SetDivisionNo");
    object[] vendorObject = new object[] { "VendorNo$", "0006630" };
    successCheck((int)poObject.InvokeMethodByRef("nSetValue", vendorObject), "SetVendorNo");
    object[] taxObject = new object[] { "TaxSchedule$", "NONTAX" };
    successCheck((int)poObject.InvokeMethodByRef("nSetValue", taxObject), "SetTaxSchedule");

    DispatchObject poLines = new DispatchObject(poObject.GetProperty("oLines"));
    successCheck((int)poLines.InvokeMethod("nAddLine"), "AddLine");
    object[] firstLine = new object[] { "ItemCode$", "/1." };
    successCheck((int)poLines.InvokeMethodByRef("nSetValue", firstLine), "PoLineItemCode");
    firstLine[0] = "QuantityOrdered";
    firstLine[1] = 1;
    successCheck((int)poLines.InvokeMethodByRef("nSetValue", firstLine), "PoLineQuantityOrdered");
    firstLine[0] = "UnitCost";
    firstLine[1] = "1";
    successCheck((int)poLines.InvokeMethodByRef("nSetValue", firstLine), "PoLineUnitCost");
    firstLine[0] = "PurchasesAcctKey$";
    firstLine[1] = "120000200";
    successCheck((int)poLines.InvokeMethodByRef("nSetValue", firstLine), "PoLinePurchasesAcctKey");
    firstLine[0] = "CommentText$";
    firstLine[1] = "An Item";
    successCheck((int)poLines.InvokeMethodByRef("nSetValue", firstLine), "PoLineCommentText");
    successCheck((int)poLines.InvokeMethod("nWrite"), "PoLinesWrite");
    poObject.InvokeMethod("nWrite");
    //MessageBox.Show(poObject.InvokeMethod("sLastErrorMsg").ToString());

    MessageBox.Show("SUCCESS! " + poNumber.ToString());

    }
    catch (Exception ex)
    {
    MessageBox.Show(ex.Message);
    }

    }
  • 0

    did you solved the problem? are you caable to receive a po?

  • 0

    did you solved the problem? are you caable to receive a po?

  • 0 in reply to yoandy valdes

    Yes, we are able to receive against PO's using the C# Dispatch Object through the BOI.  The code above shows what my final solution was.

  • 0 in reply to gpierce

    in that solutions you insert a po did you insert a receipt of good agains po?

  • 0 in reply to yoandy valdes

    Yes, I am able to insert a receipt of goods against a PO.  Below is what we are using.  There will be stuff that is specific to us, but hopefully it helps.

    using (DispatchObject pvx = new DispatchObject("ProvideX.Script"))
    {
    // Replace the text "*PATH TO MAS90\HOME*" with the correct MAS90\Home path in the line below
    pvx.InvokeMethod("Init", @"***************");

    using (DispatchObject oSS = new DispatchObject(pvx.InvokeMethod("NewObject", "SY_Session")))
    {
    try
    {
    int test = (int)oSS.InvokeMethod("nlogon");
    if (test == 0)
    {
    test = (int)oSS.InvokeMethod("nSetUser", "****", "****");
    }

    if (test == 0)
    {
    errorMessage = Regex.Replace(oSS.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error logging in.");
    }

    oSS.InvokeMethod("nSetCompany", "***");
    oSS.InvokeMethod("nSetDate", "P/O", DateTime.Now.ToString("yyyyMMdd"));
    oSS.InvokeMethod("nSetModule", "P/O");

    int TaskID = (int)oSS.InvokeMethod("nLookupTask", "PO_ReceiptofGoods_UI");
    int setProgramTest = (int)oSS.InvokeMethod("nSetProgram", TaskID);

    //we create two lists to store the line keys and quantities in.
    ArrayList lineKeyList = new ArrayList();
    ArrayList quantityList = new ArrayList();

    using (DispatchObject poObject = new DispatchObject(pvx.InvokeMethod("NewObject", "PO_Receipt_bus", oSS.GetObject())))
    {
    string nextReceiptNo = "";
    object[] nextReceiptObj = new object[] { nextReceiptNo };
    int getNextReceiptTest = (int)poObject.InvokeMethodByRef("nGetNextReceiptNo", nextReceiptObj);
    if (getNextReceiptTest == 0)
    {
    errorMessage = Regex.Replace(poObject.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error getting the next receipt.");
    }

    object[] passedObject = new object[] { "", "" };
    passedObject[0] = "receiptNo$";
    passedObject[1] = nextReceiptObj[0];
    receiptNumber = nextReceiptObj[0].ToString();
    int setReceiptNo = (int)poObject.InvokeMethodByRef("nSetKeyValue", passedObject);
    if (setReceiptNo == 0)
    {
    errorMessage = Regex.Replace(poObject.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error setting a key value");
    }
    passedObject[0] = "ReceiptType$";
    passedObject[1] = "G";
    int setReceiptType = (int)poObject.InvokeMethodByRef("nSetKeyValue", passedObject);
    if (setReceiptType == 0)
    {
    errorMessage = Regex.Replace(poObject.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error setting the receipt type.");
    }


    passedObject[0] = "VendorNo$";
    passedObject[1] = VendorNoHiddenField.Value.ToString();

    if (VendorNoHiddenField.ToString().Equals(""))
    {
    errorMessage = Regex.Replace(poObject.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Vendor number hidden field is empty");
    }

    object[] batchObj = new object[] { BatchesComboBox.SelectedItem.ToString() };
    int selectBatchTest = (int)poObject.InvokeMethodByRef("nSelectBatch", batchObj);
    if (selectBatchTest == 0)
    {
    errorMessage = Regex.Replace(poObject.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error in setting the batch.");
    }
    int setKeyTest = (int)poObject.InvokeMethod("nSetKey");
    if (setKeyTest == 0)
    {
    errorMessage = Regex.Replace(poObject.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error setting the key.");
    }

    passedObject[0] = "PurchaseOrderNo$";
    passedObject[1] = PONumberTB.Text;
    int setPoNumber = (int)poObject.InvokeMethodByRef("nSetValue", passedObject);
    if (setPoNumber == 0)
    {
    errorMessage = Regex.Replace(poObject.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error setting the PoNumber value.");
    }
    passedObject[0] = "InvoiceNo$";
    passedObject[1] = InvoiceTextBox.Text;
    int setInvoiceNo = (int)poObject.InvokeMethodByRef("nSetValue", passedObject);
    if (setInvoiceNo == 0)
    {
    errorMessage = Regex.Replace(poObject.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error setting the Invoice No. value.");
    }

    passedObject[0] = "InvoiceDate$";
    DateTime invoiceDateTime = (DateTime)InvoiceDatePicker.Value;
    string modifiedInvoiceDate = invoiceDateTime.ToString("yyyyMMdd");

    passedObject[1] = modifiedInvoiceDate;
    int setInvoiceDate = (int)poObject.InvokeMethodByRef("nSetValue", passedObject);
    if (setInvoiceDate == 0)
    {
    errorMessage = Regex.Replace(poObject.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error setting the Invoice Date value.");
    }

    passedObject[0] = "Comment$";
    if (CheckCommentsTB.Text.Length > 30)
    passedObject[1] = CheckCommentsTB.Text.Substring(0, 30);
    else
    passedObject[1] = CheckCommentsTB.Text;

    int setComments = (int)poObject.InvokeMethodByRef("nSetValue", passedObject);
    if (setComments == 0)
    {
    errorMessage = Regex.Replace(poObject.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error setting the check comments.");
    }

    try
    {
    using (DispatchObject poLines = new DispatchObject(poObject.GetProperty("oLines")))
    {
    //we first query the database to get all the line keys and quantitys.
    if (con.State == ConnectionState.Closed)
    {
    con.ConnectionString = "Data Source=*****;Initial Catalog=****;Integrated Security=True;Pooling=False";
    con.Open();
    }
    string getRequisitionItemsQuery = "Select * From RequisitionItem Where RequisitionNumber Like '" + RequisitionNumberLabel.Text + "';";
    SqlCommand getReqItemsCmd = new SqlCommand(getRequisitionItemsQuery, con);
    SqlDataReader getReqItemsDr = getReqItemsCmd.ExecuteReader();

    while (getReqItemsDr.Read())
    {
    lineKeyList.Add(getReqItemsDr["PurchaseOrderLineKey"].ToString());
    quantityList.Add(getReqItemsDr["QuantityReceived"].ToString());
    quantityReceivedToDateList.Add(getReqItemsDr["QuantityReceivedToDate"].ToString());
    }
    getReqItemsDr.Close();
    if (con.State == ConnectionState.Open)
    con.Close();

    passedObject[0] = PONumberTB.Text;
    //the "1" value on the next line indicates copy all the lines and quantities. essentially complete the order.
    passedObject[1] = 1;
    int copyPOLinesTest = (int)poLines.InvokeMethodByRef("nCopyPurchaseOrderLines", passedObject);
    if (copyPOLinesTest == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error in copying the po lines.");
    }

    int moveFirstTest = (int)poLines.InvokeMethod("nMoveFirst");
    if (moveFirstTest == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error moving to the first line.");
    }
    string orderLineKeyString = "";
    object[] lineKeyObject = new object[] { "OrderLineKey$", orderLineKeyString };
    int getValueTest = (int)poLines.InvokeMethodByRef("nGetValue", lineKeyObject);
    if (getValueTest == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error getting the first line key value.");
    }
    orderLineKeyString = lineKeyObject[1].ToString();

    //now that we've got the lineKey value from above, we need to find the quantity that we want to receive at this point
    double quantity = 0.0;
    for (int i = 0; i < lineKeyList.Count; i++)
    {
    //if we've found the line key we are looking for
    if (orderLineKeyString.Equals(lineKeyList[i].ToString()))
    {
    //set the quantity to the corresponding value in the quantity list
    quantity = double.Parse(quantityList[i].ToString());
    //get out of the for loop
    break;
    }
    }


    passedObject[0] = "QuantityReceived";
    passedObject[1] = quantity;
    double quantityOrdered = 0.0;
    object[] quantityOrderedObject = new object[] { "QuantityOrdered", quantityOrdered };
    int gettingQuantityOrderedTest = (int)poLines.InvokeMethodByRef("nGetValue", quantityOrderedObject);
    if (gettingQuantityOrderedTest == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error getting the quantity ordered.");
    }
    quantityOrdered = double.Parse(quantityOrderedObject[1].ToString());

    int setQuantityReceivedTest2 = (int)poLines.InvokeMethodByRef("nSetValue", passedObject);
    if (setQuantityReceivedTest2 == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error setting the quantity received for the first line..");
    }


    int writeFirstLineTest = (int)poLines.InvokeMethod("nWrite");
    if (writeFirstLineTest == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error writing the first line.");
    }

    int moveNextLineTest = (int)poLines.InvokeMethod("nMoveNext");
    if (moveNextLineTest == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error moving to the next line after writing the first.");
    }
    int getValueTest2 = (int)poLines.InvokeMethodByRef("nGetValue", lineKeyObject);
    if (getValueTest2 == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error getting the value when moving to the second line.");
    }
    string nextLineKey = orderLineKeyString;

    if (!nextLineKey.Equals(lineKeyObject[1].ToString()))
    {
    while (!nextLineKey.Equals(lineKeyObject[1].ToString()))
    {
    nextLineKey = lineKeyObject[1].ToString();
    passedObject[0] = "QuantityReceived";
    //find the quantity associated with that line key
    for (int i = 0; i < lineKeyList.Count; i++)
    {
    //again, if we've found the line key we are looking for
    if (nextLineKey.Equals(lineKeyList[i].ToString()))
    {
    //set the appropriate quantity value
    quantity = double.Parse(quantityList[i].ToString());
    //get out of the for loop for now
    break;
    }
    }

    passedObject[1] = quantity;
    double quantityOrdered2 = 0.0;
    object[] quantityOrderedObject2 = new object[] { "QuantityOrdered", quantityOrdered2 };
    int gettingQuantityOrderedTest2 = (int)poLines.InvokeMethodByRef("nGetValue", quantityOrderedObject2);
    if (gettingQuantityOrderedTest2 == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error getting the quantity ordered.");
    }
    quantityOrdered2 = double.Parse(quantityOrderedObject[1].ToString());

    int setQuantityReceivedTest1 = (int)poLines.InvokeMethodByRef("nSetValue", passedObject);
    if (setQuantityReceivedTest1 == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error setting the quantity received.");
    }

    int writeLineTest = (int)poLines.InvokeMethod("nWrite");
    if (writeLineTest == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error in writing the po line.");
    }
    int moveNextLineTest2 = (int)poLines.InvokeMethod("nMoveNext");
    if (moveNextLineTest2 == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error in moving to the next line.");
    }
    int getValueTest3 = (int)poLines.InvokeMethodByRef("nGetValue", lineKeyObject);
    if (getValueTest3 == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error getting the next line key value.");
    }

    }
    }
    int writeLineTest2 = (int)poLines.InvokeMethod("nWrite");
    if (writeLineTest2 == 0)
    {
    errorMessage = Regex.Replace(poLines.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error writing the po line.");
    }

    }
    int writePOObjectTest = (int)poObject.InvokeMethod("nWrite");
    if (writePOObjectTest == 0)
    {
    errorMessage = Regex.Replace(poObject.InvokeMethod("sLastErrorMsg").ToString(), "'", "");
    throw new System.Exception("Error writing the PO Object.");
    }



    }
    catch (Exception ex)
    {

    }
    }

    }
    catch (Exception ex)
    {

    }
    }
    }