Epicor Function - Trying to add new sales line to a sales order

I am working on upgrading to Kinetic 2025.2 and trying to move a customization on the Sales Order Classic UX to a server function. I was making some progress, but ran into some issues. Currently, my issue is I get the following error when calling SalesOrder MasterUpdate.

{
  "HttpStatus": 404,
  "ReasonPhrase": "REST API Exception",
  "ErrorMessage": "Record for update was not found by its SysRowID value [00000000-0000-0000-0000-000000000000].",
  "ErrorType": "Ice.Common.RecordNotFoundException",
  "ErrorDetails": [
    {
      "Message": "Record for update was not found by its SysRowID value [00000000-0000-0000-0000-000000000000].",
      "Type": "Error",
      "Program": "Epicor.Ice.dll",
      "Method": "UpdateRow",
      "LineNumber": 1052,
      "ColumnNumber": 21
    }
  ],
  "CorrelationId": "9b8f551b-697c-4c95-9868-a581d6f947f6"
}

I was getting a new order line, but after adding calls to ChangeSellingQtyMaster and ChangeUnitPrice, the error started. I get this error if I call either Update or MasterUpdate.

My code

    CallService<Erp.Contracts.SalesOrderSvcContract>(so =>
    {
        // Load exisitng order
        var soDS = so.GetByID(orderNum);

        //Add a new order line
        so.GetNewOrderDtl(ref soDS, orderNum);

        //Populate the new line
        var dtlRow = soDS.OrderDtl.Last();
        //var dtlRow = soDS.OrderDtl.First(r => r.RowMod == "A");
        dtlRow.PartNum = partNum;
        dtlRow.RowMod = "U";

        //ChangePartNumMaster out/ref parameters
        string replacingPart = partNum;
        bool substitutePartExist = false;
        bool isPhantom = false;
        string uomCode = ""; // returned by the method
        string deleteComponentMsg = "";
        string questionString = "";
        string warningMessage = "";
        bool multipleMatch = false;
        bool promptToExplodeBOM = false;
        string partMessage = "";
        string subPartMessage = "";
        string explodeBOMerrMessage = "";
        string msgType = "";
        bool multiSubsAvail = false;
        bool runOutQtyAvail = false;
        string cMsgTypeSaleable = "";

        so.ChangePartNumMaster(
            ref replacingPart,
            ref substitutePartExist,
            ref isPhantom,
            ref uomCode,
            Guid.Empty,
            "",
            false,
            false,
            false,
            true,
            true,
            true,
            false,
            out deleteComponentMsg,
            out questionString,
            out warningMessage,
            out multipleMatch,
            out promptToExplodeBOM,
            out partMessage,
            out subPartMessage,
            out explodeBOMerrMessage,
            out msgType,
            out multiSubsAvail,
            out runOutQtyAvail,
            out cMsgTypeSaleable,
            ref soDS
        );

        //dtlRow.LineDesc = partDesc;
        dtlRow.OrderQty = partOrderQuantity;
        dtlRow.SellingQuantity = partOrderQuantity;
        dtlRow.UnitPrice = partUnitPrice;
        dtlRow.SalesUM = GetPartUM(partNum);
        dtlRow.RowMod = "U";

        //ChangeSellingQtyMaster out/ref parameters
        decimal ipSellingQuantity = partOrderQuantity;
        bool chkSellQty = false;
        bool negInvTest = false;
        bool chgSellQty = true;
        bool chgDiscPer = true;
        bool suppressUserPrompts = false;
        bool lKeepUnitPrice = true;
        string pcPartNum = partNum;
        string pcWhseCode = "";
        string pcBinNum = "";
        string pcLotNum = "";
        int pcAttributeSetID = 0;
        string pcDimCode = GetPartUM(partNum);
        decimal pdDimConvFactor = 0;
        string pcMessage = "";
        string pcNeqQtyAction = "";
        string opWarningMsg = "";
        string cSellingQuantityChangedMsgText = "";

        so.ChangeSellingQtyMaster(
            ref soDS,
            ipSellingQuantity,
            chkSellQty,
            negInvTest,
            chgSellQty,
            chgDiscPer,
            suppressUserPrompts,
            lKeepUnitPrice,
            pcPartNum,
            pcWhseCode,
            pcBinNum,
            pcLotNum,
            pcAttributeSetID,
            pcDimCode,
            pdDimConvFactor,
            out pcMessage,
            out pcNeqQtyAction,
            out opWarningMsg,
            out cSellingQuantityChangedMsgText
        );

        dtlRow.LineDesc = partDesc;
        dtlRow.UnitPrice = partUnitPrice;
        dtlRow.DocUnitPrice = partUnitPrice;
        dtlRow.DocListPrice = partUnitPrice;

        dtlRow.DocOrdBasedPrice = partUnitPrice;
        dtlRow.ExtPriceDtl = partUnitPrice;
        dtlRow.DocExtPriceDtl = partUnitPrice;
        dtlRow.DspUnitPrice = partUnitPrice;

        dtlRow.RowMod = "U";
        var hedRow = soDS.OrderHed.FirstOrDefault();
        hedRow.RowMod = "U";

        so.ChangeUnitPrice(ref soDS);

        //MasterUpdate out/ref parameters
        bool lCheckForOrderChangedMsg = false;
        bool lcheckForResponse = false;
        string cTableName = "OrderDtl";
        int iCustNum = GetOrdCustNum(orderNum);
        int iOrderNum = orderNum;
        bool lweLicensed = false;
        bool lContinue = false;
        string cResponseMsg = "";
        string cCreditShipAction = "";
        string cDisplayMsg = "";
        string cCompliantMsg = "";
        string cResponseMsgOrdRel = "";
        string cAgingMessage = "";
        string cShipByDateMessage = "";
        string cNeedByDateMessage = "";
        cMsgTypeSaleable = "";

        dtlRow.RowMod = "U";
        hedRow.RowMod = "U";

        so.MasterUpdate(
            lCheckForOrderChangedMsg,
            lcheckForResponse,
            cTableName,
            iCustNum,
            iOrderNum,
            lweLicensed,
            out lContinue,
            out cResponseMsg,
            out cCreditShipAction,
            out cDisplayMsg,
            out cCompliantMsg,
            out cResponseMsgOrdRel,
            out cAgingMessage,
            out cShipByDateMessage,
            out cNeedByDateMessage,
            out cMsgTypeSaleable,
            ref soDS
        );
    });

Am I doing something wrong or missing something?

RowMod=’U’ is for existing records with real SysRowID. If you add something, you need RowMod=A

5 Likes

Suggest doing a trace of the process to see how Epicor does it checking the data but my money is on @Olga said

I have come this far by doing a trace and adding the same methods. I did use RowMod = “A” initially, but when I do that I get an internal server error.

Generally you can’t update a header and a dtl row at the same time. You create the header first, update, then add the dtl rows. The header shouldn’t have a row mod at all at that time. So having an “A” on header and detail is probably what your problem is.

The sales order will always be existing, no need to create it. I only added the header update last when trying to resolve this. The 500 error still persists after removing all reference to the header row.

Can you post your updated code then?


    CallService<Erp.Contracts.SalesOrderSvcContract>(so =>
    {
        // Load exisitng order
        var soDS = so.GetByID(orderNum);

        //Add a new order line
        so.GetNewOrderDtl(ref soDS, orderNum);

        //Populate the new line
        var dtlRow = soDS.OrderDtl.Last();
        //var dtlRow = soDS.OrderDtl.First(r => r.RowMod == "A");
        dtlRow.PartNum = partNum;
        dtlRow.RowMod = "A";

        //ChangePartNumMaster out/ref parameters
        string replacingPart = partNum;
        bool substitutePartExist = false;
        bool isPhantom = false;
        string uomCode = ""; // returned by the method
        string deleteComponentMsg = "";
        string questionString = "";
        string warningMessage = "";
        bool multipleMatch = false;
        bool promptToExplodeBOM = false;
        string partMessage = "";
        string subPartMessage = "";
        string explodeBOMerrMessage = "";
        string msgType = "";
        bool multiSubsAvail = false;
        bool runOutQtyAvail = false;
        string cMsgTypeSaleable = "";

        so.ChangePartNumMaster(
            ref replacingPart,
            ref substitutePartExist,
            ref isPhantom,
            ref uomCode,
            Guid.Empty,
            "",
            false,
            false,
            false,
            true,
            true,
            true,
            false,
            out deleteComponentMsg,
            out questionString,
            out warningMessage,
            out multipleMatch,
            out promptToExplodeBOM,
            out partMessage,
            out subPartMessage,
            out explodeBOMerrMessage,
            out msgType,
            out multiSubsAvail,
            out runOutQtyAvail,
            out cMsgTypeSaleable,
            ref soDS
        );

        dtlRow.OrderQty = partOrderQuantity;
        dtlRow.SellingQuantity = partOrderQuantity;
        dtlRow.UnitPrice = partUnitPrice;
        dtlRow.SalesUM = GetPartUM(partNum);
        dtlRow.RowMod = "A";


        //ChangeSellingQtyMaster out/ref parameters
        decimal ipSellingQuantity = partOrderQuantity;
        bool chkSellQty = false;
        bool negInvTest = false;
        bool chgSellQty = true;
        bool chgDiscPer = true;
        bool suppressUserPrompts = false;
        bool lKeepUnitPrice = true;
        string pcPartNum = partNum;
        string pcWhseCode = "";
        string pcBinNum = "";
        string pcLotNum = "";
        int pcAttributeSetID = 0;
        string pcDimCode = GetPartUM(partNum);
        decimal pdDimConvFactor = 0;
        string pcMessage = "";
        string pcNeqQtyAction = "";
        string opWarningMsg = "";
        string cSellingQuantityChangedMsgText = "";

        so.ChangeSellingQtyMaster(
            ref soDS,
            ipSellingQuantity,
            chkSellQty,
            negInvTest,
            chgSellQty,
            chgDiscPer,
            suppressUserPrompts,
            lKeepUnitPrice,
            pcPartNum,
            pcWhseCode,
            pcBinNum,
            pcLotNum,
            pcAttributeSetID,
            pcDimCode,
            pdDimConvFactor,
            out pcMessage,
            out pcNeqQtyAction,
            out opWarningMsg,
            out cSellingQuantityChangedMsgText
        );

        dtlRow.LineDesc = partDesc;
        dtlRow.UnitPrice = partUnitPrice;
        dtlRow.DocUnitPrice = partUnitPrice;
        dtlRow.DocListPrice = partUnitPrice;

        dtlRow.DocOrdBasedPrice = partUnitPrice;
        dtlRow.ExtPriceDtl = partUnitPrice;
        dtlRow.DocExtPriceDtl = partUnitPrice;
        dtlRow.DspUnitPrice = partUnitPrice;

        dtlRow.RowMod = "A";

        so.ChangeUnitPrice(ref soDS);

        //MasterUpdate out/ref parameters
        bool lCheckForOrderChangedMsg = false;
        bool lcheckForResponse = false;
        string cTableName = "OrderDtl";
        int iCustNum = GetOrdCustNum(orderNum);
        int iOrderNum = orderNum;
        bool lweLicensed = false;
        bool lContinue = false;
        string cResponseMsg = "";
        string cCreditShipAction = "";
        string cDisplayMsg = "";
        string cCompliantMsg = "";
        string cResponseMsgOrdRel = "";
        string cAgingMessage = "";
        string cShipByDateMessage = "";
        string cNeedByDateMessage = "";
        cMsgTypeSaleable = "";

        dtlRow.RowMod = "A";

        so.MasterUpdate(
            lCheckForOrderChangedMsg,
            lcheckForResponse,
            cTableName,
            iCustNum,
            iOrderNum,
            lweLicensed,
            out lContinue,
            out cResponseMsg,
            out cCreditShipAction,
            out cDisplayMsg,
            out cCompliantMsg,
            out cResponseMsgOrdRel,
            out cAgingMessage,
            out cShipByDateMessage,
            out cNeedByDateMessage,
            out cMsgTypeSaleable,
            ref soDS
        );
    });

I would change this back to what you have in commented out. The new record should have a row mod of “A” and while last should work, you don’t know how the results are ordered so it’s risky.

Other than that, I don’t see anything sticking out at me, but I haven’t run to code to test anything.

When programmatically adding new sales order lines (or using most any other service), I always reset the variable used for the OrderDtl row after each service method call before making further changes to it.

In your example, I would add this after the call ChangePartNumMaster:

dtlRow = soDS.OrderDtl.First(r => r.Added());

And then do same after each call before calling MasterUpdate.

Because the variable stores a reference to the OrderDtlRow object, it may no longer be referencing the correct object after the service method call, depending on how the method modifies the dataset that was passed into it.

2 Likes

I got past the server error; there was a type mismatch while setting a UD field in another part of the code not shown above. However, even though it does run, prices and quantities are not being updated. I am adding the suggestion to reset the OrderDtl variable.

My code is running without error, but the price is not being updated. Here is my updated code with UD fields added.

    CallService<Erp.Contracts.SalesOrderSvcContract>(so =>
    {
        // Load exisitng order
        var soDS = so.GetByID(orderNum);

        //Add a new order line
        so.GetNewOrderDtl(ref soDS, orderNum);

        //Populate the new line
        var dtlRow = soDS.OrderDtl.First(r => r.RowMod == "A");
        dtlRow.PartNum = partNum;
        dtlRow.RowMod = "A";

        //ChangePartNumMaster out/ref parameters
        string replacingPart = partNum;
        bool substitutePartExist = false;
        bool isPhantom = false;
        string uomCode = ""; // returned by the method
        string deleteComponentMsg = "";
        string questionString = "";
        string warningMessage = "";
        bool multipleMatch = false;
        bool promptToExplodeBOM = false;
        string partMessage = "";
        string subPartMessage = "";
        string explodeBOMerrMessage = "";
        string msgType = "";
        bool multiSubsAvail = false;
        bool runOutQtyAvail = false;
        string cMsgTypeSaleable = "";

        so.ChangePartNumMaster(
            ref replacingPart,
            ref substitutePartExist,
            ref isPhantom,
            ref uomCode,
            Guid.Empty,
            "",
            false,
            false,
            false,
            true,
            true,
            true,
            true,
            out deleteComponentMsg,
            out questionString,
            out warningMessage,
            out multipleMatch,
            out promptToExplodeBOM,
            out partMessage,
            out subPartMessage,
            out explodeBOMerrMessage,
            out msgType,
            out multiSubsAvail,
            out runOutQtyAvail,
            out cMsgTypeSaleable,
            ref soDS
        );

        //Reset OrderDtlTableet
        dtlRow = soDS.OrderDtl.First(r => r.Added());
        
        //dtlRow.LineDesc = partDesc;
        dtlRow.OrderQty = partOrderQuantity;
        dtlRow.SellingQuantity = partOrderQuantity;
        dtlRow.UnitPrice = partUnitPrice;
        dtlRow.SalesUM = GetPartUM(partNum);
        dtlRow.RowMod = "A";
        //dtlRow.PricePerCode = "E";
        //dtlRow.ProdCode = GetPartProductGroup(partNum);
        //dtlRow.SalesUM = GetPartUM(partNum);
        //dtlRow.SellingQuantity = partOrderQuantity;
        //dtlRow.SalesUM = "";

        //ChangeSellingQtyMaster out/ref parameters
        decimal ipSellingQuantity = partOrderQuantity;
        bool chkSellQty = false;
        bool negInvTest = false;
        bool chgSellQty = true;
        bool chgDiscPer = true;
        bool suppressUserPrompts = false;
        bool lKeepUnitPrice = true;
        string pcPartNum = partNum;
        string pcWhseCode = "";
        string pcBinNum = "";
        string pcLotNum = "";
        int pcAttributeSetID = 0;
        string pcDimCode = GetPartUM(partNum);
        decimal pdDimConvFactor = 1;
        string pcMessage = "";
        string pcNeqQtyAction = "";
        string opWarningMsg = "";
        string cSellingQuantityChangedMsgText = "";

        so.ChangeSellingQtyMaster(
            ref soDS,
            ipSellingQuantity,
            chkSellQty,
            negInvTest,
            chgSellQty,
            chgDiscPer,
            suppressUserPrompts,
            lKeepUnitPrice,
            pcPartNum,
            pcWhseCode,
            pcBinNum,
            pcLotNum,
            pcAttributeSetID,
            pcDimCode,
            pdDimConvFactor,
            out pcMessage,
            out pcNeqQtyAction,
            out opWarningMsg,
            out cSellingQuantityChangedMsgText
        );

        //Reset OrderDtlTableet
        dtlRow = soDS.OrderDtl.First(r => r.Added());

        dtlRow.SetUDField<decimal>("Weight_c", partUnitNetWeight);
        dtlRow.SetUDField<string>("WeightUOM_c", partWeightUnits);
        dtlRow.SetUDField<decimal>("Length_c", partUnitLength);
        dtlRow.SetUDField<decimal>("Width_c", partUnitWidth);
        dtlRow.SetUDField<decimal>("Heigth_c", partUnitHeight);
        dtlRow.SetUDField<string>("DimensionUOM_c", partLWHUnits);

        dtlRow.LineDesc = partDesc;
        dtlRow.UnitPrice = partUnitPrice;
        dtlRow.DocUnitPrice = partUnitPrice;
        dtlRow.DocListPrice = partUnitPrice;

        dtlRow.DocOrdBasedPrice = partUnitPrice;
        dtlRow.ExtPriceDtl = partUnitPrice;
        dtlRow.DocExtPriceDtl = partUnitPrice;
        dtlRow.DspUnitPrice = partUnitPrice;

        dtlRow.SetUDField<int>("QuoteQty_c", quoteQuantity);
        dtlRow.SetUDField<decimal>("LabourHours_c", quoteLabourHours);
        dtlRow.SetUDField<decimal>("LabourCosts_c", quoteLabourCosts);
        dtlRow.SetUDField<decimal>("MaterialCosts_c", quoteMaterialCosts);
        
        dtlRow.RowMod = "A";

        so.ChangeUnitPrice(ref soDS);

        //Reset OrderDtlTableet
        dtlRow = soDS.OrderDtl.First(r => r.Added());

        //MasterUpdate out/ref parameters
        bool lCheckForOrderChangedMsg = true;
        bool lcheckForResponse = true;
        string cTableName = "OrderDtl";
        int iCustNum = GetOrdCustNum(orderNum);
        int iOrderNum = orderNum;
        bool lweLicensed = false;
        bool lContinue = false;
        string cResponseMsg = "";
        string cCreditShipAction = "";
        string cDisplayMsg = "";
        string cCompliantMsg = "";
        string cResponseMsgOrdRel = "";
        string cAgingMessage = "";
        string cShipByDateMessage = "";
        string cNeedByDateMessage = "";
        cMsgTypeSaleable = "";

        dtlRow.RowMod = "A";

        so.MasterUpdate(
            lCheckForOrderChangedMsg,
            lcheckForResponse,
            cTableName,
            iCustNum,
            iOrderNum,
            lweLicensed,
            out lContinue,
            out cResponseMsg,
            out cCreditShipAction,
            out cDisplayMsg,
            out cCompliantMsg,
            out cResponseMsgOrdRel,
            out cAgingMessage,
            out cShipByDateMessage,
            out cNeedByDateMessage,
            out cMsgTypeSaleable,
            ref soDS
        );
    });

Just curious, maybe it was a workaround originally when this was written for 10.2. Here is a snippet of code from our Classic Sales Order customization changing the unit price. It calls ChangeUnitPrice and Update multiple times.

salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].DocOrdBasedPrice = header.HeaderInfo.UnitPrice;
salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].ExtPriceDtl = header.HeaderInfo.UnitPrice;
salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].DocExtPriceDtl = header.HeaderInfo.UnitPrice;
salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].DspUnitPrice = header.HeaderInfo.UnitPrice;

salesOrderAdapter.ChangeUnitPrice();
// salesOrderAdapter.MasterUpdate(true, true, "", 0,iOrderNum, true, out lContinue, out cResponseMsg, out cCreditShipAction,out cDisplayMessage, out cCompliantMsg, out cResponseMsgOrdRel);
salesOrderAdapter.Update();

salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].UnitPrice = header.HeaderInfo.UnitPrice;
salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].DocUnitPrice = header.HeaderInfo.UnitPrice;
salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].DocListPrice = header.HeaderInfo.UnitPrice;

salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].DocOrdBasedPrice = header.HeaderInfo.UnitPrice;
salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].ExtPriceDtl = header.HeaderInfo.UnitPrice;
salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].DocExtPriceDtl = header.HeaderInfo.UnitPrice;
salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].DspUnitPrice = header.HeaderInfo.UnitPrice;
salesOrderAdapter.Update();
salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].DocDspUnitPrice = header.HeaderInfo.UnitPrice;
salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].CurrencySwitch=false;
salesOrderAdapter.SalesOrderData.OrderDtl[salesOrderAdapter.SalesOrderData.OrderDtl.Count - 1].RowMod="U";
salesOrderAdapter.ChangeUnitPrice();
salesOrderAdapter.Update();

Here is code we use to create web order lines. We “override” price lists so they don’t screw up the price coming from the web, but I’m not sure if that’s what you want for your use case. Anyway, hope this helps.

  				// Create New Line                
                salesOrderSvc.GetNewOrderDtl(ref TsSalesOrder, orderNum);

                salesOrderSvc.ChangePartNumMaster(ref partNum, ref outBool, ref outBool, ref outString, Guid.Empty, 
                        "", false, false, true, true, true, true, out outString, out outString, out outString, out outBool, 
                        out outBool, out outString, out outString, out outString, out outString, out outBool, out outBool,
                        ref TsSalesOrder);


                string defaultUOM = TsSalesOrder.OrderDtl.Where(od => od.Added()).FirstOrDefault().SalesUM;

                if (containerUOMCode != "")
                {
                    foreach (var rowDtl in TsSalesOrder.OrderDtl.Where(od => od.Added()))
                    {
                        rowDtl.SalesUM = containerUOMCode;
                    }
                    salesOrderSvc.ChangeSalesUOM(ref TsSalesOrder);
                }

                salesOrderSvc.ChangeSellingQtyMaster(ref TsSalesOrder, decimal.Parse(jsonLine["Quantity"].ToString()), false, false, true, true, false, true, 
                        partNum, "", "", "", 0, (containerUOMCode == "" ? defaultUOM : containerUOMCode), 1, 
                        out outString, out outString, out outString, out outString);


                foreach (var rowDtl in TsSalesOrder.OrderDtl.Where(od => od.Added()))
                {
                    rowDtl.OverridePriceList = true;
                    rowDtl.OrderComment = jsonLine["LineComment"];
                }
                salesOrderSvc.ChangeOverridePriceList(ref TsSalesOrder);


                foreach (var rowDtl in TsSalesOrder.OrderDtl.Where(od => od.Added()))
                {
                    rowDtl.BreakListCode = "";
                }
                salesOrderSvc.ChangePriceList(ref TsSalesOrder);


                foreach (var rowDtl in TsSalesOrder.OrderDtl.Where(od => od.Added()))
                {
                    rowDtl.DocDspUnitPrice = jsonLine["UnitPrice"];
                    rowDtl.UnitPrice = jsonLine["UnitPrice"];
                    rowDtl.DocUnitPrice = jsonLine["UnitPrice"];
                    rowDtl.DspUnitPrice = jsonLine["UnitPrice"];
                }
                salesOrderSvc.ChangeUnitPrice(ref TsSalesOrder);


                foreach (var rowDtl in TsSalesOrder.OrderDtl.Where(od => od.Added()))
                {
                    rowDtl.LockPrice = true;
                }
                salesOrderSvc.ChangeSellingQuantity(ref TsSalesOrder, true, decimal.Parse(jsonLine["Quantity"].ToString()), out outString);


                foreach (var rowDtl in TsSalesOrder.OrderDtl.Where(od => od.Added()))
                {
                    rowDtl.DocDspDiscount = jsonLine["DiscountAmt"];
                    rowDtl.DocDiscount = jsonLine["DiscountAmt"];
                    rowDtl.Discount = jsonLine["DiscountAmt"];
                    rowDtl.DspDiscount = jsonLine["DiscountAmt"];
                }
                salesOrderSvc.ChangeDiscountAmount(ref TsSalesOrder);


                foreach (var rowDtl in TsSalesOrder.OrderDtl.Where(od => od.Added()))
                {
                    rowDtl.NeedByDate = jsonLine["NeedByDate"];
                }
                salesOrderSvc.ChangeNeedByDate(ref TsSalesOrder, "OrderDtl");

             
                foreach (var rowDtl in TsSalesOrder.OrderDtl.Where(od => od.Added()))
                {
                    rowDtl.RequestDate = jsonLine["ShipByDate"];
                }
                salesOrderSvc.MasterUpdate(false, false, "OrderDtl", custNum, orderNum, true,
                        out outBool, out outString, out outString, out outString, out outString, out outString, out outString,
                        ref TsSalesOrder);
1 Like

Thanks, I will take a look.

If you’re explicitly setting the prices, you’ll likely need to set LockPrice = true to prevent it from automatically resetting the price based on your pricing setup.

We never had to do that before. I tested setting LockPrice = true and it had no effect, still no price.

ok, I have the pricing working. I changed this

        dtlRow.LineDesc = partDesc;
        dtlRow.UnitPrice = partUnitPrice;
        dtlRow.DocUnitPrice = partUnitPrice;
        dtlRow.DocListPrice = partUnitPrice;

        dtlRow.DocOrdBasedPrice = partUnitPrice;
        dtlRow.ExtPriceDtl = partUnitPrice;
        dtlRow.DocExtPriceDtl = partUnitPrice;
        dtlRow.DspUnitPrice = partUnitPrice;

to this. I was not setting DocDspUnitPrice.

        dtlRow.LineDesc = partDesc;

        dtlRow.DspUnitPrice = partUnitPrice;
        dtlRow.DocDspUnitPrice = partUnitPrice;
        dtlRow.UnitPrice = partUnitPrice;
        dtlRow.DocUnitPrice = partUnitPrice;
2 Likes

Ok, I am losing my mind trying to find out what has gone wrong. The code was working on Friday, new sales line added, quantity and pricing updated correctly. Today I demote the library and make a copy of the working function before moving on. Now neither the original or the copy work. There are no errors, but no new sales line is created. Did I accidently change something? Does anyone notice anything in my code that looks wrong?

    CallService<Erp.Contracts.SalesOrderSvcContract>(so =>
    {
        // Load exisitng order
        var soDS = so.GetByID(orderNum);

        //Add a new order line
        so.GetNewOrderDtl(ref soDS, orderNum);

        //Populate the new line
        var dtlRow = soDS.OrderDtl.First(r => r.RowMod == "A");
        dtlRow.PartNum = partNum;
        dtlRow.RowMod = "A";

        //ChangePartNumMaster out/ref parameters
        string replacingPart = partNum;
        bool substitutePartExist = false;
        bool isPhantom = false;
        string uomCode = ""; // returned by the method
        string deleteComponentMsg = "";
        string questionString = "";
        string warningMessage = "";
        bool multipleMatch = false;
        bool promptToExplodeBOM = false;
        string partMessage = "";
        string subPartMessage = "";
        string explodeBOMerrMessage = "";
        string msgType = "";
        bool multiSubsAvail = false;
        bool runOutQtyAvail = false;
        string cMsgTypeSaleable = "";

        so.ChangePartNumMaster(
            ref replacingPart,
            ref substitutePartExist,
            ref isPhantom,
            ref uomCode,
            Guid.Empty,
            "",
            false,
            false,
            false,
            true,
            true,
            true,
            true,
            out deleteComponentMsg,
            out questionString,
            out warningMessage,
            out multipleMatch,
            out promptToExplodeBOM,
            out partMessage,
            out subPartMessage,
            out explodeBOMerrMessage,
            out msgType,
            out multiSubsAvail,
            out runOutQtyAvail,
            out cMsgTypeSaleable,
            ref soDS
        );

        //Reset OrderDtlTableet
        dtlRow = soDS.OrderDtl.First(r => r.Added());
        
        //dtlRow.LineDesc = partDesc;
        dtlRow.OrderQty = partOrderQuantity;
        dtlRow.SellingQuantity = partOrderQuantity;
        dtlRow.UnitPrice = partUnitPrice;
        dtlRow.SalesUM = GetPartUM(partNum);
        dtlRow.RowMod = "A";
        //dtlRow.PricePerCode = "E";
        //dtlRow.ProdCode = GetPartProductGroup(partNum);
        //dtlRow.SalesUM = GetPartUM(partNum);
        //dtlRow.SellingQuantity = partOrderQuantity;
        //dtlRow.SalesUM = "";

        //ChangeSellingQtyMaster out/ref parameters
        decimal ipSellingQuantity = partOrderQuantity;
        bool chkSellQty = false;
        bool negInvTest = false;
        bool chgSellQty = true;
        bool chgDiscPer = true;
        bool suppressUserPrompts = false;
        bool lKeepUnitPrice = true;
        string pcPartNum = partNum;
        string pcWhseCode = "";
        string pcBinNum = "";
        string pcLotNum = "";
        int pcAttributeSetID = 0;
        string pcDimCode = GetPartUM(partNum);
        decimal pdDimConvFactor = 1;
        string pcMessage = "";
        string pcNeqQtyAction = "";
        string opWarningMsg = "";
        string cSellingQuantityChangedMsgText = "";

        so.ChangeSellingQtyMaster(
            ref soDS,
            ipSellingQuantity,
            chkSellQty,
            negInvTest,
            chgSellQty,
            chgDiscPer,
            suppressUserPrompts,
            lKeepUnitPrice,
            pcPartNum,
            pcWhseCode,
            pcBinNum,
            pcLotNum,
            pcAttributeSetID,
            pcDimCode,
            pdDimConvFactor,
            out pcMessage,
            out pcNeqQtyAction,
            out opWarningMsg,
            out cSellingQuantityChangedMsgText
        );

        //Reset OrderDtlTableet
        dtlRow = soDS.OrderDtl.First(r => r.Added());

        dtlRow.SetUDField<decimal>("Weight_c", partUnitNetWeight);
        dtlRow.SetUDField<string>("WeightUOM_c", partWeightUnits);
        dtlRow.SetUDField<decimal>("Length_c", partUnitLength);
        dtlRow.SetUDField<decimal>("Width_c", partUnitWidth);
        dtlRow.SetUDField<decimal>("Heigth_c", partUnitHeight);
        dtlRow.SetUDField<string>("DimensionUOM_c", partLWHUnits);

        dtlRow.LineDesc = partDesc;

        dtlRow.DspUnitPrice = partUnitPrice;
        dtlRow.DocDspUnitPrice = partUnitPrice;
        dtlRow.UnitPrice = partUnitPrice;
        dtlRow.DocUnitPrice = partUnitPrice;

        dtlRow.SetUDField<int>("QuoteQty_c", quoteQuantity);
        dtlRow.SetUDField<decimal>("LabourHours_c", quoteLabourHours);
        dtlRow.SetUDField<decimal>("LabourCosts_c", quoteLabourCosts);
        dtlRow.SetUDField<decimal>("MaterialCosts_c", quoteMaterialCosts);
        
        dtlRow.RowMod = "A";

        so.ChangeUnitPrice(ref soDS);

        //Reset OrderDtlTableet
        dtlRow = soDS.OrderDtl.First(r => r.Added());

        //MasterUpdate out/ref parameters
        bool lCheckForOrderChangedMsg = true;
        bool lcheckForResponse = true;
        string cTableName = "OrderDtl";
        int iCustNum = GetOrdCustNum(orderNum);
        int iOrderNum = orderNum;
        bool lweLicensed = false;
        bool lContinue = false;
        string cResponseMsg = "";
        string cCreditShipAction = "";
        string cDisplayMsg = "";
        string cCompliantMsg = "";
        string cResponseMsgOrdRel = "";
        string cAgingMessage = "";
        string cShipByDateMessage = "";
        string cNeedByDateMessage = "";
        cMsgTypeSaleable = "";

        dtlRow.RowMod = "A";

        so.MasterUpdate(
            lCheckForOrderChangedMsg,
            lcheckForResponse,
            cTableName,
            iCustNum,
            iOrderNum,
            lweLicensed,
            out lContinue,
            out cResponseMsg,
            out cCreditShipAction,
            out cDisplayMsg,
            out cCompliantMsg,
            out cResponseMsgOrdRel,
            out cAgingMessage,
            out cShipByDateMessage,
            out cNeedByDateMessage,
            out cMsgTypeSaleable,
            ref soDS
        );
    });

I think I found the problem. I changed MasterUpdate to Update and it worked. I checked the return messages from MasterUpdate and it passed back a Credit Hold Dialog message. I changed the two boolean inputs to false, lCheckForOrderChangedMsg and lcheckForResponse. I assume the suppress user response to messages. It started working again.

2 Likes

You can avoid having those dialog messages sent back by setting the lCheckForOrderChangedMsg and lcheckForResponse parameters to false.

Never mind - I guess you already found that out.

1 Like