As @Mark_Wonsil always says I would highly recommend you write a function that will take the 2 or 3 parameters you actually need and do the Issue Return from there server side thus abstracting the complexity.
Abstracting complex logic into a server-side function has several advantages over directly hitting complex endpoints from the client:
- Simplified Client Code: By abstracting the logic, your client code becomes much simpler. You can encapsulate all the intricate details and business rules on the server side, leaving the client with a clean, straightforward interface.
- Centralized Error Handling: Handling errors and exceptions can be more effectively managed in a centralized location on the server. This ensures consistent error responses and simplifies debugging and maintenance.
- Enhanced Security: By reducing the exposure of complex endpoints and business logic, you minimize the risk of security vulnerabilities. The client only interacts with a well-defined and narrow interface, reducing the attack surface. Specially if you use Acess Scope
- Maintainability: Changes to business logic or workflows can be made on the server without requiring updates to the client code. This makes it easier to maintain and evolve the application.
- Performance Optimization: Server-side functions are faster because all the complex logic already happens server side. Any additional BO calls etc don’t have to stand up and break down a TCP Stack or a Db Connection.
- Data Integrity: Ensuring data integrity and consistency is easier when managed on the server. You can enforce validation rules, transactional integrity, and other critical business rules more effectively.
I have a function that does this already, see below:
Library | Function ID |
---|---|
MtlFunctions | IssueMaterial |
Request Parameters
Parameter Name | type |
---|---|
JobNum | String |
AsmSeq | Int |
MtlSeq | Int |
PCID | String |
PartNum | String |
LotNum | String |
Qty | Decimal |
BinNum | String |
Output Parameters
Parameter Name | type | Remarks |
---|---|---|
Success | Boolean | |
InfoMessage | String | |
ErrorMessage | String |
Functionality:
StringBuilder myInfo = new StringBuilder();
try
{
this.CallService<Erp.Contracts.IssueReturnSvcContract>(ir =>{
Erp.Tablesets.SelectedJobAsmblTableset asmDS = new Erp.Tablesets.SelectedJobAsmblTableset();
SelectedJobAsmblRow asmDSRow = (SelectedJobAsmblRow)asmDS.SelectedJobAsmbl.NewRow();
asmDSRow.Company = this.Session.CompanyID;
asmDSRow.JobNum = this.JobNum;
asmDSRow.AssemblySeq = this.AsmSeq;
asmDSRow.RowMod = "A";
asmDS.SelectedJobAsmbl.Add(asmDSRow);
string callProcess = "IssueMaterial";
string message;
IssueReturnTableset issueReturnDS = ir.GetNewJobAsmblMultiple("STK-MTL", Guid.Empty, callProcess, ref asmDS, out message);
var myRow = issueReturnDS.IssueReturn.FirstOrDefault();
myRow.RowMod = "U";
string pcMessage;
ir.OnChangeToJobNum(ref issueReturnDS, callProcess, out pcMessage);
myRow.RowMod = "U";
ir.OnChangeToAssemblySeq(ref issueReturnDS, callProcess);
myRow.RowMod = "U";
myRow.ToJobSeq = this.MtlSeq;
ir.OnChangingToJobSeq(this.MtlSeq, ref issueReturnDS);
myRow.RowMod = "U";
ir.OnChangeToJobSeq(ref issueReturnDS, callProcess, out message);
if (string.IsNullOrEmpty(this.PCID))
{
myRow.PartNum = this.PartNum;
myRow.RowMod = "U";
ir.OnChangePartNum(ref issueReturnDS, callProcess);
myRow.RowMod = "U";
ir.OnChangeLotNum(this.LotNum, ref issueReturnDS);
myRow.RowMod = "U";
myRow.FromBinNum = this.BinNum;
ir.OnChangingFromBinNum(ref issueReturnDS, out message);
ir.OnChangeFromBinNum(ref issueReturnDS);
}
else
{
myRow.RowMod = "U";
string questionMsg;
ir.OnChangeFromPCID(this.PCID, false, false, callProcess, out questionMsg, ref issueReturnDS, out message);
}
myRow.RowMod = "U";
ir.OnChangeTranQty(this.Qty, ref issueReturnDS);
bool requiredUserInput;
myRow.TranReference = "Issued via Job-Mat web app";
ir.PrePerformMaterialMovement(ref issueReturnDS, out requiredUserInput);
string NeqQtyAction;
string NeqQtyMessage;
string PCBinAction;
string PCBinMessage;
string OutBinAction;
string OutBinMessage;
ir.MasterInventoryBinTests(ref issueReturnDS, out NeqQtyAction, out NeqQtyMessage, out PCBinAction, out PCBinMessage, out OutBinAction, out OutBinMessage);
bool NegQtyAction = false;
string legalNumberMessage;
string partTrakPKs;
ir.PerformMaterialMovement(NegQtyAction, ref issueReturnDS, out legalNumberMessage, out partTrakPKs);
myInfo.Append($"{this.PartNum} issued to job {this.JobNum}");
Success = true;
InfoMessage = myInfo.ToString();
});
}
catch (Exception ex)
{
Success = false;
InfoMessage = myInfo.ToString();
ErrorMessage = ex.ToString();
}
finally
{
var Dbcontext = Ice.Services.ContextFactory.CreateContext<ErpContext>();
Erp.Internal.Lib.ErpCallContext.Add("PBOnHand-Post",""); // PartBin
Erp.Internal.Lib.ErpCallContext.Add("PQDemand-Post",""); // Part Quantity
Erp.Internal.Lib.ErpCallContext.Add("PLOnHand-Post",""); // Part Lot
Erp.Internal.Lib.DeferredUpdate libDeferredUpdate = new Erp.Internal.Lib.DeferredUpdate(Dbcontext);
libDeferredUpdate.UpdPQDemand();
Erp.Internal.Lib.ErpCallContext.RemoveValue("PBOnHand-Post");
Erp.Internal.Lib.ErpCallContext.RemoveValue("PQDemand-Post");
Erp.Internal.Lib.ErpCallContext.RemoveValue("PLOnHand-Post");
}