Custom BPM to add QuoteHed_UD field to Sales Order on Opp to Sales Order processing

I am trying to understand how to COPY/Transfer data from a created QuoteHed UD field (DecorType) to OrderHed UD field (DecorType).

When user goes to Action > Create Sales Order from Opportunity/Quote I would like the content of QuoteHed_UD DecorType to automatically populate into OrderHed_UD DecorType.

Since OrderHed has no tt table, I am more than a bit confused on how to accomplish this DD.

Any help?

1 Like

With the data from the ttOrderHed as criteria, you could do a linq query to the Db.QuoteHed to pull that field. Depending on the BO method you are writing, you could do this in a pre-processing directive and it should write that data to the database.

Not completely following.
Data or method directive?

Depends on the process you are writing the BPM for. I would think this could be done using a Method Directive.

OK, I am not getting this at ALL. It almost looks as if I will need to write custom but weak in this area.

Seems like I would need a pre and some time of post process but I am just not seeing it.

Ok, so you’re looking to copy a UD field from the QuoteHed to the OrderHed when the quote is won?

Yes. Action > Create Sales Order from inside the actual quote.

Ok, it looks like what you will need is a PostProcessing Method Directive on Erp.BO.Quote.CreateOrder

In there you can access your UD field in QuoteHed:

image

Get SO uses the Erp.SalesOrder.GetByID with the orderNum variable that is in the CreateOrder definition. You can use this to create a DataSet variable that will be returned with the sales order information.
image

The Set SO_UD is used to set the Sales Order UD field to the QuoteHed UD field. Remember in a post processing there is no added/updated … rows.

image

So the Properties of Set SO_UD would look like:

Set the dsSalesOrder.OrderHed.DecorType_c field of all rows to the dsQuoteHedRow.DecorType_c

The Save SO uses the Erp.SalesOrder.Update with the DataSet created by the Get SO block.

image

That’s a real basic look at the concept I think you’re trying to get to.

I believe that @Doug.C’s solution would work, BUT, only when you convert a quote to an order from the quote… BUT there are three different ways to create an order.

  1. From Quote Entry
  2. From Order Entry/Actions
  3. from Order Entry / Get line from quote
    Each of these runs a different business object, so you will need to have three BPMs.
    Ahhh… but now we have FUNCTIONS available. One way to make this consistent would be to create a Function that does all your work, and then call that function from the three places.
    OR
    You create a DATA BPM on the OrderDtl that looks for new line items associated with a quote line, and lookup the data there.
1 Like

OH… and there might be a FOURTH way to convert quotes if you are running ECC… @Timothy_Melatis may have info on that… If I remember correctly, when ECC converts quotes to orders, it does it a different way than the previous 3 methods mentioned. We had to use a Data BPM to move data from a quote to an order.

1 Like

Here is a DD Design which I think is what you are asking for as this Sync’s up Order/Quote Comments & a PartsList_c field from the Quote to Order.

Code to grab the field data from QuoteDtl Line and store in Variable for widget access using other widget defined variables.

this.qdPartsList_c = 
  Db.QuoteDtl.Where(r => r.Company == Session.CompanyID && r.QuoteNum == this.iQuoteNum && r.QuoteLine == this.iQuoteLine)
    .Select(r => r.PartsList_c)
    .FirstOrDefault() ?? "";

FWIW, this is for QuoteDtl lines and not the Header but it should get you the idea…

Tim,

Hey thank you. I had already thought of that. Personnel in our company fortunately only know one way to do it Opp/Duote action >Create Sales Order and have been told to only use that method based on my predecessor creating another BPM for sending email to Sales Rep when converted. Whew!

Thank you. This worked well but… I failed to say there are actually two UD fields, DecorType and BldgType. Am I going to have to create Two Separate BPM for this?

Just add in another Set Field block and set the BldgType to what you need. Then do the Save SO.

Doug C.'s BPM validated and should work fine but now I cannot save the Method Directive. Of course Epicor Support says they cannot help with this as it is outside scope of maintenance. I want so bad to argue with them that NO, the method validates but wont save. Obvious some kind of bug in version 10.1.500.x or a logic error.

Anyway this is the error I receive. Any help would be appreciated.

This process validates and saves. However, when I SAVE the Method Directive itself, I receive a compilation error as follows.

Server Side Exception

There is at least one compilation error.

Exception caught in: Epicor.ServiceModel

Error Detail

Description: There is at least one compilation error.

Details:
Error CS0433: The type ‘Erp.Tablesets.ETCAddrValidationTableset’ exists in both ‘d:\Websites\EpicorERP10\Server\Assemblies\Erp.Contracts.BO.SalesOrder.dll’ and ‘d:\Websites\EpicorERP10\Server\Assemblies\Erp.Contracts.BO.Quote.dll’ [CustomizationAdapter.cs(264,30)]
Error CS0433: The type ‘Erp.Tablesets.QuoteQtyTable’ exists in both ‘d:\Websites\EpicorERP10\Server\Assemblies\Erp.Contracts.BO.SalesOrder.dll’ and ‘d:\Websites\EpicorERP10\Server\Assemblies\Erp.Contracts.BO.Quote.dll’ [CreateOrder.CommonTypes.cs(281,33)]
Error CS0433: The type ‘Erp.Tablesets.HedTaxSumTable’ exists in both ‘d:\Websites\EpicorERP10\Server\Assemblies\Erp.Contracts.BO.SalesOrder.dll’ and ‘d:\Websites\EpicorERP10\Server\Assemblies\Erp.Contracts.BO.Quote.dll’ [CreateOrder.CommonTypes.cs(301,33)]
Error CS0433: The type ‘Erp.Tablesets.PartSubsTable’ exists in both ‘d:\Websites\EpicorERP10\Server\Assemblies\Erp.Contracts.BO.SalesOrder.dll’ and ‘d:\Websites\EpicorERP10\Server\Assemblies\Erp.Contracts.BO.Quote.dll’ [CreateOrder.CommonTypes.cs(306,33)]
Error CS0433: The type ‘Erp.Tablesets.TaxConnectStatusTable’ exists in both ‘d:\Websites\EpicorERP10\Server\Assemblies\Erp.Contracts.BO.SalesOrder.dll’ and ‘d:\Websites\EpicorERP10\Server\Assemblies\Erp.Contracts.BO.Quote.dll’ [CreateOrder.CommonTypes.cs(311,33)]
Program: Epicor.Customization.dll
Method: PrepareException
Line Number: 99
Column Number: 13
Server Trace Stack: at Epicor.Customization.Standard.CustomizationCompiler.PrepareException(CompilerErrorCollection errors) in D:_Releases\ICE\3.1.500.46\Source\Framework\Epicor.Customization\Standard\CustomizationCompiler.cs:line 99
at Epicor.Customization.Standard.CustomizationCompiler.Compile(BuildEnvironment input, String outputAssembly) in D:_Releases\ICE\3.1.500.46\Source\Framework\Epicor.Customization\Standard\CustomizationCompiler.cs:line 29
at Epicor.Customization.Standard.CustomizationBuilder.Process(CustomizationProject project) in D:_Releases\ICE\3.1.500.46\Source\Framework\Epicor.Customization\Standard\CustomizationBuilder.cs:line 78
at Ice.Services.BO.BpMethodSvc.AfterUpdate() in D:_Releases\ICE\3.1.500.46\Source\Server\Services\BO\BpMethod\BpMethod.Events.cs:line 149
at Ice.Services.Trace.TablesetProfilingCollector.DoTablesetEventTrace(String tablesetName, String methodName, Action action) in D:_Releases\ICE\3.1.500.46\Source\Framework\Epicor.Ice\Services\TablesetProfilingCollector.cs:line 200
at Ice.TablesetBound3.InnerUpdate(IceDataContext dataContext, TFullTableset tableset) in D:\_Releases\ICE\3.1.500.46\Source\Framework\Epicor.Ice\Services\TablesetBound.cs:line 816 at Ice.Services.BO.BpMethodSvc.Update(BpMethodTableset& ds) in D:\_Releases\ICE\3.1.500.46\Source\Server\Services\BO\BpMethod\BpMethod.Designer.cs:line 835 at Ice.Services.BO.BpMethodSvcFacade.Update(BpMethodTableset& ds) in D:\_Releases\ICE\3.1.500.46\Source\Server\Services\BO\BpMethod\BpMethodSvcFacade.cs:line 640 at SyncInvokeUpdate(Object , Object[] , Object[] ) at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs) at Epicor.Hosting.OperationBoundInvoker.InnerInvoke(Object instance, Func2 func) in D:_Releases\ICE\3.1.500.46\Source\Framework\Epicor.System\Hosting\OperationBoundInvoker.cs:line 59
at Epicor.Hosting.OperationBoundInvoker.Invoke(Object instance, Func2 func) in D:\_Releases\ICE\3.1.500.46\Source\Framework\Epicor.System\Hosting\OperationBoundInvoker.cs:line 28 at Epicor.Hosting.Wcf.EpiOperationInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs) in D:\_Releases\ICE\3.1.500.46\Source\Framework\Epicor.System\Hosting\Wcf\EpiOperationInvoker.cs:line 23 at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc) at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet) at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext) at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext) at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(IAsyncResult result) at System.ServiceModel.Dispatcher.ChannelHandler.OnAsyncReceiveComplete(IAsyncResult result) at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result) at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously) at System.ServiceModel.Channels.SecurityChannelListener1.ReceiveItemAndVerifySecurityAsyncResult`2.InnerTryReceiveCompletedCallback(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.Channels.TransportDuplexSessionChannel.TryReceiveAsyncResult.OnReceive(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.Channels.SynchronizedMessageSource.ReceiveAsyncResult.OnReceiveComplete(Object state)
at System.ServiceModel.Channels.SessionConnectionReader.OnAsyncReadComplete(Object state)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Security.NegotiateStream.ProcessFrameBody(Int32 readBytes, Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.NegotiateStream.ReadCallback(AsyncProtocolRequest asyncRequest)
at System.Net.AsyncProtocolRequest.CompleteRequest(Int32 result)
at System.Net.FixedSizeReader.CheckCompletionBeforeNextRead(Int32 bytes)
at System.Net.FixedSizeReader.ReadCallback(IAsyncResult transportResult)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.Channels.ConnectionStream.IOAsyncResult.OnAsyncIOComplete(Object state)
at System.Net.Sockets.SocketAsyncEventArgs.OnCompleted(SocketAsyncEventArgs e)
at System.Net.Sockets.SocketAsyncEventArgs.FinishOperationSuccess(SocketError socketError, Int32 bytesTransferred, SocketFlags flags)
at System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

Client Stack Trace

at Epicor.ServiceModel.Channels.ImplBase`1.ShouldRethrowNonRetryableException(Exception ex, DataSet[] dataSets)
at Ice.Proxy.BO.BpMethodImpl.Update(BpMethodDataSet ds)
at Ice.Adapters.BpMethodAdapter.OnUpdate()
at Ice.Lib.Framework.EpiBaseAdapter.Update()
at Ice.UI.App.BpMethodEntry.Transactions.MainTransactionBase.adapterUpdate()

HELP! I do not understand why these are stopping the compile.

Hello @bschiefen
We use the same method to convert all our Quotes (from the quote entry screen)
We also have fields to copy across to the OrderHed from the QuoteHed

We use a Method Directive on the Erp.Quote.CreateOrder directive, and use a Post-Processing type

The Post-Processing already has the orderNum variable available in it already

image

image

We added a Custom Code block that has code like this in it (I modified it to suit your fields)

UPDATED - I’ve updated this code based on @timshuwy’s comments below

//Sets SO fields from quote
var quoteNum = Db.OrderDtl.Where(o => o.Company == Session.CompanyID && o.OrderNum == orderNum).Select(x => x.QuoteNum).FirstOrDefault();
if(quoteNum != null)
{
 
   var quote = Db.QuoteHed.Where(q => q.Company == Session.CompanyID && q.QuoteNum == quoteNum).Select(x => new {x.DecorType_c, x.BldgType_c}).FirstOrDefault();       
   if(quote != null)
   {
   //UD fields to copy to SO from Quote BldgType
	using(var txScope = IceContext.CreateDefaultTransactionScope())
	{ 
    var order = Db.OrderHed.Where(o => o.Company == Session.CompanyID && o.OrderNum == orderNum).FirstOrDefault()

      order.DecorType_c = quote.DecorType_c; 
      order.BldgType_c = quote.BldgType_c;
      Db.Validate();
      txScope.Complete();     
    }
}
}

Thanks that’s a great example. I’m trying to make changes to the lines instead of the header. When i run this it modifies the first line of the order but not the following lines.

My Method Parameters dont look right to me.

Does this seem right?

image

Yep, looks the same as mine