How to make an EpicorRest.DynamicPost work in a Data Directive BPM wth c# code

I am trying to program my first Rest code in a BPM and do not know where to start.

My one code line is:

dynamic edata = EpicorRest.DynamicPost(“Erp.BO.QuoteAsmSvc”, “GetNewQuoteMtl”, mdata);

The compile error is:

The name “EpicorRest” does not exist in the current context.

Does anyone have a road map on what I need to do to get this code to work?

Please help!!!

Thanks,

Richard

ryan reynolds hd GIF

Thank you for your reply.

Why?

I figure if I can get this one code line to work then I can make any BO work in a BPM using EpicorRest.

Please help!

Thanks,

Richard

You can do that already. Calling through rest server side is horribly inefficient.

Why use REST when you can just use the Business Objects?

Thank you for your reply.

I tryed to get my c# code to work using Business Objects but I failed.

I found a post where someone used the EpicorRest to do almost the same thing that I needed to do which worked. So I wanted to give EpicorRest a try.

Please help!

Thanks,

Richard

It was a hack then and a hack now.

I think you should spend more time figuring out why your approach isn’t working.

No offense intended, but from your other posts, you lack a lot of clarifying details that we need to help you. We want to, but you gotta give us something to work with.

As @klincecum said please provide more details on what you’re trying to do and we can help.

Thank you for your replies.

Here is the big picture.

I am adding a Change Part Number button to the Manufacturing/Materials form, along with a text box where the user can enter a new part number.

The user will be on a quote material record. They will enter the new part number, click the button, and the BPM will look through all QuoteMtl records on the quote. Any material row with the same part number as the current material on the form should be changed to the new part number.

The customer wants to mass-change certain part numbers on quotes that may have thousands of materials, instead of changing them manually one at a time.

Here is the trace I am trying to duplicate in a BPM. I created the trace by going into Opportunity/Quote Entry and changing a part number in an assembly.

<tracePacket>
  <businessObject>Erp.Proxy.BO.QuoteImpl</businessObject>
  <methodName>GetPartXRefInfo</methodName>
  <parameters>
    <parameter name="partNum" type="System.String"><![CDATA[55074]]></parameter>
    <parameter name="SysRowID" type="System.Guid"><![CDATA[00000000-0000-0000-0000-000000000000]]></parameter>
    <parameter name="rowType" type="System.String"><![CDATA[]]></parameter>
    <parameter name="uomCode" type="System.String"><![CDATA[]]></parameter>
  </parameters>
  <returnValues>
    <returnParameter name="partNum" type="System.String"><![CDATA[55074]]></returnParameter>
    <returnParameter name="uomCode" type="System.String"><![CDATA[]]></returnParameter>
    <returnParameter name="serialWarning" type="System.String"><![CDATA[]]></returnParameter>
    <returnParameter name="questionString" type="System.String"><![CDATA[PART]]></returnParameter>
    <returnParameter name="multipleMatch" type="System.Boolean"><![CDATA[False]]></returnParameter>
  </returnValues>
</tracePacket>

<tracePacket>
  <businessObject>Erp.Proxy.BO.QuoteAsmImpl</businessObject>
  <methodName>CheckPrePartInfo</methodName>
  <parameters>
    <parameter name="partNum" type="System.String"><![CDATA[55074]]></parameter>
    <parameter name="sourceTable" type="System.String"><![CDATA[QuoteMtl]]></parameter>
    <parameter name="sourceSysRowID" type="System.Guid"><![CDATA[dffb9512-86c9-4dec-8a91-ffc4aeb72bf0]]></parameter>
  </parameters>
  <returnValues>
    <returnParameter name="partNum" type="System.String"><![CDATA[55074]]></returnParameter>
    <returnParameter name="vMessage" type="System.String"><![CDATA[]]></returnParameter>
    <returnParameter name="vSubAvail" type="System.Boolean"><![CDATA[False]]></returnParameter>
    <returnParameter name="vMsgType" type="System.String"><![CDATA[]]></returnParameter>
    <returnParameter name="productConfiguratorMessage" type="System.String"><![CDATA[]]></returnParameter>
  </returnValues>
</tracePacket>

<tracePacket>
  <businessObject>Erp.Proxy.BO.QuoteAsmImpl</businessObject>
  <methodName>CheckQuoteMtlPartNum</methodName>
  <parameters>
    <parameter name="ds" type="Erp.BO.QuoteAsmDataSet">
      <QuoteAsmDataSet xmlns="http://www.epicor.com/Ice/300/BO/QuoteAsm/QuoteAsm">
        ...
      </QuoteAsmDataSet>
    </parameter>
  </parameters>
</tracePacket>

<tracePacket>
  <businessObject>Erp.Proxy.BO.QuoteAsmImpl</businessObject>
  <methodName>GetMtlPartInfo</methodName>
  <parameters>
    <parameter name="ds" type="Erp.BO.QuoteAsmDataSet">
      <QuoteAsmDataSet xmlns="http://www.epicor.com/Ice/300/BO/QuoteAsm/QuoteAsm">
        ...
      </QuoteAsmDataSet>
    </parameter>
  </parameters>
</tracePacket>

<tracePacket>
  <businessObject>Erp.Proxy.BO.QuoteAsmImpl</businessObject>
  <methodName>Update</methodName>
  <parameters>
    <parameter name="ds" type="Erp.BO.QuoteAsmDataSet">
      <QuoteAsmDataSet xmlns="http://www.epicor.com/Ice/300/BO/QuoteAsm/QuoteAsm">
        ...
      </QuoteAsmDataSet>
    </parameter>
  </parameters>
</tracePacket>

Here is the code I currently have in test mode:

this.CallService<Erp.Contracts.QuoteSvcContract>(qmc => qmc.GetPartXRefInfo(ref pn, Guid.Empty, "", ref uomcode, out sw, out qs, out mm));

this.PublishInfoMessage(sw.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "", "");
this.PublishInfoMessage(qs.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "", "");
this.PublishInfoMessage(mm.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "", "");

st = "QuoteMtl";
sourceSysRowID = Guid.Parse("DFFB9512-86C9-4DEC-8A91-FFC4AEB72BF0");

this.CallService<Erp.Contracts.QuoteAsmSvcContract>(qmc => qmc.CheckPrePartInfo(ref pn, st, sourceSysRowID, out vm, out vs, out vmt, out pc));

this.PublishInfoMessage(vm.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "", "");
this.PublishInfoMessage(vs.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "", "");
this.PublishInfoMessage(vmt.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "", "");
this.PublishInfoMessage(pc.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "", "");

pn = "25391";
this.CallService<Erp.Contracts.QuoteAsmSvcContract>(qmc => qmc.CheckQuoteMtlPartNum(ref qats, pn));

pn = "PartNum";
this.CallService<Erp.Contracts.QuoteAsmSvcContract>(qmc => qmc.GetMtlPartInfo(ref qats, pn));

this.CallService<Erp.Contracts.QuoteAsmSvcContract>(qmc => qmc.Update(ref qats));

Here is the error I am getting:

Business Layer Exception

QuoteMtl record is not avaialble.
QuoteMtl record is not avaialble.

Exception caught in: Epicor.ServiceModel

Correlation ID: f14027d3-1b14-4588-a423-2516c6d3de2e

Message No.: 1
Description: QuoteMtl record is not avaialble.
Program: Erp.Services.BO.QuoteAsm.dll
Method: CheckQuoteMtlPartNum
Line Number: 13567
Column Number: 17
Table: QuoteMtl

Message No.: 2
Description: QuoteMtl record is not avaialble.
Program: Erp.Services.BO.QuoteAsm.dll
Method: GetMtlPartInfo
Line Number: 13618
Column Number: 17
Table: QuoteMtl

Here is similar Epicor REST code that worked for someone else. This example is adding a new quote material, but I am trying to change existing quote materials.

bool AddQuoteMtl(string quoteNum, string quoteLine, string assemblySeq, string partNum, double QtyPer, string IUM, string Class, string Operation)
{
    dynamic pData = new { Company = "78863", quoteNum, quoteLine, assemblySeq, ds = new object() };
    dynamic rData = EpicorRest.DynamicPost("Erp.BO.QuoteAsmSvc", "GetNewQuoteMtl", pData);

    pData = new { partNum, SysRowID = "00000000-0000-0000-0000-000000000000", rowType = "", uomCode = "", serialWarning = "", questionString = "", multipleMatch = "", rData.parameters.ds };
    EpicorRest.DynamicPost("Erp.BO.QuoteSvc", "GetPartXRefInfo", pData);
    if (EpicorRest.LastCallResult != System.Net.HttpStatusCode.OK) return false;

    pData = new { partNum, sourceTable = "QuoteMtl", sourceSysRowID = "00000000-0000-0000-0000-000000000000", vMessage = "", vSubAvail = "False", vMsgType = "", productConfiguratorMessage = "", rData.parameters.ds };
    EpicorRest.DynamicPost("Erp.BO.QuoteAsmSvc", "CheckPrePartInfo", pData);
    if (EpicorRest.LastCallResult != System.Net.HttpStatusCode.OK) return false;

    pData = new { ipProposedPartNum = partNum, rData.parameters.ds };
    EpicorRest.DynamicPost("Erp.BO.QuoteAsmSvc", "CheckQuoteMtlPartNum", pData);
    if (EpicorRest.LastCallResult != System.Net.HttpStatusCode.OK) return false;

    pData = new { partName = "PartNum", rData.parameters.ds };
    rData = EpicorRest.DynamicPost("Erp.BO.QuoteAsmSvc", "GetMtlPartInfo", pData);
    if (EpicorRest.LastCallResult != System.Net.HttpStatusCode.OK) return false;

    rData.parameters.ds.QuoteMtl[0]["partNum"] = partNum;
    rData.parameters.ds.QuoteMtl[0]["QtyPer"] = QtyPer.ToString();
    rData.parameters.ds.QuoteMtl[0]["IUM"] = IUM;
    rData.parameters.ds.QuoteMtl[0]["Class"] = Class;
    rData.parameters.ds.QuoteMtl[0]["RelatedOperation"] = Operation;

    pData = new { Part = PlatePart, rData.parameters.ds };
    EpicorRest.DynamicPost("Erp.BO.QuoteAsmSvc", "Update", pData);
    if (EpicorRest.LastCallResult != System.Net.HttpStatusCode.OK) return false;

    return true;
}

My main question is this:

For changing existing QuoteMtl rows, do I need to first load the existing QuoteAsmDataSet containing the target QuoteMtl rows before calling CheckQuoteMtlPartNum and GetMtlPartInfo?

It seems like those methods are failing because my qats dataset does not currently contain an available QuoteMtl row. The REST example works because it calls GetNewQuoteMtl first, which creates a QuoteMtl row in the dataset before the validation calls. Since I am not adding a new material, I assume I should not use GetNewQuoteMtl, but instead should load the existing quote/assembly/material data, update the matching QuoteMtl rows, set RowMod = "U", and then call Update.

Does that sound like the correct direction?

Thanks,

Richard

Did you call GetByID or something similar to populate qats?

int quoteNum = 262881;
int quoteLine = 1;
int assemblySeq = 0;

string oldPartNum = "25391";
string newPartNum = "55074";

this.CallService<Erp.Contracts.QuoteAsmSvcContract>(qmc =>
{
    var qats = qmc.GetByID(quoteNum, quoteLine, assemblySeq);

    var rows = qats.QuoteMtl
        .Where(r => String.Equals(r.PartNum, oldPartNum, StringComparison.OrdinalIgnoreCase))
        .ToList();

    foreach (var mtl in rows)
    {
        string pn = newPartNum;
        string uomCode = "";
        string serialWarning = "";
        string questionString = "";
        bool multipleMatch = false;

        this.CallService<Erp.Contracts.QuoteSvcContract>(qsvc =>
            qsvc.GetPartXRefInfo(ref pn, Guid.Empty, "", ref uomCode, out serialWarning, out questionString, out multipleMatch));

        string vMessage = "";
        bool vSubAvail = false;
        string vMsgType = "";
        string productConfiguratorMessage = "";

        qmc.CheckPrePartInfo(ref pn, "QuoteMtl", mtl.SysRowID, out vMessage, out vSubAvail, out vMsgType, out productConfiguratorMessage);

        mtl.PartNum = pn;
        mtl.RowMod = "U";

        qmc.CheckQuoteMtlPartNum(ref qats, pn);
        qmc.GetMtlPartInfo(ref qats, "PartNum");

        mtl.PartNum = pn;
        mtl.RowMod = "U";
    }

    if (rows.Count > 0) qmc.Update(ref qats);
});

Ok so the other thing you can do as an on prem is you can dump your sources of your bpm and then look at how Epicor builds the function call.

Start small and work your way up. Create some working examples as your boiler plate.

OMG!!!

Your new code worked perfectly.

I thank you 1,000,000 times.

Without you, I was lost.

You are the best!

Richard

I’ll add it to my collection.