I was going through some rest documentation for Rest v2 and ran into an issue. The only way I see to post new records was to post one record at a time. Is there a way to batch post several entries at a time instead of a single one?
Functions! You can create a function to accept a string parameter of serialized JSON for your batch data and then parse it inside your function to cycler over the inputs and create the records.
I know absolutely nothing about functions. But, I will certainly be digging into those now. Thanks Aaron!
Functions are great, let me know if you need help with it!
Hi Aaron,
Would you mind sharing an example if you already have set up a function doing the similar? Weāre trying to set up a function to create records for a UD table but completely stuck.
Hi Harry,
Are you stuck on the āinsideā part of the function to create a UD record, or are you stuck on how to pass serialized data to a function, parse into multiple rows, and then consume?
Hi Aaron,
I am actually working on this project with Harry.
The issue I am facing is the āinsideā part of the function. I can serialize the data as JSON and send it through my .Net code to the function but, I just can not get the Epicor function to loop through the JSON data and add a new row to a UD table for each set of JSON data.
I was playing around with the Epicor Function and when I came to the āInvoke BO Methodā block, I noticed that we could only use the custom methods that appear in the Swagger API and not the OData methods. Is there any way to get the OData methods to work in the Epicor Function interface?
Hello Malith,
Iāll show how I took a serialized input string from a function and parse it inside of a function.
I created the request signature with a string variable āproductListā, which will represent the serialized string of products I will parse
Here is what my call to this function looks like with the serialized string:
Pass that string into your function via the body of your call.
Once inside the function, use a Custom Code block to parse your string and iterate over the results (note; I donāt know of a way to do this with pure widgets, so you must have a custom code block in this example).
I consume the variable by deserializing it like so:
//Add Order Lines
//iterate over incoming params to add part lines
dynamic prodList = Newtonsoft.Json.JsonConvert.DeserializeObject(productList);
//msg = prodList.ToString();
int rowCnt = 0;
foreach(var product in prodList)
{
//Get New Order Dtl
this.CallService<Erp.Contracts.SalesOrderSvcContract>(ss =>{
ss.GetNewOrderDtl(ref tsSalesOrder, salesOrderNum);
//ChangePartNumMaster
string partNum = product.PartNum.ToString();
bool lSubstitutePartExist = false;
bool lIsPhantom = false;
string uomCode = "";
Guid SysRowID = Guid.Empty;
string rowType = "";
bool salesKitView = false;
bool removeKitComponents = false;
bool suppressUserPrompts = false;
bool getPartXRefInfo = true;
bool checkPartRevisionChange = true;
bool checkChangeKitParent = true;
string cDeleteComponentsMessage = "";
string questionString = "";
string cWarningMessage = "";
bool multipleMatch = false;
bool promptToExplodeBOM = false;
string cConfigPartMessage = "";
string cSubPartMessage= "";
string explodeBOMerrMessage = "";
string cMsgType = "";
bool multiSubsAvail = false;
bool runOutQtyAvail = false;
tsSalesOrder.OrderDtl[rowCnt].PartNum = product.PartNum.ToString();
tsSalesOrder.OrderDtl[rowCnt]["DrawNumFromQuote_c"] = product.LotNum.ToString();
tsSalesOrder.OrderDtl[rowCnt].RowMod = "A";
ss.ChangePartNumMaster(ref partNum, ref lSubstitutePartExist, ref lIsPhantom, ref uomCode, SysRowID, rowType, salesKitView, removeKitComponents, suppressUserPrompts, getPartXRefInfo, checkPartRevisionChange, checkChangeKitParent, out cDeleteComponentsMessage, out questionString, out cWarningMessage, out multipleMatch, out promptToExplodeBOM, out cConfigPartMessage, out cSubPartMessage, out explodeBOMerrMessage, out cMsgType, out multiSubsAvail, out runOutQtyAvail, ref tsSalesOrder);
//ChangeSellingQtyMaster
decimal ipSellingQuantity = 1.00M;
bool chkSellQty = false;
bool negInvTest = false;
bool chgSellQty = true;
bool chgDiscPer = true;
//bool suppressUserPrompts = false;
bool lKeepUnitPrice = true;
string pcPartNum = product.PartNum.ToString();
string pcWhseCode = "";
string pcBinNum = "";
string pcLotNum = "";
int pcAttributeSetID = 0;
string pcDimCode = "EA";
decimal pdDimConvFactor = 1;
string pcMessage = "";
string pcNeqQtyAction = "";
string opWarningMsg = "";
string cSellingQuantityChangedMsgText = "";
tsSalesOrder.OrderDtl[rowCnt].PartNum = product.PartNum.ToString();
tsSalesOrder.OrderDtl[rowCnt]["DrawNumFromQuote_c"] = product.LotNum.ToString();
tsSalesOrder.OrderDtl[rowCnt].RowMod = "A";
ss.ChangeSellingQtyMaster(ref tsSalesOrder, ipSellingQuantity, chkSellQty, negInvTest, chgSellQty, chgDiscPer, suppressUserPrompts, lKeepUnitPrice,pcPartNum, pcWhseCode, pcBinNum, pcLotNum, pcAttributeSetID, pcDimCode,pdDimConvFactor, out pcMessage, out pcNeqQtyAction, out opWarningMsg, out cSellingQuantityChangedMsgText);
//UpdateMaster
bool lCheckForOrderChangedMsg = true;
bool lcheckForResponse = true;
string cTableName = "OrderDtl";
int iCustNum = soldToCustNum;
int iOrderNum = salesOrderNum;
bool lweLicensed = false;
bool lContinue = false;
string cResponseMsg = "";
string cCreditShipAction = "";
string cDisplayMsg = "";
string cCompliantMsg = "";
string cResponseMsgOrdRel = "";
string cAgingMessage = "";
//Update Rep
tsSalesOrder.OrderHed[0].SalesRepCode1 = "ARTHREX";
tsSalesOrder.OrderHed[0].SalesRepName1 = "Arthrex Commissions";
tsSalesOrder.OrderHed[0].RowMod = "U";
ss.MasterUpdate(lCheckForOrderChangedMsg,lcheckForResponse, cTableName, iCustNum, iOrderNum, lweLicensed, out lContinue, out cResponseMsg, out cCreditShipAction, out cDisplayMsg, out cCompliantMsg, out cResponseMsgOrdRel, out cAgingMessage, ref tsSalesOrder);
//Invoke Function to ChangeTendonReserveStatus
var result = this.EfxLib.UD100Functions.ChangeTendonReserveStatus(product.LotNum.ToString(), product.PartNum.ToString(), soldToCustNum, salesOrderNum,rowCnt+1, true);
rowCnt++;
}
);
//msg += product.PartNum.ToString()+ ": ";
}
Of note, to call a business object programatically (without widget), you can use the āCallServiceā method available to the function. You will still need to add any references to Business Objects in your library as well as to your scope.
this.CallService<Erp.Contracts.SalesOrderSvcContract>(ss =>{
ss.GetNewOrderDtl(ref tsSalesOrder, salesOrderNum);
To answer more questions; no, inside of Epicor you will use the Business Object methods, not OData methods. This is far easier, in my opinion, because you will have access to the datasets and methods available to the BO. Just take a client trace of any transaction and you will be able to re-create it using the InvokeBOMethod blocks, or programatically, if you choose.
Thanks a lot for your in-depth reply Aaron
Hi,Aaron,Is there a way to batch create parts? I need to create 40,000 parts at once
DMT is best bet here.
Thank you for your replyļ¼I need to develop an API to quickly add 40000 pieces of part information. I need to accept data containing 40000 parts and add them. Can DMT be directly called to add them in BPM?
From what type of input? More details here would be helpful. What business need are you trying to fulfill/solve.