BPM Needby Automatically - working days

i have a formula for that in either a customization or a bpm…you could make either work, but it assumes working days are Mon-Fri… let me know if that works for you. Working days for everyone isn’'t always a straight foward answer and could get hairy if your’s aren’t consistent and you have to do look ups to your calendars for exceptions etc

My working days is monday to friday.

OK… to EXCLUDE HOLIDAYS, here is snippet of C# code that you can insert anywhere you need (BPM, etc)…
It calculates using one of the Epicor Calendars. It still assumes that Saturday and Sunday are non-work days, but it removes any holidays that are declared in the Shop Calendar you have specified.
I borrowed much of the logic from multiple sources on the internet, but also had to create my own little logic to use the Epicor calendar. Note that if you feed a starting date that is a weekend, it automatically moves it to the next working date.
While it seems odd to have to loop to do this calculation, I found no other clean way to do it… I did put some timers on this initially, and even when counting 1000s of days, the routine below only took a very brief number of milliseconds.

// Calculate Promise Date
// inputs:
// LeadTime = the lead DAYS you want to calculate
// StartingDate = the date you want to start counting form
// Outputs:
// pd = Promise date
//

string CalendarToUse = “Shipping” //change this to the epicor calendar you want to calculate against

DateTime pd = StartingDate ?? DateTime.Today; //promise date
bool WorkDay=true;
int RemainingDays = LeadTime+1; //add one to the leadtime
pd = pd.AddDays(-1); //make it yesterday

while (RemainingDays>0)
{
if (pd.DayOfWeek == DayOfWeek.Friday) pd=pd.AddDays(3);
else if (pd.DayOfWeek == DayOfWeek.Saturday) pd=pd.AddDays(2);
else if (pd.DayOfWeek == DayOfWeek.Sunday) pd=pd.AddDays(1);
else pd=pd.AddDays(1);

//now make sure that we are not on a holiday
var Holiday = Db.ProdCalDay.Where(r => r.CalendarID == CalendarToUse && r.ModifiedDay == pd).Select( row => new {row.ModifiedDay, row.WorkingDay} ).FirstOrDefault();
WorkDay = (Holiday == null)|| Holiday.WorkingDay; // WorkDay = true; else WorkDay=false;

if (WorkDay) RemainingDays -=1;
Inputs.ErrorText.Value +=string.Format("point1: {0} {1} {2}\n",pd,RemainingDays,(WorkDay)?"":"Holiday");
}
1 Like

I receive and error message, for this line : Inputs.ErrorText.Value +=string.Format(“point1: {0} {1} {2}\n”,pd,RemainingDays,(WorkDay)?"":“Holiday”);

and my error message is :
The name inputs does not exist in the current context

Tim is a great Product Configurator programmer and the Inputs is a text field that he’s assigning the error message to. You can change this to a string that gets displayed in your BPM.

Mark W.

I have an other questions for this code.

For this string, you add friday for what ? Me I work from monday to friday. do I need to add the friday?
if (pd.DayOfWeek == DayOfWeek.Friday) pd=pd.AddDays(3);
else if (pd.DayOfWeek == DayOfWeek.Saturday) pd=pd.AddDays(2);
else if (pd.DayOfWeek == DayOfWeek.Sunday) pd=pd.AddDays(1);
else pd=pd.AddDays(1);

the code is determining the day of the week and if it’s a friday it adds 3 days to the running total, two from saturday etc… to get you to the following monday. It’s in a loop and will do this until it arrives to the shipdate. There are several ways to approach what you are doing, but like Tim said, a loop of some sort is the most effective manner to get this done. You could also do (pseudo logic) while day of the week not sat/sun : count.

1 Like

In my production calendar, I entered my holiday. But my code doesn’t take into my holiday in my calendar. In the production calendar, I entered on my toggle day, Holiday.

//now make sure that we are not on a holiday
var Holiday = Db.ProdCalDay.Where(r => r.CalendarID == CalendarToUse && r.ModifiedDay == pd).Select( row => new {row.ModifiedDay, row.WorkingDay} ).FirstOrDefault();
WorkDay = (Holiday == null)|| Holiday.WorkingDay;
if (WorkDay) RemainingDays -=1;
vMessage =string.Format(“point1: {0} {1} {2}\n”,pd,RemainingDays,(WorkDay)?"":“Holiday”);

Have you modified the variable “CalendarToUse” to be the code of your calendar?

for this customer, they always have at least ONE day… so if we are starting on a friday, I know that i need to bump to monday. I am just trying to prevent looping through two extra times.

Yes, I did that, in the variable I indicate my calendar : string CalendarToUse = “EVE01” . But it does not take into consider my holidays

And, you added the holidays into EVE01? The code that I produced did work… it looked through the specified calendar to and skipped holidays as it scrolled through the dates.

in your calendar, the toggle day, what did you enter as name ? My I entered the name Holiday
Thanks.

image

Hmm… i named it the day of the holiday… but the code doesnt care, it simply is looking to see if it exists.

What’s Up Gang! Here’s what I got. So you set the date you would like and then it will check if its Weekend or Holiday based on your Calendar and give you additional days… If I say Saturday it will return Monday as my next valid date or possibly even Tuesday if Monday is a Holiday.

The Benefit is what If Saturday is a Work Day for you or what If you make both Weekends a Work Day for 3 weeks… It will account for that as well. Instead of checking DayOfWeek it checks your settings in your calendar.

// Initialize Variables
DateTime? newDate = DateTime.Now;
bool validDateFound = false;
const string calendarName = "MAIN";

// Assign Due Date to Global Var this is the date we start our iteration checking from
newDate = tqhRow.DueDate;

// Get Production Calendar Row
var prodCalRow =
	(from row in Db.ProdCal.With(LockHint.NoLock)
	 where row.Company == Session.CompanyID && row.CalendarID == calendarName
	 select row
	).FirstOrDefault();


if (prodCalRow != null)
{

	while (validDateFound == false)
	{
		// Let's Check if this Date falls under a Holiday or Exception Non-Working Day
		bool prodCalDayRow =
			(from row in Db.ProdCalDay
			 where row.CalendarID == calendarName && row.ModifiedDay == newDate && row.WorkingDay == false
			 select row
			).Any();

		// No Holiday or special Non-Working Day Exception Found
		// Let us check if the day is simply a Workin Day in the Work Week
		if (prodCalDayRow == false)
		{
			// Epicors Sunday is WorkWeek1 and Saturday WorkWeek7
			// In .NET it is 0 through 6 - so let us always + 1
			int newWorkWeek = ((int)newDate.Value.DayOfWeek) + 1;

			if (Convert.ToBoolean(prodCalRow["WorkWeek" + newWorkWeek]) == true)
			{
				validDateFound = true;
			}

		}

		// Either we hit a Holiday or the day is not a Working Day
		// Let us continue to the next day if that is the case
		if (validDateFound == false)
		{
			newDate = newDate.Value.AddDays(1);
			Ice.Diagnostics.Log.WriteEntry(String.Format("[ {0} ] No Valid Date Found - Increment by +1 Day...", bpmName));
		}

	}
}

// Assign New Due Date
tqhRow["Date02"] = newDate; // Our Permanent Due Date Placeholder
tqhRow.DueDate = newDate;
7 Likes

I’m trying to use Haso’s code for a BPM that sets a specific quote task to +2 working days.

@Haso - I’m getting the following errors. What is tqhRow? Do I declare a variable called ‘tqhRow’? Replace ‘tqhRow’ with ‘ttTask’?
image

I tried creating a tqhRow variable in the variables tab and setting it to int, but then that errors too.

Also, is the ‘bpmName’ at the end supposed to be replaced with my bpm name in quotes (hard coded), or is it supposed to pick it up from the bpm automatically?

Since this thread is 3 years old, and we’re now on 10.2.700 instead of 10.1.500, would other changes apply?

Ultimately I’ll see if I can add this into a function, and then use for other BPM’s with inputs set in the BPM…

Thanks for helping me learn, guys!

The ideal way to do this now is to create a new Epicor Function, which you could call from your BPM. This way, you can reuse the calculation for other purposes.
As a very early exercise with Epicor functions, i did do this as a test, and I was successful.

3 Likes

I used his code in 10.2.400, but I don’t have it with me anymore. :frowning: Maybe @hkeric.wci can clarify the tqhrow.

I’m looking for help on this as well. Where do you set this up, pre-processing, base processing, or post-processing? Is this during the Update process? Also, I have multiple calendars depending on which operations are being used based on the Group Code. E.g. If I use a group code that starts with a certain set of letters, the operations that are used during those processes use a different calendar than the other group codes. How would I account for that? Any help would be greatly appreciated!

I don’t have this code anymore, but @jdewitt6029 might be able to find it for you if he is available.