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