Epicor 10 Linking a BAQ in BPM Workflow Designer (Avoiding Custom Code) - erp

Currently I have been tasked with reviewing a BPM created by Epicor that is not functioning as expected. Currently with the BPM based on the code below its purpose is to reference orders in the system and when its time to ship the orders if there is a price change the order/part will reflect a new price. It seems that the code is causing incorrect price lists to be retrieved from customers not expected. For example a price list is attached to customer #1242 but its updating the price based on customer #1269. (Guessing they share a common part # and the code retrieves the latest value)
Now my problem is I don't have experience in writing code, I have reviewed code before but to a small extent and from what I listed above that was provided to me. Now what I thought may be an easier practice for me to understand is create a BAQ and reference that in the BPM and utilize the BAQ as a reference for the BPM to update prices.
With researching a few forums and Epicors training material I haven't found a definitive answer on how to link a BAQ in a BPM.
(Also if my description makes sense and the code reflects the issue feel free take a guess)
BPM Code:
var ttShipHead_xRow = (from ttShipHead_Row in ttShipHead
where ttShipHead_Row.ReadyToInvoice == true
select ttShipHead_Row).FirstOrDefault();
if (ttShipHead_xRow != null)
{
foreach (var ShipDtl_iterator in (from ShipDtl_Row in Db.ShipDtl
where ttShipHead_xRow.PackNum == ShipDtl_Row.PackNum
&& ttShipHead_xRow.Company == ShipDtl_Row.Company
select ShipDtl_Row))
{
var ShipDtl_xRow = ShipDtl_iterator;
//ShipDtl_xRow.UnitPrice = 1;
var today = DateTime.Today;
var PriceList_xRow = (from PriceLst_Row in Db.PriceLst
from PriceLstParts_Row in Db.PriceLstParts
where ShipDtl_xRow.PartNum == PriceLstParts_Row.PartNum
&& PriceLst_Row.ListCode == PriceLstParts_Row.ListCode
&& PriceLst_Row.Company == PriceLstParts_Row.Company
&& PriceLst_Row.Company == ShipDtl_xRow.Company
&& PriceLst_Row.EndDate >= today
select PriceLstParts_Row).FirstOrDefault();
if (PriceList_xRow != null)
{
var OrderDtl_xRow = (from OrderDtl_Row in Db.OrderDtl
where ShipDtl_xRow.OrderLine == OrderDtl_Row.OrderLine
&& ShipDtl_xRow.PartNum == OrderDtl_Row.PartNum
&& ShipDtl_xRow.OrderNum == OrderDtl_Row.OrderNum
&& ShipDtl_xRow.Company == OrderDtl_Row.Company
select OrderDtl_Row).FirstOrDefault();
{
if (OrderDtl_xRow != null)
{
if (ShipDtl_xRow.UnitPrice != PriceList_xRow.BasePrice)
{
ShipDtl_xRow.UnitPrice = PriceList_xRow.BasePrice;
}
if (ShipDtl_xRow.UnitPrice != OrderDtl_xRow.UnitPrice)
{
OrderDtl_xRow.DocUnitPrice = PriceList_xRow.BasePrice;
OrderDtl_xRow.UnitPrice = PriceList_xRow.BasePrice;
}
}
}
}
}
}

I resolved the code but still could not determine a valid method to link a BAQ in the BPM
The problem was the following code was missing:
&& ttShipHead_xRow.CustNum == ShipDtl_Row. CustNum
to the first foreach statement.

Related

How can I ensure Random function does not refresh and present another Form until the First Form presented gets worked by individual?

I have created a function to audit all Chats that were entered using WebApp. WebApp is created using ASP.Net MVC.
The functions works great, and does present a random Chat entered in WebApp last week.
However, the issue I can see is that if an Auditor opens a Chat, but by refreshing the page the previous Chat Audit gets replaced with a new One.
How can I ensure Auditor refreshing or doing any action the same Chat Audit Form stays or gets presented to auditor, and he cannot proceed unless he completes the Audit.
This is my Action Created
public ActionResult Feedback()
{
var mostRecentMonday = DateTime.Now.AddDays(-7).StartOfWeek(DayOfWeek.Monday);
var weekEnd = mostRecentMonday.AddDays(7).AddSeconds(-1); //will return the end of the day on Sunday
using (Db db = new Db())
{
var uName = User.Identity.Name;
//int total = db.Chats.Where(x => x.ChatCreateDateTime >= mostRecentMonday && x.ChatCreateDateTime <= weekEnd && x.Feedback == null).ToArray().ToList().Count();
var result = db.Chats.Where(x => x.ChatCreateDateTime >= mostRecentMonday && x.ChatCreateDateTime <= weekEnd && x.Feedback == null && x.Username != uName).OrderBy(x => Guid.NewGuid()).FirstOrDefault();
result.Scenarios = new SelectList(db.Scenarios.ToList(), "ScenarioId", "ScenarioList");
return View(result);
}
}
Help is very much appreciated

Empty FullText property with Tweetmode.Extended [update May 30th]

I'm programming a .Net Core (2.1 preview, C# 7.3) Streaming Console App with L2T (5.0.0 beta 2) but even with the strm.TweetMode == TweetMode.Extended the query gives "compat" tweets back, the FullText property is empty.
You can reproduce this with the L2T query below.
I searched online, I've found something similar (with 'search' instead of 'Streaming') but no answers, except to add && strm.TweetMode == TweetMode.Extended, which I did.
Any ideas?
try
{
await
(from strm in twitterCtx.Streaming
.WithCancellation(cancelTokenSrc.Token)
where
strm.Type == StreamingType.Filter
&& strm.Track == "twitter"
&& strm.Language == "nl"
&& strm.TweetMode == TweetMode.Extended
select strm)
.StartAsync(async strm =>
{
await HandleStreamResponse(strm);
if (count++ >= 20)
cancelTokenSrc.Cancel();
});
}
[Update May 30th]
Found something. It's in the subroutine "HandleStreamResponse" (code below). The Status.TweetMode and Status.ExtendedTweet.TweetMode both return "Compat" for all tweets, but the full text of a tweet is in status.ExtendedTweet.FullText
But even with this check, retweets are truncated to 140 chars max. I do not need retweets for my progam so I filter them out.
I do not know, yet, how to filter retweets from a stream directly (is it possible?), so I check the retweetstatus of the Status from the stream result. It's in the code below.
FYI: In the examples of Linq To Twitter for this subroutine Joe Mayo uses the following line of code, but that doesn't work: Console.WriteLine("{0}: {1} {2}", status.StatusID, status.User.ScreenNameResponse, status.Text ?? status.FullText);
Even with && strm.TweetMode == TweetMode.Extended in the L2T query, the status.FullText is empty.
There is more code than neccesary in the example below, but I used it for clarity.
static async Task<int> HandleStreamResponse(StreamContent strm)
{
switch (strm.EntityType)
{
case StreamEntityType.Status:
var status = strm.Entity as Status;
if (status.RetweetedStatus.StatusID == 0)
{
if (status.ExtendedTweet.FullText != null)
{
Console.WriteLine("Longer than 140 - \"#{0}\": {1} (TweetMode:{2})",
status.User.ScreenNameResponse, status.ExtendedTweet.FullText, status.TweetMode);
}
else
{
Console.WriteLine("Shorter than 140 - \"#{0}\": {1} (TweetMode:{2})",
status.User.ScreenNameResponse, status.Text, status.TweetMode);
}
}
// Console.WriteLine("{0}: {1} {2}", status.StatusID, status.User.ScreenNameResponse, status.Text ?? status.FullText);
break;
default:
Console.WriteLine("Unknown - " + strm.Content + "\n");
break;
}
return await Task.FromResult(0);
}
}
Here are my observations:
status.ExtentendedTweet.FullText should hold the tweet in normal circumstances.
However, if the tweet is retweeted, then status.RetweetedStatus.ExtendedTweet.FullText should hold the tweet.
If you can't find the FullText in either of those circumstances, use status.Text.
I'm updating the sample with the following:
case StreamEntityType.Status:
var status = strm.Entity as Status;
string text = null;
if (status.ExtendedTweet?.FullText != null)
text = status.ExtendedTweet?.FullText;
else if (status.RetweetedStatus?.ExtendedTweet?.FullText != null)
text = status.RetweetedStatus?.ExtendedTweet?.FullText;
else
text = status.Text;
Console.WriteLine("Status - #{0}: {1}", status.User.ScreenNameResponse, text);
break;
Note: Via Twitter documentation (see Standard Streams), TweetMode doesn't apply to streams. Additionally, the docs say the ExtentedTweet should always be there with FullText. As we can see, that isn't the full picture in practice. I'll mark Streaming.TweetMode as obsolete in upcoming releases.

Inability to display image after deployment to Azure server but works in localhost

I am having difficulty displaying images after deploying to Azure.
I am currently developing my application on ASP.NET MVC 5.
My methodology is for admin to upload a particular image, which would be accessible by users. The image is to be uploaded into a folder.
The issue is that I am able to get the image upload and displaying to work in my own localhost. However, it failed to work when I publish my app to Azure.
I have tried with many of the suggestions found in stackoverflow.
E.g. Changing the Permission settings in the folder, but up to no avail.
I have attached my code for reference. I appreciate any help! =D
Controller (file upload):
if (file != null && file.ContentLength > 0)
try
{
string path = Path.Combine(Server.MapPath("~/ExerciseImagesDepository"),
Path.GetFileName(file.FileName));
file.SaveAs(path);
ExerciseImage eI = new ExerciseImage();
eI.ExerciseID = ex.ExerciseID;
eI.ImageURL = Path.GetFileName(file.FileName);
db.ExerciseImages.Add(eI);
db.SaveChanges();
}
catch (Exception exc)
{
ViewBag.FileUploadErrorMessage = "ERROR:" + exc.Message.ToString();
}
Controller (Details display)
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
List<ExerciseViewModel> evmLIst = new List<ExerciseViewModel>();
int a = 0;
List<Exercise> exercise = db.Exercises.ToList();
foreach (var item in exercise)
{
ExerciseViewModel evm = new ExerciseViewModel();
a = a + 1;
evm.ExerciseViewModelID = a;
evm.ExerciseRegion = db.ExerciseRegions.Find(item.ExerciseRegionID);
evm.ExerciseDescription = item.Description;
evm.ExerciseType = db.ExerciseTypes.Find(item.ExerciseTypeID);
int ExerciseID = item.ExerciseID;
ExerciseVideo ev = db.ExerciseVideos.Where(m => m.ExerciseID == ExerciseID).SingleOrDefault();
evm.VideoURL = ev.VideoURL;
ExerciseImage ei = db.ExerciseImages.Where(m => m.ExerciseID == id).SingleOrDefault();
if (ei != null)
{
evm.ImageURL = ei.ImageURL;
}
else
{
evm.ImageURL = "No Image Is Available For This Exercise";
}
evm.Exercise = item.Name;
evmLIst.Add(evm);
}
View
<div>
<p> TESTING HERE #Html.Raw(Model.ImageURL) </p>
<img src="~/ExerciseImagesDepository/#Html.Raw(Model.ImageURL)"/>
Folder Structure:
I solve it! I figured that perhaps folder that are not default in the MVC 5 framework might be causing the issue. So instead, I created a new folder within the content directory and added a folder inside. Next, I tried changing that particular folder permission settings by adding a group or usernames "IUSR" and allowing full control. I then published the particular folder specifically to Azure and it works. Although I have no idea why I manage to do it.

Entity Framework 5 installation verification

I have an ASP.NET MVC 3 project using .NET framework 4.0 and LINQ to SQL. Because I have serious problems of performance with some queries the first time they are executed I decided to use Entity Framework 5 in order to take advantage of the new LINQ auto compiled feature.
Now I have installed VS 2012, .NET framework 4.5 and Entity Framework 5 and changed my project to point to the .NET framework 4.5 as well as updated my Data Context file to use EF5. The queries now have exactly the same performance, some of them are so slow at the first time execution that even I get a time out exception, the second time everything is fine, I am wondering if the problem is that maybe the migration process was not correct and I am using still the EF4 or it is just a problem of my query construction which can't use the auto compiled feature for an unknown reason.
The EntityFramework dll has the 5.0 version, and the System.Data.Entity dll the version 4, that is right, isn't? Any suggestions?
I include the most problematic query, it retrieves paginated the result for a grid (Telerik MVC grid) which I need to build through 2 queries (originally was a SQL sentence with a sub query):
/// <summary>
/// Get the elements for the AppLog grid.
/// </summary>
public void GetAppLogElements(
int clientID, string language, int functionID, int errorLevel,
int numPage, int pageSize, IList<IFilterDescriptor> filterDescriptors, IList<SortDescriptor> sortDescriptors, IList<GroupDescriptor> groupDescriptors,
ref IQueryable<Model_AppLog> rows, ref int numRows)
{
string orderString = string.Empty;
var items =
from ap in objDataContext.applicationLogs
where
ap.clientID == clientID &&
ap.recordGroup != null
join alf in objDataContext.appLogFunctions on
new { functionID = ap.functionID.Value } equals new { functionID = alf.functionID }
join ale in objDataContext.appLogErrorLevels on
new { errorLevel = ap.errorLevel.Value } equals new { errorLevel = ale.errorLevelID }
join als in objDataContext.appLogSeverities on
new { severity = ap.severity.Value } equals new { severity = als.severityID }
group new { ap, alf, als } by new { ap.functionID, ap.recordGroup, ap.clerkID } into queryGrouped
select new Model_AppLog()
{
sequence = queryGrouped.Max(c => c.ap.sequence),
functionID = queryGrouped.Key.functionID,
recordGroup = queryGrouped.Key.recordGroup,
clerkID = queryGrouped.Key.clerkID,
date = queryGrouped.Min(c => c.ap.date),
errorLevel = (queryGrouped.Max(c => c.ap.errorLevel) == null || !queryGrouped.Max(c => c.ap.errorLevel).HasValue ? 0 : queryGrouped.Max(c => c.ap.errorLevel)),
severity = queryGrouped.Max(c => c.ap.severity)
};
if (errorLevel != -1)
items = items.Where(column => column.errorLevel >= errorLevel);
var _items =
from subSelect in items
join alf in objDataContext.appLogFunctions on
new { functionID = subSelect.functionID.Value } equals new { functionID = alf.functionID }
join alft in objDataContext.appLogFunctionTexts on
new { alf.functionID, language } equals new { alft.functionID, alft.language }
join ale in objDataContext.appLogErrorLevels on
new { errorLevel = subSelect.errorLevel.Value } equals new { errorLevel = ale.errorLevelID }
join alet in objDataContext.appLogErrorLevelTexts on
new { errorLevelID = subSelect.errorLevel.Value, language } equals new { alet.errorLevelID, alet.language }
join als in objDataContext.appLogSeverities on
new { severity = subSelect.severity.Value } equals new { severity = als.severityID }
join alst in objDataContext.appLogSeverityTexts on
new { als.severityID, language } equals new { alst.severityID, alst.language }
select new Model_AppLog()
{
sequence = subSelect.sequence,
functionID = subSelect.functionID,
recordGroup = subSelect.recordGroup,
clerkID = subSelect.clerkID,
date = subSelect.date,
errorLevel = subSelect.errorLevel,
severity = subSelect.severity,
functionDescription = alft.denotation,
errorLevelDescription = alet.denotation,
severityDescription = alst.denotation
};
//Apply filters
if (filterDescriptors != null && filterDescriptors.Any())
{
_items = _items.Where(ExpressionBuilder.Expression<Model_AppLog>(filterDescriptors));
}
if (functionID != -1)
_items = _items.Where(column => column.functionID == functionID);
//Apply sorting
if (sortDescriptors != null)
{
GlobalMethods objGlobalMethods = new GlobalMethods();
orderString = objGlobalMethods.GetOrderString(sortDescriptors);
}
//Apply ordering
if (orderString != string.Empty)
_items = _items.OrderBy(orderString);
else
_items = _items.OrderByDescending(x => x.date);
//Set total number of rows
numRows = _items.AsEnumerable<Model_AppLog>().Count();
//Get paginated results
_items = _items.Skip(pageSize * (numPage - 1)).Take(pageSize);
//Set data result
rows = _items;
}
Here's a paper about EF performance: MSDN
The most important thing you can do to improve start up time is to precompile your views ( there's a section near the end of the MSDN paper )
If you're using database first, there's a T4 template here you can use.
If you're using code first, there's a project here, although I haven't tried it myself.
Note: when you upgrade your project from .NET 4.0 to .NET 4.5, you have to uninstall the EF NuGet package and reinstall it - there are different version of EF 5 for the different runtimes.

Looking for speedups for A* search

I've got the following working A* code in C#:
static bool AStar(
IGraphNode start,
Func<IGraphNode, bool> check,
out List<IGraphNode> path)
{
// Closed list. Hashset because O(1).
var closed =
new HashSet<IGraphNode>();
// Binary heap which accepts multiple equivalent items.
var frontier =
new MultiHeap<IGraphNode>(
(a, b) =>
{ return Math.Sign(a.TotalDistance - b.TotalDistance); }
);
// Some way to know how many multiple equivalent items there are.
var references =
new Dictionary<IGraphNode, int>();
// Some way to know which parent a graph node has.
var parents =
new Dictionary<IGraphNode, IGraphNode>();
// One new graph node in the frontier,
frontier.Insert(start);
// Count the reference.
references[start] = 1;
IGraphNode current = start;
do
{
do
{
frontier.Get(out current);
// If it's in the closed list or
// there's other instances of it in the frontier,
// and there's still nodes left in the frontier,
// then that's not the best node.
} while (
(closed.Contains(current) ||
(--references[current]) > 0) &&
frontier.Count > 0
);
// If we have run out of options,
if (closed.Contains(current) && frontier.Count == 0)
{
// then there's no path.
path = null;
return false;
}
closed.Add(current);
foreach (var edge in current.Edges)
{
// If there's a chance of a better path
// to this node,
if (!closed.Contains(edge.End))
{
int count;
// If the frontier doesn't contain this node,
if (!references.TryGetValue(edge.End, out count) ||
count == 0)
{
// Initialize it and insert it.
edge.End.PathDistance =
current.PathDistance + edge.Distance;
edge.End.EstimatedDistance = CalcDistance(edge.End);
parents[edge.End] = current;
frontier.Insert(edge.End);
references[edge.End] = 1;
}
else
{
// If this path is better than the existing path,
if (current.PathDistance + edge.Distance <
edge.End.PathDistance)
{
// Use this path.
edge.End.PathDistance = current.PathDistance +
edge.Distance;
parents[edge.End] = current;
frontier.Insert(edge.End);
// Keeping track of multiples equivalent items.
++references[edge.End];
}
}
}
}
} while (!check(current) && frontier.Count > 0);
if (check(current))
{
path = new List<IGraphNode>();
path.Add(current);
while (current.PathDistance != 0)
{
current = parents[current];
path.Add(current);
}
path.Reverse();
return true;
}
// Yep, no path.
path = null;
return false;
}
How do I make it faster? No code samples, please; that's a challenge I've set myself.
Edit: To clarify, I'm looking for any advice, suggestions, links, etc. that apply to A* in general. The code is just an example. I asked for no code samples because they make it too easy to implement the technique(s) being described.
Thanks.
Have you looked at this page or this page yet? They have plenty of helpful optimization tips as well as some great information on A* in general.
Change to using a Random Meldable Queue for the heap structure. Since you wanted a programming challenge, I won't show you how I changed the recursive Meld method to not be recursive. That's the trick to getting speed out of that structure. More info in Gambin's paper "Randomized Meldable Priority Queues" (search on the web for that).

Resources