I have an issue where I have successfully written a BPM to Mass Issue & Mass Return job materials based on a trigger (Job Released / Un Released). All of the transactions show up how I would expect in Part Transaction History Tracker except for the following issues:
The “Running Total” behaves unexpectedly, and seems to always add the Qty to the running total no matter what, even increasing the “running total” for PAST transactions in the tracker upon refresh…
Similar to the Running Total issue, the On Hand Qty behaves the same as the running total where it seems to only increase or stay the same, and not go up and down equally for Issue/Return as expected.
The “Amount” field on the part tran ($amt) shows “0.00” and never calculates the ExtCost for the STK-MTL transactions that are occuring via BPM code.
I am currently digging online and through tracelogs to try and find what field / parameter I am missing in the BO Method Calls in the BPM.
The couple things I found and verified are correct already so far are that the “InventoryTrans” field is TRUE, and the “TranClass” field is “I” which both match the transactions done through the base epicor form for Mass Issue and Mass Return. So I have ruled these two fields out of the solution for now.
It’s hard to say from the screenshot and your descriptions alone.
I’m thinking we would need to see a combination of your BPM code and PartTran records to get the full picture.
Part Transaction History Tracker is driven off of PartTran data. As a starting point, you should probably review your PartTran records to compare those generated by your BPM vs those from manual Issue/Return commands.
Understood. I have begun first by looking at the PartTran entries as you’ve suggested, the only differences I see are:
“ExtCost” fields (not populated / =0.00 on my custom transactions versus the expected $amt on the base epicor transactions),
Here is the BPM Code (NOTE This is still a Work In Progress! ):
//Set the transaction scope variable txScope, which completes at the end of the code and ensures the execution and final termination of this transaction.
using (var txScope = Erp.ErpContext.CreateDefaultTransactionScope())
{
bool isReturn = callContextBpmData.Checkbox01;
//callContextBpmData.Checkbox01 = false;
//Loop through each updated JobHead row (in order to handle jobs created and released via wizard, when its more than 1 job).
foreach (var ttjhRow in ttJobHead.Where(r => r.RowMod != "")) {
string company = ttjhRow.Company;
string jobNum = ttjhRow.JobNum;
//Create the Mass Issue to MFG BO Service Contract. "using (...){...}" to ensure termination of code block upon Dispose().
using (var massIssue = ServiceRenderer.GetService<Erp.Contracts.MassIssueToMfgSvcContract>(Db)) {
//Use try {} catch {} to handle any exceptions (errors).
try {
//Get JobHead row from Database using company and jobNum set above.
var job = Db.JobHead.Where(jhRow => jhRow.Company == company && jhRow.JobNum == jobNum).FirstOrDefault();
//Create parameter variables that will be fed to the BO Methods below.
string ipSysRowId = Convert.ToString(job.SysRowID);
string pcMessage;
string pcQuestion;
string pcError;
System.Collections.Hashtable htPrePerform = new System.Collections.Hashtable();
DateTime tranDate = DateTime.Today;
//Create MassIssueInputTableset.
Erp.Tablesets.MassIssueInputTableset massIssueInputTs = new Erp.Tablesets.MassIssueInputTableset();
//Call GetNewMassIssueInput() BO method. Feed the Tableset created above as parameter 1.
//Parameter 2 "isReturn" set to False to indicate that this new Mass Issue is NOT a return, and True to indicate that this IS a return.
massIssue.GetNewMassIssueInput(ref massIssueInputTs, isReturn);
//Call OnChangeJobNum() BO method. Feed JobNum to parameter 1.
//Feed MassIssueInputTableset with "ref" keyword to parameter 2.
massIssue.OnChangeJobNum(jobNum, ref massIssueInputTs);
//Referencing ROW 0 ("[0]") of the MassIssueInput table in the MassIssueInputTableset:
//Set "IncludeSubassemblies" (true OR false per your need).
//Set RowMod = "U" for Updated.
if (isReturn) massIssueInputTs.MassIssueInput[0].IsReturn = true;
//massIssueInputTs.MassIssueInput[0].SysRowID = job.SysRowID;
massIssueInputTs.MassIssueInput[0].IncludeSubassemblies = true;
massIssueInputTs.MassIssueInput[0].RowMod = "U";
//Create the MassIssueToMfg Tableset with the data returned from the BuildMassIssueBrowse() method.
//Feed MassIssueInputTableset to parameter 1 with "ref" keyword.
//Feeds SysRowId from "[0]" row in MassIssueInputTableset.MassIssueInput table above to parameter 2.
//Feed "pcMessage" (blank string) to parameter 3 with "out" keyword.
Erp.Tablesets.MassIssueToMfgTableset massIssueToMfgTs = massIssue.BuildMassIssueBrowse(ref massIssueInputTs, Convert.ToString(massIssueInputTs.MassIssueInput[0].SysRowID), out pcMessage);
//Loop through rows existing in MassIssueToMfgTableset.MassIssue table:
//Set RowMod = "U" on any rows where current OnHandQty exists for PartNum to issue.
foreach (var row in massIssueToMfgTs.MassIssue)
{
//***if() statement below checking OnHandQty negative or 0.***
//***"continue;" will exit the loop and therefore not update those rows.***
//if ((decimal)row["StockQty"] <= 0) continue;
//Uncomment the above if() statement if you want to NOT ISSUE when OnHandQty <= 0.
row.RowMod = "U";
}
string sysTranTypeID = isReturn ? "WIPStock" : "StockWIP";
string availTypes = "";
massIssue.GetAvailTranDocTypes(sysTranTypeID, out availTypes);
//Call the IssueAll() BO method:
//Feed string "Open" to the "pcView" parameter 1 to indicate that the IssueAll() method will execute on open materials in this BOM.
//Feed the MassIssueToMfgTableset from above to parameter 2 with "ref" keyword.
string pcView = "Open";
if (isReturn) pcView = "ALL";
massIssue.IssueAll(pcView, ref massIssueToMfgTs);
//Create hasTrans boolean variable as False. (Used below as a check to exit method).
bool hasTrans = false;
//Loop through MassIssueToMfgTableset.MassIssue table:
//Set fields and RowMod on rows (representing materials) to Issue.
foreach (var row in massIssueToMfgTs.MassIssue)
{
//***The if() statement below will exit the loop and disregard materials with nothing left to issue. This prevents an exception/error in these cases.***
if ((decimal)row["ThisTransaction"] <= 0) continue;
row.IsReturn = isReturn;
row.OKToIssue = true;
row.JustQtyIssued = row.ThisTransaction;
row.RowMod = "U";
hasTrans = true;
}
//If nothing to issue - leave method;
if (!hasTrans) return; //&& !isReturn) return;
//Call NegativeStockCheck() BO Method:
//Feed JobNum to parameter 1.
//Feed MassIssueToMfgTableset to parameter 2 with "ref" keyword.
//Feed pcQuestion and pcError (blank strings) to parameter 3 and 4 respectively with "out" keyword.
massIssue.NegativeStockCheck(jobNum, ref massIssueToMfgTs, out pcQuestion, out pcError);
/*
//setup message box parameters: mbp
var s1 = "pcQuestion: " + pcQuestion + " / pcError: " + pcError; // text to appear on popup
var s2 = Ice.Common.BusinessObjectMessageType.Information; //req'd don't change
var s3 = Ice.Bpm.InfoMessageDisplayMode.Individual; //req'd don't change
var s4 = "JobHead Standard Data Directive"; // text that appears in popup Details button ->program field
var s5 = "In attempt to MassIssueToMfg PrevWageJob"; // text that appears in popup Details button ->method field
//call popup message
this.PublishInfoMessage(s1, s2, s3, s4, s5);
*/
//Set AbleToIssue & rowMod on any rows where qty exists in-stock to issue;
foreach (var row in massIssueToMfgTs.MassIssue)
{
//The if() statement below will exit the loop if qty in stock <= 0.
//if ((decimal)row.JustQtyIssued <= 0) continue;
if (!isReturn) {
row.TranReference = "PrevWageJob Mass Issued by manager.";
} else {
row.TranReference = "PrevWageJob Mass Returned by manager.";
}
row.AbleToIssue = true;
row.RowMod = "U";
}
if(isReturn) {
string ipTranDocType = "";
string ipSysTranType = "WIPStock";
bool requireUserInput = false;
//Call PrePerformMassIssue() BO Method:
massIssue.PrePerformMassIssue(tranDate,ipTranDocType,ipSysTranType,ref massIssueToMfgTs, out requireUserInput);
} else {
//Call PrePerformMassIssueHT() BO Method:
//Feed MassIssueToMfgTableset to parameter 1 with "ref" keyword.
//Feed empty Hashtable to parameter 2 with "ref" keyword.
massIssue.PrePerformMassIssueHT(ref massIssueToMfgTs, ref htPrePerform);
}
//Call PerformMassIssue() BO Method:
//Feed JobNum to parameter 1.
//Feed TranDate (today) to parameter 2.
//"piCallNum" as parameter 3 = 0.
//"piMaterialComplete" as parameter 4 = false.
//"piNegStockCheckContinue" as parameter 5 = true.
//Feed MassIssueToMfgTableset to parameter 6 with "ref" keyword.
//Feed pcMessage blank string to parameter 7 with "out" keyword.
massIssue.PerformMassIssue(jobNum, tranDate, 0, false, true, ref massIssueToMfgTs, out pcMessage);
}
catch (Exception e) {
string msg = e.Message.ToString();
//setup message box parameters: mbp
var mbp1 = msg; // text to appear on popup
var mbp2 = Ice.Common.BusinessObjectMessageType.Information; //req'd don't change
var mbp3 = Ice.Bpm.InfoMessageDisplayMode.Individual; //req'd don't change
var mbp4 = "JobHead Standard Data Directive"; // text that appears in popup Details button ->program field
var mbp5 = "In attempt to MassIssueToMfg PrevWageJob"; // text that appears in popup Details button ->method field
msg = mbp4 + "\n" + mbp5 + "\n" + mbp1;
//write error to server event viewer (Epicor App Server).
Ice.Diagnostics.Log.WriteEntry(msg);
//call popup message
this.PublishInfoMessage(mbp1, mbp2, mbp3, mbp4, mbp5);
}
//Dispose of the MassIssueToMfg BO service contract, ending the execution of this block of code.
massIssue.Dispose();
}
}
//Complete and dispose of the Transaction Scope to end the execution of this transaction.
txScope.Complete();
txScope.Dispose();
}
And the Part Tran Hist tracker (blue underline are the epi base issues/returns showing amount properly:
The Running Total quantities appear to be correct. For example, the most recent transaction: Start with 29,195.64… Issue 232.81 to a job from stock… you have 28,962.83 remaining.
As for the Extended Costs… I’m not sure yet but I would imagine there’s some missing method call or parameter.
I also should note that I learned that the Running Total field is calculated off the On Hand Qty so its really the effect on the OnHandQty that I am focused on, if I can fix that then the running total should follow correctly.
The running totals you are seeing are deceiving-- they ALL go up (including the PAST trans), so what you’re seeing now is like a couple 1,000 more than what it started with. Every time I Issue and Return as a test, the on hand qty goes up and the running total for ALL the trans goes up.
My gut instinct is that the Amount fields not calculating (ExtCost not calculating on the PartTran) and the issue with the Running Total calculation/On Hand Qty are related somehow.
I’ll do my best to answer that about the single row:
That first table Row [0] is only used to feed as a parameter into the “BuildMassIssueBrowse” method which builds and returns the MassIssueToMfgTableset, which is in turn the actual tableset with all of the rows for mtls that is used in the IssueAll and PerformMassIssue methods later.
At least this is how I understand it and how I’ve seen any other code examples of this type of BPM.
It seems to be like a single “header row” essentially for beginning the MassIssue process. It tells the buildmassissuebrowse method that its going to include subassemblies and whether it is a return or not.