Automating Fulfillment Workbench Via Epicor Function

Hello,

I’ve been working on automating the Fulfillment Workbench via an Epicor Function over the REST API and it’s causing a weird error to appear in Fulfilment Workbench in the client after it’s run.

  1. Erp.OrderAlloc.GetListOfOrders()
  2. Erp.OrderAlloc.OrderAllocationGetRows()
  3. Erp.OrderAlloc.Recalculate()
  4. Erp.OrderAlloc.CheckDates()
  5. Erp.OrderAlloc.OneDemandType()
  6. Erp.OrderAlloc.GetLotBinOnHand()
  7. Erp.OrderAlloc.AllocateByLotBin()
  8. Erp.OrderAlloc.GetFWBLimitedRefresh()
  9. Erp.OrderAlloc.GetFWBLimitedRefresh() // I don’t know why, but all my traces show this is called twice in a row

So my Epicor Function works fine (maybe), but I’m getting a weird error when trying to use “Allocate by Lot” in Fulfillment Workbench after having run the Epicor Function. My exact procedure:

  1. Run the Epicor Function described above
  2. Open Fulfillment work bench to verify allocations have changed (they have)
  3. Attempt to allocate more material to the order via Fulfilment Workbench (by Lot).
  4. receive the error below:

My gut says some tables are probably not getting updated (maybe I’m not using GetFWBLimitedRefresh correctly). The Error occurs only for the part (specifically the lot) that I ran the customization on.

I have already tried “Refresh PartBin QOH” and “Refresh Part Quantities and Allocations”. At one point I fixed it but I’m not sure what I did. The error returned once I ran the function again…

Any guidance is greatly appreciated.

Edit: Interesting to note that changing AllocateByLotBin() to AutoAllocation() does not result in the same issue… Must be something specific to AllocateByLotBin() that I am implementing incorrectly

I am going to continue to update this post in case someone is trying to automate Fulfillment Workbench in the future.


I believe the problem is that the “Available Qty” is not being decremented when I call OrderAlloc.AllocateByLotBin(). You can see in the below screenshot the quantity circled in red should be 0. The exact procedure to arrive at the below screenshot is as follows.

  1. start by clearing all allocations of the given part

  2. Run the Epicor function which is supposed to allocate 501 pieces of lot XXXXX to demand Order YYYY/YYY/Y

  3. Open Fulfillment Workbench in the client to see if allocations have updated properly (below screenshot)

I have not solved this problem yet.

Does this happen only when you try multiple allocations with the same transaction key value(PartNumber)?

If so, refer to this response and how to process deferred transactions:
I had to add this to a simialr workflow to handle this case, I was getting the same(or similar) exception message.

Hello Adam,

I might be misunderstanding your question, but I believe this happens after having run my Epicor Function and only for additional allocations for that same Lot. This is a problem for me because in the final iteration of this project, I will be implementing some logic that splits lots between multiple demands.

I also believe, that this is indicative of a larger problem where I’m not doing something that keeps the tables in sync. For example:

I can confirm via BAQ that there is one row in Erp.PartAlloc for this part which has a value of 501 in the “Allocated” field as expected. Thus one would expect Erp.PartWhse.AvailableQty for the part would also be 501 (I’m assuming one of the Methods I called is responsible for the synchronization?). However, it is currently 0, indicating a desynchronization… :frowning:

Edit: I just saw your second post. I will read it now

Adam,

That seems like what I’m after. Thanks! Only problem is that the syntax given does not seem valid for an Epicor Function. Its flagged as “the namespace Internal does not exist in Erp”. Any ideas on how to get a similar result in an Epicor Function?

Did you try adding a reference to Erp.Internal.Lib.DeferredUpdate.dll? This is a server-side assembly that does the stuff.

3 Likes

Yup, should’ve mentioned this reference is needed.

1 Like

I did and resolved the first error. Now I don’t know where to get “Db” (name does not exist)

Functions give you a limited data model. You start off with nothing and need to opt in tables using the reference tab. However this gives a different type of Db context that cannot be automatically converted to an ErpContext.

You can create an ErpContext in a function code block with the below code and pass it. Fair warning, I have not tested that this actually processes the deferred transaction. I know it creates a Db context of the correct type and it compiles:

var context = Ice.Services.ContextFactory.CreateContext<ErpContext>();

Erp.Internal.Lib.DeferredUpdate libDeferredUpdate = new Erp.Internal.Lib.DeferredUpdate(context);
libDeferredUpdate.UpdPQDemand();

I was using this call in an SDK generated object which has a native ErpContext which is why I did not bump into this issue.

4 Likes

Thank you for your suggestion. Running just those lines inside of a new Epicor Function does not appear to processes the deferred transactions (assuming that a sign of the deferred transactions being processed would be the Available Qty decrementing to 0).

Somewhere in another thread I saw someone mention that there is a System Agent Process that automatically sweeps up the deferred transactions. This is consistent with what I experience because over the past few days I have desynced my system and the next morning it will appear to have resolved itself (meaning the Available Qtys decremented to 0).

So “Refresh Part Quantities and Allocations” was the process/report. I ran it in “update” mode and it resolved the “Available Qty” for each lot to 0 which was what was expected. However, I still can’t make an additional Allocation or modification to the lots and I get the “unable to allocate at this time error”

Update: @adaniell I think your suggestion may have actually worked! I just didn’t realize it at first because I kept testing on a part that had already been corrupted. After switching to a new part, it appears to be working correctly. I may just wait a day for the corrupted part to be swept up by the nightly process that purges the deferred transactions. I will update the post with a solution after a little more testing to confirm.

Thank you very much for your input on this issue @adaniell and @josephmoeller
:slight_smile:

@mikelyndersOKCC, I am also working on Reserve Parts automatically functionality while creating Sales Order. I have written one BPM for that but I am getting one error while Reserving Parts. Could you please suggest me…?

@Hari_Dutt

What kind of error are you getting? I have other posts on my profile that have more details on what I ended up doing.

Auto Reservation Error The underlying provider failed on EnlistTransaction.
System.Data.SqlClient.SqlException (0x80131904): The operation failed because the session is not single threaded.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) at System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest) at System.Data.SqlClient.SqlInternalConnectionTds.PropagateTransactionCookie(Byte[] cookie) at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx) at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx) at System.Data.SqlClient.SqlInternalConnection.EnlistTransaction(Transaction transaction) at System.Data.SqlClient.SqlConnection.EnlistTransaction(Transaction transaction) at Epicor.Data.Provider.EpiConnection.EnlistTransaction(Transaction transaction) in C:\_Releases\ICE\ICE3.2.200.16\Source\Framework\Epicor.System\Data\EpiProvider2\EpiConnection.cs:line 208 at System.Data.Entity.Infrastructure.Interception.InternalDispatcher1.Dispatch[TTarget,TInterceptionContext](TTarget target, Action2 operation, TInterceptionContext interceptionContext, Action3 executing, Action`3 executed)
at System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.EnlistTransaction(DbConnection connection, EnlistTransactionInterceptionContext interceptionContext)
at System.Data.Entity.Core.EntityClient.EntityConnection.EnlistTransaction(Transaction transaction)
ClientConnectionId:2ddc0e58-4dc6-4bcd-91c6-8bfc45ac51a3
Error Number:3983,State:2,Class:16

@Hari_Dutt Sorry, I haven’t come across that one. Try posting your code and more details about your application? Are you working in Epicor Functions?