UBAQ to update Primary Warehouse and Bin

I’m trying to create an updateable BAQ for users to be able to set or modify the primary warehouse and bin.
I see that the fields aren’t DB fields, so I’m trying to use the advanced BPM to write a base processing directive to use the BO and update the data set, but I’m getting an out of range error. Can someone point me in the right direction?

Here’s the code I’m running on base:

foreach(var r in ttResults.Where(r => r.Updated()))
{
  using(var partBO = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.PartSvcContract>(Db))
  {
      string desc = (
	   from wb in Db.WhseBin.With(LockHint.NoLock)
   	   where wb.Company==Session.CompanyID && wb.BinNum==r.PlantWhse_PrimBin
	   select wb.Description).ToString();	

      PartTableset pds = new PartTableset();
      pds.PartWhse[0].PrimBinNum = r.PlantWhse_PrimBin;
      pds.PartWhse[0].PrimBinNumDescription = desc;
      partBO.Update(ref pds);
  }
}

And this is the method called in the trace logs:

<tracePacket>
  <businessObject>Erp.Proxy.BO.PartImpl</businessObject>
  <methodName>Update</methodName>
  <appServerUri>net.tcp://isiepicor/PILOT/</appServerUri>
  <returnType>System.Void</returnType>
  <localTime>3/16/2018 07:34:14:7779543 AM</localTime>
  <executionTime total="629" roundTrip="566" channel="0" bpm="0" other="63" />
  <retries>0</retries>
  <parameters>
    <parameter name="ds" type="Erp.BO.PartDataSet">
      <PartDataSet xmlns="http://www.epicor.com/Ice/300/BO/Part/Part" />
    </parameter>
  </parameters>
  <paramDataSetChanges>
    <paramDataSet name="ds" useDataSetNbr="0">
      <changedValue tableName="PartWhse" rowState="Modified" rowNum="0" colName="PrimBinNum"><![CDATA[WIP]]></changedValue>
      <changedValue tableName="PartWhse" rowState="Modified" rowNum="0" colName="PrimBinNumDescription"><![CDATA[WIP - Work in Process]]></changedValue>
    </paramDataSet>
  </paramDataSetChanges>
</tracePacket>

When I try and update, I get this error:

Server Side Exception

BPM runtime caught an unexpected exception of ‘ArgumentOutOfRangeException’ type.
See more info in the Inner Exception section of Exception Details.

Exception caught in: Epicor.ServiceModel

Error Detail

Description: BPM runtime caught an unexpected exception of ‘ArgumentOutOfRangeException’ type.
See more info in the Inner Exception section of Exception Details.
Program: CommonLanguageRuntimeLibrary
Method: ThrowArgumentOutOfRangeException
Original Exception Type: ArgumentOutOfRangeException
Framework Method: A001_CustomCodeAction
Framework Line Number: 0
Framework Column Number: 0
Framework Source: A001_CustomCodeAction at offset 1441 in file:line:column :0:0

Server Trace Stack: at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
at Epicor.Customization.Bpm.UbaqAA1B173E317A427497ABBF4811474172.UpdateBaseDirective_BASE_ADW_7155508E611643E4812270BF77196D80.A001_CustomCodeAction()
at Epicor.Customization.Bpm.UbaqAA1B173E317A427497ABBF4811474172.UpdateBaseDirective_BASE_ADW_7155508E611643E4812270BF77196D80.ExecuteCore()
at Epicor.Customization.Bpm.DirectiveBase`3.Execute(TParam parameters) in c:_Releases\ICE\3.1.500\Current\Source\Server\Internal\Lib\Epicor.Customization.Bpm\DirectiveBase.Generic.cs:line 160

Client Stack Trace

at Epicor.ServiceModel.Channels.ImplBase1.ShouldRethrowNonRetryableException(Exception ex, DataSet[] dataSets) at Ice.Proxy.BO.DynamicQueryImpl.Update(DynamicQueryDataSet queryDS, DataSet queryResultDataset) at Ice.Adapters.DynamicQueryAdapter.<>c__DisplayClass64_0.<Update>b__0(DataSet datasetToSend) at Ice.Adapters.DynamicQueryAdapter.ProcessUbaqMethod(String methodName, DataSet updatedDS, Func2 methodExecutor, Boolean refreshQueryResultsDataset)
at Ice.Adapters.DynamicQueryAdapter.Update(DynamicQueryDataSet queryDS, DataSet updatedDS, Boolean refreshQueryResultsDataset)
at Ice.UI.App.BAQDesignerEntry.BAQTransaction.b__358_0(Int32& rowReturned)
at Ice.UI.App.BAQDesignerEntry.Forms.BAQDiagramForm.ShowQueryResults(DataSet dsResults, getQueryResult getResults, ReportAdditionalInfo additionalInfo)
at Ice.UI.App.BAQDesignerEntry.BAQTransaction.CallUpdate()

Inner Exception

Specified argument was out of the range of valid values.
Parameter name: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

Aaron you first have to do a GetByID on the part and assign it to our dataset. Otherwise you won’t have a record in pds

Well, that just makes too much sense.
:sweat_smile:

1 Like

Okay, now assuming this line of code is correct… It will update the value in the UBAQ, but the moment I click Get List again, it goes back to its original value. No errors.

			pds = partBO.GetByID(r.PlantWhse_PartNum);

RowMod :wink:

And just like that, it works. Lol, thanks!

Scratch that. My row number was off on the second table. Should have been a 1 and not a 0.

How would I update two tables using the same service call?
I’m trying to update the Primary Warehouse and the Primary Bin, but if I do the below, I get a “Record has been Modified by another user” error.

foreach(var r in ttResults.Where(r => r.Updated()))
{
    if( r != null )
    {
      using(var partBO = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.PartSvcContract>(Db))
      {
			string binDesc = (
				from wb in Db.WhseBin.With(LockHint.NoLock)
				where wb.Company==Session.CompanyID && wb.BinNum==r.PlantWhse_PrimBin
				select wb.Description).ToString();	

			string whseDesc = (
				from whse in Db.Warehse.With(LockHint.NoLock)
				where whse.Company==Session.CompanyID && whse.WarehouseCode==r.PartPlant_PrimWhse
				select whse.Description).ToString();

            PartTableset pds = new PartTableset();
			pds = partBO.GetByID(r.PlantWhse_PartNum);

			pds.PartPlant[0].PrimWhse = r.PartPlant_PrimWhse;
			pds.PartPlant[0].PrimWhseDescription = whseDesc;
			pds.PartPlant[0].RowMod = "U";
			pds.PartWhse[0].WarehouseCode = r.PlantWhse_WarehouseCode;
            pds.PartWhse[0].PrimBinNum = r.PlantWhse_PrimBin;
            pds.PartWhse[0].PrimBinNumDescription = binDesc;
			pds.PartWhse[0].RowMod = "U";
            partBO.Update(ref pds);
  }
}

}

What’s the scoop on getting this to work for multiple rows?
I got as far as figuring it’s something to do with the index of the table, but I’m having troubles figuring out the logic to dynamically assign that index.
I tried putting a counter variable that incremented after each foreach loop, but that still resulted in the “Record modified by another user” error.

It should work for multiple rows… are you talking about Multiple PartWhse records? or Multiple what?

I filtered my BAQ to focus on 1 part for testing.
It has 3 warehouses set up.

image

I can change the first one (BULK) just fine, but if I try the other 2, it will give me that modified error.
If I set an int counter I can update them in order, meaning I can update the first one, the first two, or all three and it will work, but if I update the middle one, or the last two, I get the error. Thinking it was indexing on all rows instead of just updated rows, I redefined my counter to included non-updated rows, but the same behavior happens.

ok a couple of things, do a trace on doing this manually. I don’t think they set the Description by hand like you are doing (Isn’t there a ChangeWhse , ChangeBin method the trace does?) you should always mimic the trace

Secondly, in your code you are addressing pds.PartPlant[0] (0 being the FIRST one) so you need to select the right one to modify. Not just 0 but rather find the record within that needs to be modified. You can do that with a Link query or a Loop in the pds.PartPlant or pds.PartWhse to find the right one.
See if that helps.

Make sure you are only looping on stuff that is modified Where(r => r.Updated()))

1 Like

This is what the trace reveals and is why I was setting the description manually:

<tracePacket>
  <businessObject>Erp.Proxy.BO.PartOnHandWhseImpl</businessObject>
  <methodName>GetPartOnHandWhse</methodName>
  <appServerUri>net.tcp://isiepicor/PILOT/</appServerUri>
  <returnType>Erp.Tablesets.PartOnHandWhseTableset</returnType>
  <localTime>3/16/2018 10:06:37:6610776 AM</localTime>
  <executionTime total="376" roundTrip="72" channel="302" bpm="0" other="2" />
  <retries>0</retries>
  <parameters>
    <parameter name="cPartNum" type="System.String"><![CDATA[12-12-008]]></parameter>
    <parameter name="cPlant" type="System.String"><![CDATA[MfgSys]]></parameter>
  </parameters>
</tracePacket>

<tracePacket>
  <businessObject>Erp.Proxy.BO.PartImpl</businessObject>
  <methodName>Update</methodName>
  <appServerUri>net.tcp://isiepicor/PILOT/</appServerUri>
  <returnType>System.Void</returnType>
  <localTime>3/16/2018 10:06:40:9944599 AM</localTime>
  <executionTime total="399" roundTrip="106" channel="273" bpm="0" other="20" />
  <retries>0</retries>
  <parameters>
    <parameter name="ds" type="Erp.BO.PartDataSet">
      <PartDataSet xmlns="http://www.epicor.com/Ice/300/BO/Part/Part" />
    </parameter>
  </parameters>
  <paramDataSetChanges>
    <paramDataSet name="ds" useDataSetNbr="0">
      <changedValue tableName="PartWhse" rowState="Modified" rowNum="1" colName="PrimBinNum"><![CDATA[AA]]></changedValue>
      <changedValue tableName="PartWhse" rowState="Modified" rowNum="1" colName="PrimBinNumDescription"><![CDATA[AA - Art Department]]></changedValue>
    </paramDataSet>
  </paramDataSetChanges>
</tracePacket>

Correct me if I’m wrong, but I had assumed the the “foreach(var r in ttResults.Where(r=>r.Updated())” was looping through only the updated rows in the dataset.
So, if I updated only the highlighted rows in the BAQ, then that foreach statement would only process those two giving an index of 0 to MAIN-WIP and and index of 1 to REMWH1-TRK. Is that wrong?

image

This is what I have been doing since the last time I posted code. I had gotten rid of the index of zero hardcode, and added a counter:

int i = 0;

foreach(var r in ttResults.Where(r=>r.Updated()))
{
    using(var partWhseBO = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.PartOnHandWhseSvcContract>(Db))
  {
	    partWhseBO.GetPartOnHandWhse(r.PlantWhse_PartNum, "MfgSys");
    }

  using(var partBO = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.PartSvcContract>(Db))
  {
		    string binDesc = (
			    from wb in Db.WhseBin.With(LockHint.NoLock)
			    where wb.Company==Session.CompanyID && wb.BinNum==r.PlantWhse_PrimBin
			    select wb.Description).ToString();	

            PartTableset pds = new PartTableset();
		    pds = partBO.GetByID(r.PlantWhse_PartNum);

		    pds.PartWhse[i].WarehouseCode = r.PlantWhse_WarehouseCode;
            pds.PartWhse[i].PrimBinNum = r.PlantWhse_PrimBin;
            pds.PartWhse[i].PrimBinNumDescription = binDesc;
		    pds.PartWhse[i].RowMod = "U";
            partBO.Update(ref pds);

		    i++;
  }
}

What you said about looping through the pds clicked after I made it output what it was doing.
I see what you’re saying now. The dataset isn’t what the foreach is looping through. The foreach is looping through the updated records of the temp table. So, I have to loop through the pds to find the right record and then I can update it.

For anyone else, here’s the train of thought that helped me understand the above a little more:

I wrote the index, before, and afters of all three to an out file and it all looks like I would expect:
Index: 0 - FROM: B | CON1 TO: B | BULK
Index: 1 - FROM: MAIN | WIP TO: MAIN | AA
Index: 2 - FROM: REMWH1 | TRK TO: REMWH1 | Staging

And if I run it for just the middle row:
Index: 0 - FROM: B | CON1 TO: MAIN | AA

image

The “FROM” is the pds.PartWhse[i] and the TO: is the ttResults table.
It clicked when I saw that the “FROM” data was the first record in the dataset and the TO was the updated record in the temp table.

1 Like

Bingo!

I need to achieve the same thing, could someone share the complete code?

It seems this was resolved. Could you share the complete steps as I need to achieve the same thing. Possibly share the exported dashboard + baq files? Thanks

Unfortunately, this project was scrapped, so I don’t have the files anymore.
It looks like the code for the base update is a few posts up: UBAQ to update Primary Warehouse and Bin - #12 by hmwillett - ERP 10 - Epicor User Help Forum

I don’t remember the exact reason why it was scrapped, but I do recall it being somewhat clunky to update.

thanks

After stumbling over this looking for information on the PrimBinNum, you might be better off using the PartWarehouse DMT to update. I don’t imagine this would be something you change regularly, or is it.

Thanks @hmwillett and @josecgomez for a great post. I’m sure the information will come in handy down the track. Your contributions are invaluable to all.

2 Likes

Utterly ignorant question here, but what “reference” do you use to avoid this error:

image

I guessed at Erp.Contracts.BO.Part (and a bunch of other ones) but that got me nowhere.

I cannot believe there is not a simpler solution to the Primary Bin uBAQ. Wow.